如何沿 y 轴平移球体(它只是上升,所以平移时不会下降)以及如何变形

How to translate the sphere along y-axis (it just go up, so not come down on translation) and how to deform

如何让物体上下移动,碰到顶底变形?

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

我的旋转球体代码是(我已经按照Git Hub 教程的第 11 课学习了 link https://github.com/gpjt/webgl-lessons/blob/master/lesson11/index.html):

 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 和下降时触及 -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() 函数)**

我的尝试是这样的(但是sphere一直往上升,永远不会下降,怎么下降)?

   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 轴的变形,同时上下触摸顶部和底部的球体,我的代码有什么问题吗?

更改您的 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;
}