如何沿y轴平移球体(它只是上升,所以不要翻译)以及如何变形

时间:2015-10-15 12:41:54

标签: javascript webgl

如何上下移动物体,使其在接触屋顶和底部时变形?

我已经创建了一个球体,它可以通过沿y轴平移而无限旋转并向上移动,但现在我必须将其向下移动,我希望它在向上和向下碰撞时变形,现在我的问题是:   (1)如何让我的球体在y轴上上下移动?   (2)触摸顶部时如何变形?并且当上下移动时接触完成顶部或底部恢复相同的形状。

我的旋转球体代码是(我已经在此链接上的Git Hub教程第{11课}上进行了第11课):

 var newRotationMatrix = mat4.create();
        mat4.identity(newRotationMatrix);          
        mat4.rotate(newRotationMatrix, degToRad(2 / 10), [0, 1, 0]);
        mat4.multiply(newRotationMatrix, [1,0,0], moonRotationMatrix);
        gl.drawElements(gl.TRIANGLES, moonVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

完整的功能是:

function tick()
        {
            requestAnimFrame(tick);
            gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

            gl.uniform1i(shaderProgram.useLightingUniform, false);
            mat4.identity(mvMatrix);
            mat4.translate(mvMatrix, [0, 0, -6]);
            mat4.multiply(mvMatrix, moonRotationMatrix);
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, moonTexture);
            gl.uniform1i(shaderProgram.samplerUniform, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexPositionBuffer);
            gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, moonVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexTextureCoordBuffer);
            gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, moonVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexNormalBuffer);
            gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, moonVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, moonVertexIndexBuffer);
            setMatrixUniforms();

          /*rotation part is below*/
            var newRotationMatrix = mat4.create();
            mat4.identity(newRotationMatrix);          
            mat4.rotate(newRotationMatrix, degToRad(2 / 10), [0, 1, 0]);
            mat4.multiply(newRotationMatrix, [1,0,0], moonRotationMatrix);
            gl.drawElements(gl.TRIANGLES, moonVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

        }

在此代码中添加的内容是它将旋转并且必须触及顶部和底部(从y轴的中心开始距离为250和-250,因为运动必须沿着y-轴) 当球体在上升时接触250并且随着球体与顶部或底部之间的接触完成后立即恢复并立即恢复,如何变形,这个过程应无限重复。

修改

在这个问题中,moonVertexIndexBuffer包含tick函数中的square的顶点。 这是我的initfuffer功能

function initBuffers(latitudeBands, longitudeBands)
        {           
            var radius = 1;
            var vertexPositionData = [];
            var normalData = [];
            var textureCoordData = [];
            for (var latNumber = 0; latNumber <= latitudeBands; latNumber++)
            {
                var theta = latNumber * Math.PI / latitudeBands;
                var sinTheta = Math.sin(theta);
                var cosTheta = Math.cos(theta);
                for (var longNumber = 0; longNumber <= longitudeBands; longNumber++)
                {
                    var phi = longNumber * 2 * Math.PI / longitudeBands;
                    var sinPhi = Math.sin(phi);
                    var cosPhi = Math.cos(phi);
                    var x = cosPhi * sinTheta;
                    var y = cosTheta;
                    var z = sinPhi * sinTheta;
                    var u = 1 - (longNumber / longitudeBands);
                    var v = 1 - (latNumber / latitudeBands);
                    normalData.push(x);
                    normalData.push(y);
                    normalData.push(z);
                    textureCoordData.push(u);
                    textureCoordData.push(v);
                    vertexPositionData.push(radius * x);
                    vertexPositionData.push(radius * y);
                    vertexPositionData.push(radius * z);                   
                }
            }
            alert("vertexPositionData:" + vertexPositionData);
            var indexData = [];
            for (var latNumber = 0; latNumber < latitudeBands; latNumber++) {
                for (var longNumber = 0; longNumber < longitudeBands; longNumber++) {
                    var first = (latNumber * (longitudeBands + 1)) + longNumber;
                    var second = first + longitudeBands + 1;
                    indexData.push(first);
                    indexData.push(second);
                    indexData.push(first + 1);
                    indexData.push(second);
                    indexData.push(second + 1);
                    indexData.push(first + 1);
                    //console.log("four points for iteration" + latNumber, +longNumber + " are " + "1: " + first + "2 :" + (first + 1) + "3: " + (second) + "4 :" + (second + 1));
                }
            }
            moonVertexNormalBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexNormalBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
            moonVertexNormalBuffer.itemSize = 3;
            moonVertexNormalBuffer.numItems = normalData.length / 3;

            moonVertexTextureCoordBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexTextureCoordBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordData), gl.STATIC_DRAW);
            moonVertexTextureCoordBuffer.itemSize = 2;
            moonVertexTextureCoordBuffer.numItems = textureCoordData.length / 2;
                       ///
            moonVertexPositionBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexPositionBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
            moonVertexPositionBuffer.itemSize = 3;
            moonVertexPositionBuffer.numItems = vertexPositionData.length / 3;

            moonVertexIndexBuffer = gl.createBuffer();
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, moonVertexIndexBuffer);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.DYNAMIC_DRAW);
            moonVertexIndexBuffer.itemSize = 1;
            moonVertexIndexBuffer.numItems = indexData.length;
        }

        function tick()
        {
            requestAnimFrame(tick);
            gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
            // var lighting = false;
            gl.uniform1i(shaderProgram.useLightingUniform, false);

            /*I removed some part here */

            mat4.identity(mvMatrix);
            mat4.translate(mvMatrix, [0, 0, -6]);
            mat4.multiply(mvMatrix, moonRotationMatrix);
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, moonTexture);
            gl.uniform1i(shaderProgram.samplerUniform, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexPositionBuffer);
            gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, moonVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexTextureCoordBuffer);
            gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, moonVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ARRAY_BUFFER, moonVertexNormalBuffer);
            gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, moonVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, moonVertexIndexBuffer);
            setMatrixUniforms();

            var newRotationMatrix = mat4.create();
            mat4.identity(newRotationMatrix);
            mat4.rotate(newRotationMatrix, degToRad(2 / 10), [0, 1, 0], newRotationMatrix);
            mat4.multiply(newRotationMatrix, moonRotationMatrix, moonRotationMatrix);

            gl.drawElements(gl.TRIANGLES, moonVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

        }

这是我的顶点着色器:

 <script id="shader-vs" type="x-shader/x-vertex">
        attribute vec3 aVertexPosition;
        attribute vec3 aVertexNormal;
        attribute vec2 aTextureCoord;
        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;
        uniform mat3 uNMatrix;
        uniform vec3 uAmbientColor;
        uniform vec3 uLightingDirection;
        uniform vec3 uDirectionalColor;
        uniform bool uUseLighting;
        varying vec2 vTextureCoord;
        varying vec3 vLightWeighting;
        void main(void) {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        vTextureCoord = aTextureCoord;
        if (!uUseLighting) {
        vLightWeighting = vec3(1.0, 1.0, 1.0);
        } else {
        vec3 transformedNormal = uNMatrix * aVertexNormal;
        float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);
        vLightWeighting = uAmbientColor + uDirectionalColor * directionalLightWeighting;
        }
        }
    </script>

这是initshaders功能

 function initShaders()
        {
            var fragmentShader = getShader(gl, "shader-fs");
            var vertexShader = getShader(gl, "shader-vs");
            shaderProgram = gl.createProgram();
            gl.attachShader(shaderProgram, vertexShader);
            gl.attachShader(shaderProgram, fragmentShader);
            gl.linkProgram(shaderProgram);
            if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
                alert("Could not initialise shaders");
            }
            gl.useProgram(shaderProgram);
            shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
            gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
            shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
            gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
            shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
            gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);
            shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
            shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
            shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
            shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
            shaderProgram.useLightingUniform = gl.getUniformLocation(shaderProgram, "uUseLighting");
            shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");
            shaderProgram.lightingDirectionUniform = gl.getUniformLocation(shaderProgram, "uLightingDirection");
            shaderProgram.directionalColorUniform = gl.getUniformLocation(shaderProgram, "uDirectionalColor");
        }

**我无法理解如何无限地上下移动(沿y轴平移),因为我们拥有数组中的所有正方形,因为球体是由正方形组成的(取决于传入的纬度和经度) initBuffers()函数)**

我的尝试是这样的(但是球体无限上升,永远不会再回落,如何降低它?)

   var translation = [0, 0.5,0];
 function tick()
        {
          ....//I am elminating the code which was shown previously
          var translationMatrix = makeTranslation(translation[0], translation[1], translation[2]);
            mat4.multiply(moonRotationMatrix, translationMatrix, moonRotationMatrix);
        }
 function makeTranslation(tx, ty, tz) {

            return [
               1, 0, 0, 0,
               0, 1, 0, 0,
               0, 0, 1, 0,
               tx, ty, tz, 1
            ];
        }

EDIT2:在第一个回答之后,我尝试缩放变形: 在顶点着色器中,我保持统一,如下所示:

 <script id="shader-vs" type="x-shader/x-vertex">
        uniform  vec4 uScaleY;
        void main(void) {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
         }
        }
    </script>

在initshader()中,我这样做:

shaderProgram.uScaleYAttribute = gl.getUniformLocation(shaderProgram, "uScaleY");

在setuniform中我这样做:

var yScale =[0,1,0];
  function setMatrixUniforms()
  {
            gl.uniformMatrix4fv(shaderProgram.uScaleYAttribute, false, yScale);
  }

在我的tick()中,我尝试这样做:

  var newRotationMatrix = mat4.create();
        mat4.identity(newRotationMatrix);
        mat4.rotate(newRotationMatrix, degToRad(2 / 10), [0, 1, 0]);
        mat4.multiply(newRotationMatrix, moonRotationMatrix, moonRotationMatrix);
        translateMatrix = translation(translate[0], translate[1], translate[2]);
        mat4.multiply(moonRotationMatrix, translateMatrix,moonRotationMatrix);
        var maxY =1.5;
        var moonPosY = moonRotationMatrix[3 * 4 +1];
        if (moonPosY > maxY || moonPosY < (-maxY))
        {
            translate[1] *= -1;
        }

        var maxDiff = 0.05;
        var minDiff = 0.01;
        var diff = Math.abs(moonPosY - maxY);

        if (diff < maxDiff)//sphere when go up
        {
            yScale = 1 - (minDiff - diff) * 0.1;
        }
            /*
        else if (moonPosY > (-maxDiff)) // scaling when sphere come down
        {
            yScale = 1 - (minDiff - diff) * 0.1;
        }
        */
        gl.drawElements(gl.TRIANGLES, moonVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);

缩放不适用于y轴的变形,而顶部和底部的球体上下触摸,我的代码中有什么错误?

1 个答案:

答案 0 :(得分:1)

更改您的tick,以便跟踪总翻译并反转达到阈值时使用的翻译向量。

它类似于:

var maxY = 100;
var moonPosY = moonRotationMatrix[/*row*/ 3 * 4 + /*col*/ 1];

if (moonPosY < maxY || moonPosY < (-maxY)) {
    translation = translation.map(a => -a);
    // or simply
    // translation[1] *= -1;
    // if you want to reverse it just on Y axis
}

要使其变形,它取决于您想要的变形,但如果您只是想沿Y轴压扁它,您可以为顶点着色器添加一个制服以进行Y刻度,并用以下内容填充它:

var yScale = 1;
var maxDiff = 10;

var diff = Math.abs(moonPosY - maxY);

if (diff < maxDiff) { 
    yScale = 1 - (minDiff - diff) * 0.1;
}