webgl 2d 将两个透明纹理相互混合
webgl 2d blending two transparent textures on top of each other
我正在尝试将两个纹理与一个 alpha 通道相互混合。
网上查了下好像没有什么简单的方法可以解决这个问题。我在片段着色器中尝试了这个技巧:
if(gl_FragColor.a < 0.5){
discard;
}
这适用于没有太多 alpha 变化的简单纹理,例如背景中的人类精灵。但我希望能够处理更复杂的图像,例如根本不起作用的渐变精灵。
这是我的片段着色器:
precision mediump float;
varying vec3 fragColor;
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main()
{
vec4 tex = texture2D(uSampler, vTextureCoord);
gl_FragColor = tex * vec4(fragColor, 1.0);
if(gl_FragColor.a < 0.5){
discard;
}
}'
这是我的顶点着色器:
precision mediump float;
attribute vec3 vertPosition;
attribute vec3 vertColor;
attribute vec2 aTextureCoord;
varying vec3 fragColor;
varying highp vec2 vTextureCoord;
uniform mat4 uPMatrix;
uniform mat4 uMVMatrix;
uniform vec2 uvOffset;
uniform vec2 uvScale;
void main()
{
fragColor = vertColor;
gl_Position = uPMatrix * uMVMatrix * vec4(vertPosition.x, vertPosition.y, vertPosition.z, 1.0);
vTextureCoord = aTextureCoord * uvScale + uvOffset;
}
这是我使用的 gl 设置的一部分:
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.SRC_ALPHA, gl.ON);
目前所有精灵都在同一个 z 轴 0 上绘制。但是我不知道这是否是问题的根源,因为我测试了给每个对象一个随机 z 值并且问题仍然存在。
编辑:
回应 Rabbid76 的评论。
这个效果很好! Alpha 已混合,但唯一的问题是精灵看起来 "burned":
我试图将片段着色器更改为:
<strike>gl_FragColor = tex * vec4(tex.rgb, tex.a);</strike>
但看起来还是烧焦了。
编辑 2
我解决了。 gl_FragColor 应该 b:
gl_FragColor = vec4(tex.rgb, tex.a);
而不是
gl_FragColor = vec4(fragColor* tex.rgb, tex.a);
否则会产生加深混合效果
Currently all sprites are being drawn on the same z axis, 0.
由于启用了深度测试(gl.enable(gl.DEPTH_TEST)
), and the default depth function (depthFunc
)是gl.LESS
,第二个绘制的精灵将无法通过深度测试。
您必须禁用深度测试:
gl.disable(gl.DEPTH_TEST);
此外,我建议调整混合函数 (blendFunc
):
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
或者你使用Alpha premultiplication。因此你必须调整片段着色器:
gl_FragColor = tex * vec4(fragColor * tex.rgb, tex.a);
并且您必须使用以下混合函数 (blendFunc
):
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
请注意,您不再需要 if(gl_FragColor.a < 0.5) discard;
。
我正在尝试将两个纹理与一个 alpha 通道相互混合。
网上查了下好像没有什么简单的方法可以解决这个问题。我在片段着色器中尝试了这个技巧:
if(gl_FragColor.a < 0.5){
discard;
}
这适用于没有太多 alpha 变化的简单纹理,例如背景中的人类精灵。但我希望能够处理更复杂的图像,例如根本不起作用的渐变精灵。
这是我的片段着色器:
precision mediump float;
varying vec3 fragColor;
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main()
{
vec4 tex = texture2D(uSampler, vTextureCoord);
gl_FragColor = tex * vec4(fragColor, 1.0);
if(gl_FragColor.a < 0.5){
discard;
}
}'
这是我的顶点着色器:
precision mediump float;
attribute vec3 vertPosition;
attribute vec3 vertColor;
attribute vec2 aTextureCoord;
varying vec3 fragColor;
varying highp vec2 vTextureCoord;
uniform mat4 uPMatrix;
uniform mat4 uMVMatrix;
uniform vec2 uvOffset;
uniform vec2 uvScale;
void main()
{
fragColor = vertColor;
gl_Position = uPMatrix * uMVMatrix * vec4(vertPosition.x, vertPosition.y, vertPosition.z, 1.0);
vTextureCoord = aTextureCoord * uvScale + uvOffset;
}
这是我使用的 gl 设置的一部分:
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.SRC_ALPHA, gl.ON);
目前所有精灵都在同一个 z 轴 0 上绘制。但是我不知道这是否是问题的根源,因为我测试了给每个对象一个随机 z 值并且问题仍然存在。
编辑: 回应 Rabbid76 的评论。
这个效果很好! Alpha 已混合,但唯一的问题是精灵看起来 "burned":
我试图将片段着色器更改为:
<strike>gl_FragColor = tex * vec4(tex.rgb, tex.a);</strike>
但看起来还是烧焦了。
编辑 2
我解决了。 gl_FragColor 应该 b:
gl_FragColor = vec4(tex.rgb, tex.a);
而不是
gl_FragColor = vec4(fragColor* tex.rgb, tex.a);
否则会产生加深混合效果
Currently all sprites are being drawn on the same z axis, 0.
由于启用了深度测试(gl.enable(gl.DEPTH_TEST)
), and the default depth function (depthFunc
)是gl.LESS
,第二个绘制的精灵将无法通过深度测试。
您必须禁用深度测试:
gl.disable(gl.DEPTH_TEST);
此外,我建议调整混合函数 (blendFunc
):
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
或者你使用Alpha premultiplication。因此你必须调整片段着色器:
gl_FragColor = tex * vec4(fragColor * tex.rgb, tex.a);
并且您必须使用以下混合函数 (blendFunc
):
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
请注意,您不再需要 if(gl_FragColor.a < 0.5) discard;
。