我有一个带webgl的画布。我初始化webgl,创建一个片段和一个顶点着色器,两个三角形覆盖整个和一个纹理。
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);
}
`;
我从ImageData对象创建纹理,其元素是随机选择的(每个像素都是不同的颜色)。当我应用纹理时,它似乎覆盖整个区域,左上角的像素颜色拉伸覆盖整个画布。
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, IMAGEDATA);
这是我到目前为止的代码:
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>
如何正确放置纹理?
答案 0 :(得分:1)
只有两个错误,a_texCoords
的错误位置类型和错误的纹理坐标应该在0到1的范围内。
请参阅下面的代码进行更正。
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);
// You had the wrong location type getUniformLocation a_exCoord is an attribute
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
// You had the wrong texture coords.Coords are in the range 0 to 1
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0, 0,
1, 0,
0, 1,
0, 1,
1, 1,
1, 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);
// changed this as I thought you where indexing a 8bit array then saw you
// correctly index a 32 bit array. Id did not change the code back but yours was
// correct as well.
for (let i = 0; i < imageData.dataBuf8.length; i += 4) {
imageData.dataBuf8[i] = Math.random() * 255;; // red
imageData.dataBuf8[i + 1] = Math.random() * 255; // green
imageData.dataBuf8[i + 2] = Math.random() * 255; // blue
imageData.dataBuf8[i + 3] = Math.random() * 255; // alpha //
}
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);
&#13;
canvas {
border: 2px solid black;
}
&#13;
<div id="container"></div>
&#13;