THREE.js r83
Я пытаюсь отобразить каркас сетки в декартовом стиле поверх моей модели, которую нужно анимировать (с помощью AnimationMixer). Я пробовал использовать подход EdgesGeometry / LineBasicMaterial / LineSegments, как показано ниже (из этот ответ):
var geo = new THREE.EdgesGeometry( mesh.geometry );
var mat = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } );
var wireframe = new THREE.LineSegments( geo, mat );
mesh.add( wireframe );
но если я чего-то не упускаю, не похоже, что это можно анимировать (нет атрибута morphTargets и т. д.).
Я переключился на использование собственного шейдера с использованием ShaderMaterial или RawShaderMaterial со следующими шейдерами (на основе https://github.com/rreusser/glsl-solid-wireframe/tree/master/cartesian):
// vertex shader
precision mediump float;
uniform mat4 projection, view;
attribute vec3 position;
attribute vec3 barycentric;
varying vec3 b;
varying vec3 p;
void main () {
b = barycentric;
p = position;
gl_Position = projection * view * vec4(position, 1);
}
// fragment shader
precision mediump float;
varying vec3 b;
varying vec3 p;
uniform float cartesianX, cartesianY, cartesianZ;
uniform float width, feather;
float gridFactor (float parameter, float width_0, float feather_0) {
float w1 = width_0 - feather_0 * 0.5;
float d = fwidth(parameter);
float looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
return smoothstep(d * w1, d * (w1 + feather_0), looped);
}
float gridFactor (vec2 parameter, float width_0, float feather_0) {
float w1 = width_0 - feather_0 * 0.5; vec2 d = fwidth(parameter);
vec2 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec2 a2 = smoothstep(d * w1, d * (w1 + feather_0), looped);
return min(a2.x, a2.y);
}
float gridFactor (vec3 parameter, float width_0, float feather_0) {
float w1 = width_0 - feather_0 * 0.5;
vec3 d = fwidth(parameter);
vec3 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec3 a3 = smoothstep(d * w1, d * (w1 + feather_0), looped);
return min(min(a3.x, a3.y), a3.z);
}
float gridFactor (vec4 parameter, float width_0, float feather_0) {
float w1 = width_0 - feather_0 * 0.5;
vec4 d = fwidth(parameter);
vec4 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec4 a4 = smoothstep(d * w1, d * (w1 + feather_0), looped);
return min(min(min(a4.x, a4.y), a4.z), a4.w);
}
float gridFactor (float parameter, float width_0) {
float d = fwidth(parameter);
float looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
return smoothstep(d * (width_0 - 0.5), d * (width_0 + 0.5), looped);
}
float gridFactor (vec2 parameter, float width_0) {
vec2 d = fwidth(parameter);
vec2 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec2 a2 = smoothstep(d * (width_0 - 0.5), d * (width_0 + 0.5), looped);
return min(a2.x, a2.y);
}
float gridFactor (vec3 parameter, float width_0) {
vec3 d = fwidth(parameter);
vec3 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec3 a3 = smoothstep(d * (width_0 - 0.5), d * (width_0 + 0.5), looped);
return min(min(a3.x, a3.y), a3.z);
}
float gridFactor (vec4 parameter, float width_0) {
vec4 d = fwidth(parameter);
vec4 looped = 0.5 - abs(mod(parameter, 1.0) - 0.5);
vec4 a4 = smoothstep(d * (width_0 - 0.5), d * (width_0 + 0.5), looped);
return min(min(min(a4.x, a4.y), a4.z), a4.z);
}
void main () {
float g = gridFactor( vec3( cartesianX > 0.0 ? p.x * cartesianX : 0.5, cartesianY > 0.0 ? p.y * cartesianY : 0.5, cartesianZ > 0.0 ? p.z * cartesianZ : 0.5 ), width, feather);
gl_FragColor = vec4(mix(vec3(0), vec3(0.8), g), 1);
}
А вот как определяется RawShaderMaterial:
new THREE.RawShaderMaterial({
// uniforms: uniforms,
derivatives: true,
vertexShader: document.getElementById('vertexshader').textContent,
fragmentShader: document.getElementById('fragmentshader').textContent,
depthTest: false,
side: THREE.DoubleSide,
wireframe: true,
lights: false,
visible: true,
color: 0x000000
}))
Но при таком подходе ничего не отображается, хотя я получаю следующее предупреждение:
three.js:17014 THREE.WebGLProgram: gl.getProgramInfoLog() WARNING: Output of vertex shader 'b' not read by fragment shader
Я плохо разбираюсь в необработанном коде webgl, поэтому не уверен, насколько это важно.
Обобщить:
У меня сложилось впечатление, что подход EdgesGeometry / LineBasicMaterial / LineSegments не может быть анимирован как есть, я ошибаюсь?
Если это правда, я остаюсь с шейдерным подходом. Может ли кто-нибудь с большим опытом работы с webgl сказать мне, что здесь не так?
Обновлено: Похоже, что подход шейдера НЕ будет работать для меня, поскольку, похоже, мой шейдер должен будет иметь возможность обрабатывать анимацию, и я думаю, что это будет слишком сложно для меня в настоящее время. Итак, вернемся к первой части: есть ли способ заставить LineSegments анимировать с помощью AnimationMixer или, может быть, просто воспроизвести этот вид с помощью другой настройки?
В вашем шейдере много чего происходит. Один из способов отладки шейдеров - выводить цвет на любую трансформируемую сетку. С необработанным шейдером у вас есть больше движущихся частей, которые могут сломаться, например, ваши view
и projection
настроены правильно? По крайней мере, с ShaderMaterial
вы можете рассчитывать на эти два (projectionMatrix
и viewMatrix
имеют 100% точность). Оттуда я отлаживал эти функции фрагментов одну за другой. Без них можно вывести плоский цвет и получить желаемую форму геометрии. Проверять. Далее, одна из этих функций, желаемые результаты? Проверять. Следующий...
Загляните на этот форум нить.