0
我一直在試圖學習一些webgl,基本上有兩個程序渲染像素存儲在紋理中,然後在其他程序的着色器中使用。webgl readpixels紋理着色器問題
webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);
這將調用,並嘗試在屏幕的readpixels,並把修改後的數據返回到紋理在接下來的程序中使用的渲染程序。
我得到的只是一個逐漸變得更加透明的黑色屏幕,但是也應該看到u_image(因爲這是在第一個用readpixels讀取像素的程序中渲染的)。
如果我註釋掉第二個方案的渲染:
gl.useProgram(webgl.program);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
然後,它會只呈現u_image沒有任何衰減。 所以我不確定是什麼問題。似乎也許它沒有正確讀取像素?但那麼,如果情況如此,衰落怎麼會起作用呢?試圖使用這兩種紋理有什麼問題嗎?
希望有人可以看看代碼,看看可能是什麼問題。
//webgl stuff
var webgl = new webglData();
function webglData(){
this.then = 0; //used for deltatime in rendering
this.request; //requestanimationframe, used when stopping/starting
this.canvas;
this.context;
this.div;
this.program;
this.cellProgram;
this.texture = [];
this.frameBuffer = [];
this.cellVShader = `
attribute vec2 aVertexPosition;
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
varying vec2 v_NW;
varying vec2 v_N;
varying vec2 v_NE;
varying vec2 v_W;
varying vec2 v_E;
varying vec2 v_SW;
varying vec2 v_S;
varying vec2 v_SE;
vec2 getOffset(int x, int y){
vec2 v = floor(a_texCoord * u_resolution);
v.x += float(x), v.y += float(y);
v /= u_resolution;
return v;
}
void main() {
//v_texCoord = a_texCoord;
//gl_Position = vec4(aVertexPosition, 0.0, 1.0);
// 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;
v_NW = getOffset(-1, 1);
v_N = getOffset(0, 1);
v_NE = getOffset(1, 1);
v_W = getOffset(-1, 0);
v_E = getOffset(1, 0);
v_SW = getOffset(-1, -1);
v_S = getOffset(0, -1);
v_SE = getOffset(1, -1);
}
`;
this.cellFShader = `
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_canvas1;
uniform vec4 uColor;
// our texture
uniform sampler2D u_before;
uniform sampler2D u_after;
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
varying vec2 v_NW;
varying vec2 v_N;
varying vec2 v_NE;
varying vec2 v_W;
varying vec2 v_E;
varying vec2 v_SW;
varying vec2 v_S;
varying vec2 v_SE;
void main() {
// Look up a color from the texture.
gl_FragColor = texture2D(u_image, v_W);
//gl_FragColor = uColor;
}
`;
this.vertexShader = `
attribute vec2 aVertexPosition;
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
//v_texCoord = a_texCoord;
//gl_Position = vec4(aVertexPosition, 0.0, 1.0);
// 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;
}
`;
this.fragmentShader = `
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_canvas1;
uniform vec4 uColor;
// our texture
uniform sampler2D u_before;
uniform sampler2D u_after;
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
// Look up a color from the texture.
gl_FragColor = texture2D(u_before, v_texCoord);
//gl_FragColor = uColor;
}
`;
this.init = function(){
this.div = innerDoc.getElementById('webglDiv');
gui.Window.get().showDevTools();
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext("experimental-webgl");
this.canvas.width = 512;
this.canvas.height = 512;
this.canvas.style.position = 'absolute';
this.canvas.style.zIndex = -1;
this.canvas.style.pointerEvents = 'none';
this.div.appendChild(this.canvas);
if(!this.context)return;
var gl = this.context;
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
//compile the shaders and create the program for webgl
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, this.vertexShader);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, this.fragmentShader);
gl.compileShader(fs);
var cvs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(cvs, this.cellVShader);
gl.compileShader(cvs);
var cfs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(cfs, this.cellFShader);
gl.compileShader(cfs);
this.program = gl.createProgram();
gl.attachShader(this.program, vs);
gl.attachShader(this.program, fs);
gl.linkProgram(this.program);
//gl.useProgram(this.program);
this.cellProgram = gl.createProgram();
gl.attachShader(this.cellProgram, cvs);
gl.attachShader(this.cellProgram, cfs);
gl.linkProgram(this.cellProgram);
//gl.useProgram(this.cellProgram);
//output any errors
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(vs));
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(fs));
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))console.log(gl.getProgramInfoLog(this.program));
if (!gl.getShaderParameter(cvs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(cvs));
if (!gl.getShaderParameter(cfs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(cfs));
if (!gl.getProgramParameter(this.cellProgram, gl.LINK_STATUS))console.log(gl.getProgramInfoLog(this.cellProgram));
this.setupStuff(gl, this.program);
this.setupStuff(gl, this.cellProgram);
this.texture.push(this.setupTexture(tool.canvas, 0, "u_image"));
this.texture.push(this.createBlankTexture(gl, tool.canvas.width*tool.canvas.height*4, gl.RGBA, tool.canvas.width, tool.canvas.height, "u_before"));
this.texture.push(this.createBlankTexture(gl, tool.canvas.width*tool.canvas.height*4, gl.RGBA, tool.canvas.width, tool.canvas.height, "u_after"));
this.frameBuffer.push(gl.createFramebuffer());
this.request = requestAnimationFrame(this.render);
}
this.render = function(now){
if(!webgl.context || config.tab!='scene'){cancelAnimationFrame(webgl.request); return;}
var gl = webgl.context;
// Convert the time to seconds
now *= 0.001;
// Subtract the previous time from the current time
var deltaTime = now - webgl.then;
// Remember the current time for the next frame.
webgl.then = now;
gl.useProgram(webgl.cellProgram);
gl.drawArrays(gl.TRIANGLES, 0, 6);
webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);
gl.useProgram(webgl.program);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
this.request = requestAnimationFrame(webgl.render);
}
this.setupStuff = function(gl, program){
gl.useProgram(program);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
// provide texture coordinates for the rectangle.
//this will be what the texture gets displayed on?
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
0.0, 1.0,
1.0, 0.0,
1.0, 1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
// lookup uniforms
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
// set the resolution
gl.uniform2f(resolutionLocation, this.canvas.width, this.canvas.height);
// Create a buffer for the position of the rectangle corners.
// store the data for the texture coordinates that were defined above, into the a_position?
var buffer = gl.createBuffer();
//this.frameBuffer.push(buffer);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Set a rectangle the same size as the image.
//I guess this adjusts the buffer data that was just created?
this.setRectangle(gl, 0, 0, this.canvas.width, this.canvas.height);
//var tex2 = setupTexture(canvas2, 1, program, "u_canvas2");
// Draw the rectangle.
//gl.drawArrays(gl.TRIANGLES, 0, 6);
//gl.drawArrays(gl.TRIANGLES, 0, numItems);
}
this.refreshTexture = function(){
if(!this.context)return;
var gl = this.context;
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, this.texture[0]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tool.canvas);
//gl.drawArrays(gl.TRIANGLES, 0, 6);
}
this.modTexture = function(gl, sTexture, framebuffer){
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, sTexture, 0);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE)
{
var sTextureSize = sTexture.width * sTexture.height * 4; // r, g, b, a
var pixels = new Uint8Array(sTextureSize);
gl.readPixels(0, 0, sTexture.width, sTexture.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
for(var i=0 ; i<sTextureSize ; i+=4)
{
if(pixels[i+3] > 0)
{
pixels[i+3] = Math.min(255, pixels[i+3]*0.995); // set half alpha
}
}
// upload changes
gl.activeTexture(gl.TEXTURE0 + 1);
gl.bindTexture(gl.TEXTURE_2D, sTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
sTexture.width, sTexture.height, 0,
gl.RGBA, gl.UNSIGNED_BYTE, pixels);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
this.setupFrameBuffer = function(canvas, textureUnit, program, uniformName) {
if(!this.context)return;
var gl = this.context;
var rttFramebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
rttFramebuffer.width = this.canvas.width;
rttFramebuffer.height = this.canvas.height;
var rttTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, rttTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rttFramebuffer.width, rttFramebuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rttTexture, 0);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return rttFrameBuffer;
}
this.setupTexture = function(canvas, textureUnit, uniformName) {
var gl = this.context;
var tex = gl.createTexture();
this.updateTextureFromCanvas(tex, canvas, textureUnit);
tex.width = canvas.width;
tex.height= canvas.height;
// Set the parameters so we can render any size image.
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);
gl.useProgram(this.program);
var location = gl.getUniformLocation(this.program, uniformName);
gl.uniform1i(location, textureUnit);
gl.useProgram(this.cellProgram);
location = gl.getUniformLocation(this.cellProgram, uniformName);
gl.uniform1i(location, textureUnit);
return tex;
}
this.updateTextureFromCanvas = function(tex, canvas, textureUnit) {
if(!this.context)return;
var gl = this.context;
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
}
this.createBlankTexture = function(gl, dataArray, type, width, height, uniformName) {
var dataTypedArray = new Uint8Array(dataArray); // Don't need to do this if the data is already in a typed array
for(var i=0 ; i<dataArray ; i+=4)
{
dataTypedArray[i+3] = 255;
}
var texture = gl.createTexture();
texture.width = width;
texture.height= height;
gl.activeTexture(gl.TEXTURE0 + this.texture.length);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, type, width, height, 0, type, gl.UNSIGNED_BYTE, dataTypedArray);
// Other texture setup here, like filter modes and mipmap generation
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);
gl.useProgram(this.program);
var location = gl.getUniformLocation(this.program, uniformName);
gl.uniform1i(location, this.texture.length);
gl.useProgram(this.cellProgram);
location = gl.getUniformLocation(this.cellProgram, uniformName);
gl.uniform1i(location, this.texture.length);
return texture;
}
this.setRectangle = function(gl, x, y, width, height) {
var x1 = x;
var x2 = x + width;
var y1 = y;
var y2 = y + height;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
x1, y1,
x2, y1,
x1, y2,
x1, y2,
x2, y1,
x2, y2]), gl.STATIC_DRAW);
}
}