移动整个形状以指向圆 webgl

Moving entire shape to point on circle webgl

我有以下代码试图通过将星星放在圆上的点上来绘制花圈。我可以画一颗星,但是当我试图画一个花圈时,它只会在圆圈周围画一个分支,或者现在在圆圈的一个点上。我知道嵌套 modelViewMatrices 的方式存在问题,我想不出进行转换的正确方法。我需要画星星,然后翻译整个星星。

   function DrawWreath()
    {
        var radius = 0.5;
        for (var i = 0; i < 1; i++) {
            var theta = i * 30;
            var x = radius * Math.cos(theta);
            var y = radius * Math.sin(theta);
            var t = translate(x, y, 0);
             if (modelViewMatrix) {
                modelViewMatrix = mult(modelViewMatrix, t) ;
             } else {
                modelViewMatrix = t;
             }
            modelViewStack.push(modelViewMatrix);
            DrawOneStar();
            modelViewMatrix = modelViewStack.pop();
        }

    }

function DrawOneStar()
{
    // draw the full star
    for (var i=1; i <= 5; i++) {
         r = rotate(72*i, 0, 0, 1);
         if (modelViewMatrix) {
            modelViewMatrix = mult(r, modelViewMatrix) ;
         } else {
            modelViewMatrix = r;
         }
         modelViewMatrix = r;
         DrawOneBranch();

    }
}

function DrawOneBranch()
{
    var s;

    // one branch
    s = scale4(1/16, 1/16, 1); 
    modelViewStack.push(modelViewMatrix);
    modelViewMatrix = mult(modelViewMatrix, s);
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays( gl.LINE_LOOP, 0, vertices.length);

    /*
    modelViewMatrix = modelViewStack.pop();
    //s = scale4(1/8, -1/8, 1);
    modelViewMatrix = mult(modelViewMatrix, s);
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays( gl.LINE_STRIP, 0, vertices.length);
    */
}

代码有很多问题

  • DrawOneStar中的代码向左旋转

    mult(r, modelViewMatrix)    // ???
    

    看来你想要这个

    mult(modelViewMatrix, r)
    

    就像您对 translatescale

  • 所做的一样
  • DrawOneStar中的代码没有保存矩阵

    这意味着您要么想要修复代码以便保存 矩阵,或者,你想旋转一个固定的量。

    因为代码现在是旋转 72,然后旋转 72 + 144,然后旋转 72 + 144 + 216 因为每次它旋转之前的矩阵 旋转

  • DrawOneBranch 中的代码没有弹出矩阵

    该行被注释掉了

  • theta 正在使用度数

    大多数数学库都使用弧度,所以这段代码可能没有用 你期待什么

      var theta = i * 30;
      var x = radius * Math.cos(theta);
      var y = radius * Math.sin(theta);
    

    Math.sinMath.cos 需要弧度而不是度数。

  • 外循环只做一次迭代

    for (var i = 0; i < 1; i++) {   // ???
    

其他建议

  • 使用更好的数学库。无论数学库需要调用 flatten 函数来准备可供 WebGL 使用的矩阵,都会比不调用的数学库慢。还有一个采用弧度旋转和视野的库意味着它将匹配其他内置数学函数,如 Math.cos 等...

  • modelViewMatrix中放一个矩阵开始。然后你可以删除所有检查是否有矩阵

  • 当循环和计算一个值时,考虑使用标准化数字(从 0 到 1 的数字),然后基于它计算其他值。

    例如,代码在外循环中有 theta = i * 30,在下一个循环中有 rotate(i * 72, ...),但如果您更改迭代次数,那么您还必须更改这些数字以匹配。

    而是首先根据循环计算一个从 0 到 1 的值。范例

    const numStars = 10;
    for (let i = 0; i < numStars; ++i) {
      const l = i / numStars;   // goes from 0 to 1
    

    然后使用该值计算角度;

      const theta = l * 360;  // or l * Math.PI * 2 for radians
    

    同样

      const numRotations = 5;
      for (let i = 0; i < numRotations; ++i) {
         const l = i / numRotations;  // goes from 0 to 1
         rotate(i * 360, ....
    

    这样你就可以轻松更改 numStarsnumRotations 必须更改任何其他代码

function DrawWreath()
    {
        var radius = 0.5;
        for (var i = 0; i < 10; i++) {
            var theta = i / 10 * Math.PI * 2;
            var x = radius * Math.cos(theta);
            var y = radius * Math.sin(theta);
            var t = translate(x, y, 0);
            modelViewStack.push(modelViewMatrix);
            modelViewMatrix = mult(modelViewMatrix, t) ;
            DrawOneStar();
            modelViewMatrix = modelViewStack.pop();
        }

    }

function DrawOneStar()
{
    // draw the full star
    for (var i=1; i <= 5; i++) {
         var r = rotate(72, 0, 0, 1);
         modelViewMatrix = mult(modelViewMatrix, r) ;
         DrawOneBranch();

    }
}

function DrawOneBranch()
{
    var s;

    // one branch
    s = scale4(1/16, 1/16, 1); 
    modelViewStack.push(modelViewMatrix);
    modelViewMatrix = mult(modelViewMatrix, s);
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays( gl.LINE_LOOP, 0, vertices.length);
    

    modelViewMatrix = modelViewStack.pop();
    /*
    //s = scale4(1/8, -1/8, 1);
    modelViewMatrix = mult(modelViewMatrix, s);
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays( gl.LINE_STRIP, 0, vertices.length);
    */
}

function flatten(m) {
  return m;
}

function translate(x, y, z) {
  return m4.translation([x, y, z]);
}

function scale4(x, y, z) {
  return m4.scaling([x, y, z]);
}

function rotate(a, x, y, z) {
  return m4.axisRotation([x, y, z], a * Math.PI / 180);
}

function mult(a, b) {
  return m4.multiply(a, b);
}

const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const modelViewStack = [];
let modelViewMatrix = m4.identity();

const vs = `
attribute vec4 position;
uniform mat4 u_projectionMatrix;
uniform mat4 u_modelViewMatrix;
void main() {
  gl_Position = u_projectionMatrix * u_modelViewMatrix * position;
}
`;

const fs = `
void main() { gl_FragColor = vec4(1,0,0,1); }
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: {
    numComponents: 2,
    data: [
      0, 1,
      -.33, 0,
      .33, 0,
    ],
  },
});

twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const scale = 1;
twgl.setUniforms(programInfo, {
  u_projectionMatrix: m4.ortho(
     -aspect / scale, aspect / scale, -1 / scale, 1 / scale, -1, 1),
  u_modelViewMatrix: m4.identity(),
});
const vertices = { length: 3, };
const modelViewMatrixLoc = gl.getUniformLocation(programInfo.program, "u_modelViewMatrix");
DrawWreath();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>

还有一点,除了手动计算圆上的位置,您还可以使用矩阵函数,旋转,然后平移

function DrawWreath()
    {
        const radius = 0.5;
        const numStars = 20;
        for (let i = 0; i < numStars; ++i) {
            const l = i / numStars;
            const theta = l * Math.PI * 2;
            const r = rotateInRadians(theta, 0, 0, 1);
            const t = translate(radius, 0, 0);            
            modelViewStack.push(modelViewMatrix);
            modelViewMatrix = mult(modelViewMatrix, r);
            modelViewMatrix = mult(modelViewMatrix, t);
            DrawOneStar();
            modelViewMatrix = modelViewStack.pop();
        }

    }

function DrawOneStar()
{
    // draw the full star
    const numParts = 6;
    for (let i = 0; i < numParts; ++i) {
         const l = i / numParts;
         const r = rotateInRadians(l * Math.PI * 2, 0, 0, 1);
         modelViewStack.push(modelViewMatrix);
         modelViewMatrix = mult(modelViewMatrix, r) ;
         DrawOneBranch();
         modelViewMatrix = modelViewStack.pop();
    }
}

function DrawOneBranch()
{
    var s;

    // one branch
    s = scale4(1/16, 1/16, 1); 
    modelViewStack.push(modelViewMatrix);
    modelViewMatrix = mult(modelViewMatrix, s);
    gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix));
    gl.drawArrays( gl.LINE_LOOP, 0, vertices.length);
    
    modelViewMatrix = modelViewStack.pop();
}

function flatten(m) {
  return m;
}

function translate(x, y, z) {
  return m4.translation([x, y, z]);
}

function scale4(x, y, z) {
  return m4.scaling([x, y, z]);
}

function rotate(a, x, y, z) {
  return m4.axisRotation([x, y, z], a * Math.PI / 180);
}

function rotateInRadians(a, x, y, z) {
  return m4.axisRotation([x, y, z], a);
}

function mult(a, b) {
  return m4.multiply(a, b);
}

const m4 = twgl.m4;
const gl = document.querySelector("canvas").getContext("webgl");
const modelViewStack = [];
let modelViewMatrix = m4.identity();

const vs = `
attribute vec4 position;
uniform mat4 u_projectionMatrix;
uniform mat4 u_modelViewMatrix;
void main() {
  gl_Position = u_projectionMatrix * u_modelViewMatrix * position;
}
`;

const fs = `
void main() { gl_FragColor = vec4(1,0,0,1); }
`;
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  position: {
    numComponents: 2,
    data: [
      0, 1,
      -.33, 0,
      .33, 0,
    ],
  },
});

twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const scale = 1;
twgl.setUniforms(programInfo, {
  u_projectionMatrix: m4.ortho(
     -aspect / scale, aspect / scale, -1 / scale, 1 / scale, -1, 1),
  u_modelViewMatrix: m4.identity(),
});
const vertices = { length: 3, };
const modelViewMatrixLoc = gl.getUniformLocation(programInfo.program, "u_modelViewMatrix");
DrawWreath();
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas></canvas>

您可能会发现 these articles useful