我正在尝试在我的战略游戏中实现“战争迷雾”功能。我一直在阅读关于SO的其他问答,我认为我需要使用自定义GLSL着色器。所以我定义了一个包含“视觉点”的数组:
let vision_points = [
new THREE.Vector2(1500, 1500),
new THREE.Vector2(1500, -1500),
new THREE.Vector2(-1500, 1500),
new THREE.Vector2(-1500, -1500)
]
并使用ShaderMaterial
作为制服传递视点。由于数组长度可以是任何值,因此我在顶点着色器代码的开头注入了VPOINTSMAX
常量:
let material = new THREE.ShaderMaterial({
uniforms: {
u_texture: {type: 't', value: this.texture},
vision_points: {
type: 'v2v',
value: vision_points
}
},
vertexShader: "#define VPOINTSMAX "+vision_points.length+"\n"+fow_vs,
fragmentShader: fow_fs
});
然后,顶点着色器计算顶点本身与每个vision_point之间的距离。然后根据顶点是否在视觉范围内,将varying float in_vision
设置为0.0或1.0:
uniform vec2 vision_points[VPOINTSMAX];
varying vec2 v_texCoord;
varying float in_vision;
void main() {
in_vision = 0.0;
for (int v = 0; v < VPOINTSMAX; v++) {
vec2 pos2 = vec2(position.x, position.z);
float distance = length(pos2-vision_points[v]);
if (distance < 1000.0) {
in_vision = 1.0;
}
}
// Pass the texcoord to the fragment shader.
v_texCoord = uv;
gl_Position = projectionMatrix *
modelViewMatrix *
vec4(position,1.0);
}
最后,如果in_vision值不大于0,片段着色器会使颜色变暗:
uniform sampler2D u_texture;
varying vec2 v_texCoord;
varying float in_vision;
void main() {
vec4 color = texture2D(u_texture, v_texCoord);
if (in_vision > 0.0) {
gl_FragColor = color;
} else {
gl_FragColor = color/2.0;
}
}
现在的问题是,在游戏运行时,vision_points
数组的内容及其长度都会发生变化。更改统一值应该没有任何麻烦,但是随着数组长度的变化,我需要找到一种重新定义VPOINTSMAX
常量的方法。到目前为止,我唯一想到的解决方案是重建ShaderMaterial
并使用注入的新VPOINTSMAX
值重新编译着色器代码。然后只需将新材料应用于网格即可。但是我担心这可能会导致性能问题。
您还建议其他哪些方法来将长度动态变化的数组统一更新/传递到GLSL着色器中?
答案 0 :(得分:2)
制作多个ShaderMaterial
,每个要支持的VPOINTSMAX
个。当您想使用其他Mesh
VPOINTSMAX
上的材质
GLSL不支持可变大小的数组。
唯一的其他解决方案是将VPOINTSMAX
设置为您将使用的最大大小,然后像on一样退出for循环
uniform int maxPoints;
#define VPOINTSMAX 20
...
for (int v = 0; v < VPOINTSMAX; v++) {
if (v >= maxPoints) {
break;
}
...
}
但是这似乎会比较慢,因为循环通常会在GPU中展开