层次模型
复杂模型
听到复杂两个字别害怕,再复杂的大模型都是由简单的小模型组成哒
以机器人手臂为例
就像拼乐高一样,大模型的的单位就是这些小零件,你需要知道的就是 有哪些零件 和 拼接关系。
要实现这样一个简单的机器人手臂,你需要考虑一下这样几个关节:
部位 | 旋转轴 | 带动部位 | 无影响部位 |
---|---|---|---|
上臂 | 肩关节 | 前臂、手掌、手指 | |
前臂 | 肘关节 | 手掌、手指 | 上臂 |
手掌 | 腕关节 | 手指 | 上臂、前臂 |
手指 | 上臂、前臂、手掌 |
层次结构模型
最常用的方法就是按 层次顺序-由高到低 逐一绘制。
三维模型各个部件的运动最重要的就是实现:
部件A转动带动部件B转动
单关节模型
- arm2 前臂
- joint1 肘关节
- arm1 上臂
- 垂直交点 肩关节
单关节模型变换的核心就是 joint1-肘关节:
- 上臂 以肘关节所在的 y轴旋转
- 前臂 以肘关节所在的 z轴旋转
JointMode
1 | let VSHADER_SOURCE = ` |
1 | function main() { |
1 | function initVertexBuffers(gl) { |
1 | let ANGLE_STEP = 5.0; // the increments of rotation angle |
1 |
|
多节点模型
- finger1&finger2 两根手指
- palm 手掌
- arm2 前臂
- arm1 上臂
- base 基座
变量名 | 对应部位 | 操控键 |
---|---|---|
g_arm1Angle | 上臂 | ←→ |
g_joint1Angle | 肘关节 | ↑↓ |
g_joint2Angle | 腕关节 | xz |
g_joint3Angle | 指张角 | cv |
MultiJointModel
1 | function keydown(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix, ev) { |
1 | let baseHeight = 2.0; |
1 | let g_matrixStack = []; //Array for storing matrix |
绘制部件
drawSegments
MultiJoinModel方法概括
总体来说聚焦于 模型矩阵:
- 一切部件的 缓冲区数据 都一样
- 通过改变 模型矩阵 来绘制出外形不同的部件
- 低层级绘制使用的模型矩阵需要 基于 高层级的模型矩阵
- 需要对多个部件进行缩放变换时,需要使用 矩阵管理栈
绘制部件的方法有如下的特性:
- 对每一个部件都定义一个单独的 缓冲区对象 存储对应顶点数据
- 各个部件可以根据部件特性选择性 共享 某些数据
MultiJointModel_segment
不同点在于segment方法在main中就引入了 a_Position,
因为之后需要使用不同部件的 坐标缓冲区数据 。
MultiJoinModel
1 | function main() { |
MultiJointModel_segment
1 | function main() { |
不同点在于:
- ModelJointModel 使用模型矩阵对同一个模型进行拉伸创建不同的部件
- ModelJointModel_segment 使用不同的缓冲区数据给a_Position重新赋值以创建不同的部件
ModelJointModel
1 | function draw(gl, n, u_MvpMatrix, u_NormalMatrix, vpMatrix) { |
ModelJointModel_segment
1 | function draw(gl, n, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix) { |
- drawBox 需要根据尺寸对组件进行拉伸,需要通过栈对未拉伸的矩阵进行保存
- drawSegment 需要根据缓冲区重新对a_Position赋值
ModelJointModel
1 | function drawBox(gl, n, width, height, depth, vpMatrix, u_MvpMatrix, u_NormalMatrix) { |
ModelJointModel_segment
1 | function drawSegment(gl, n, buffer, vpMatrix, a_Position, u_MvpMatrix, u_NormalMatrix) { |
segment方法不在这里对 a_Position 进行赋值,
这里需要对所有部件的缓冲区进行 数据写入,但是不对a_Position进行赋值。
MultiJoinModel
1 | function initVertexBuffers(gl) { |
MultiJointModel_segment
1 | function initVertexBuffers(gl) { |