19层次结构模型

以机械臂为例,当肩关节转动时手臂上的所有部件跟着转动;当前臂转动时,只有前臂、手掌和手指转动,不影响上臂;当手指转动时,只影响手指。

也就是说模型之间要存在层次关系,高级别层次对象的变换会影响低层次对象,反之低级别层次对象的变换不会影响高级别层次对象。下面阐述如何在代码中实现。

1.发生转动的部位是关节处,为每个部位添加事件监听,并用变量存储旋转角度

function keyDown(ev,gl,n,viewProjMatrix,u_MvpMatrix,u_NormalMatrix)
{
    console.log(ev.keyCode);
    switch(ev.keyCode){
        case 38:
            if(g_joint1Angle < 135.0) g_joint1Angle += ANGLE_STEP;
            break;
        case 40:
            if(g_joint1Angle>-135.0) g_joint1Angle -= ANGLE_STEP;
            break;
        case 39:
            g_arm1Angle = (g_arm1Angle + ANGLE_STEP) % 360;
            break;
        case 37:
            g_arm1Angle = (g_arm1Angle - ANGLE_STEP)%360;
            break ;
        case 90:
            g_joint2Angle = (g_joint2Angle + ANGLE_STEP)%360;
            break;
        case 88:
            g_joint2Angle = (g_joint2Angle - ANGLE_STEP)%360;
            break;
        case 86:
            if(g_joint3Angle < 60.0) g_joint3Angle = (g_joint3Angle+ANGLE_STEP)%360;
            break;
        case 67:
            if(g_joint3Angle > -60.0) g_joint3Angle = (g_joint3Angle-ANGLE_STEP)%360;
            break;
        default :return ;
    }
    draw(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix);

}

2.实现高级别层次对象对低级别层次对象的控制

    控制对象姿态的始终是mvp_Matrix矩阵,我们将viewProjMatrix和modelMatrix分离开来,因为viewProjMatrix是不变的,接下来对modelMatrix进行操作,

    矩阵之间相乘地顺序即代表先后进行地变换操作,我们在绘制时先绘制高级别层次对象,最后绘制低级别层次对象,绘制时皆使用同一个modelMatrix,那么后进行的变换就不会影响先绘制的对象

    模型变换--->绘制(对象1)--->模型变换--->绘制(对象2)--->......

    即,后进行的变换在先进行的变换的基础上,这样就实现了层次结构

3.同级别对象的绘制:

    在同一级别中有时存在多个对象(如两个手指),但绘制始终是分先后顺序的,这时我们希望他们使用的modelMatrix状态相同,但是只要进行了对象绘制,modelMatrix就会发生改变。这时,我们采取如下解决方案:在绘制同一级别的对象1之前,将modelMatrix存储在另一个Matrix4中,当对象1绘制完成,我们再将原先的值赋给modelMatrix来参与对象2的绘制,具体实现看下面代码:

//点光源
var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'attribute vec4 a_Normal;\n' +
    'uniform mat4 u_MvpMatrix;\n' +
    'uniform mat4 u_ModelMatrix;\n' +
    'uniform mat4 u_NormalMatrix;\n' +
    'uniform vec3 u_PointLightPosition;\n' +
    'uniform vec3 u_PointLightColor;\n' +
    'uniform vec3 u_AmbientColor;\n' +
    'varying vec4 v_Color;\n' +
    'void main(){\n' +
    'vec4 a_Color = vec4(0.0,1.0,0.0,1.0);\n' +
    'gl_Position = u_MvpMatrix * a_Position;\n' +
    'vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +//计算法向量并进行归一化
    'vec4 vertexPosition = u_ModelMatrix * a_Position;\n' +//计算顶点世界坐标
    'vec3 lightDirection = normalize(u_PointLightPosition - vec3(vertexPosition));\n' +//计算光线方向向量并进行归一化
    'float NDotL = max(dot(normal,lightDirection),0.0);\n' +//计算法向量和方向向量的点积
    'vec3 diffuse = u_PointLightColor * vec3(a_Color) * NDotL;\n' +//计算点光源的反射光的颜色
    'vec3 ambient = u_AmbientColor * a_Color.rgb;\n' +//计算环境光反射光颜色
    'v_Color = vec4(ambient + diffuse,a_Color.a);' +
    '}\n';

var FSHADER_SOURCE =
    'precision mediump float;\n' +
    'varying vec4 v_Color;\n' +
    'void main(){\n' +
    'gl_FragColor = v_Color;\n' +
    '}\n';


var ANGLE_STEP = 3.0;
var g_arm1Angle = 90.0;
var g_joint1Angle = 0.0;

var g_modelMatrix = new Matrix4();
var g_mvpMatrix = new Matrix4();

function main()
{
    var canvas = document.getElementById('webgl');
    var gl = canvas.getContext('webgl');
    initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE);
    var n = initVertexBuffers(gl);
    //开启深度检测
    gl.enable(gl.DEPTH_TEST);
    gl.clearColor(1.0,1.0,1.0,1.0);


    //对光源数据进行赋值
    var u_PointLightPosition = gl.getUniformLocation(gl.program,'u_PointLightPosition');
    gl.uniform3f(u_PointLightPosition,0.0,3.0,4.0);
    var u_PointLightColor = gl.getUniformLocation(gl.program,'u_PointLightColor');
    gl.uniform3f(u_PointLightColor,1.0,1.0,1.0);
    var u_AmbientColor = gl.getUniformLocation(gl.program,'u_AmbientColor');
    gl.uniform3f(u_AmbientColor,0.2,0.2,0.2);

    //法向量变换矩阵
    var u_NormalMatrix = gl.getUniformLocation(gl.program,'u_NormalMatrix');

    //模型视图矩阵
    var u_MvpMatrix = gl.getUniformLocation(gl.program,'u_MvpMatrix');
    var viewProjMatrix = new Matrix4();
    viewProjMatrix.setPerspective(50,canvas.width/canvas.height,1,100);
    viewProjMatrix.lookAt(0,0,90.0,0.0,0.0,0.0,0.0,1.0,0.0);

    document.onkeydown = function(ev){
        keyDown(ev,gl,n,viewProjMatrix,u_MvpMatrix,u_NormalMatrix);
    };
    draw(gl,n,viewProjMatrix,u_MvpMatrix,u_NormalMatrix);

}
function initVertexBuffers(gl)
{
    var vertices = new Float32Array([
        1.5, 10.0, 1.5, -1.5, 10.0, 1.5, -1.5,  0.0, 1.5,  1.5,  0.0, 1.5, // v0-v1-v2-v3 front
        1.5, 10.0, 1.5,  1.5,  0.0, 1.5,  1.5,  0.0,-1.5,  1.5, 10.0,-1.5, // v0-v3-v4-v5 right
        1.5, 10.0, 1.5,  1.5, 10.0,-1.5, -1.5, 10.0,-1.5, -1.5, 10.0, 1.5, // v0-v5-v6-v1 up
        -1.5, 10.0, 1.5, -1.5, 10.0,-1.5, -1.5,  0.0,-1.5, -1.5,  0.0, 1.5, // v1-v6-v7-v2 left
        -1.5,  0.0,-1.5,  1.5,  0.0,-1.5,  1.5,  0.0, 1.5, -1.5,  0.0, 1.5, // v7-v4-v3-v2 down
        1.5,  0.0,-1.5, -1.5,  0.0,-1.5, -1.5, 10.0,-1.5,  1.5, 10.0,-1.5  // v4-v7-v6-v5 back
    ]);

    // Normal
    var normals = new Float32Array([
        0.0, 0.0, 1.0,  0.0, 0.0, 1.0,  0.0, 0.0, 1.0,  0.0, 0.0, 1.0, // v0-v1-v2-v3 front
        1.0, 0.0, 0.0,  1.0, 0.0, 0.0,  1.0, 0.0, 0.0,  1.0, 0.0, 0.0, // v0-v3-v4-v5 right
        0.0, 1.0, 0.0,  0.0, 1.0, 0.0,  0.0, 1.0, 0.0,  0.0, 1.0, 0.0, // v0-v5-v6-v1 up
        -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
        0.0,-1.0, 0.0,  0.0,-1.0, 0.0,  0.0,-1.0, 0.0,  0.0,-1.0, 0.0, // v7-v4-v3-v2 down
        0.0, 0.0,-1.0,  0.0, 0.0,-1.0,  0.0, 0.0,-1.0,  0.0, 0.0,-1.0  // v4-v7-v6-v5 back
    ]);

    // Indices of the vertices
    var indices = new Uint8Array([
        0, 1, 2,   0, 2, 3,    // front
        4, 5, 6,   4, 6, 7,    // right
        8, 9,10,   8,10,11,    // up
        12,13,14,  12,14,15,    // left
        16,17,18,  16,18,19,    // down
        20,21,22,  20,22,23     // back
    ]);
    var indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);

    initArrayBuffer(gl,vertices,3,gl.FLOAT,'a_Position');
    initArrayBuffer(gl,normals,3,gl.FLOAT,'a_Normal');
    return indices.length;
}
function initArrayBuffer(gl,data,num,type,attribute){
    var buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
    gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
    var a_attribute = gl.getAttribLocation(gl.program,attribute);
    gl.vertexAttribPointer(a_attribute,num,type,false,0,0);
    gl.enableVertexAttribArray(a_attribute);
    return true;
}

var g_joint2Angle = 0,g_joint3Angle = 0;
function keyDown(ev,gl,n,viewProjMatrix,u_MvpMatrix,u_NormalMatrix)
{
    console.log(ev.keyCode);
    switch(ev.keyCode){
        case 38:
            if(g_joint1Angle < 135.0) g_joint1Angle += ANGLE_STEP;
            break;
        case 40:
            if(g_joint1Angle>-135.0) g_joint1Angle -= ANGLE_STEP;
            break;
        case 39:
            g_arm1Angle = (g_arm1Angle + ANGLE_STEP) % 360;
            break;
        case 37:
            g_arm1Angle = (g_arm1Angle - ANGLE_STEP)%360;
            break ;
        case 90:
            g_joint2Angle = (g_joint2Angle + ANGLE_STEP)%360;
            break;
        case 88:
            g_joint2Angle = (g_joint2Angle - ANGLE_STEP)%360;
            break;
        case 86:
            if(g_joint3Angle < 60.0) g_joint3Angle = (g_joint3Angle+ANGLE_STEP)%360;
            break;
        case 67:
            if(g_joint3Angle > -60.0) g_joint3Angle = (g_joint3Angle-ANGLE_STEP)%360;
            break;
        default :return ;
    }
    draw(gl, n, viewProjMatrix, u_MvpMatrix, u_NormalMatrix);

}
function draw(gl,n,viewProjMatrix,u_MvpMatrix,u_NormalMatrix)
{
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    //base
    var baseHeight = 2.0;
    g_modelMatrix.setTranslate(0.0, -12.0, 0.0);
    drawBox(gl, n, 10.0,baseHeight,10.0,viewProjMatrix, u_MvpMatrix, u_NormalMatrix);
    // Arm1
    var arm1Length = 10.0; // Length of arm1
    g_modelMatrix.translate(0.0,baseHeight,0.0);
    g_modelMatrix.rotate(g_arm1Angle, 0.0, 1.0, 0.0);    // Rotate around the y-axis
    drawBox(gl, n, 3.0,arm1Length,3.0,viewProjMatrix, u_MvpMatrix, u_NormalMatrix); // Draw

    //arm2
    var arm2Length = 8;
    g_modelMatrix.translate(0.0,arm1Length,0.0);
    g_modelMatrix.rotate(g_joint1Angle, 0.0, 0.0, 1.0);
    drawBox(gl, n, 4,arm2Length,4,viewProjMatrix, u_MvpMatrix, u_NormalMatrix); // Draw

    // palm
    var palmLength = 2.0;
    g_modelMatrix.translate(0.0, arm2Length, 0.0);    // Move to joint1
    g_modelMatrix.rotate(g_joint2Angle, 0.0, 1.0, 0.0);  // Rotate around the z-axis
    drawBox(gl, n,3,palmLength,6,viewProjMatrix, u_MvpMatrix, u_NormalMatrix); // Draw

    //finger1
    pushMatrix(g_modelMatrix);
    g_modelMatrix.translate(0.0, palmLength, 2);
    g_modelMatrix.rotate(g_joint3Angle, 1.0, 0.0, 0.0);
    drawBox(gl, n,1,2,1,viewProjMatrix, u_MvpMatrix, u_NormalMatrix);

    //finger2
    g_modelMatrix = popMatrix();
    g_modelMatrix.translate(0.0,palmLength, -2);
    g_modelMatrix.rotate(-g_joint3Angle, 1.0, 0.0, 0.0);
    drawBox(gl, n,1,2,1,viewProjMatrix, u_MvpMatrix, u_NormalMatrix);

}
var g_matrixStack = [];
function pushMatrix(m)
{
    var m2 = new Matrix4(m);
    g_matrixStack.push(m2);
}
function popMatrix()
{
    return g_matrixStack.pop();
}
var g_normalMatrix = new Matrix4();
var WIDTH = 3.0,HEIGHT = 10,DEPTH=3.0;

function drawBox(gl,n,width,height,depth,viewProjMatrix,u_MvpMatrix,u_NormalMatrix)
{
    //将模型视图矩阵赋值给顶点着色器
    g_mvpMatrix.set(viewProjMatrix);
    g_mvpMatrix.multiply(g_modelMatrix);
    g_mvpMatrix.scale(width/WIDTH,height/HEIGHT,depth/DEPTH);
    //WIDTH = width,HEIGHT=height,DEPTH = depth;

    gl.uniformMatrix4fv(u_MvpMatrix,false,g_mvpMatrix.elements);
    gl.uniformMatrix4fv(gl.getUniformLocation(gl.program,'u_ModelMatrix'),false,g_modelMatrix.elements);

    //计算法向量变换矩阵
    g_normalMatrix.setInverseOf(g_modelMatrix);
    g_normalMatrix.transpose();
    gl.uniformMatrix4fv(u_NormalMatrix,false,g_normalMatrix.elements);
    //绘制
    gl.drawElements(gl.TRIANGLES,n,gl.UNSIGNED_BYTE,0);
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值