WebGL尝试绘制球体

时间:2017-12-11 15:23:14

标签: buffer webgl

我尝试使用三角形和2个缓冲区(gl.ARRAY_BUFFER和gl.ELEMENT_ARRAY_BUFFER)绘制球体,但是出了点问题。我只看到空显示...我使用了一些代码http://learningwebgl.com/blog/?p=1253和这个{{ 3}}。

  var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '  gl_PointSize = 10.0;\n' +
    '}\n';

var FSHADER_SOURCE =
    'void main() {\n' +
    '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
    '}\n';

function resize(canvas) 
{
  var displayWidth  = canvas.clientWidth;
  var displayHeight = canvas.clientHeight;
  if (canvas.width  != displayWidth || canvas.height != displayHeight) 
  {
    canvas.width  = displayWidth;
    canvas.height = displayHeight;
  }
}

function initArrayBuffers(gl)
{
  var SPHERE_DIV = 6;
  var i, ai, si, ci;
  var j, aj, sj, cj;
  var p1, p2;
  var vertices = [],indices = [];
  for (j = 0; j <= SPHERE_DIV; j++) 
  {
    aj = j * Math.PI / SPHERE_DIV;
    sj = Math.sin(aj);
    cj = Math.cos(aj);
    for (i = 0; i <= SPHERE_DIV; i++) 
    {
      ai = i * 2 * Math.PI / SPHERE_DIV;
      si = Math.sin(ai);
      ci = Math.cos(ai);
      vertices.push(si * sj);  // X
      vertices.push(cj);       // Y
      vertices.push(ci * sj);  // Z
    }

    for (j = 0; j < SPHERE_DIV; j++)
    {
      for (i = 0; i < SPHERE_DIV; i++)
      {
        p1 = j * (SPHERE_DIV+1) + i;
        p2 = p1 + (SPHERE_DIV+1);
        indices.push(p1);
        indices.push(p2);
        indices.push(p1 + 1);
        indices.push(p1 + 1);
        indices.push(p2);
        indices.push(p2 + 1);
      }
    }
    var vertexBuffer = gl.createBuffer();
    if (!vertexBuffer) 
    {
      console.log('Failed to create the buffer object');
      return -1;
    }
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
    var indexBuffer = gl.createBuffer(); 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
  }
  return indices.length;
}

function main() 
{  
  var canvas = document.getElementById('webgl');  
  var gl = getWebGLContext(canvas);
  resize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  var n=initArrayBuffers(gl);
  if (!gl) 
  { 
    console.log('Failed to retrieve the <canvas> element');
    return; 
  } 
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) 
  {
    console.log('Failed to intialize shaders.');
    return;
  }
  gl.clearColor(0.0, 0.0, 0.0, 0.0);
  gl.clear(gl.COLOR_BUFFER_BIT );
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    if (a_Position < 0) 
      {
        console.log('Failed to get the storage location of a_Position');
        return -1;
      }
   gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
}

2 个答案:

答案 0 :(得分:2)

你的代码中有2个问题:

您必须定义通用顶点属性数据(gl.vertexAttribPointer)的数组,并且必须在绘制网格时启用顶点属性(gl.enableVertexAttribArray):

var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer( a_Position, 3, gl.FLOAT, false, 0, 0 );
gl.enableVertexAttribArray( a_Position );
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);


并且函数initArrayBuffers

中的曲线括号未对齐
function initArrayBuffers(gl)
{
  var SPHERE_DIV = 6;
  var i, ai, si, ci;
  var j, aj, sj, cj;
  var p1, p2;
  var vertices = [],indices = [];
  for (j = 0; j <= SPHERE_DIV; j++) 
  {
    aj = j * Math.PI / SPHERE_DIV;
    sj = Math.sin(aj);
    cj = Math.cos(aj);
    for (i = 0; i <= SPHERE_DIV; i++) 
    {
      ai = i * 2 * Math.PI / SPHERE_DIV;
      si = Math.sin(ai);
      ci = Math.cos(ai);
      vertices.push(si * sj);  // X
      vertices.push(cj);       // Y
      vertices.push(ci * sj);  // Z
    }
  } // <------------------------------------------------------------- ADD 

  for (j = 0; j < SPHERE_DIV; j++)
  {
    for (i = 0; i < SPHERE_DIV; i++)
    {
      p1 = j * (SPHERE_DIV+1) + i;
      p2 = p1 + (SPHERE_DIV+1);
      indices.push(p1);
      indices.push(p2);
      indices.push(p1 + 1);
      indices.push(p1 + 1);
      indices.push(p2);
      indices.push(p2 + 1);
    }
  }
  var vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) 
  {
    console.log('Failed to create the buffer object');
    return -1;
  }
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); 
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
  var indexBuffer = gl.createBuffer(); 
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

  // } <------------------------------------------------------ REMOVE

  return indices.length;
} 

请参阅代码段:

var VSHADER_SOURCE =
    'attribute vec4 a_Position;\n' +
    'void main() {\n' +
    '  gl_Position = a_Position;\n' +
    '  gl_PointSize = 10.0;\n' +
    '}\n';

var FSHADER_SOURCE =
    'void main() {\n' +
    '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
    '}\n';

var ShaderProgram = {};
ShaderProgram.Create = function( shaderList ) {
    var shaderObjs = [];
    for ( var i_sh = 0; i_sh < shaderList.length; ++ i_sh ) {
        var shderObj = this.CompileShader( shaderList[i_sh].source, shaderList[i_sh].stage );
        if ( shderObj == 0 )
            return 0;
        shaderObjs.push( shderObj );
    }
    var progObj = this.LinkProgram( shaderObjs )
    if ( progObj != 0 ) {
        progObj.attribIndex = {};
        var noOfAttributes = gl.getProgramParameter( progObj, gl.ACTIVE_ATTRIBUTES );
        for ( var i_n = 0; i_n < noOfAttributes; ++ i_n ) {
            var name = gl.getActiveAttrib( progObj, i_n ).name;
            progObj.attribIndex[name] = gl.getAttribLocation( progObj, name );
        }
        progObj.unifomLocation = {};
        var noOfUniforms = gl.getProgramParameter( progObj, gl.ACTIVE_UNIFORMS );
        for ( var i_n = 0; i_n < noOfUniforms; ++ i_n ) {
            var name = gl.getActiveUniform( progObj, i_n ).name;
            progObj.unifomLocation[name] = gl.getUniformLocation( progObj, name );
        }
    }
    return progObj;
}
ShaderProgram.AttributeIndex = function( progObj, name ) { return progObj.attribIndex[name]; } 
ShaderProgram.UniformLocation = function( progObj, name ) { return progObj.unifomLocation[name]; } 
ShaderProgram.Use = function( progObj ) { gl.useProgram( progObj ); } 
ShaderProgram.SetUniformI1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1i( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF1  = function( progObj, name, val ) { if(progObj.unifomLocation[name]) gl.uniform1f( progObj.unifomLocation[name], val ); }
ShaderProgram.SetUniformF2  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform2fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF3  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform3fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformF4  = function( progObj, name, arr ) { if(progObj.unifomLocation[name]) gl.uniform4fv( progObj.unifomLocation[name], arr ); }
ShaderProgram.SetUniformM33 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix3fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.SetUniformM44 = function( progObj, name, mat ) { if(progObj.unifomLocation[name]) gl.uniformMatrix4fv( progObj.unifomLocation[name], false, mat ); }
ShaderProgram.CompileShader = function( source, shaderStage ) {
    var shaderScript = document.getElementById(source);
    if (shaderScript) {
      source = "";
      var node = shaderScript.firstChild;
      while (node) {
        if (node.nodeType == 3) source += node.textContent;
        node = node.nextSibling;
      }
    }
    var shaderObj = gl.createShader( shaderStage );
    gl.shaderSource( shaderObj, source );
    gl.compileShader( shaderObj );
    var status = gl.getShaderParameter( shaderObj, gl.COMPILE_STATUS );
    if ( !status ) alert(gl.getShaderInfoLog(shaderObj));
    return status ? shaderObj : 0;
} 
ShaderProgram.LinkProgram = function( shaderObjs ) {
    var prog = gl.createProgram();
    for ( var i_sh = 0; i_sh < shaderObjs.length; ++ i_sh )
        gl.attachShader( prog, shaderObjs[i_sh] );
    gl.linkProgram( prog );
    status = gl.getProgramParameter( prog, gl.LINK_STATUS );
    if ( !status ) alert("Could not initialise shaders");
    gl.useProgram( null );
    return status ? prog : 0;
}

function initShaders(gl, vert_code, frag_code)
{
    var progDraw = ShaderProgram.Create( 
      [ { source : VSHADER_SOURCE, stage : gl.VERTEX_SHADER },
        { source : FSHADER_SOURCE, stage : gl.FRAGMENT_SHADER }
      ] );
    progDraw.inPos = gl.getAttribLocation( progDraw, "a_Position" );
    if ( progDraw == 0 )
        return false;
    ShaderProgram.Use( progDraw );
    gl.program = progDraw;
    return true;     
}

    function initArrayBuffers(gl)
    {
      var SPHERE_DIV = 6;
      var i, ai, si, ci;
      var j, aj, sj, cj;
      var p1, p2;
      var vertices = [],indices = [];
      for (j = 0; j <= SPHERE_DIV; j++) 
      {
        aj = j * Math.PI / SPHERE_DIV;
        sj = Math.sin(aj);
        cj = Math.cos(aj);
        for (i = 0; i <= SPHERE_DIV; i++) 
        {
          ai = i * 2 * Math.PI / SPHERE_DIV;
          si = Math.sin(ai);
          ci = Math.cos(ai);
          vertices.push(si * sj);  // X
          vertices.push(cj);       // Y
          vertices.push(ci * sj);  // Z
        }
      }

      for (j = 0; j < SPHERE_DIV; j++)
      {
        for (i = 0; i < SPHERE_DIV; i++)
        {
          p1 = j * (SPHERE_DIV+1) + i;
          p2 = p1 + (SPHERE_DIV+1);
          indices.push(p1);
          indices.push(p2);
          indices.push(p1 + 1);
          indices.push(p1 + 1);
          indices.push(p2);
          indices.push(p2 + 1);
        }
      }
      var vertexBuffer = gl.createBuffer();
      if (!vertexBuffer) 
      {
        console.log('Failed to create the buffer object');
        return -1;
      }
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); 
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
      var indexBuffer = gl.createBuffer(); 
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

      return indices.length;
    }

var n = 0;        
function drawScene(){

    var canvas = document.getElementById( "glow-canvas" );
    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.enable( gl.DEPTH_TEST );
    
    gl.clearColor(0.0, 0.0, 0.0, 0.0);
    gl.clear(gl.COLOR_BUFFER_BIT );
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    if (a_Position < 0) 
    {
      console.log('Failed to get the storage location of a_Position');
      return -1;
    }
    gl.vertexAttribPointer( a_Position, 3, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( a_Position );
    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_SHORT, 0);
}

var gl;
function sceneStart() {

    var canvas = document.getElementById( "glow-canvas");
    var vp = [canvas.width, canvas.height];
    gl = canvas.getContext( "experimental-webgl" );
    if ( !gl )
      return;

    n = initArrayBuffers(gl);
    if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) 
    {
      console.log('Failed to intialize shaders.');
      return;
    }

    setInterval(drawScene, 50);
}
<body onload="sceneStart();">
    <canvas id="glow-canvas" style="border: none;" width="512" height="512"></canvas>
</body>

答案 1 :(得分:0)

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<style>
			body {
				background-color: black;
			}
			
			canvas {
				position: absolute;
				margin-left: auto;
				margin-right: auto;
				left: 0;
				right: 0;
				border: solid 1px white;
				border-radius: 10px;
			}
		</style>
		
		<canvas id="canvas"></canvas>
		<script type="application/javascript">
		
		var imageWidth = 180;
		var imageHeight = 160;
		var canvas = null;
		var gl = null;
		var indexBuffer = null; // element array buffer
		var vertexBuffer = null; // array buffer
		var program = null;
		var uAngle = null;
		
		var circleAngle = 0.0;
		var circleRadius = 0.75;
		var circleVertexCount = 5; // No of verticies going around the circle's edge
		
		// ES6 has handy dandy `` syntax for strings, they allow for multiple lines.
		var vsCode = `
			precision lowp float;
			
			attribute vec2 aPosition;
			attribute vec3 aColour;
			
			varying vec3 vColour;
			
			uniform float uAngle;
			
			void main() {
				float s = sin(uAngle);
				float c = cos(uAngle);
				mat2 rot = mat2(
					c,-s,
					s,c
				);
				
				vColour = aColour;
				gl_Position = vec4(rot * aPosition,0.0,1.0);
			}
		`;
		
		var fsCode = `
			precision lowp float;
			
			varying vec3 vColour;
			
			void main() {
				gl_FragColor = vec4(vColour,1.0);
			}
		`;
		
		function loop() {
			circleAngle += 0.05;
			if (circleAngle > 2.0 * Math.PI) { circleAngle = 0.0; }
			gl.uniform1f(uAngle,circleAngle);
			
			gl.clear(gl.COLOR_BUFFER_BIT);
			gl.drawElements(gl.TRIANGLES,circleVertexCount * 3,gl.UNSIGNED_SHORT,0);
			requestAnimationFrame(loop);
		}
		
		window.onload = function() {
			canvas = document.getElementById("canvas");
			canvas.width = imageWidth;
			canvas.height = imageHeight;
			
			gl = canvas.getContext("webgl") || console.error("Couldn't get WebGL context");
			gl.clearColor(0.5,0.5,0.5,1.0);
			
			// generate verticies
			// There will be one vertex in the center of the circle, 
			// with the rest covering the outer edge.
			// vec2 + vec3 per vertex = 5 floats per vertex
			var circleVerticies = new Float32Array(circleVertexCount * 5 + 5);
			
			// add an extra point for the center
			
			// position
			circleVerticies[0] = 0.0;
			circleVerticies[1] = 0.0;
			
			// colour
			circleVerticies[2] = 0.5;
			circleVerticies[3] = 0.5;
			circleVerticies[4] = 0.5;
			
			for (
				var i = 5, angle = 0.0;
				i < circleVerticies.length;
				i += 5, angle += (2.0 * Math.PI) / circleVertexCount
			) {
				// position
				circleVerticies[i  ] = Math.sin(angle) * circleRadius;
				circleVerticies[i+1] = Math.cos(angle) * circleRadius;
				
				// colour
				circleVerticies[i+2] = Math.random();
				circleVerticies[i+3] = Math.random();
				circleVerticies[i+4] = Math.random();
			}
			
			// generate indexes
			var circleIndicies = new Uint16Array(circleVertexCount * 3);
			
			for (var i = 0, j = 1; i < circleIndicies.length - 3; i += 3, ++j) {
				circleIndicies[i  ] = 0;
				circleIndicies[i+1] = j;
				circleIndicies[i+2] = j + 1;
			}
			
			// Last triangle to connect the edge to the start
			/*
				    |\
				>   | \
				  ---  |
				  \   /
				   \ /
			*/
			circleIndicies[circleIndicies.length - 3] = 0;
			circleIndicies[circleIndicies.length - 2] = j;
			circleIndicies[circleIndicies.length - 1] = 1;
			
			// upload buffers to gpu
			vertexBuffer = gl.createBuffer();
			gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
			gl.bufferData(gl.ARRAY_BUFFER,circleVerticies,gl.STATIC_DRAW);
			
			indexBuffer = gl.createBuffer();
			gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
			gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,circleIndicies,gl.STATIC_DRAW);
			
			// create program
			var vertexShader = gl.createShader(gl.VERTEX_SHADER);
			var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
			
			gl.shaderSource(vertexShader,vsCode);
			gl.shaderSource(fragmentShader,fsCode);
			gl.compileShader(vertexShader);
			gl.compileShader(fragmentShader);
			
			console.log(gl.getShaderInfoLog(vertexShader));
			console.log(gl.getShaderInfoLog(fragmentShader));
			
			program = gl.createProgram();
			gl.attachShader(program,vertexShader);
			gl.attachShader(program,fragmentShader);
			gl.linkProgram(program);
			gl.deleteShader(vertexShader);
			gl.deleteShader(fragmentShader);
			
			uAngle = gl.getUniformLocation(program,"uAngle");
			
			// set state for rendering
			gl.useProgram(program);
			
			gl.vertexAttribPointer(
				0, // attrib location
				2, // attrib size
				gl.FLOAT, // value type
				gl.FALSE, // normalize?
				5 * Float32Array.BYTES_PER_ELEMENT, // total vertex size in bytes (5 * 4)
				0 * Float32Array.BYTES_PER_ELEMENT  // offset from the start of the vertex in bytes
			);
			
			gl.vertexAttribPointer(
				1, // attrib location
				3, // attrib size
				gl.FLOAT, // value type
				gl.FALSE, // normalize?
				5 * Float32Array.BYTES_PER_ELEMENT, // total vertex size in bytes (5 * 4)
				2 * Float32Array.BYTES_PER_ELEMENT  // offset from the start of the vertex in bytes
			);
			
			// Enable these attributes on the bound buffer for use
			gl.enableVertexAttribArray(0);
			gl.enableVertexAttribArray(1);
			
			requestAnimationFrame(loop);
		}
		
		window.onunload = function() {
			gl.deleteBuffer(indexBuffer);
			gl.deleteBuffer(vertexBuffer);
			gl = null;
		}
		
		</script>
	</head>
</html>