javascript - 在 WebGL 中绘制 3D 形状的第一步

标签 javascript 3d webgl

我已经学习 WebGL 几周了,但在绘制一些 3D 形状时遇到了问题。我猜我正在正确地计算顶点和索引,以及每个三 Angular 形的颜色,但它不起作用。有人可以告诉我我做错了什么吗? 我想做金字塔,它看起来像: enter image description here

这是代码:

var gl = null,
    canvas = null,
    glProgram = null,
    fragmentShader = null,
    vertexShader = null;

var coordinateArray = [ ],
    triangleVerticeColors = [ ],
    verticesArray = [ ],
    verticesIndexArray = [ ];

var vertexPositionAttribute = null,
    trianglesVerticeBuffer = null,
    vertexColorAttribute = null,
    trianglesColorBuffer = null,
    triangleVerticesIndexBuffer = null;

var P = mat4.create(),
    V = mat4.create();
M = mat4.create();

function initWebGL() {
  canvas = document.getElementById("my-canvas");
  try {
    gl = canvas.getContext("webgl") ||
        canvas.getContext("experimental-webgl");
  } catch (e) {
  }
  if (gl) {
    setupWebGL();
    initShaders();
    setupBuffers();
    getMatrixUniforms();
    setMatrixUniforms();
    animationLoop();
    //drawScene();
  } else {
    alert("Error: Your browser does not appear to" + "support WebGL.");
  }
}

function animationLoop() {
  var R = mat4.create();
  var angle = 0;
  var i = 0;

  var loop = function() {
      angle = performance.now() / 1000 / 6 * 2 * Math.PI;
      i++;
      mat4.rotate(M, R, angle, [ 0, 1, 0 ]);
      gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, M);

      gl.clearColor(0.1, 0.5, 0.1, 1.0);
      gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
      drawScene();
      requestAnimationFrame(loop);
  };
  requestAnimationFrame(loop);
}

function setupWebGL() {
  gl.enable(gl.DEPTH_TEST);
  gl.clearColor(0.1, 0.5, 0.1, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  console.log(P);
  console.log(V);
  console.log(M);

  mat4.lookAt(V, [ 3, -1, -5 ], [ 0, 0, 0 ], [ 0, 1, 0 ]);
  mat4.perspective(P, glMatrix.toRadian(45), canvas.width / canvas.height, 0.1, 1000.0);

}

function initShaders() {
  var fs_source = document.getElementById('shader-fs').innerHTML,
      vs_source = document.getElementById('shader-vs').innerHTML;

  vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
  fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);

  glProgram = gl.createProgram();

  gl.attachShader(glProgram, vertexShader);
  gl.attachShader(glProgram, fragmentShader);
  gl.linkProgram(glProgram);
  if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
    alert("Unable to initialize the shader program.");
  }

  gl.useProgram(glProgram);
}
function makeShader(src, type) {
  var shader = gl.createShader(type);

  gl.shaderSource(shader, src);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
  }
  return shader;
}

function setupBuffers() {
  // n-sides polygon
  var n = 6;
  var radius = 1;
  var	angle = (Math.PI * 2) / n;
  var xCoordinate = 0;
  var yCoordinate = 0;
  for (var i = 0; i < n; i++) {

    var a = angle * i;
    var xNewCoordinate = xCoordinate + radius * Math.cos(a);
    var yNewCoordinate = yCoordinate + radius * Math.sin(a);
    var zNewCoordinate = 0;
    coordinateArray.push(xNewCoordinate);
    coordinateArray.push(yNewCoordinate);
    coordinateArray.push(zNewCoordinate);

  }

  verticesArray = [

      //Bottom Face
      0.0, 0.0, 0.0,
      0.0, 0.0, -1.0,
      1.0, 0.0, -1.0,
      0.0, 0.0, 0.0,
      1.0, 0.0, -1.0,
      1.0, 0.0, 0.0,

      //Front Face
      0.0, 0.0, 0.0,
      1.0, 0.0, 0.0,
      0.5, 1.0, -0.5,

      //Right Face
      1.0, 0.0, 0.0,
      1.0, 0.0, -1.0,
      0.5, 1.0, -0.5,

      //Back Face
      1.0, 0.0, -1.0,
      0.0, 0.0, -1.0,
      0.5, 1.0, -0.5,

      //Left Face
      0.0, 0.0, -1.0,
      0.0, 0.0, 0.0,
      0.5, 1.0, -0.5,
      ];

  trianglesVerticeBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesArray), gl.STATIC_DRAW);

  verticesIndexArray = [
      3, 2, 1,
      3, 1, 0,
      3, 0, 4,
      0, 1, 4,
      1, 2, 4,
      2, 3, 4,
      ];

  triangleVerticesIndexBuffer = gl.createBuffer();
  triangleVerticesIndexBuffer.number_vertext_points = verticesIndexArray.length;
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleVerticesIndexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(verticesIndexArray), gl.STATIC_DRAW);

  triangleVerticeColors = [
      1.0, 0.0, 0.0,
      1.0, 0.0, 0.0,
      1.0, 0.0, 0.0,

      0.0, 1.0, 0.0,
      0.0, 1.0, 0.0,
      0.0, 1.0, 0.0,

      1.0, 0.0, 1.0,
      1.0, 0.0, 1.0,
      1.0, 0.0, 1.0,

      0.5, 0.0, 0.0,
      0.5, 0.0, 0.0,
      0.5, 0.0, 0.0,

      0.0, 5.0, 0.0,
      0.0, 5.0, 0.0,
      0.0, 5.0, 0.0,

      1.0, 1.0, 0.0,
      1.0, 1.0, 0.0,
      1.0, 1.0, 0.0,
      ];

  trianglesColorBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVerticeColors), gl.STATIC_DRAW);

}

function getMatrixUniforms() {
  glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");
  glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
  glProgram.vMatrixUniform = gl.getUniformLocation(glProgram, "uVMatrix");
}

function setMatrixUniforms() {
  gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, M);
  gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, P);
  gl.uniformMatrix4fv(glProgram.vMatrixUniform, false, V);
}

function drawScene() {
  vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
  gl.enableVertexAttribArray(vertexPositionAttribute);
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

  vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
  gl.enableVertexAttribArray(vertexColorAttribute);
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
  gl.vertexAttribPointer(vertexColorAttribute, 3, gl.FLOAT, false, 0, 0);



  gl.drawElements(gl.TRIANGLE_STRIP, triangleVerticesIndexBuffer.number_vertext_points,  gl.UNSIGNED_SHORT, 0);
}


initWebGL();
body{ background-color: grey; }
canvas{ background-color: white; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>

<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec4 aVertexPosition;
  attribute vec4 aVertexColor;

  varying vec4 vColor;

  // Model matrix
  uniform mat4 uMVMatrix;
  // Projection matrix
  uniform mat4 uPMatrix;
  // View matrix
  uniform mat4 uVMatrix;

  void main(void) {
    vColor = aVertexColor;
    gl_Position = uPMatrix * uVMatrix * uMVMatrix * aVertexPosition;
  }
</script>
<script id="shader-fs" type="x-shader/x-fragment">
 precision mediump float;
 varying vec4 vColor;

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

<canvas id="my-canvas" width="400" height="300">
  Your browser does not support the HTML5 canvas element.
</canvas>

输出如下:

enter image description here

我在 atm 上工作的第二件事是在 GPU 中计算“gl_position”

gl_Position = uPMatrix * uVMatrix * uMVMatrix * aVertexPosition;

如何利用 CPU?

提前致谢!

最佳答案

顶点索引错误。尝试一下

  verticesIndexArray = [
    0, 1, 2,
    3, 4, 5,
    6, 7, 8,
    9, 10, 11,
    12, 13, 14,
    15, 16, 17,
  ];

var gl = null,
    canvas = null,
    glProgram = null,
    fragmentShader = null,
    vertexShader = null;

var coordinateArray = [ ],
    triangleVerticeColors = [ ],
    verticesArray = [ ],
    verticesIndexArray = [ ];

var vertexPositionAttribute = null,
    trianglesVerticeBuffer = null,
    vertexColorAttribute = null,
    trianglesColorBuffer = null,
    triangleVerticesIndexBuffer = null;

var P = mat4.create(),
    V = mat4.create();
M = mat4.create();

function initWebGL() {
  canvas = document.getElementById("my-canvas");
  try {
    gl = canvas.getContext("webgl") ||
        canvas.getContext("experimental-webgl");
  } catch (e) {
  }
  if (gl) {
    setupWebGL();
    initShaders();
    setupBuffers();
    getMatrixUniforms();
    setMatrixUniforms();
    animationLoop();
    //drawScene();
  } else {
    alert("Error: Your browser does not appear to" + "support WebGL.");
  }
}

function animationLoop() {
  var R = mat4.create();
  var angle = 0;
  var i = 0;

  var loop = function() {
      angle = performance.now() / 1000 / 6 * 2 * Math.PI;
      i++;
      mat4.rotate(M, R, angle, [ 0, 1, 0 ]);
      gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, M);

      gl.clearColor(0.1, 0.5, 0.1, 1.0);
      gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
      drawScene();
      requestAnimationFrame(loop);
  };
  requestAnimationFrame(loop);
}

function setupWebGL() {
  gl.enable(gl.DEPTH_TEST);
  gl.clearColor(0.1, 0.5, 0.1, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  mat4.lookAt(V, [ 3, -1, -5 ], [ 0, 0, 0 ], [ 0, 1, 0 ]);
  mat4.perspective(P, glMatrix.toRadian(45), canvas.width / canvas.height, 0.1, 1000.0);

}

function initShaders() {
  var fs_source = document.getElementById('shader-fs').innerHTML,
      vs_source = document.getElementById('shader-vs').innerHTML;

  vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
  fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);

  glProgram = gl.createProgram();

  gl.attachShader(glProgram, vertexShader);
  gl.attachShader(glProgram, fragmentShader);
  gl.linkProgram(glProgram);
  if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
    alert("Unable to initialize the shader program.");
  }

  gl.useProgram(glProgram);
}
function makeShader(src, type) {
  var shader = gl.createShader(type);

  gl.shaderSource(shader, src);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
  }
  return shader;
}

function setupBuffers() {
  // n-sides polygon
  var n = 6;
  var radius = 1;
  var	angle = (Math.PI * 2) / n;
  var xCoordinate = 0;
  var yCoordinate = 0;
  for (var i = 0; i < n; i++) {

    var a = angle * i;
    var xNewCoordinate = xCoordinate + radius * Math.cos(a);
    var yNewCoordinate = yCoordinate + radius * Math.sin(a);
    var zNewCoordinate = 0;
    coordinateArray.push(xNewCoordinate);
    coordinateArray.push(yNewCoordinate);
    coordinateArray.push(zNewCoordinate);

  }

  verticesArray = [

      //Bottom Face
      0.0, 0.0, 0.0,
      0.0, 0.0, -1.0,
      1.0, 0.0, -1.0,
      0.0, 0.0, 0.0,
      1.0, 0.0, -1.0,
      1.0, 0.0, 0.0,

      //Front Face
      0.0, 0.0, 0.0,
      1.0, 0.0, 0.0,
      0.5, 1.0, -0.5,

      //Right Face
      1.0, 0.0, 0.0,
      1.0, 0.0, -1.0,
      0.5, 1.0, -0.5,

      //Back Face
      1.0, 0.0, -1.0,
      0.0, 0.0, -1.0,
      0.5, 1.0, -0.5,

      //Left Face
      0.0, 0.0, -1.0,
      0.0, 0.0, 0.0,
      0.5, 1.0, -0.5,
      ];

  trianglesVerticeBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesArray), gl.STATIC_DRAW);

  verticesIndexArray = [
    0, 1, 2,
    3, 4, 5,
    6, 7, 8,
    9, 10, 11,
    12, 13, 14,
    15, 16, 17,
  ];

  triangleVerticesIndexBuffer = gl.createBuffer();
  triangleVerticesIndexBuffer.number_vertext_points = verticesIndexArray.length;
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, triangleVerticesIndexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(verticesIndexArray), gl.STATIC_DRAW);

  triangleVerticeColors = [
      1.0, 0.0, 0.0,
      1.0, 0.0, 0.0,
      1.0, 0.0, 0.0,

      0.0, 1.0, 0.0,
      0.0, 1.0, 0.0,
      0.0, 1.0, 0.0,

      1.0, 0.0, 1.0,
      1.0, 0.0, 1.0,
      1.0, 0.0, 1.0,

      0.5, 0.0, 0.0,
      0.5, 0.0, 0.0,
      0.5, 0.0, 0.0,

      0.0, 5.0, 0.0,
      0.0, 5.0, 0.0,
      0.0, 5.0, 0.0,

      1.0, 1.0, 0.0,
      1.0, 1.0, 0.0,
      1.0, 1.0, 0.0,
      ];

  trianglesColorBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVerticeColors), gl.STATIC_DRAW);

}

function getMatrixUniforms() {
  glProgram.mvMatrixUniform = gl.getUniformLocation(glProgram, "uMVMatrix");
  glProgram.pMatrixUniform = gl.getUniformLocation(glProgram, "uPMatrix");
  glProgram.vMatrixUniform = gl.getUniformLocation(glProgram, "uVMatrix");
}

function setMatrixUniforms() {
  gl.uniformMatrix4fv(glProgram.mvMatrixUniform, false, M);
  gl.uniformMatrix4fv(glProgram.pMatrixUniform, false, P);
  gl.uniformMatrix4fv(glProgram.vMatrixUniform, false, V);
}

function drawScene() {
  vertexPositionAttribute = gl.getAttribLocation(glProgram, "aVertexPosition");
  gl.enableVertexAttribArray(vertexPositionAttribute);
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer);
  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);

  vertexColorAttribute = gl.getAttribLocation(glProgram, "aVertexColor");
  gl.enableVertexAttribArray(vertexColorAttribute);
  gl.bindBuffer(gl.ARRAY_BUFFER, trianglesColorBuffer);
  gl.vertexAttribPointer(vertexColorAttribute, 3, gl.FLOAT, false, 0, 0);



  gl.drawElements(gl.TRIANGLES, triangleVerticesIndexBuffer.number_vertext_points,  gl.UNSIGNED_SHORT, 0);
}


initWebGL();
body{ background-color: grey; }
canvas{ background-color: white; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>

<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec4 aVertexPosition;
  attribute vec4 aVertexColor;

  varying vec4 vColor;

  // Model matrix
  uniform mat4 uMVMatrix;
  // Projection matrix
  uniform mat4 uPMatrix;
  // View matrix
  uniform mat4 uVMatrix;

  void main(void) {
    vColor = aVertexColor;
    gl_Position = uPMatrix * uVMatrix * uMVMatrix * aVertexPosition;
  }
</script>
<script id="shader-fs" type="x-shader/x-fragment">
 precision mediump float;
 varying vec4 vColor;

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

<canvas id="my-canvas" width="400" height="300">
  Your browser does not support the HTML5 canvas element.
</canvas>

这些索引也将起作用

 verticesIndexArray = [
      0, 1, 2,
      0, 2, 5,
      5, 0, 8,
      0, 1, 8,
      1, 2, 8,
      2, 5, 8,
  ];

不同之处在于,如果您共享顶点,它们也会共享颜色。如果您希望每个面都能够具有唯一的颜色,那么每个顶点都必须是唯一的(或者您必须使用基于复杂纹理的顶点索引)。

查看你的顶点,从底面算起的前 6 个顶点

  verticesArray = [

      //Bottom Face
      0.0, 0.0, 0.0,  // 0
      0.0, 0.0, -1.0, // 1       
      1.0, 0.0, -1.0, // 2       
      0.0, 0.0, 0.0,  // 3       
      1.0, 0.0, -1.0, // 4
      1.0, 0.0, 0.0,  // 5

他们制作的正方形将每个顶点放在这些位置

   1----24 
   |     |
   |     |
   03----5

所以你可以使用

0, 1, 2,
3, 4, 5,

或者(例如)

0, 1, 2,
0, 2, 5,

看看其余的点

  //Front Face
  0.0, 0.0, 0.0,  // 6
  1.0, 0.0, 0.0,  // 7
  0.5, 1.0, -0.5, // 8

  //Right Face
  1.0, 0.0, 0.0,  // 9 
  1.0, 0.0, -1.0, // 10
  0.5, 1.0, -0.5, // 11

  //Back Face
  1.0, 0.0, -1.0, // 12
  0.0, 0.0, -1.0, // 13
  0.5, 1.0, -0.5, // 14

  //Left Face
  0.0, 0.0, -1.0, // 15
  0.0, 0.0, 0.0,  // 16
  0.5, 1.0, -0.5, // 18

点 8、11、14、18 都是底座上方的同一点。所有其他点都是基点的副本。

如上所述,如果您希望能够为特定面上使用的每个顶点指定不同的颜色和/或法线和/或纹理坐标,则需要副本。

还有一个问题。该代码使用 gl.TRIANGLE_STRIP 而不是 gl.TRIANGLES

既然你可以看到差异。如果你使用单个顶点,你会得到这个

enter image description here

如果你使用共享顶点,你会得到这个

enter image description here

关于javascript - 在 WebGL 中绘制 3D 形状的第一步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40327590/

相关文章:

javascript - BigText 和 FitText 都不起作用

matlab - 如何定义 3 个维度的功率谱?

javascript - 在 python 中使用 Bokeh 实现完整的 3d 散点图

opengl - 绘制3D孔的图形技术是什么?

javascript - 多个对象 Glsl

opengl-es - Webgl:最远平面能见度

javascript - 如何计算骨骼动画中的最终骨骼矩阵?

javascript - 如何在博文中添加自动跳转符

javascript - 如何检测一周中的某一天,然后用它来改变风格

javascript - 如果所选文本是 HTML,如何使用 javascript 获取所选 DOM?