【问题标题】:Can't load texture in webgl无法在 webgl 中加载纹理
【发布时间】:2018-11-18 08:47:46
【问题描述】:

我正在尝试在 webgl 中的三角形上加载单个纹理。这是我的代码。我没有收到错误,但有 2 个警告,我无法找出原因,警告是:

INVALID_VALUE: enableVertexAttribArray: index out of range
INVALID_VALUE: vertexAttribPointer: index out of range

程序应该加载给定的纹理并显示矩形。 我正在关注here 的教程。可能的原因是什么?这里是JSBIN OUTPUT

var canvas = document.createElement('canvas')
canvas.width = window.innerWidth
canvas.height = window.innerHeight
document.body.appendChild(canvas)

// Create a canvas webgl context as a base to draw upon
var gl = canvas.getContext('webgl')
//  Clear canvas with any color you want
gl.clearColor(0.75, 0.85, 0.8, 1.0)
gl.clear(gl.COLOR_BUFFER_BIT)

// webgl pipeline need 2 shaders 1) vertex shader & fragment shader
// crate a vertex shader & compile it
var vertexShader = gl.createShader(gl.VERTEX_SHADER)
gl.shaderSource(vertexShader, [
'attribute vec2 a_texcoord;',
'varying vec2 v_texcoord;',

'attribute vec2 position;',
 'void main() {',
   'gl_Position = vec4(position, 0.0, 1.0);',
    'v_texcoord = a_texcoord;',
  '}'
].join('\n'))
gl.compileShader(vertexShader)

if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
        console.error('ERROR compiling vertex shader!', gl.getShaderInfoLog(vertexShader));
}

// create a fragment shader & compile it 
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(fragmentShader, [
'precision mediump float;',
'varying vec2 v_texcoord;',
'uniform sampler2D u_texture;',
 'void main() {',
   '   gl_FragColor = texture2D(u_texture, v_texcoord);',
 '}'
].join('\n'))
gl.compileShader(fragmentShader)

if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
   console.error('ERROR compiling fragment shader!',     
   gl.getShaderInfoLog(fragmentShader));
}

// Create a program that will be offloaded to the GPU
var program = gl.createProgram()

// Attach vertex shader & fragment shaders to the the program
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)

// Link program
// gl.linkProgram(program)
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.error('ERROR linking program!', gl.getProgramInfoLog(program));
}
gl.validateProgram(program);
if (!gl.getProgramParameter(program, gl.VALIDATE_STATUS)) {
console.error('ERROR validating program!', gl.getProgramInfoLog(program));
}

// Define vertex positions as float32 array elemnets
var vertices = new Float32Array([
  -0.5, -0.5,
  0.5,  -0.5,
  0.0,   0.5
]);

// Create buffer where data will be stored
var buffer = gl.createBuffer()
// Mark the given buffer as current/active buffer
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
// Add data to the active buffer
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

const colors = [
    1,  0.5,  1.0,  1.0,    // white
    0,  1.0,  0.3,  1.0,    // red
    0.0,  0.0,  0.8,  1.0,  // green
];

const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

// Tell webgl to use the progr that we created
gl.useProgram(program)

gl.bindBuffer(gl.ARRAY_BUFFER, buffer)

// Get location of the attribute `position` defined in our shader program
program.position = gl.getAttribLocation(program, 'position')
gl.enableVertexAttribArray(program.position)
gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0)

var texcoordLocation = gl.getAttribLocation(program, "a_texcoords");

var Texbuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, Texbuffer);
gl.enableVertexAttribArray(texcoordLocation);

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

// We'll supply texcoords as floats.
gl.vertexAttribPointer(texcoordLocation, 2, gl.FLOAT, false, 0, 0);

var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

// Fill the texture with a 1x1 blue pixel.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
              new Uint8Array([0, 0, 255, 255]));

// Asynchronously load an image
var image = new Image();

image.src = "tex.jpg";
image.addEventListener('load', function() {
  // Now that the image has loaded make copy it to the texture.
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
  gl.generateMipmap(gl.TEXTURE_2D);
});

gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 2)

【问题讨论】:

    标签: javascript html5-canvas webgl


    【解决方案1】:

    您在顶点着色器中拼错了一个属性变量。

    var texcoordLocation = gl.getAttribLocation(program, "a_texcoords");
    

    应该改为"a_texcoord"

    还有一个小技巧,你可以在 JS 中使用 ``.

    创建多行字符串

    例如

    var vertexShader = `
        precision lowp float;
    
        attribute aPosition;
        attribute aUV;
    
        varying vec2 vUV;
    
        void main() {
            vUV = aUV;
            gl_Position = vec4(aPosition,0.0,1.0);
        }
    `;
    

    编辑:

    如果您找不到问题的解决方案,我已经创建了一个示例,可以向您展示您想要做什么。

    <!doctype html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<style>
    			body {
    				background-color: black;
    			}
    			
    			canvas {
    				display: block;
    				margin-top: 30px;
    				margin-left: auto;
    				margin-right: auto;
    				border: solid 1px white;
    				border-radius: 10px;
    			}
    			
    			script {
    				display: none;
    			}
    		</style>
    	</head>
    	
    	<body>
    		<canvas id="canvas"></canvas>
    		<script type="application/javascript">
    		
    		// Self executing function
    		void function() {
    		
    			// Turn on strict rules for JS
    			"use strict";
    			
    			var canvasWidth = 180;
    			var canvasHeight = 160;
    			var canvas = null;
    			var gl = null;
    			
    			// helper functions
    			
    			// Creates shader programs with vs & fs code as a single string
    			function createProgram(vertexCode,fragmentCode) {
    				var vertexShader = gl.createShader(gl.VERTEX_SHADER);
    				var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    				
    				gl.shaderSource(vertexShader,vertexCode);
    				gl.shaderSource(fragmentShader,fragmentCode);
    				gl.compileShader(vertexShader);
    				gl.compileShader(fragmentShader);
    				
    				try {
    					if (!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)) {
    						throw "VS: " + gl.getShaderInfoLog(vertexShader);
    					}
    					
    					if (!gl.getShaderParameter(fragmentShader,gl.COMPILE_STATUS)) {
    						throw "FS: " + gl.getShaderInfoLog(fragmentShader);
    					}
    				} catch(log) {
    					gl.deleteShader(vertexShader);
    					gl.deleteShader(fragmentShader);
    					console.error(log);
    				}
    				
    				var program = gl.createProgram();
    				
    				gl.attachShader(program,vertexShader);
    				gl.attachShader(program,fragmentShader);
    				gl.linkProgram(program);
    				gl.deleteShader(vertexShader);
    				gl.deleteShader(fragmentShader);
    				
    				return program;
    			}
    			
    			function createBuffer(data) {
    				data = data instanceof Float32Array ? data : new Float32Array(data);
    			
    				var buffer = gl.createBuffer();
    				
    				gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
    				gl.bufferData(gl.ARRAY_BUFFER,data,gl.STATIC_DRAW);
    				
    				return buffer;
    			}
    			
    			// Creates a texture from an existing canvas or HTMLImage (new Image())
    			// without needing width & height or with a typed array (Uint8Array) that has
    			// a specified width & height
    			// e.g.
    			// createTexture(HTMLImageElement) will work just fine
    			// createTexture(Uint8Array,width,height), remember that a texture needs four values for one pixel
    			function createTexture(image,width,height) {
    				var texture = gl.createTexture();
    				
    				// Set the active texture slot to 0
    				// WebGL has ~30 texture slots, meaning you could have about 30 textures bound at once
    				// Think of it as an array of 30 pointers to texture objects that you can set
    				gl.activeTexture(gl.TEXTURE0); // Sets the current 'index'
    				gl.bindTexture(gl.TEXTURE_2D,texture); // binds the selected texture object to the current pointer
    				
    				// How to filter the texture when it needs resizing when sampled
    				// (Is it going to be blurred when streched?)
    				// (gl.NEAREST means no blur)
    				gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);
    				gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);
    				
    				// What to do if UV coordinates go outside the texture's size
    				// gl.CLAMP_TO_EDGE repeats the pixel at the texture's border.
    				gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
    				gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
    				
    				width === undefined && height === undefined ?
    					gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,image):
    					gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,width,height,0,gl.RGBA,gl.UNSIGNED_BYTE,image);
    					
    				return texture;
    			}
    			
    			var program = null;
    			var buffer = null;
    			var texture = null;
    			
    			// Program Attributes
    			var aPosition = null;
    			var aUV = null;
    			
    			// Program uniforms
    			var uTexture = null;
    			
    			// Runs when page is finished loading
    			// Treat it like the 'main' function seen in other languages
    			onload = function() {
    				canvas = document.getElementById("canvas");
    				canvas.width = canvasWidth;
    				canvas.height = canvasHeight;
    				
    				gl = canvas.getContext("webgl") || console.error("WebGL is not supported");
    				
    				// Create GL resources
    				program = createProgram(`
    					precision lowp float;
    					
    					attribute vec2 aPosition; // Vertex Pos
    					attribute vec2 aUV; // Texture Coordinate
    					
    					varying vec2 vUV; // Texture coordinate to interpolate across pixels
    					
    					void main() {
    						vUV = aUV;
    						gl_Position = vec4(aPosition,0.0,1.0);
    					}
    				`,`
    					precision lowp float;
    					
    					varying vec2 vUV; // Interpolated value from the vertex shader
    					
    					uniform sampler2D uTexture; // uniforms are values sent to the shader from JS
    												// sampler2D vars are just integers that say what
    												// texture index they are going to read from
    					
    					void main() {
    						gl_FragColor = texture2D(uTexture,vUV);
    					}
    				`);
    				
    				aPosition = gl.getAttribLocation(program,"aPosition");
    				aUV = gl.getAttribLocation(program,"aUV");
    				
    				uTexture = gl.getUniformLocation(program,"uTexture");
    				
    				// Vertex floats that are given to the GPU
    				// It's more efficient to think of verticies as groups of
    				// floats that form 1 set of attributes
    				// e.g. the program I made has two attributes
    				// aPosition & aUV which are two 2D vectors, four floats in total.
    				// Therefore each four floats in my vertex buffer make up one vertex
    				buffer = createBuffer([
    					// X  Y     U   V
    					 0.5, 0.5,	1.0,0.0,
    					-0.5, 0.5,	0.0,0.0,
    					 0.5,-0.5,	1.0,1.0,
    					 
    					 0.5,-0.5,	1.0,1.0,
    					-0.5, 0.5,	0.0,0.0,
    					-0.5,-0.5,	0.0,1.0,
    				]);
    				
    				// Create some noise to use as a texture
    				var width = 32;
    				var height = 32;
    				var pixels = new Uint8Array((width * height) << 2);
    				
    				for (var i = 0; i < pixels.length; i += 4) {
    					pixels[i + 0] = (Math.random() * 255) | 0;
    					pixels[i + 1] = (Math.random() * 255) | 0;
    					pixels[i + 2] = (Math.random() * 255) | 0;
    					pixels[i + 3] = 255;
    				}
    				
    				texture = createTexture(pixels,width,height);
    				
    				// Setup GL State
    				gl.useProgram(program);	
    				gl.uniform1i(uTexture,0);
    				
    				gl.activeTexture(gl.TEXTURE0);
    				gl.bindTexture(gl.TEXTURE_2D,texture);
    				
    				gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
    				
    				// These functions tell WebGL how to interpret the vertexbuffer data
    				
    				// Every sixteen bytes, use the first eight (4 bytes is a float) for the 'aPosition' attribute
    				gl.vertexAttribPointer(aPosition,2,gl.FLOAT,gl.FALSE,16,0);
    				
    				// Every sixteen bytes, use the last eight bytes for the 'aUV' attribute
    				gl.vertexAttribPointer(aUV,2,gl.FLOAT,gl.FALSE,16,8);
    				
    				// These need to be enabled or the vertex data isn't fed indo the vertex shader
    				gl.enableVertexAttribArray(aPosition);
    				gl.enableVertexAttribArray(aUV);
    				
    				gl.clearColor(0.5,0.5,0.5,1.0);
    				gl.clear(gl.COLOR_BUFFER_BIT);
    				gl.drawArrays(gl.TRIANGLES,0,6);
    			}
    			
    			// Runs when the page is refreshed/closed
    			onunload = function() {
    				gl.deleteProgram(program);
    				gl.deleteBuffer(buffer);
    				gl.deleteTexture(texture);
    				gl = null;
    			}
    		
    		}();
    		
    		</script>
    	</body>
    </html>

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 2014-12-28
    相关资源
    最近更新 更多