定义渲染节点
我们可以用node对象来完整地表示一个模型,它可以包含任意多个实体,还可以包含一个Node数组。比如一个包含了很多家具、房间、甚至室外花圃的房子,也可以被当作一个模型来操作。
node对象的定义接口
Node对象需要用_node接口定义,让我们一起看看如何使用它。
// 调用方式一
const node: JNode = {
mesh: {
primitives: [{ geometry, material }]
}
};
// 调用方式二
const node = Node({
mesh: {
primitives: [{ geometry, material }]
}
});
案例学习
下面我们以一个具体的例子,来掌握node对象的定义方式。这个例子中,我们只定义了一个几何geometry,构成一个渲染单元。三个不同的渲染节点node, subnode1, subnode2都使用了该渲染单元,但subnode1, subnode2中对该渲染单元的位置做了变换。另外,这三个渲染节点中分别定义了不同颜色的材质,方便我们识别不同节点的渲染几何。最后,我们将subnode1, subnode2都指定为node的子节点,然后利用node的transform矩阵对所有渲染几何同步变换。
const min = vec3(-38.21760177612305, -25.4783992767334, 0);
const max = vec3(43.67150115966797, 25.4783992767334, 40.12839889526367);
const interval = max.sub(min).mul(1.5);
// 定义了一个物体几何
const geometry = await loadStanford('teapot');
// 利用上面的材质、几何构成一个渲染单元,该渲染单元对象将被后续的各个渲染节点共同使用
const primitive = Primitive({ geometry });
// 定义了一个变换矩阵1
const transform1 = mat4();
// 向X轴正向平移interval.at(0)的距离
transform1.translate(vec3(interval.at(0), 0, 0));
// 围绕Z轴负向旋转了90度
transform1.rotate(quat(vec3(0, 0, 1), -Math.PI / 2));
// 定义了一个渲染节点subnode1,具备上面定义的渲染单元对象和变换矩阵1
const subnode1: JNode = {
mesh: {
primitives: [primitive]
},
material: head_light_color(clr3(0.2, 0.6, 0.2)),
transform: transform1
};
// 定义了一个变换矩阵2
const transform2 = mat4();
// 向X轴正向平移2 * interval.at(0)的距离
transform2.translate(vec3(2 * interval.at(0), 0, 0));
// 围绕Z轴正向旋转了90度
transform2.rotate(quat(vec3(0, 0, 1), Math.PI / 2));
// 定义了一个渲染节点subnode2,具备上面定义的渲染单元对象和变换矩阵2
const subnode2: JNode = {
mesh: {
primitives: [primitive]
},
material: head_light_color(clr3(0.4, 0.2, 0.2)),
transform: transform2
};
// 定义了一个新的渲染节点node
const node: JNode = {
mesh: {
primitives: [primitive]
},
material: head_light_color(clr3(0.4, 0.7, 0.8)),
}
// 指定了渲染节点node的子模型渲染节点,也就是上面定义的subnode1, subnode2
node.children = [subnode1, subnode2];
// 定义了一个变换矩阵
const transform = mat4();
// 围绕X轴正向旋转了90度
transform.rotate(quat(vec3(1, 0, 0), Math.PI / 2));
// 将上面定义的变换矩阵作用到渲染节点node上,发现该节点中所有的渲染对象(包括子节点的渲染对象)都被同步旋转了。
node.transform = transform;
const background = Background({
size: ivec2(canvas.width, canvas.height),
colorMask: clr4(0.8, 0.7, 0.6, 1.0),
depthMask: float(1.0)
});
const camera = Camera();
const pass: JPass = Pass({
background: background,
camera: camera,
node: node,
});
const scene: JScene = {
name: 'scene',
passes: [pass],
};
const boundingBox = bbox();
boundingBox.min = min;
boundingBox.max = vec3(interval.at(0) * 4, interval.at(1) * 4, interval.at(2) * 2).add(min);
camera.orbitPoint = boundingBox.center();
project(camera, boundingBox, background.size);
home(camera, boundingBox);
