无法在webgl中加载纹理

时间:2018-06-08 10:01:36

标签: javascript html5-canvas webgl

我正在尝试在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)

1 个答案:

答案 0 :(得分:1)

您拼错了顶点着色器中的属性变量。

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

应该是"a_texcoord"

另外一个提示,您可以使用``。

在JS中创建多行字符串

e.g。

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>
&#13;
&#13;
&#13;