简体   繁体   中英

Why doesn't my sphere render complete?

I'm trying to render a sphere in webgl, im using a method from webglfundamentals but somehow in my programm the sphere is just rendered to 20%. In chrome i get this error: L ERROR :GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1

 var canvas; var gl; var index = 0; var pointsArray = []; var normalsArray = []; var indexArray = []; var colorArray = []; var near = -10; var far = 10; var radius = 1.5; var theta = 0.0; var phi = 0.0; var dr = 5.0 * Math.PI/180.0; var left = -3.0; var right = 3.0; var ytop =3.0; var bottom = -3.0; var va = vec4(0.0, 0.0, -1.0,1); var vb = vec4(0.0, 0.942809, 0.333333, 1); var vc = vec4(-0.816497, -0.471405, 0.333333, 1); var vd = vec4(0.816497, -0.471405, 0.333333,1); var lightPosition = vec4(0.0, 1.0, 1.0, 0.0 ); var lightAmbient = vec4(0.2, 0.2, 0.2, 1.0 ); var lightDiffuse = vec4( 1.0, 1.0, 1.0, 1.0 ); var lightSpecular = vec4( 1.0, 1.0, 1.0, 1.0 ); var materialAmbient = vec4( 1.0, 0.0, 1.0, 1.0 ); var materialDiffuse = vec4( 1.0, 0.0, 0.0, 1.0 ); var materialSpecular = vec4( 1.0, 0.8, 0.0, 1.0 ); var materialShininess = 100.0; var ctm; var ambientColor, diffuseColor, specularColor; var texture; var modelViewMatrix, projectionMatrix; var modelViewMatrixLoc, projectionMatrixLoc; var eye; var at = vec3(0.0, 0.0, 0.0); var up = vec3(0.0, 1.0, 0.0); var iBuffer; function createSphereVertices( radius, subdivisionsAxis, subdivisionsHeight, opt_startLatitudeInRadians, opt_endLatitudeInRadians, opt_startLongitudeInRadians, opt_endLongitudeInRadians) { if (subdivisionsAxis <= 0 || subdivisionsHeight <= 0) { throw Error('subdivisionAxis and subdivisionHeight must be > 0'); } opt_startLatitudeInRadians = opt_startLatitudeInRadians || 0; opt_endLatitudeInRadians = opt_endLatitudeInRadians || Math.PI; opt_startLongitudeInRadians = opt_startLongitudeInRadians || 0; opt_endLongitudeInRadians = opt_endLongitudeInRadians || (Math.PI * 2); var latRange = opt_endLatitudeInRadians - opt_startLatitudeInRadians; var longRange = opt_endLongitudeInRadians - opt_startLongitudeInRadians; // We are going to generate our sphere by iterating through its // spherical coordinates and generating 2 triangles for each quad on a // ring of the sphere. // var numVertices = (subdivisionsAxis + 1) * (subdivisionsHeight + 1); var positions = []; // var normals = webglUtils.createAugmentedTypedArray(3, numVertices); // var texCoords = webglUtils.createAugmentedTypedArray(2 , numVertices); // Generate the individual vertices in our vertex buffer. for (var y = 0; y <= subdivisionsHeight; y++) { for (var x = 0; x <= subdivisionsAxis; x++) { // Generate a vertex based on its spherical coordinates var u = x / subdivisionsAxis; var v = y / subdivisionsHeight; var theta = longRange * u; var phi = latRange * v; var sinTheta = Math.sin(theta); var cosTheta = Math.cos(theta); var sinPhi = Math.sin(phi); var cosPhi = Math.cos(phi); var ux = cosTheta * sinPhi; var uy = cosPhi; var uz = sinTheta * sinPhi; positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0)); normalsArray.push(vec4(ux, uy, uz,1.0)); // texCoords.push(1 - u, v); } } var numVertsAround = subdivisionsAxis + 1; // var indices = webglUtils.createAugmentedTypedArray(3, subdivisionsAxis * subdivisionsHeight * 2, Uint16Array); for (var x = 0; x < subdivisionsAxis; x++) { for (var y = 0; y < subdivisionsHeight; y++) { // Make triangle 1 of quad. pointsArray.push(positions[(y + 0) * numVertsAround + x]); pointsArray.push(positions[(y + 0) * numVertsAround + x + 1]); pointsArray.push(positions[(y + 1) * numVertsAround + x]); // Make triangle 2 of quad. pointsArray.push(positions[(y + 1) * numVertsAround + x]); pointsArray.push(positions[(y + 0) * numVertsAround + x + 1]); pointsArray.push(positions[(y + 1) * numVertsAround + x + 1]); index +=6; } } } window.onload = function init() { canvas = document.getElementById( "gl-canvas" ); gl = WebGLUtils.setupWebGL( canvas ); if ( !gl ) { alert( "WebGL isn't available" ); } gl.viewport( 0, 0, canvas.width, canvas.height ); gl.clearColor( 0.0, 0.0, 0.0, 1.0 ); gl.enable(gl.DEPTH_TEST); // // Load shaders and initialize attribute buffers // var program = initShaders( gl, "vertex-shader", "fragment-shader" ); gl.useProgram( program ); createSphereVertices(1,12,12); ambientProduct = mult(lightAmbient, materialAmbient); diffuseProduct = mult(lightDiffuse, materialDiffuse); specularProduct = mult(lightSpecular, materialSpecular); var nBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer); gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW ); var vNormal = gl.getAttribLocation( program, "vNormal" ); gl.vertexAttribPointer( vNormal, 4, gl.FLOAT, false, 0, 0 ); gl.enableVertexAttribArray( vNormal); var vBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer); gl.bufferData(gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW); var vPosition = gl.getAttribLocation( program, "vPosition"); gl.vertexAttribPointer(vPosition, 4, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(vPosition); modelViewMatrixLoc = gl.getUniformLocation( program, "modelViewMatrix" ); projectionMatrixLoc = gl.getUniformLocation( program, "projectionMatrix" ); gl.uniform4fv( gl.getUniformLocation(program, "ambientProduct"),flatten(ambientProduct) ); gl.uniform4fv( gl.getUniformLocation(program, "diffuseProduct"),flatten(diffuseProduct) ); gl.uniform4fv( gl.getUniformLocation(program, "specularProduct"),flatten(specularProduct) ); gl.uniform4fv( gl.getUniformLocation(program, "lightPosition"),flatten(lightPosition) ); gl.uniform1f( gl.getUniformLocation(program, "shininess"),materialShininess ); render(); } function render() { gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); eye = vec3(radius*Math.sin(theta)*Math.cos(phi), radius*Math.sin(theta)*Math.sin(phi), radius*Math.cos(theta)); modelViewMatrix = lookAt(eye, at , up); projectionMatrix = ortho(left, right, bottom, ytop, near, far); gl.uniformMatrix4fv(modelViewMatrixLoc, false, flatten(modelViewMatrix) ); gl.uniformMatrix4fv(projectionMatrixLoc, false, flatten(projectionMatrix) ); for( var i=0; i<index; i+=3) gl.drawArrays( gl.TRIANGLES, i, 3); window.requestAnimFrame(render); } project1.html 
 <!DOCTYPE html> <html> <script id="vertex-shader" type="x-shader/x-vertex"> attribute vec4 vPosition; attribute vec4 vNormal; varying vec3 N, L, E; uniform mat4 modelViewMatrix; uniform mat4 projectionMatrix; uniform vec4 lightPosition; void main() { vec3 pos = -(modelViewMatrix * vPosition).xyz; vec3 light = lightPosition.xyz; L = normalize( light - pos ); E = -pos; N = normalize( (modelViewMatrix*vNormal).xyz); gl_Position = projectionMatrix * modelViewMatrix * vPosition; } </script> <script id="fragment-shader" type="x-shader/x-fragment"> precision mediump float; uniform vec4 ambientProduct; uniform vec4 diffuseProduct; uniform vec4 specularProduct; uniform float shininess; varying vec3 N, L, E; void main() { vec4 fColor; vec3 H = normalize( L + E ); vec4 ambient = ambientProduct; float Kd = max( dot(L, N), 0.0 ); vec4 diffuse = Kd*diffuseProduct; float Ks = pow( max(dot(N, H), 0.0), shininess ); vec4 specular = Ks * specularProduct; if( dot(L, N) < 0.0 ) specular = vec4(0.0, 0.0, 0.0, 1.0); fColor = ambient + diffuse +specular; fColor.a = 1.0; gl_FragColor = fColor; } </script> <script type="text/javascript" src="./Common/webgl-utils.js"></script> <script type="text/javascript" src="./Common/initShaders.js"></script> <script type="text/javascript" src="./Common/MV.js"></script> <script type="text/javascript" src="project1.js"></script> <body> <canvas id="gl-canvas" width="512" height="512"> Oops ... your browser doesn't support the HTML5 canvas element </canvas> </body> </html> 

This is what i get only a unfinished sphere: 球

I don't know this is actual correct answer since I didn't check this by running codes. But, I just guess why this error occured.

Major reason of "out of range in attribute variable"

Basically, this will happen when the buffer you passed didn't have enough length. Therefore, you need to check the count of buffer source you created.

And your error is ":GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1" . In this case, attribute 1 in the error message means "vNormal" attribute in your GLSL code. Because it is 2nd attribute variable in your GLSL code. (If the error code says attribute 0 , this problem should be made by vPosition)

As long as I saw your code, I think there is mismatch of length with normal buffer and position buffer.

  • Surface count in your code : Subdivision Height * Subdivision Axis * 2
  • Position element count in your code: Subdivision Height * Subdivision Axis *6
  • Normal element count in your code: Subdivision Height * Subdivision Axis * 4

I guess this is the reason of the problem. Each vertex must have position and normal in this case, so your normal element count must be Subdivision Height * Subdivision Axis * 6

2nd argument in gl.vertexAttribPointer

I think you have mistake about 2nd argument in gl.vertexAttribPointer. This is the count which means how many float elements needs to be passed each vertex.

In this case, you pushed 3 float elements for each vertex. So, you needs to specify 3 as argument for vPosition even if you used vec4 in your GLSL code. By this argument, GPU can split these buffers for each vertex and pass them into vertex shader parallely.

4th element in vector

This is not strongly related to your question.But I found the code can be a reason of bug.

    positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
    normalsArray.push(vec4(ux, uy, uz,1.0));

You need to understand what the meaning of 4th element in vec4. When this vector means coordinates, 4th element must be 1.However, when this vector means directions, 4th element must be 0.

Because, if this means directions, direction can not be affected by translation transform. ( I suggest you to learn affine transform to understand this)

So, you need to rewrite that code like this.

    positions.push(vec4(radius * ux, radius * uy, radius * uz,1.0));
    normalsArray.push(vec4(ux, uy, uz,0));

I hope this answer could help you...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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