Вы неправильно написали переменную атрибута из своего вершинного шейдера.
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>