简体   繁体   English

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

[英]First steps with drawing 3D shapes in WebGL

I am learning WebGL from few weeks and I've got a problem with drawing some 3D shapes. 我从几周开始学习WebGL,但是在绘制一些3D形状时遇到了问题。 Guess I am corectly counting vertices and indices, as well as a color for each triangle, but it does not work. 猜猜我正在计算顶点和索引以及每个三角形的颜色,但是它不起作用。 Could someone tell me what am I doing wrong ? 有人可以告诉我我在做什么错吗? I would like to make pyramide which will looks like : 我想制作一个看起来像的金字塔: 在此处输入图片说明

And here is the code : 这是代码:

 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> 

With output looking like : 输出如下:

在此处输入图片说明

Second thing on which I am working atm is couting 'gl_position' in GPU 我正在处理atm的第二件事是在GPU中计算'gl_position'

gl_Position = uPMatrix * uVMatrix * uMVMatrix * aVertexPosition;

How can I count in on CPU ? 我该如何使用CPU?

Thanks in advance! 提前致谢!

The vertex indices are wrong. 顶点索引错误。 Try 尝试

  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> 

These indices will also work 这些索引也将起作用

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

The difference being if you share vertices they will also share colors. 区别在于,如果您共享顶点,它们也将共享颜色。 If you want each face to be able to have unique colors then each vertex has to be unique (or you have to use complex texture based vertex indexing). 如果希望每个面都可以具有唯一的颜色,则每个顶点都必须是唯一的(或者必须使用基于复杂纹理的顶点索引)。

Looking at your vertice the first 6 vertices from the base 看着顶点,从底部开始的前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

The square they make puts each vertex at these locations 他们制作的正方形将每个顶点放在这些位置

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

So you can use 所以你可以使用

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

Or (for example) 或(例如)

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

Looking at the rest of the points 看剩下的要点

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

Points 8, 11, 14, 18 are all the same point above the base. 点8、11、14、18都位于基准上方的同一点。 All the other points are copies of the base points. 所有其他点都是基点的副本。

As mentioned above you need copies if you want to be able to specify different colors and or normals and or texture coordinates for each vertex's use on a specific face. 如上所述,如果希望能够为特定面上的每个顶点使用指定不同的颜色和/或法线和/或纹理坐标,则需要复制。

There's one more issue. 还有一个问题。 The code is using gl.TRIANGLE_STRIP instead of gl.TRIANGLES 该代码使用gl.TRIANGLE_STRIP而不是gl.TRIANGLES

So given that you can see the difference. 因此,您可以看到其中的区别。 If you use the individual vertices you get this 如果使用单个顶点,则得到此

在此处输入图片说明

If you use the shared vertices you get this 如果使用共享顶点,您将获得此

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM