Я пытаюсь внедрить функцию «туман войны» в мою стратегическую игру. Я читал некоторые другие вопросы и ответы по 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 в виде униформы?