【发布时间】:2017-01-03 18:46:39
【问题描述】:
我正在开发一款自上而下的 2D HTML5 游戏,该游戏使用逐像素区域采样和操作来创建波浪波纹效果。我在 JavaScript 中启动并运行了它,但在 FireFox 上的性能很差,在 Chrome 上完全不可接受。我考虑将我的整个原型移植到性能更好的平台,但在此过程中了解了 GL 着色器。
我认为将我的算法应用于 GL 片段着色器会很简单。我连续第四天试图让我的着色器产生任何输出。我已尽我所能将其他问题和教程中的解决方案改编为我正在做的事情,但没有一个足够接近我的具体需求。
首先,我将从概念上概述我需要发生的事情。然后我将提供代码并解释到目前为止我尝试采用的方法。如果我能理解我需要做什么,我愿意从头开始。
波浪效果的算法如here 所述工作。它涉及通过基于每个像素的波高数据置换某些像素来从源图像渲染新图像,这些数据存储在两个矩阵中,图像中的每个像素都有相应的条目。一个用作水的当前状态,另一个存储上一帧的结果,用于计算电流。
每帧:waveMapCurrent 是通过平均值 waveMapPrevious 计算得出的
每像素:位移是根据 waveMapCurrent 中的高度和(在伪代码中)newPixelData[current] = sourcePixelData[current+displacement]
至少,我需要我的片段着色器能够访问来自当前波高矩阵的数据和用作源的图像。如果我理解正确,将新数据传递到 GL 管道的次数降到最低,而是在着色器中执行波高计算,这对性能最有利,但我也可以在我的脚本中进行计算和每帧将波高矩阵的更新版本传递给片段着色器。
不过,在我思考片段着色器在做什么之前,我的任务是设置一个对象以实际绘制片段。据我所知,这需要设置顶点来表示画布并将它们设置到画布的角落,以使 WebGL 将其渲染为平面的 2D 图像,但这似乎不直观。我要么需要将其渲染为图像以用作背景纹理,要么初始化第二个画布并将第一个画布的背景设置为透明(这是我在下面的代码中尝试做的)。如果有任何方法可以让片段着色器运行并简单地渲染其输出,每个片段与画布/图像的像素 1:1 对应,那将是崇高的,但我假设 GLSL 没有。
我尝试做的是将当前波高矩阵打包为纹理并将其作为统一的 sampler2D 发送。在当前状态下,我的代码运行,但 WebGL 告诉我,活动纹理 1 是我打包为纹理的波高矩阵,它是不完整的,并且它的缩小/放大过滤未设置为 NEAREST,即使我尝试过明确地将其设置为 NEAREST。我不知道如何进一步调试它,因为 WebGL 引用我对 gl.drawElements 的调用作为错误源。
这就是我能描述的那样聪明。这是我所拥有的:
ws.glProgram = function(gl, tex) {
var flExt = gl.getExtension("OES_texture_float");
ws.program = gl.createProgram();
var vertShader = gl.createShader(gl.VERTEX_SHADER);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
var vertSrc = [
"attribute vec4 position;",
"void main(void) {",
"gl_Position = position;",
"}"
]
var fragSrc = [
"precision highp float;",
"uniform sampler2D canvasTex;",
"uniform sampler2D dataTex;",
"uniform vec2 mapSize;",
"uniform float dispFactor;",
"uniform float lumFactor;",
"void main(void) {",
"vec2 mapCoord = vec2(gl_FragCoord.x+1.5, gl_FragCoord.y+1.5);",
"float wave = texture2D(dataTex, mapCoord).r;",
"float displace = wave*dispFactor;",
"if (displace < 0.0) {",
"displace = displace+1.0;",
"}",
"vec2 srcCoord = vec2(gl_FragCoord.x+displace,gl_FragCoord.y+displace);",
"if (srcCoord.x < 0.0) {",
"srcCoord.x = 0.0;",
"}",
"else if (srcCoord.x > mapSize.x-2.0) {",
"srcCoord.x = mapSize.x-2.0;",
"}",
"if (srcCoord.y < 0.0) {",
"srcCoord.y = 0.0;",
"}",
"else if (srcCoord.y > mapSize.y-2.0) {",
"srcCoord.y = mapSize.y-2.0;",
"}",
"float lum = wave*lumFactor;",
"if (lum > 40.0) { lum = 40.0; }",
"else if (lum < -40.0) { lum = -40.0; }",
"gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);", // Fragment Shader is not producing output
/*"gl_FragColor = texture2D(canvasTex, srcCoord);",
"gl_FragColor.r = gl_FragColor.r + lum;",
"gl_FragColor.g = gl_FragColor.g + lum;",
"gl_FragColor.b = gl_FragColor.b + lum;",*/
"}"];
vertSrc = vertSrc.join('\n');
fragSrc = fragSrc.join('\n');
gl.shaderSource(vertShader, vertSrc);
gl.compileShader(vertShader);
gl.attachShader(ws.program, vertShader);
gl.shaderSource(fragShader, fragSrc);
gl.compileShader(fragShader);
gl.attachShader(ws.program, fragShader);
console.log(gl.getShaderInfoLog(vertShader));
gl.linkProgram(ws.program);
gl.useProgram(ws.program);
// Vertex Data for rendering surface
var vertices = [ 0,0,0, 1,0,0,
0,1,0, 1,1,0 ];
var indices = [ 0,1,2, 0,2,3 ];
ws.program.vertices = new Float32Array(vertices);
ws.program.indices = new Float32Array(indices);
gl.enableVertexAttribArray(0);
var vBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuffer);
gl.bufferData(gl.ARRAY_BUFFER, ws.program.vertices, gl.STATIC_DRAW);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
var iBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, ws.program.indices, gl.STATIC_DRAW);
// Send texture data from tex to WebGL
var canvasTex = gl.createTexture();
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, canvasTex);
// Non-Power-of-Two Texture Dimensions
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tex.imageData);
gl.uniform1i(gl.getUniformLocation(ws.program, "canvasTex"), 2);
// Send empty wave map to WebGL
ws.activeWaveMap = new Float32Array((ws.width+2)*(ws.height+2));
ws.dataPointerGL = gl.createTexture();
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, ws.dataPointerGL);
// Non-Power-of-Two Texture Dimensions
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
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.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, ws.width+2,ws.height+2,0, gl.LUMINANCE, gl.FLOAT, ws.activeWaveMap);
gl.uniform1i(gl.getUniformLocation(ws.program, "dataTex"), 1);
// Numeric Uniforms
gl.uniform2f(gl.getUniformLocation(ws.program, "mapSize"), ws.width+2,ws.height+2);
gl.uniform1f(gl.getUniformLocation(ws.program, "dispFactor"), ws.dispFactor);
gl.uniform1f(gl.getUniformLocation(ws.program, "lumFactor"), ws.lumFactor);
return ws.program;
}
ws.render = function(gl, moves, canvas) {
//canvas.clear();
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // specify gl.clearColor?
for (g=0, fl=0; g < ws.tempWaveMap.length; g++) {
for (b=0; b < ws.tempWaveMap[g].length; b++) {
ws.tempWaveMap[g][b] = ws.activeWaveMap[fl];
fl += 1;
}
}
for (j=0; j < moves.length; j++) {
ws.setWave(moves[j],ws.tempWaveMap);
}
for (x=1; x <= ws.width; x++) {
for (y=1; y <= ws.height; y++) {
ws.resolveWaves(ws.inactiveWaveMap, ws.tempWaveMap, x,y);
}
}
for (g=0, fl=0; g < ws.inactiveWaveMap.length; g++) {
for (b=0; b < ws.inactiveWaveMap[g].length; b++) {
ws.outgoingWaveMap[fl] = ws.inactiveWaveMap[g][b];
ws.inactiveWaveMap[g][b] = ws.tempWaveMap[g][b];
fl += 1;
}
}
ws.activeWaveMap.set(ws.outgoingWaveMap);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, ws.width+2,ws.height+2,0, gl.LUMINANCE, gl.FLOAT, ws.activeWaveMap);
gl.drawElements(gl.TRIANGLES, ws.program.indices.length, gl.UNSIGNED_BYTE, 0);
}
更新:我已经设法使用角顶点设置了我的 2D 绘图表面。 (教程here 对我使用 VAO 的基础很有帮助。)现在我正在尝试找出上传、存储和操作数据的最佳方法。
已解决:感谢 gman,我的代码可以正常工作。波浪行为本身仍需要调试,但 GL 管道方面的所有内容都在正常运行。除了奇怪的波浪行为外,游戏每隔几秒钟就会延迟片刻,然后以正常速度恢复。性能测试表明,非增量垃圾收集是原因,并且在禁用水效果时不会发生这种情况,所以它绝对是我的代码中的东西,可能数组newIndices 被新初始化每一帧,但我不确定。除非和 GL 的行为有关,否则超出了这个问题的范围。
这里是相关代码。除了这里的内容之外,您真正需要知道的是 GL 上下文、用于绘制 2D 表面的顶点着色器和 VAO 是从另一个对象传入的,并且该对象每帧都运行 render 函数。
function waterStage(gl, vao, vShader) {
var ws = new Object();
ws.width = game.world.width; ws.height = game.world.height;
// Initialize Background Texture
ws.img = game.make.bitmapData(ws.width, ws.height);
ws.img.fill(0,10,40);
ws.img.ctx.strokeStyle = "#5050FF";
ws.img.ctx.lineWidth = 2;
ws.img.ctx.moveTo(0,0);
for (y=0; y < ws.height; y+=10) {
ws.img.ctx.beginPath();
ws.img.ctx.moveTo(0,y);
ws.img.ctx.lineTo(ws.width,y);
ws.img.ctx.closePath();
ws.img.ctx.stroke();
}
ws.img.update();
gl.flExt = gl.getExtension("OES_texture_float");
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
// Source Image
ws.srcTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, ws.srcTexture);
// Enable all texture sizes
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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, ws.img.imageData);
delete ws.img;
// Map Textures
ws.clearProgram = gl.createProgram();
gl.attachShader(ws.clearProgram, vShader);
var clearSrc = [
"precision highp float;",
"void main(void) {",
"gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0);",
"}"
];
clearSrc = clearSrc.join("\n");
var clearShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(clearShader, clearSrc);
gl.compileShader(clearShader);
gl.attachShader(ws.clearProgram, clearShader);
gl.linkProgram(ws.clearProgram);
ws.mapTextures = [];
ws.frameBuffers = [];
for (t=0; t < 2; t++) {
var map = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, map);
// Enable all texture sizes
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);
// Initialize empty texture of the same size as the canvas
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, ws.width, ws.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
ws.mapTextures.push(map);
var fbo = gl.createFramebuffer()
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, map, 0);
ws.frameBuffers.push(fbo);
gl.useProgram(ws.clearProgram);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); // Set output to new map
gl.vao_ext.bindVertexArrayOES(vao);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// Blank texture to be copied to in render()
ws.copyTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, ws.copyTexture);
// Enable all texture sizes
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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, ws.width, ws.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// Blank texture for entering new wave values through GL
ws.nwTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, ws.nwTexture);
// Enable all texture sizes
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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, ws.width, ws.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
ws.newWaves = new Array(ws.width*ws.height);
ws.nwProgram = gl.createProgram();
ws.mapProgram = gl.createProgram();
ws.displaceProgram = gl.createProgram();
gl.attachShader(ws.nwProgram, vShader);
gl.attachShader(ws.mapProgram, vShader);
gl.attachShader(ws.displaceProgram, vShader);
var nwSrc = [
"precision highp float;",
"uniform sampler2D newWaves;",
"uniform sampler2D previous;",
"uniform vec2 size;",
"void main(void) {",
"vec2 texCoord = vec2((gl_FragCoord.x/size.x),(gl_FragCoord.y/size.y));",
"float nw = texture2D(newWaves, texCoord).r;",
"if (nw == 0.0) {",
"gl_FragColor = texture2D(previous, texCoord);",
"}",
"else {",
"float current = texture2D(previous, texCoord).r;",
"nw = float(current+nw);",
"gl_FragColor = vec4(nw, nw, nw, 1.0);",
"}",
"}"
]
nwSrc = nwSrc.join("\n");
var nwShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(nwShader, nwSrc);
gl.compileShader(nwShader);
console.log(gl.getShaderInfoLog(nwShader));
gl.attachShader(ws.nwProgram, nwShader);
gl.linkProgram(ws.nwProgram);
var mapSrc = [
"precision highp float;",
"uniform sampler2D previous;",
"uniform sampler2D current;",
"uniform vec2 size;",
"uniform float damper;",
"void main(void) {",
"vec4 surrounding;",
"vec2 texCoord = vec2((gl_FragCoord.x/size.x),(gl_FragCoord.y/size.y));",
"float active = texture2D(current, texCoord).r-0.5;",
"vec2 shifted = vec2(((gl_FragCoord.x-1.0)/size.x),texCoord.y);", // x-1
"if (gl_FragCoord.x == 0.0) {",
"surrounding.x = 0.0;",
"}",
"else {",
"surrounding.x = texture2D(previous, shifted).r-0.5;",
"}",
"shifted = vec2(((gl_FragCoord.x+1.0)/size.x),texCoord.y);", // x+1
"if (gl_FragCoord.x == size.x-1.0) {",
"surrounding.z = 0.0;",
"}",
"else {",
"surrounding.z = texture2D(previous, shifted).r-0.5;",
"}",
"shifted = vec2(texCoord.x,((gl_FragCoord.y-1.0)/size.y));", // y-1
"if (gl_FragCoord.y == 0.0) {",
"surrounding.y = 0.0;",
"}",
"else {",
"surrounding.y = texture2D(previous, shifted).r-0.5;",
"}",
"shifted = vec2(texCoord.x,((gl_FragCoord.y+1.0)/size.y));", // y+1
"if (gl_FragCoord.y == size.y-1.0) {",
"surrounding.w = 0.0;",
"}",
"else {",
"surrounding.w = texture2D(previous, shifted).r-0.5;",
"}",
"active = ((surrounding.x+surrounding.y+surrounding.z+surrounding.w)/2.0)-active;",
"active = active-(active/damper);",
"gl_FragColor = vec4(active+0.5, active+0.5, active+0.5, 1.0);",
// "gl_FragColor = texture2D(current, vec2(gl_FragCoord.x/size.x),(gl_FragCoord.y/size.y));",
"}"
];
mapSrc = mapSrc.join("\n");
var mapShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(mapShader, mapSrc);
gl.compileShader(mapShader);
console.log(gl.getShaderInfoLog(mapShader));
gl.attachShader(ws.mapProgram, mapShader);
gl.linkProgram(ws.mapProgram);
var displaceSrc = [
"precision highp float;",
"uniform sampler2D current;",
"uniform sampler2D srcImg;",
"uniform vec2 size;",
"uniform float dspFactor;",
"uniform float lumFactor;",
"void main(void) {",
"vec2 texCoord = vec2((gl_FragCoord.x/size.x),(gl_FragCoord.y/size.y));",
"float wave = texture2D(current, texCoord).r-0.5;",
"float displacement = wave * dspFactor * 1.5;",
"if (displacement == 0.0) {",
"gl_FragColor = texture2D(srcImg, texCoord);",
"}",
"else {",
"if (displacement < 0.0) {",
"displacement = displacement + 1.0;",
"}",
"float lum = wave * lumFactor;",
"if (lum > 0.16) { lum = 0.16; }",
"else if (lum < -0.16) { lum = -0.16; }",
"float dspX = (gl_FragCoord.x+displacement);",
"float dspY = (gl_FragCoord.y+displacement);",
"if (dspX < 0.0) { dspX = 0.0; }",
"else if (dspX >= size.x) { dspX = size.x-1.0; }",
"if (dspY < 0.0) { dspY = 0.0; }",
"else if (dspY >= size.y) { dspY = size.y-1.0; }",
"vec2 srcCoord = vec2((dspX/size.x),(dspY/size.y));",
// Just for testing
//"gl_FragColor = texture2D(current, vec2((gl_FragCoord.x/size.x),(gl_FragCoord.y/size.y)));",
"vec4 newColor = texture2D(srcImg, srcCoord);", // srcCoord
"gl_FragColor.r = newColor.r+lum;",
"gl_FragColor.g = newColor.g+lum;",
"gl_FragColor.b = newColor.b+lum;",
"}",
"}"
];
displaceSrc = displaceSrc.join("\n");
var displaceShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(displaceShader, displaceSrc);
gl.compileShader(displaceShader);
console.log(gl.getShaderInfoLog(displaceShader));
gl.attachShader(ws.displaceProgram, displaceShader);
gl.linkProgram(ws.displaceProgram);
ws.render = function(gl, vao, moves) {
// Calculate wave values as texture data, then render to screen with displacement fragment shader
if (moves.length > 0) {
for (x=0, len=ws.width*ws.height; x < len; x++) {
ws.newWaves[x] = 0;
}
var newIndices = [];
for (m=0; m < moves.length; m++) {
newIndices.push(moves[m].y*ws.width + moves[m].x);
}
for (i=0; i < newIndices.length; i++) {
ws.newWaves[newIndices[i]] = moves[i].magnitude/1;
}
gl.useProgram(ws.nwProgram);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, ws.nwTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, ws.width, ws.height, 0, gl.LUMINANCE, gl.FLOAT, new Float32Array(ws.newWaves));
gl.uniform1i(gl.getUniformLocation(ws.nwProgram, "newWaves"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, ws.copyTexture);
gl.uniform1i(gl.getUniformLocation(ws.nwProgram, "previous"), 1);
gl.bindFramebuffer(gl.FRAMEBUFFER, ws.frameBuffers[0]); // Set output to previous map texture [0]
gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, ws.width, ws.height, 0); // Copy mapTextures[0] into copyTexture
gl.uniform2f(gl.getUniformLocation(ws.nwProgram, "size"), ws.width, ws.height);
gl.vao_ext.bindVertexArrayOES(vao);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
// Map Texture Manipulation
gl.useProgram(ws.mapProgram);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, ws.mapTextures[0]);
gl.uniform1i(gl.getUniformLocation(ws.mapProgram, "previous"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, ws.copyTexture);
gl.uniform1i(gl.getUniformLocation(ws.mapProgram, "current"), 1);
gl.uniform2f(gl.getUniformLocation(ws.mapProgram, "size"), ws.width, ws.height);
gl.uniform1f(gl.getUniformLocation(ws.mapProgram, "damper"), 1000);
gl.bindFramebuffer(gl.FRAMEBUFFER, ws.frameBuffers[1]); // Set output to current map texture [1]
gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, ws.width, ws.height, 0); // Copy mapTextures[1] into copyTexture
gl.vao_ext.bindVertexArrayOES(vao);
gl.drawArrays(gl.TRIANGLES, 0, 6);
// Output Texture Manipulation
gl.useProgram(ws.displaceProgram);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, ws.mapTextures[1]);
gl.uniform1i(gl.getUniformLocation(ws.displaceProgram, "current"), 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, ws.srcTexture);
gl.uniform1i(gl.getUniformLocation(ws.displaceProgram, "srcImg"), 1);
gl.uniform2f(gl.getUniformLocation(ws.displaceProgram, "size"), ws.width, ws.height);
gl.uniform1f(gl.getUniformLocation(ws.displaceProgram, "dspFactor"), 20);
gl.uniform1f(gl.getUniformLocation(ws.displaceProgram, "lumFactor"), 0.5);
gl.bindFramebuffer(gl.FRAMEBUFFER, null); // Output to canvas
gl.vao_ext.bindVertexArrayOES(vao);
gl.drawArrays(gl.TRIANGLES, 0, 6);
ws.mapTextures.sort(function(a,b) { return 1; });
ws.frameBuffers.sort(function(a,b) { return 1; });
}
【问题讨论】:
-
只是一些提示:除了缩小过滤器之外,您还希望将放大过滤器设置为
NEAREST。如果您想用输出填充画布,您需要在 NDC 空间 -1 ... 1 而不是 0...1 中提供顶点坐标。可执行代码 sn-p 会很有帮助。 -
并设置
viewport -
@LJᛃ 我不确定我是否可以隔离一个如果与游戏循环的其余部分分开会运行的 sn-p。 ws 对象从另一个对象 StageLoader 获取其输入及其 GL 上下文,该对象从活动游戏对象访问位置数据并在游戏引擎的 update() 方法期间进行更新。不过,如果有帮助的话,我可以创建它的基本模型
-
@LJᛃ 我也确实得到了正确显示的 2D 表面,所以现在它只是关于数据流
-
我要传递 these tutorials 只是因为你声称你已经阅读了很多东西,但如果你不知道 WebGL 只关心剪辑空间坐标而不是你,看起来你可能错过了一些关于 WebGL 的非常基本的东西
标签: glsl webgl fragment-shader