venkat_glb_creation / scripts /scene_graph_generator.js
Antigravity AI
Initial HF commit
37ed7e4
Raw
History Blame Contribute Delete
11 kB
// Scene Graph Generator
// Converts parsed scene data into a structured scene graph JSON
export class SceneGraphGenerator {
constructor() {
this.nodeIdCounter = 0;
}
generate(sceneData) {
const sceneGraph = {
version: "2.0",
metadata: {
generator: "GLB Generation Engine",
sceneName: sceneData.sceneName || "generated_scene",
timestamp: new Date().toISOString()
},
scene: {
nodes: [],
extensions: {},
extras: {}
},
nodes: [],
meshes: [],
materials: [],
textures: [],
images: [],
lights: [],
cameras: [],
animations: [],
audio: {
ambient: [],
spatial: []
},
physics: {
enabled: false,
gravity: [0, 0, -9.8]
},
extras: {} // Initialize extras at root level
};
const rootNode = this.createNode("Scene", [0, 0, 0], [0, 0, 0], [1, 1, 1]);
sceneGraph.scene.nodes = [rootNode.id];
sceneGraph.nodes.push(rootNode);
this.generateEnvironment(sceneGraph, sceneData);
this.generateGround(sceneGraph, sceneData);
this.generateObjects(sceneGraph, sceneData);
if (sceneData.avatar && sceneData.avatar.present) {
this.generateAvatar(sceneGraph, sceneData);
}
this.generateLighting(sceneGraph, sceneData);
this.generateCamera(sceneGraph, sceneData);
this.generateAudio(sceneGraph, sceneData);
this.generateEffects(sceneGraph, sceneData);
this.generateAnimations(sceneGraph, sceneData);
return sceneGraph;
}
createNode(name, translation = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1], extras = {}) {
const node = {
id: this.nodeIdCounter++,
name: name,
translation: translation,
rotation: rotation,
scale: scale,
children: [],
mesh: null,
camera: null,
light: null,
extensions: {},
extras: extras
};
return node;
}
generateEnvironment(sceneGraph, sceneData) {
const envNode = this.createNode(
`Environment_${sceneData.environment}`,
[0, 0, 0],
[0, 0, 0],
[1, 1, 1],
{
type: "environment",
environment: sceneData.environment,
hdri: sceneData.lighting?.hdri || null,
skybox: sceneData.environment
}
);
sceneGraph.nodes[0].children.push(envNode.id);
sceneGraph.nodes.push(envNode);
}
generateGround(sceneGraph, sceneData) {
if (!sceneData.ground) return;
const groundNode = this.createNode(
"Ground",
[0, 0, 0],
[0, 0, 0],
[sceneData.ground.size || 20, sceneData.ground.size || 20, 1],
{
type: "ground",
texture: sceneData.ground.texture,
material: "ground_material"
}
);
const meshId = sceneGraph.meshes.length;
const materialId = this.createMaterial(
sceneGraph,
"ground_material",
sceneData.ground.color || [0.5, 0.5, 0.5, 1],
sceneData.ground.roughness || 0.8,
sceneData.ground.metallic || 0.0
);
groundNode.mesh = meshId;
sceneGraph.meshes.push({
id: meshId,
name: "GroundMesh",
primitives: [{
attributes: {
POSITION: "ground_positions",
NORMAL: "ground_normals",
TEXCOORD_0: "ground_texcoords"
},
indices: "ground_indices",
material: materialId,
mode: 4
}]
});
sceneGraph.nodes[0].children.push(groundNode.id);
sceneGraph.nodes.push(groundNode);
}
generateObjects(sceneGraph, sceneData) {
if (!sceneData.objects || sceneData.objects.length === 0) return;
const objectsNode = this.createNode("Objects", [0, 0, 0], [0, 0, 0], [1, 1, 1]);
sceneGraph.nodes[0].children.push(objectsNode.id);
sceneGraph.nodes.push(objectsNode);
sceneData.objects.forEach((obj, index) => {
const objNode = this.createNode(
obj.name || `Object_${index}`,
obj.location || [0, 0, 0],
obj.rotation || [0, 0, 0],
obj.scale || [1, 1, 1],
{
type: "object",
primitive: obj.type,
size: obj.size,
radius: obj.radius
}
);
const materialId = this.createMaterial(
sceneGraph,
`material_${obj.name || index}`,
obj.color || [0.8, 0.8, 0.8, 1],
obj.roughness || 0.5,
obj.metallic || 0.0,
obj.emission,
obj.emissionStrength
);
const meshId = sceneGraph.meshes.length;
objNode.mesh = meshId;
sceneGraph.meshes.push({
id: meshId,
name: `${obj.name || `Object_${index}`}_Mesh`,
primitives: [{
attributes: {
POSITION: `${obj.name}_positions`,
NORMAL: `${obj.name}_normals`
},
material: materialId,
mode: 4
}],
extras: {
primitiveType: obj.type,
size: obj.size,
radius: obj.radius
}
});
if (obj.animation) {
objNode.extras.animation = obj.animation;
}
objectsNode.children.push(objNode.id);
sceneGraph.nodes.push(objNode);
});
}
generateAvatar(sceneGraph, sceneData) {
const avatar = sceneData.avatar;
const avatarNode = this.createNode(
avatar.name || "Avatar",
avatar.position || [0, 0, 0],
[0, 0, 0],
[avatar.scale || 1.0, avatar.scale || 1.0, avatar.scale || 1.0],
{
type: "avatar",
action: avatar.action || "stand",
rigged: true,
bones: ["root", "spine", "head", "left_arm", "right_arm", "left_leg", "right_leg"]
}
);
const meshId = sceneGraph.meshes.length;
const materialId = this.createMaterial(
sceneGraph,
"avatar_material",
[1, 0.8, 0.6, 1],
0.5,
0.0
);
avatarNode.mesh = meshId;
sceneGraph.meshes.push({
id: meshId,
name: "AvatarMesh",
primitives: [{
attributes: {
POSITION: "avatar_positions",
NORMAL: "avatar_normals",
JOINTS_0: "avatar_joints",
WEIGHTS_0: "avatar_weights"
},
material: materialId,
mode: 4
}],
extras: {
skinned: true,
skeleton: "avatar_skeleton"
}
});
if (avatar.action && avatar.action !== "stand") {
avatarNode.extras.animation = {
type: avatar.action,
speed: avatar.animation?.speed || 1.0
};
}
sceneGraph.nodes[0].children.push(avatarNode.id);
sceneGraph.nodes.push(avatarNode);
}
generateLighting(sceneGraph, sceneData) {
if (!sceneData.lighting) return;
const lighting = sceneData.lighting;
const lightsNode = this.createNode("Lights", [0, 0, 0], [0, 0, 0], [1, 1, 1]);
sceneGraph.nodes[0].children.push(lightsNode.id);
sceneGraph.nodes.push(lightsNode);
if (lighting.lights && lighting.lights.length > 0) {
lighting.lights.forEach((light, index) => {
const lightNode = this.createNode(
`Light_${light.type}_${index}`,
light.location || [0, 0, 0],
[0, 0, 0],
[1, 1, 1],
{
type: "light",
lightType: light.type,
energy: light.energy || 1.0,
color: light.color || lighting.color || [1, 1, 1],
angle: light.angle
}
);
const lightId = sceneGraph.lights.length;
lightNode.light = lightId;
sceneGraph.lights.push({
id: lightId,
name: `Light_${light.type}_${index}`,
type: light.type,
color: light.color || lighting.color || [1, 1, 1],
intensity: light.energy || 1.0,
range: light.range || 100,
innerConeAngle: light.innerConeAngle,
outerConeAngle: light.outerConeAngle
});
lightsNode.children.push(lightNode.id);
sceneGraph.nodes.push(lightNode);
});
}
// Ensure extras exists before setting ambientLight
if (!sceneGraph.extras) {
sceneGraph.extras = {};
}
// Ensure extras exists
if (!sceneGraph.extras) {
sceneGraph.extras = {};
}
sceneGraph.extras.ambientLight = {
color: lighting.color || [1, 1, 1],
strength: lighting.ambient_strength || 0.3
};
}
generateCamera(sceneGraph, sceneData) {
if (!sceneData.camera) return;
const camera = sceneData.camera;
const cameraNode = this.createNode(
"Camera",
camera.position || [4, -4, 2.2],
camera.rotation || [1.05, 0, 0.78],
[1, 1, 1]
);
const cameraId = sceneGraph.cameras.length;
cameraNode.camera = cameraId;
sceneGraph.cameras.push({
id: cameraId,
name: "MainCamera",
type: "perspective",
perspective: {
aspectRatio: 16 / 9,
yfov: (camera.fov || 50) * Math.PI / 180,
znear: 0.1,
zfar: 1000
}
});
sceneGraph.nodes[0].children.push(cameraNode.id);
sceneGraph.nodes.push(cameraNode);
}
generateAudio(sceneGraph, sceneData) {
if (!sceneData.audio) return;
sceneGraph.audio.ambient = sceneData.audio.ambient || [];
sceneGraph.audio.spatial = sceneData.audio.spatial || [];
}
generateEffects(sceneGraph, sceneData) {
if (!sceneData.effects) return;
const effectsNode = this.createNode("Effects", [0, 0, 0], [0, 0, 0], [1, 1, 1], {
type: "effects",
effects: sceneData.effects
});
sceneGraph.nodes[0].children.push(effectsNode.id);
sceneGraph.nodes.push(effectsNode);
if (sceneData.effects.fog) {
sceneGraph.extras.fog = {
type: "fog",
color: [0.8, 0.8, 0.9, 1],
density: 0.05,
near: 1,
far: 50
};
}
}
generateAnimations(sceneGraph, sceneData) {
const animations = [];
if (sceneData.avatar && sceneData.avatar.present && sceneData.avatar.action) {
animations.push({
name: "avatar_animation",
type: sceneData.avatar.action,
target: "avatar",
duration: 2.0,
channels: []
});
}
sceneData.objects?.forEach((obj, index) => {
if (obj.animation) {
animations.push({
name: `${obj.name}_animation`,
type: obj.animation.type,
target: obj.name,
duration: 3.0,
channels: []
});
}
});
sceneGraph.animations = animations;
}
createMaterial(sceneGraph, name, baseColor, roughness, metallic, emission = null, emissionStrength = null) {
const materialId = sceneGraph.materials.length;
const material = {
id: materialId,
name: name,
pbrMetallicRoughness: {
baseColorFactor: baseColor,
metallicFactor: metallic,
roughnessFactor: roughness
}
};
if (emission) {
material.emissiveFactor = emission.slice(0, 3);
if (emissionStrength) {
material.extras = { emissionStrength: emissionStrength };
}
}
sceneGraph.materials.push(material);
return materialId;
}
}