I have a canvas with webgl. I initialize webgl, create a fragment and a vertex shader, two triangles to cover the whole and a texture.
const vertexShaderSource = `
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
`;
const fragmentShaderSource = `
precision mediump float;
// our texture
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
`;
I create the texture from a ImageData object whose elements are randomly chosen (each pixel a different color). When I apply the texture, it seems to cover the whole area with the upper-left pixel color stretching to cover the whole canvas.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, IMAGEDATA);
This is the code I have so far:
const width = 128;
const height = 128;
var createShader = function (gl, shaderSource, shaderType) {
const shader = gl.createShader(shaderType);
gl.shaderSource(shader, shaderSource);
gl.compileShader(shader);
const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
console.log(`Error compiling shader: ${gl.getShaderInfoLog(shader)}`);
return;
}
return shader;
};
var createProgram = function(gl, shaders, opt_attribs, opt_locations) {
const program = gl.createProgram();
for (var ii = 0; ii < shaders.length; ++ii) {
gl.attachShader(program, shaders[ii]);
}
if (opt_attribs) {
for (var ii = 0; ii < opt_attribs.length; ++ii) {
gl.bindAttribLocation(program, opt_locations ? opt_locations[ii] : ii, opt_attribs[ii]);
}
}
gl.linkProgram(program);
// Check the link status
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
console.log(`Error linking shader parameter: ${gl.getProgramInfoLog(program)}`);
gl.deleteProgram(program);
return;
}
return program;
}
// create canvas
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
// imagedata to update the texture
const imageData = {
imageData: new ImageData(width, height),
dataBuf: null,
dataBuf8: null,
data: null
};
imageData.dataBuf = new ArrayBuffer(imageData.imageData.data.length);
imageData.dataBuf8 = new Uint8ClampedArray(imageData.dataBuf);
imageData.data = new Uint32Array(imageData.dataBuf);
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
document.getElementById('container').appendChild(canvas);
// shaders
const vertexShaderSource = `
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
`;
const fragmentShaderSource = `
precision mediump float;
// our texture
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
`;
const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = createProgram(gl, [vertexShader, fragmentShader]);
gl.useProgram(program);
// triangle and triangle buffers
var positionLocation = gl.getAttribLocation(program, "a_position");
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
canvas.width, 0,
0, canvas.height,
0, canvas.height,
canvas.width, canvas.height,
canvas.width, 0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
var texCoordLocation = gl.getUniformLocation(program, "a_texCoord");
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
canvas.width, 0,
0, canvas.height,
0, canvas.height,
canvas.width, canvas.height,
canvas.width, 0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
// texture
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
for (let i = 0; i < imageData.data.length; i++) {
const r = Math.round(Math.random() * 100);
const g = Math.round(Math.random() * 100);
const b = Math.round(Math.random() * 100);
imageData.data[i] = (255 << 24) | // alpha
(b << 16) | // blue
(g << 8) | // green
r; //
}
imageData.imageData.data.set(imageData.dataBuf8);
// bind texture and draw
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageData.imageData);
gl.drawArrays(gl.TRIANGLES, 0, 6);
<div id="container"></div>
How can I correctly place the texture?
a_texCoordattribute that defines the texture coordinates for each vertex so they are all 0. Set it up the same as you do with thea_positionbuffer.Get the attribute location, create a buffer, bind it, set it withgl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0,0,1,0,0,1,0,1,1,1,1,0]), gl.STATIC_DRAW);then enable the a_texture attribute - Blindman67