Я занят передачей некоторого кода из OpenGL в WebGL2 (чтобы выполнить дилинг глубины дуэли), но в консоли я получаю предупреждение, которое не могу понять, и вывод просто черный.
Я прошел процесс рисования некоторых буферов по отдельности и обнаружил, что предупреждение появляется только внутри цикла for (var p = 1; p < numPasses; p++)
, когда я выполняю геометрические проходы.
Шейдеры, которые я основал, также широко использовалиgl_NormalMatrix
, gl_ModelViewMatrix
и gl_Vertex
, которые, я думаю, также могут быть результатом вывода черного цвета.Я предполагаю, что просто замена gl_ModelViewMatrix * gl_Vertex
на uProjMatrix * uViewMatrix * uModelMatrix * vec4(inVertexPosition, 1.0);
даст тот же результат.
(function() {
var script = document.createElement("script");
script.onload = function() {
main();
};
script.src = "https://mdn.github.io/webgl-examples/tutorial/gl-matrix.js";
document.head.appendChild(script);
})();
var initShader, peelShader, blendShader, finalShader;
var accumTex0, accumTex1;
var backBlenderFBO, peelingSingleFBO;
var depthTex = [], frontBlenderTex = [], backTempTex = [], backBlenderTex = [];
var quadVAO;
var drawBuffers;
function main() {
const canvas = document.querySelector("#glcanvas");
const gl = canvas.getContext("webgl2", { alpha: false });
if (!gl) {
alert("Unable to initialize WebGL. Your browser or machine may not support it.");
return;
}
var ext = gl.getExtension("EXT_color_buffer_float");
if (!ext) { alert("Unable to initialize WebGL. Your browser or machine may not support it."); return; }
quadVAO = newMesh(gl);
drawBuffers = [gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT2, gl.COLOR_ATTACHMENT3, gl.COLOR_ATTACHMENT4, gl.COLOR_ATTACHMENT5, gl.COLOR_ATTACHMENT6];
// Dual Peeling Render Targets
backBlenderTex = newTexture(gl, gl.TEXTURE_2D, gl.RGBA32F, 640, 480, gl.RGBA, gl.FLOAT, null);
backBlenderFBO = newFramebuffer(gl, [backBlenderTex]);
depthTex[0] = newTexture(gl, gl.TEXTURE_2D, gl.RG32F, 640, 480, gl.RG, gl.FLOAT, null);
frontBlenderTex[0] = newTexture(gl, gl.TEXTURE_2D, gl.RGBA32F, 640, 480, gl.RGBA, gl.FLOAT, null);
backTempTex[0] = newTexture(gl, gl.TEXTURE_2D, gl.RGBA32F, 640, 480, gl.RGBA, gl.FLOAT, null);
depthTex[1] = newTexture(gl, gl.TEXTURE_2D, gl.RG32F, 640, 480, gl.RG, gl.FLOAT, null);
frontBlenderTex[1] = newTexture(gl, gl.TEXTURE_2D, gl.RGBA32F, 640, 480, gl.RGBA, gl.FLOAT, null);
backTempTex[1] = newTexture(gl, gl.TEXTURE_2D, gl.RGBA32F, 640, 480, gl.RGBA, gl.FLOAT, null);
peelingSingleFBO = newFramebuffer(gl, [depthTex[0], frontBlenderTex[0], backTempTex[0], depthTex[1], frontBlenderTex[1], backTempTex[1], backBlenderTex]);
bindFramebuffer(gl, null);
initShader = newShader(gl, vsInitSource, fsInitSource);
peelShader = newShader(gl, vsPeelSource, fsPeelSource);
blendShader = newShader(gl, vsBlendSource, fsBlendSource);
finalShader = newShader(gl, vsFinalSource, fsFinalSource);
gl.disable(gl.CULL_FACE);
draw(gl);
}
// See below link to make sense of this function
// https://stackoverflow.com/questions/37381980/get-some-trounble-when-using-drawbuffers-in-webgl2
function getDrawBuffers(gl, ...idx) {
var buffers = [gl.NONE, gl.NONE, gl.NONE, gl.NONE, gl.NONE, gl.NONE, gl.NONE];
for (var i = 0; i < idx.length; i++) {
if (i == idx[i]) buffers[i] = drawBuffers[i];
}
return buffers;
}
function draw(gl) {
// setup MVP
const proj = mat4.create();
const cameraSize = 0.2;
mat4.ortho(proj, 0.0, 1.0, 0.0, 1.0, 0.0001, 10.0);
const view = mat4.create();
mat4.lookAt(view, [0, 0, 2], [0, 0, 0], [0, 1, 0]);
gl.disable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
bindFramebuffer(gl, peelingSingleFBO);
gl.drawBuffers(getDrawBuffers(gl, 1, 2));
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
const maxDepth = 1;
gl.drawBuffers(getDrawBuffers(gl, 0));
gl.clearColor(-maxDepth, -maxDepth, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.blendEquation(gl.MAX);
// init
// bindFramebuffer(gl, null); // to test with
// gl.drawBuffers([gl.BACK]); // to test with
gl.useProgram(initShader);
drawMesh(gl, initShader, proj, view, { x: 0.0, y: 0.0, z: 0.0 }, { r: 1.0, g: 0.0, b: 0.0, a: 1.0 });
gl.useProgram(null);
// return; // to test with
// peeling & blending
gl.drawBuffers(getDrawBuffers(gl, 6));
var backgroundColor = [1, 1, 1];
gl.clearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// return; // to test with
// for each pass
var numPasses = 4;
var currID = 0;
for (var p = 1; p < numPasses; p++) {
currID = p % 2;
var prevID = 1 - currID;
var bufID = currID * 3;
gl.drawBuffers(getDrawBuffers(gl, bufID + 1, bufID + 2));
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawBuffers(getDrawBuffers(gl, bufID));
gl.clearColor(-maxDepth, -maxDepth, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
// all three blending render targets
gl.drawBuffers(getDrawBuffers(gl, bufID, bufID + 1, bufID + 2));
gl.blendEquation(gl.MAX);
gl.useProgram(peelShader);
bindTexture(gl, gl.TEXTURE0, gl.TEXTURE_2D, depthTex[prevID]); // DepthBlenderTex
bindTexture(gl, gl.TEXTURE1, gl.TEXTURE_2D, frontBlenderTex[prevID]); // FrontBlenderTex
gl.uniform1f(gl.getUniformLocation(peelShader, "uAlpha"), 0.6);
drawMesh(gl, peelShader, proj, view, { x: 0.0, y: 0.0, z: 0.0 }, { r: 1.0, g: 0.0, b: 0.0, a: 1.0 });
gl.useProgram(null);
// alpha blend the back color
gl.drawBuffers(getDrawBuffers(gl, 6));
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.useProgram(blendShader);
bindTexture(gl, gl.TEXTURE0, gl.TEXTURE_2D, backTempTex[currID]); // TempTex
drawFullscreenQuad(gl);
gl.useProgram(null);
}
gl.disable(gl.BLEND);
// final pass
bindFramebuffer(gl, null);
gl.drawBuffers([gl.BACK]);
gl.useProgram(finalShader);
bindTexture(gl, gl.TEXTURE0, gl.TEXTURE_2D, depthTex[currID]); // DepthBlenderTex
bindTexture(gl, gl.TEXTURE1, gl.TEXTURE_2D, frontBlenderTex[currID]); // FrontBlenderTex
bindTexture(gl, gl.TEXTURE2, gl.TEXTURE_2D, backBlenderTex); // BackBlenderTex
drawFullscreenQuad(gl);
gl.useProgram(null);
}
function newShader(gl, vsSource, fsSource) {
const vertexShader = loadSource(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadSource(gl, gl.FRAGMENT_SHADER, fsSource);
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Unable to initialize the shader program: " + gl.getProgramInfoLog(shaderProgram));
return null;
}
return shaderProgram;
}
function loadSource(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function newMesh(gl) {
var vertices = [1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0];
var indicies = [0, 1, 3, 1, 2, 3];
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
const vb = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
const eb = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, eb);
gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(indicies),
gl.STATIC_DRAW
);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 2 * 4, 0);
gl.enableVertexAttribArray(null);
gl.bindVertexArray(null);
return vao;
}
function drawFullscreenQuad(gl) {
gl.bindVertexArray(quadVAO);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
gl.bindVertexArray(null);
}
function drawMesh(gl, prog, proj, view, pos, col) {
gl.uniformMatrix4fv(gl.getUniformLocation(prog, "uProjMatrix"), false, proj);
gl.uniformMatrix4fv(gl.getUniformLocation(prog, "uViewMatrix"), false, view);
gl.bindVertexArray(quadVAO);
const model = mat4.create();
var trans = vec3.create();
vec3.set(trans, pos.x, pos.y, pos.z);
mat4.translate(model, model, trans);
gl.uniform4fv(gl.getUniformLocation(prog, "uColor"), [col.r, col.g, col.b, col.a]);
gl.uniformMatrix4fv(gl.getUniformLocation(prog, "uModelMatrix"), false, model);
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
gl.bindVertexArray(null);
}
function newTexture(gl, target, internalFormat, height, width, format, type, pixels) {
var tid = gl.createTexture();
gl.bindTexture(target, tid);
gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texImage2D(target, 0, internalFormat, width, height, 0, format, type, pixels);
return tid;
}
function bindTexture(gl, idx, target, id) {
gl.activeTexture(idx);
gl.bindTexture(target, id);
// wait should I be doing glUniforml1(id, ...) here?
}
function newFramebuffer(gl, colorAttachments) {
var fib = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fib);
for (var i = 0; i < colorAttachments.length; i++) {
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
drawBuffers[i],
gl.TEXTURE_2D,
colorAttachments[i],
0
);
}
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
alert(gl.checkFramebufferStatus(gl.FRAMEBUFFER).toString(16));
}
return fib;
}
function bindFramebuffer(gl, fib) {
gl.bindFramebuffer(gl.FRAMEBUFFER, fib);
}
const vsInitSource = `#version 300 es
layout(location=0) in vec3 inVertexPosition;
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
void main(void) {
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(inVertexPosition, 1.0);
}`;
const fsInitSource = `#version 300 es
precision mediump float;
layout(location=0) out vec2 outColor;
void main(void) {
// This seems very important because it is based on the near/far values
// What is the correct value I can expect here?
outColor.xy = vec2(-gl_FragCoord.z, gl_FragCoord.z);
}`;
const vsPeelSource = `#version 300 es
layout(location=0) in vec3 inVertexPosition;
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
// I believe this is what gives the model the green and white stripes
// Not required?
// vec3 ShadeVertex() {
// float diffuse = abs(normalize(gl_NormalMatrix * gl_Normal).z);
// return vec3(gl_Vertex.xy, diffuse);
// }
void main(void) {
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(inVertexPosition, 1.0);
//gl_TexCoord[0].xyz = ShadeVertex();
}`;
const fsPeelSource = `#version 300 es
precision mediump float;
uniform float uAlpha;
#define COLOR_FREQ 30.0
#define ALPHA_FREQ 30.0
vec4 ShadeFragment() {
vec4 color;
color.rgb = vec3(.4,.85,.0);
color.a = uAlpha;
return color;
}
uniform sampler2D DepthBlenderTex;
uniform sampler2D FrontBlenderTex;
#define MAX_DEPTH 1.0
layout(location=0) out vec4 outFragData0;
layout(location=1) out vec4 outFragData1;
layout(location=2) out vec4 outFragData2;
void main(void) {
// window-space depth interpolated linearly in screen space
float fragDepth = gl_FragCoord.z;
vec2 depthBlender = texture(DepthBlenderTex, gl_FragCoord.xy).xy;
vec4 forwardTemp = texture(FrontBlenderTex, gl_FragCoord.xy);
// Depths and 1.0-alphaMult always increase
// so we can use pass-through by default with MAX blending
outFragData0.xy = depthBlender;
// Front colors always increase (DST += SRC*ALPHA_MULT)
// so we can use pass-through by default with MAX blending
outFragData1 = forwardTemp;
// Because over blending makes color increase or decrease,
// we cannot pass-through by default.
// Each pass, only one fragment writes a color greater than 0
outFragData2 = vec4(0.0);
float nearestDepth = -depthBlender.x;
float farthestDepth = depthBlender.y;
float alphaMultiplier = 1.0 - forwardTemp.w;
if (fragDepth < nearestDepth || fragDepth > farthestDepth) {
// Skip this depth in the peeling algorithm
outFragData0.xy = vec2(-MAX_DEPTH);
return;
}
if (fragDepth > nearestDepth && fragDepth < farthestDepth) {
// This fragment needs to be peeled again
outFragData0.xy = vec2(-fragDepth, fragDepth);
return;
}
// If we made it here, this fragment is on the peeled layer from last pass
// therefore, we need to shade it, and make sure it is not peeled any farther
vec4 color = ShadeFragment();
outFragData0.xy = vec2(-MAX_DEPTH);
if (fragDepth == nearestDepth) {
outFragData1.xyz += color.rgb * color.a * alphaMultiplier;
outFragData1.w = 1.0 - alphaMultiplier * (1.0 - color.a);
} else {
outFragData2 += color;
}
}`;
const vsBlendSource = `#version 300 es
layout(location=0) in vec3 inVertexPosition;
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
void main(void) {
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(inVertexPosition, 1.0);
}`;
const fsBlendSource = `#version 300 es
precision mediump float;
uniform sampler2D TempTex;
layout(location=0) out vec4 outColor;
void main(void) {
outColor = texture(TempTex, gl_FragCoord.xy);
// for occlusion query
if (outColor.a == 0.0) discard;
}`;
const vsFinalSource = `#version 300 es
layout(location=0) in vec3 inVertexPosition;
uniform mat4 uModelMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uProjMatrix;
void main(void) {
gl_Position = uProjMatrix * uViewMatrix * uModelMatrix * vec4(inVertexPosition, 1.0);
}`;
const fsFinalSource = `#version 300 es
precision mediump float;
uniform sampler2D DepthBlenderTex;
uniform sampler2D FrontBlenderTex;
uniform sampler2D BackBlenderTex;
layout(location=0) out vec4 outColor;
void main(void)
{
vec4 frontColor = texture(FrontBlenderTex, gl_FragCoord.xy);
vec3 backColor = texture(BackBlenderTex, gl_FragCoord.xy).rgb;
float alphaMultiplier = 1.0 - frontColor.w;
// front + back
outColor.rgb = frontColor.rgb + backColor * alphaMultiplier;
// front blender
// outColor.rgb = frontColor.rgb + vec3(alphaMultiplier);
// back blender
// outColor.rgb = backColor;
}`;
<canvas id="glcanvas" width="640" height="480"></canvas>