已经着色的像素上的 Webgl 片段着色器透明度
Webgl fragment shader transparency on pixel that has already been colored
前几天刚了解Webgl,对透明行为还是有点迷糊。我正在尝试使用片段着色器在三角形内绘制一些圆圈。在我有两个三角形重叠之前,一切似乎都正常。我的片段着色器确定该点是否在圆圈内,然后将颜色设置为 (1.,0.,0.,1.)(如果在圆圈内)或 (1.,0.,0., 0.) 如果不是。
我期望的行为是,当片段着色器将像素设置为 (1.,0.,0.,0.) 时,该像素已经被着色 (1.,0.,0.,1. ),它将显示为 (1.,0.,0.,1.)。但是,它看起来与背景颜色相同。
我尝试使用以下方法打开混合模式,但它似乎仍然不起作用:
gl.enable( gl.BLEND );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
我在下面附上了我的代码。
const vertexShader = `
attribute vec4 aPosition;
attribute vec4 aCenter;
varying vec4 pos;
varying vec4 center;
void main() {
center=aCenter;
pos=aPosition;
gl_Position = aPosition;
}
`;
const fragmentShader = `
precision mediump float;
varying vec4 pos;
varying vec4 center;
void main() {
float inside = pow(pos.x - center.x, 2.0) + pow(pos.y - center.y, 2.0);
float val=max(sign(pow(center.z, 2.0)-inside),0.);
vec4 color=vec4(1.,0.,0.,val);
gl_FragColor = color;
}
`;
const DEG_TO_RAD = 0.0174532925;
const TRI_HEIGHT_MOD = 2;
// build simple circle
var points = [];
var centers = [];
function buildCircle(center, r) {
let angles=[0,120,240];
for(let k=0;k<angles.length;k++){
centers.push(center[0]);
centers.push(center[1]);
centers.push(r);
var x=r * TRI_HEIGHT_MOD * Math.cos(angles[k] * DEG_TO_RAD) + center[0];
var y=r * TRI_HEIGHT_MOD * Math.sin(angles[k] * DEG_TO_RAD) + center[1];
points.push(x);
points.push(y);
}
}
buildCircle([-.3,0],.5);
buildCircle([0,0],.5);
function loadShadersFromString(gl,vertexSource,fragmentSource){
// first compile the vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader,vertexSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(vertexShader));
return null;
}
// now compile the fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader,fragmentSource);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(fragmentShader));
return null;
}
// OK, we have a pair of shaders, we need to put them together
// into a "shader program" object
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
return shaderProgram;
}
function loadScene() {
// Get A WebGL context
/** @type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl");
if(!gl){return;}
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// gl.drawElements(gl.LINES, given_animal.vertex_indices_buffer.numItems, gl.UNSIGNED_SHORT, 0);
// gl.lineWidth(width);
// setup GLSL program
// var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
var program = loadShadersFromString(gl,vertexShader,fragmentShader);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "aPosition");
var centerLocation = gl.getAttribLocation(program, "aCenter");
// Create a buffer to put positions in
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(points),gl.STATIC_DRAW);
var centerBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(centers),gl.STATIC_DRAW);
drawScene();
function drawScene() {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas AND the depth buffer.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Turn on culling. By default backfacing triangles
// will be culled.
gl.enable(gl.CULL_FACE);
// Enable the depth buffer
gl.enable(gl.DEPTH_TEST);
gl.enable( gl.BLEND );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Turn on the position attribute
gl.enableVertexAttribArray(positionLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 3 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);
gl.enableVertexAttribArray(centerLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 3; // 3 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(centerLocation, size, type, normalize, stride, offset);
// Draw the geometry.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = points.length/2;
gl.drawArrays(primitiveType,offset,count);
// Call drawScene again next frame
requestAnimationFrame(drawScene);
}
}
loadScene();
body {
margin: 0;
background-color: wheat;
}
#html{
background-color: wheat;
}
canvas {
margin: 0;
position: absolute;
width: 90vw;
height: 90vh;
left: 5vw;
top: 5vh;
display: block;
}
<canvas id="canvas"></canvas>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
Blending can only work if the Depth Test 未启用:
gl.enable(gl.DEPTH_TEST);
启用深度测试后,深度测试可能会丢弃碎片,然后再进行混合。
前几天刚了解Webgl,对透明行为还是有点迷糊。我正在尝试使用片段着色器在三角形内绘制一些圆圈。在我有两个三角形重叠之前,一切似乎都正常。我的片段着色器确定该点是否在圆圈内,然后将颜色设置为 (1.,0.,0.,1.)(如果在圆圈内)或 (1.,0.,0., 0.) 如果不是。
我期望的行为是,当片段着色器将像素设置为 (1.,0.,0.,0.) 时,该像素已经被着色 (1.,0.,0.,1. ),它将显示为 (1.,0.,0.,1.)。但是,它看起来与背景颜色相同。
我尝试使用以下方法打开混合模式,但它似乎仍然不起作用:
gl.enable( gl.BLEND );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
我在下面附上了我的代码。
const vertexShader = `
attribute vec4 aPosition;
attribute vec4 aCenter;
varying vec4 pos;
varying vec4 center;
void main() {
center=aCenter;
pos=aPosition;
gl_Position = aPosition;
}
`;
const fragmentShader = `
precision mediump float;
varying vec4 pos;
varying vec4 center;
void main() {
float inside = pow(pos.x - center.x, 2.0) + pow(pos.y - center.y, 2.0);
float val=max(sign(pow(center.z, 2.0)-inside),0.);
vec4 color=vec4(1.,0.,0.,val);
gl_FragColor = color;
}
`;
const DEG_TO_RAD = 0.0174532925;
const TRI_HEIGHT_MOD = 2;
// build simple circle
var points = [];
var centers = [];
function buildCircle(center, r) {
let angles=[0,120,240];
for(let k=0;k<angles.length;k++){
centers.push(center[0]);
centers.push(center[1]);
centers.push(r);
var x=r * TRI_HEIGHT_MOD * Math.cos(angles[k] * DEG_TO_RAD) + center[0];
var y=r * TRI_HEIGHT_MOD * Math.sin(angles[k] * DEG_TO_RAD) + center[1];
points.push(x);
points.push(y);
}
}
buildCircle([-.3,0],.5);
buildCircle([0,0],.5);
function loadShadersFromString(gl,vertexSource,fragmentSource){
// first compile the vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader,vertexSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(vertexShader));
return null;
}
// now compile the fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader,fragmentSource);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.log(gl.getShaderInfoLog(fragmentShader));
return null;
}
// OK, we have a pair of shaders, we need to put them together
// into a "shader program" object
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
return shaderProgram;
}
function loadScene() {
// Get A WebGL context
/** @type {HTMLCanvasElement} */
var canvas = document.querySelector("#canvas");
var gl = canvas.getContext("webgl");
if(!gl){return;}
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// gl.drawElements(gl.LINES, given_animal.vertex_indices_buffer.numItems, gl.UNSIGNED_SHORT, 0);
// gl.lineWidth(width);
// setup GLSL program
// var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-3d", "fragment-shader-3d"]);
var program = loadShadersFromString(gl,vertexShader,fragmentShader);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "aPosition");
var centerLocation = gl.getAttribLocation(program, "aCenter");
// Create a buffer to put positions in
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(points),gl.STATIC_DRAW);
var centerBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(centers),gl.STATIC_DRAW);
drawScene();
function drawScene() {
webglUtils.resizeCanvasToDisplaySize(gl.canvas);
// Tell WebGL how to convert from clip space to pixels
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Clear the canvas AND the depth buffer.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Turn on culling. By default backfacing triangles
// will be culled.
gl.enable(gl.CULL_FACE);
// Enable the depth buffer
gl.enable(gl.DEPTH_TEST);
gl.enable( gl.BLEND );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE_MINUS_CONSTANT_ALPHA, gl.ONE_MINUS_SRC_ALPHA );
// Tell it to use our program (pair of shaders)
gl.useProgram(program);
// Turn on the position attribute
gl.enableVertexAttribArray(positionLocation);
// Bind the position buffer.
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 2; // 3 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);
gl.enableVertexAttribArray(centerLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
// Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
var size = 3; // 3 components per iteration
var type = gl.FLOAT; // the data is 32bit floats
var normalize = false; // don't normalize the data
var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
var offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(centerLocation, size, type, normalize, stride, offset);
// Draw the geometry.
var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = points.length/2;
gl.drawArrays(primitiveType,offset,count);
// Call drawScene again next frame
requestAnimationFrame(drawScene);
}
}
loadScene();
body {
margin: 0;
background-color: wheat;
}
#html{
background-color: wheat;
}
canvas {
margin: 0;
position: absolute;
width: 90vw;
height: 90vh;
left: 5vw;
top: 5vh;
display: block;
}
<canvas id="canvas"></canvas>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
Blending can only work if the Depth Test 未启用:
gl.enable(gl.DEPTH_TEST);
启用深度测试后,深度测试可能会丢弃碎片,然后再进行混合。