GLSL 着色器:一半颜色值在 var A 中,另一半在 var B 中,没有条件语句
GLSL Shader: Half a colour value in var A, other half in var B, without conditional statement
我正在开发支持 8 种纹理的纹理/地形展开 GLSL 着色器。
我制作的第一个版本使用 RGBA 作为输入 - 每个通道都是每个纹理的强度。
第二个版本我试图通过将 "channels" 分成两半来加倍。例如;
- R0 = Texture1 上没有内容
- R64 = 纹理 1 的一半
- R127 = 全纹理 1
- R128 = 无纹理 5
- R196 = 半纹理 5
- R254 = 全纹理 5
等等。
我开始知道着色器中的 if- 语句是非常糟糕的做法 - 它也感觉像是做错了什么。
问题是,我不知道将每个通道的一半用作完整变量的数学函数。
这是片段着色器代码;
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform sampler2D texture; //Texture
uniform float surfWidth;
uniform float surfHeight;
uniform float xpos;
uniform float ypos;
void main()
{
//Setting the main texture position
vec2 texpos = (v_vTexcoord*vec2(surfWidth, surfHeight)) + vec2(xpos, ypos);
//Modulo 1 for repeat, devide by 4 because its a 4x4 texture sheet
float tpx = mod(texpos.x,1.0)/4.0;
float tpy = mod(texpos.y,1.0)/4.0;
//Setup terrain "intensities"
float t1 = 0.0;
float t2 = 0.0;
float t3 = 0.0;
float t4 = 0.0;
float t5 = 0.0;
float t6 = 0.0;
float t7 = 0.0;
float t8 = 0.0;
//Load from the surface (splatmap)
float btr = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).r;
float btg = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).g;
float btb = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).b;
float bta = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).a;
//Calculating what texture to use (also deviding each channel into 2)
if (btr <= 0.5) {
t1 = btr*2.0;
} else {
t5 = (btr-0.5)*2.0;
}
if (btg <= 0.5) {
t2 = btg*2.0;
} else {
t6 = (btg-0.5)*2.0;
}
if (btb <= 0.5) {
t3 = btb*2.0;
} else {
t7 = (btb-0.5)*2.0;
}
if (bta <= 0.5) {
t4 = bta*2.0;
} else {
t8 = (bta-0.5)*2.0;
}
//Get terrain pixels at proper positions
vec4 ter1 = texture2D(texture, vec2(tpx, tpy));
ter1.a = t1;
vec4 ter2 = texture2D(texture, vec2(tpx+0.25, tpy));
ter2.a = t2;
vec4 ter3 = texture2D(texture, vec2(tpx+0.50, tpy));
ter3.a = t3;
vec4 ter4 = texture2D(texture, vec2(tpx+0.75, tpy));
ter4.a = t4;
vec4 ter5 = texture2D(texture, vec2(tpx, tpy+0.25));
ter5.a = t5;
vec4 ter6 = texture2D(texture, vec2(tpx+0.25, tpy+0.25));
ter6.a = t6;
vec4 ter7 = texture2D(texture, vec2(tpx+0.50, tpy+0.25));
ter7.a = t7;
vec4 ter8 = texture2D(texture, vec2(tpx+0.75, tpy+0.25));
ter8.a = t8;
//Output to screen
gl_FragColor =
ter1*vec4(t1) +
ter2*vec4(t2) +
ter3*vec4(t3) +
ter4*vec4(t4) +
ter5*vec4(t5) +
ter6*vec4(t6) +
ter7*vec4(t7) +
ter8*vec4(t8);
}
我很确定我需要 clamp()
或 lerp()
之类的东西,但我无法理解它..
此外,当纹理重叠时,它们会得到 "brighter"(因为两个纹理只是在最后一条语句中添加...我不知道如何防止这种情况发生并始终输出 "maximum" 纹理本身(这样它就不会 "light up")。对不起,如果我听起来很蠢,这是我的第一个真正的着色器 :)
分支在现代硬件上并没有那么糟糕,假设它们跨越多个片段并可能节省大量工作。在没有分支的情况下编写逻辑如下所示:
btr *= 2.;
t1 = fract(min(btr,1.));
t5 = max(btr-1.,0.);
请注意,使用您的方法不能混合两个 "splatting channels" 打包在同一颜色通道中(即混合 t1 和 t5)。仅对另一个 splatmap 进行采样会更简单(并且可能更有效)。
至于混合最终输出,假设您想要线性混合,您可以将各个权重除以所有权重的总和。
float sum = t1+t2+t3+t4+t5+t6+t7+t8;
gl_FragColor = ter1*(t1/sum) + ter2*(t2/sum) + ter3*(t3/sum) + ...
我正在开发支持 8 种纹理的纹理/地形展开 GLSL 着色器。
我制作的第一个版本使用 RGBA 作为输入 - 每个通道都是每个纹理的强度。
第二个版本我试图通过将 "channels" 分成两半来加倍。例如;
- R0 = Texture1 上没有内容
- R64 = 纹理 1 的一半
- R127 = 全纹理 1
- R128 = 无纹理 5
- R196 = 半纹理 5
- R254 = 全纹理 5
等等。
我开始知道着色器中的 if- 语句是非常糟糕的做法 - 它也感觉像是做错了什么。
问题是,我不知道将每个通道的一半用作完整变量的数学函数。
这是片段着色器代码;
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
uniform sampler2D texture; //Texture
uniform float surfWidth;
uniform float surfHeight;
uniform float xpos;
uniform float ypos;
void main()
{
//Setting the main texture position
vec2 texpos = (v_vTexcoord*vec2(surfWidth, surfHeight)) + vec2(xpos, ypos);
//Modulo 1 for repeat, devide by 4 because its a 4x4 texture sheet
float tpx = mod(texpos.x,1.0)/4.0;
float tpy = mod(texpos.y,1.0)/4.0;
//Setup terrain "intensities"
float t1 = 0.0;
float t2 = 0.0;
float t3 = 0.0;
float t4 = 0.0;
float t5 = 0.0;
float t6 = 0.0;
float t7 = 0.0;
float t8 = 0.0;
//Load from the surface (splatmap)
float btr = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).r;
float btg = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).g;
float btb = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).b;
float bta = (v_vColour * texture2D(gm_BaseTexture, v_vTexcoord)).a;
//Calculating what texture to use (also deviding each channel into 2)
if (btr <= 0.5) {
t1 = btr*2.0;
} else {
t5 = (btr-0.5)*2.0;
}
if (btg <= 0.5) {
t2 = btg*2.0;
} else {
t6 = (btg-0.5)*2.0;
}
if (btb <= 0.5) {
t3 = btb*2.0;
} else {
t7 = (btb-0.5)*2.0;
}
if (bta <= 0.5) {
t4 = bta*2.0;
} else {
t8 = (bta-0.5)*2.0;
}
//Get terrain pixels at proper positions
vec4 ter1 = texture2D(texture, vec2(tpx, tpy));
ter1.a = t1;
vec4 ter2 = texture2D(texture, vec2(tpx+0.25, tpy));
ter2.a = t2;
vec4 ter3 = texture2D(texture, vec2(tpx+0.50, tpy));
ter3.a = t3;
vec4 ter4 = texture2D(texture, vec2(tpx+0.75, tpy));
ter4.a = t4;
vec4 ter5 = texture2D(texture, vec2(tpx, tpy+0.25));
ter5.a = t5;
vec4 ter6 = texture2D(texture, vec2(tpx+0.25, tpy+0.25));
ter6.a = t6;
vec4 ter7 = texture2D(texture, vec2(tpx+0.50, tpy+0.25));
ter7.a = t7;
vec4 ter8 = texture2D(texture, vec2(tpx+0.75, tpy+0.25));
ter8.a = t8;
//Output to screen
gl_FragColor =
ter1*vec4(t1) +
ter2*vec4(t2) +
ter3*vec4(t3) +
ter4*vec4(t4) +
ter5*vec4(t5) +
ter6*vec4(t6) +
ter7*vec4(t7) +
ter8*vec4(t8);
}
我很确定我需要 clamp()
或 lerp()
之类的东西,但我无法理解它..
此外,当纹理重叠时,它们会得到 "brighter"(因为两个纹理只是在最后一条语句中添加...我不知道如何防止这种情况发生并始终输出 "maximum" 纹理本身(这样它就不会 "light up")。对不起,如果我听起来很蠢,这是我的第一个真正的着色器 :)
分支在现代硬件上并没有那么糟糕,假设它们跨越多个片段并可能节省大量工作。在没有分支的情况下编写逻辑如下所示:
btr *= 2.;
t1 = fract(min(btr,1.));
t5 = max(btr-1.,0.);
请注意,使用您的方法不能混合两个 "splatting channels" 打包在同一颜色通道中(即混合 t1 和 t5)。仅对另一个 splatmap 进行采样会更简单(并且可能更有效)。
至于混合最终输出,假设您想要线性混合,您可以将各个权重除以所有权重的总和。
float sum = t1+t2+t3+t4+t5+t6+t7+t8;
gl_FragColor = ter1*(t1/sum) + ter2*(t2/sum) + ter3*(t3/sum) + ...