将整个形状移动到圆圈webgl上

时间:2017-09-29 18:49:01

标签: javascript graphics 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);
    */
}

1 个答案:

答案 0 :(得分:0)

代码有很多问题

  • 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>

还有一件事,不是手动计算cirlce上的位置,你也可以使用矩阵函数,旋转,然后翻译

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