在x轴上平移3D立方体

时间:2015-10-17 16:27:29

标签: javascript matrix 3d webgl

我试图将两个3D立方体彼此远离。我尝试过使用剪辑空间以及翻译矩阵,但没有任何效果。我正在寻找的解决方案是优选地在x轴上并排的立方体。

这是我的代码:



var gl,program,canvas;

var vBuffer, vPosition;
var idxBuffer;

var vertices = [
    -0.5, 0.5, 1,
     0.5, 0.5, 1,
     0.5, -0.5, 1,
    -0.5, -0.5, 1,
    -0.5, 0.5, 0,
     0.5, 0.5, 0,
     0.5, -0.5, 0,
    -0.5, -0.5, 0
];

var dVecIdx = new Uint16Array([
		0, 1, 1, 2,
        2, 3, 3, 0,
		4, 5, 5, 6,
        6, 7, 7, 4,
		0, 4, 1, 5,
        2, 6, 3, 7
]);

var projection = [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 1,
    0, 0, 0, 1
];

var a = Math.sqrt(0.5);
var rotation = [
		 a, 0, a, 0,
		 0, 1, 0, 0,
		-a, 0, a, 0,
		 0, 0, 0, 1
];

window.onload = function init() {

    canvas = document.getElementById("gl-canvas");

    gl = WebGLUtils.setupWebGL(canvas);
    if (!gl) { alert("WebGL isn't available"); }

    gl.viewport(0, 0, canvas.width, canvas.height);

    gl.clearColor(1.0, 1.0, 1.0, 1.0);

    gl.enable(gl.DEPTH_TEST);

    program = initShaders(gl, "vertex-shader", "fragment-shader");

    vBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);

    vPosition = gl.getAttribLocation(program, "vPosition");
    gl.enableVertexAttribArray(vPosition);
    gl.vertexAttribPointer(vPosition, 3, gl.FLOAT, false, 0, 0);

    idxBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, idxBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, dVecIdx, gl.STATIC_DRAW);

    render();
}

function render() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.useProgram(program);
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
    projLoc = gl.getUniformLocation(program, "projectionMatrix");
    loc = gl.getUniformLocation(program, "rotate");
    gl.uniformMatrix4fv(projLoc, false, projection);
    gl.uniformMatrix4fv(loc, false, projection);
    gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);
    
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
    projLoc = gl.getUniformLocation(program, "projectionMatrix");
    loc = gl.getUniformLocation(program, "rotate");
    gl.uniformMatrix4fv(projLoc, false, projection);
    gl.uniformMatrix4fv(loc, false, rotation);
    gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);

    requestAnimFrame(render);
}

<html>
<head>
    <script src="https://www.cs.unm.edu/~angel/WebGL/7E/Common/initShaders.js"></script>
    <script src="https://www.cs.unm.edu/~angel/WebGL/7E/Common/MV.js"></script>
    <script src="https://www.cs.unm.edu/~angel/WebGL/7E/Common/webgl-utils.js"></script>

    <script id="vertex-shader" type="x-shader/x-vertex">
        attribute vec3 vPosition;
        attribute vec4 vColor;
        varying vec4 fColor;
        uniform mat4 projectionMatrix;
        uniform mat4 rotate;

        void main() {
            gl_Position = projectionMatrix * rotate * vec4(vPosition, 1);
            fColor = vColor;
        }
    </script>

    <script id="fragment-shader" type="x-shader/x-fragment">
        precision mediump float;
        varying vec4 fColor;

        void main() {
            gl_FragColor = fColor;
        }
    </script>

</head>
<body>
    <div style="border: 1px dotted black;">
        <div style="text-align:center">
            <canvas id="gl-canvas" width="500" height="500"></canvas>
        </div>
    </div>
</body>
</html>
&#13;
&#13;
&#13;

感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

如果你尝试使用你的设置得到更高级的话,我建议使用像Three.js这样的WebGL库抽象出一些数学或者真正花时间去谷歌并理解对象和相机转换矩阵。

答案:

话虽如此,简单的答案是只添加另一个翻译矩阵并将其插入着色器中的投影和旋转矩阵之间:

attribute vec3 vPosition;
attribute vec4 vColor;
varying vec4 fColor;
uniform mat4 projectionMatrix;
uniform mat4 rotate;
uniform mat4 translate;

void main() {
    gl_Position = projectionMatrix * translate * rotate * vec4(vPosition, 1);
    fColor = vColor;
}

翻译矩阵如下所示:

var translation = [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    x, y, z, 1
];

其中xyz分别是沿X轴,Y轴和Z轴的平移距离。 然后,这将以与旋转矩阵相同的方式添加到render方法中:

transLoc = gl.getUniformLocation(program, "translate");
gl.uniformMatrix4fv(transLoc, false, translation);

优化:

现在还说 ,你可以做一些更优化/更正:

1)由于WebGL维持其状态&#34;直到更改(保持绑定/设置/启用/等),您可以删除render()方法中的大量重复代码:

function render() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // set state
    gl.useProgram(program);
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
    projLoc = gl.getUniformLocation(program, "projectionMatrix");
    loc = gl.getUniformLocation(program, "rotate");
    gl.uniformMatrix4fv(projLoc, false, projection);

    // draw shape 1
    gl.uniformMatrix4fv(loc, false, projection);
    gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);

    // draw shape 2
    gl.uniformMatrix4fv(loc, false, rotation);
    gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);

    requestAnimFrame(render);
}

2)如果您不想在渲染过程中使用特定的矩阵,则应将其设置为单位矩阵,该矩阵在乘以时不会更改其他矩阵/向量:

var identity = [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
];

这是您应该用于第一个形状上的旋转矩阵而不是透视矩阵:

// draw shape 1
gl.uniformMatrix4fv(loc, false, identity);
gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);

3)您可以将progLoc,rotLoc和transLoc声明为全局变量,并在程序初始化后立即设置它们的值。这些不会因单个程序而改变,也不需要在渲染循环中重置。

program = initShaders(gl, "vertex-shader", "fragment-shader");
projLoc = gl.getUniformLocation(program, "projectionMatrix");
rotLoc = gl.getUniformLocation(program, "rotate");
transLoc = gl.getUniformLocation(program, "translate");

制作最终代码:

&#13;
&#13;
var gl,program,canvas;

var vBuffer, vPosition;
var idxBuffer;
var projLoc, rotLoc, transLoc;


var vertices = [
    -0.5, 0.5, 1,
     0.5, 0.5, 1,
     0.5, -0.5, 1,
    -0.5, -0.5, 1,
    -0.5, 0.5, 0,
     0.5, 0.5, 0,
     0.5, -0.5, 0,
    -0.5, -0.5, 0
];

var dVecIdx = new Uint16Array([
		0, 1, 1, 2,
        2, 3, 3, 0,
		4, 5, 5, 6,
        6, 7, 7, 4,
		0, 4, 1, 5,
        2, 6, 3, 7
]);

var identity = [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
];

var projection = [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 1,
    0, 0, 0, 1
];

var a = Math.sqrt(0.5);
var rotation = [
		 a, 0, a, 0,
		 0, 1, 0, 0,
		-a, 0, a, 0,
		 0, 0, 0, 1
];

// actual translations are set in the render() function
var translation = [
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
];


window.onload = function init() {

    canvas = document.getElementById("gl-canvas");

    gl = WebGLUtils.setupWebGL(canvas);
    if (!gl) { alert("WebGL isn't available"); }

    gl.viewport(0, 0, canvas.width, canvas.height);

    gl.clearColor(1.0, 1.0, 1.0, 1.0);

    gl.enable(gl.DEPTH_TEST);

    program = initShaders(gl, "vertex-shader", "fragment-shader");
    projLoc = gl.getUniformLocation(program, "projectionMatrix");
    rotLoc = gl.getUniformLocation(program, "rotate");
    transLoc = gl.getUniformLocation(program, "translate");

    vBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices), gl.STATIC_DRAW);

    vPosition = gl.getAttribLocation(program, "vPosition");
    gl.enableVertexAttribArray(vPosition);
    gl.vertexAttribPointer(vPosition, 3, gl.FLOAT, false, 0, 0);

    idxBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, idxBuffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, dVecIdx, gl.STATIC_DRAW);

    render();
}

function render() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // set non-changing states
    gl.useProgram(program);
    gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
    gl.uniformMatrix4fv(projLoc, false, projection);
    
    // draw shape 1
    translation[12] = 1; // x-axis translation (y and z are 0)
    gl.uniformMatrix4fv(transLoc, false, translation);
    gl.uniformMatrix4fv(rotLoc, false, identity);
    gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);

    // draw shape 2
    translation[12] = -1; // set x-axis translation
    gl.uniformMatrix4fv(transLoc, false, translation);
    gl.uniformMatrix4fv(rotLoc, false, rotation);
    gl.drawElements(gl.LINES, dVecIdx.length, gl.UNSIGNED_SHORT, 0);

    requestAnimFrame(render);
}
&#13;
<html>
  <head>
    <script src="https://www.cs.unm.edu/~angel/WebGL/7E/Common/initShaders.js"></script>
    <script src="https://www.cs.unm.edu/~angel/WebGL/7E/Common/MV.js"></script>
    <script src="https://www.cs.unm.edu/~angel/WebGL/7E/Common/webgl-utils.js"></script>

    <script id="vertex-shader" type="x-shader/x-vertex">
        attribute vec3 vPosition;
        attribute vec4 vColor;
        varying vec4 fColor;
        uniform mat4 projectionMatrix;
        uniform mat4 rotate;
        uniform mat4 translate;

        void main() {
            gl_Position = projectionMatrix * translate * rotate * vec4(vPosition, 1);
            fColor = vColor;
        }
    </script>

    <script id="fragment-shader" type="x-shader/x-fragment">
        precision mediump float;
        varying vec4 fColor;

        void main() {
            gl_FragColor = fColor;
        }
    </script>
  </head>

  <body>
    <div style="border: 1px dotted black;">
      <div style="text-align:center">
        <canvas id="gl-canvas" width="500" height="500"></canvas>
      </div>
    </div>
  </body>
</html>
&#13;
&#13;
&#13;

4)如果您想使用MV.js脚本,您还可以将您的矩阵声明为mat4()个对象,并使用mult()将矩阵乘以在将数据传输到GPU之前的CPU(每个形状一次乘法而不是每个顶点一次)。您还可以使用它来创建更多功能和精确的相机矩阵:

var persp = perspective(30.0, 1, 0.1, 100); // fovy, aspect, near, far
var view = lookAt([0, 0, 5], [0, 0, 0], [0, 1, 0]); // eye, look, up
var projection2D = mult(persp, view);

var projection = []; // convert to 1D array
for(var i = 0; i < projection2D.length; i++) {
    projection = projection.concat(projection2D[i]);
}

希望这有用!干杯!