gpt4 book ai didi

javascript - 如何渲染对象而不混合 webgl 中启用的透明度

转载 作者:行者123 更新时间:2023-11-28 19:19:41 25 4
gpt4 key购买 nike

我正在尝试渲染两个对象,使用两个单独的 gl.drawArrays 调用。我想让对象的透明部分不可见。此外,我想在另一个对象之上渲染一个对象,这样第一个绘制的对象在与第二个对象重叠的地方不可见。

我在我的渲染循环中使用这个设置:

 gl.clearColor(0, 0, 0, 1);
// https://stackoverflow.com/questions/18439897/webgl-fragment-shader-opacity
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
gl.enable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);

我不确定混合函数的作用,但我使用它们来启用透明度。但这会导致两个物体混合并产生黄色。 (一个物体是红色的,另一个是绿色的)。如果我最后画红色,我想要红色,反之亦然,同时启用透明度。

const fShaderSource2 = `#version 300 es

precision mediump float;

out vec4 outColor;

void main() {
outColor = vec4(0.0, 1.0, 0.0, 1.0);
}

`;


const fShaderSource = `#version 300 es

precision mediump float;

out vec4 outColor;

uniform sampler2D u_texture;

void main() {
outColor = texture(u_texture, vec2(0.0));
}

`;

const vShaderSource = `#version 300 es

precision mediump float;

in vec2 a_position;

void main() {
gl_Position = vec4(a_position, 0, 1);
}
`;

main(document.getElementById('app'));

function main(element) {

const canvas = document.createElement('canvas'),
gl = canvas.getContext('webgl2');
element.append(canvas);
const displayWidth = canvas.clientWidth,
displayHeight = canvas.clientHeight;
canvas.width = displayWidth;
canvas.height = displayHeight;


let graphics = new Graphics({width: displayWidth, height: displayHeight}, gl);

new Loop(() => {
graphics.render();
}).start();
}

function Graphics(state, gl) {

const { width, height } = state;

gl.clearColor(0, 0, 0, 0);

gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
gl.enable(gl.BLEND);
gl.disable(gl.DEPTH_TEST);



let minibatch = [];

const redText = makeGlQuad(gl, fShaderSource, canvasTexture());
const greenText = makeGlQuad(gl, fShaderSource2);

this.render = () => {

minibatch.push(redText);
minibatch.push(greenText);

gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT);

minibatch.forEach(({
program,
resUniformLocation,
vao,
glTexture
}) => {

gl.useProgram(program);

gl.uniform2f(resUniformLocation, gl.canvas.width, gl.canvas.height);

if (glTexture) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, glTexture);
}

gl.bindVertexArray(vao);
gl.drawArrays(gl.TRIANGLES, 0, 6);
});
minibatch = [];
};

}

function makeGlQuad(gl, fShaderSource, texture) {

let vShader = createShader(gl, gl.VERTEX_SHADER, vShaderSource);
let fShader = createShader(gl, gl.FRAGMENT_SHADER, fShaderSource);

let program = createProgram(gl, vShader, fShader);

let posAttrLocation = gl.getAttribLocation(program, "a_position");
let posBuffer = gl.createBuffer();

gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);


/*
(-1, 1).( 1, 1)
.
(-1,-1).( 1,-1)
*/
let positions = [
-1, 1,
-1, -1,
1, -1,
-1, 1,
1,-1,
1, 1
];

gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);


let vao = gl.createVertexArray();
gl.bindVertexArray(vao);

gl.enableVertexAttribArray(posAttrLocation);

let size = 2,
type = gl.FLOAT,
normalize = false,
stride = 0,
offset = 0;

gl.vertexAttribPointer(posAttrLocation,
size,
type,
normalize,
stride,
offset);

let glTexture;
if (texture) {
glTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, glTexture);

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture);
//gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));


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.LINEAR);
}



let resUniformLocation = gl.getUniformLocation(program, "u_resolution");
let texUniformLocation = gl.getUniformLocation(program, "u_texture");


return {
program,
resUniformLocation,
vao,
glTexture
}
}

function canvasTexture() {

return withCanvasTexture(256, 256, (w, h, canvas, ctx) => {
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, w, h);
ctx.font = '50pt Comic Sans';
ctx.fillStyle = 'white';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('label', w / 2, 50);

return canvas;
});

function withCanvasTexture(width, height, f) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
f(width, height, canvas, canvas.getContext('2d'));
const texture = canvas;
//document.body.append(canvas);
return texture;
}
}

function createShader(gl, type, source) {
let shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
let success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);

if (success) {
return shader;
}

console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
};

function createProgram(gl, vShader, fShader) {
let program = gl.createProgram();
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
gl.linkProgram(program);
let success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}

console.error(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}


// Loop Library
function Loop(fn) {

const perf = window.performance !== undefined ? window.performance : Date;

const now = () => perf.now();

const raf = window.requestAnimationFrame;

let running = false,
lastUpdate = now(),
frame = 0;

this.start = () => {
if (running) {
return this;
}

running = true;
lastUpdate = now();
frame = raf(tick);
return this;
};

this.stop = () => {
running = false;

if (frame != 0) {
raf.cancel(frame);
}

frame = 0;
return this;
};

const tick = () => {
frame = raf(tick);
const time = now();
const dt = time - lastUpdate;
fn(dt);
lastUpdate = time;
};
}
#app canvas {
position: fixed;
top: 50%;
bottom: 0;
left: 50%;
right: 0;

width: 100vmin;
height: 70vmin;

transform: translate(-50%, -25%);

image-rendering: optimizeSpeed;
cursor: none;
margin: auto;
}
<div id="app">
</div>

你可以在这里看到:

minibatch.push(redText);
minibatch.push(greenText);

我先渲染红色,然后渲染绿色,但我变成了黄色。

最佳答案

问题是您使用了错误的混合函数 (blendFunc)。混合定义了一个函数,它将片段颜色输出与颜色缓冲区中的当前颜色相结合。第一个参数是片段颜色输出的因子,第二个参数是颜色缓冲区中颜色的因子。颜色相加,因为默认混合方程 (blendEquation()) 是 FUNC_ADD

混合函数

gl.blendFunc(gl.SRC_ALPHA, gl.ONE);

可以用公式表示

destColor = srcColor * srcAlpha + destColor * 1 

其中 destColor 是帧缓冲区中的当前颜色,srcColor 是设置为片段的颜色 (outColor)。
这会导致当前帧缓冲区中的颜色被保留(乘以 1)。新颜色乘以 alpha channel 并添加到帧缓冲区中的颜色。如果帧缓冲区中的颜色为红色 (1, 0, 0),而新颜色为绿色 (0, 1, 0),则结果为黄色(如果 alpha channel 为 1):

(0, 1, 0) * 1 + (1, 0, 0) * 1 == (1, 1, 0)    

使用混合函数:

gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

这会导致 frambuffer 中的颜色和新颜色“混合”,这取决于新颜色的 alpha channel :

destColor = srcColor * srcAlpha + destColor * (1-srcAlpha)

Alpha blending的总则与 OpenGL 中的类似(因为 WebGL (2.0) 与 OpenGL ES (3.0) 非常一致),因此可以在 OpenGL 维基页面 Blending 上找到更多信息。 .

关于javascript - 如何渲染对象而不混合 webgl 中启用的透明度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57612782/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com