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