Я пытаюсь реализовать обнаружение краев в шейдере для достижения нефотореалистичного эффекта «контура» в Three.js, следуя подходу здесь: http://ar3f.in/goochShading.html . Меня в основном интересуют темные контуры, а не затенение Гуча. Я понимаю подход, использованный в этом коде, который заключается в том, чтобы сначала визуализировать модель с использованием нормалей объектного пространства, затем использовать обнаружение края Кэнни на этом изображении (после некоторой фильтрации) и, наконец, инвертировать, чтобы получить изображение контура. Затем это контурное изображение умножается на обычный («диффузный») рендеринг сцены.
Однако в этом примере для реализации двух визуализаций (одной для краев и одной для диффузного изображения) автор дублирует основную геометрию и создает две сетки в двух разных сценах, чтобы отдельно применить два разных материала (тот, который просто рендерит на основе нормалей, а тот, который рендерит с использованием затенения Гуча). Этот подход не очень привлекателен в моем приложении, потому что геометрия довольно велика и обновляется динамически. Неважно, я решил просто использовать overrideMaterial
на RenderPass
, чтобы нарисовать все объекты с NormalShader
(ниже). К сожалению, это не сработало, так как некоторые из моих объектов имеют THREE.Line
или что-то в этом роде и не имеют нормальных атрибутов, что приводит к таким ошибкам:
WebGL: INVALID_OPERATION: vertexAttribPointer: no bound ARRAY_BUFFER three.js:21636
WebGL: INVALID_OPERATION: drawArrays: attribute 1 is enabled but has no buffer bound three.js:21748
WebGL: INVALID_OPERATION: vertexAttribPointer: no bound ARRAY_BUFFER three.js:21636
2[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 1 dev.html:1
[.WebGLRenderingContext]GL ERROR :GL_INVALID_OPERATION : glDrawArrays: attempt to access out of range vertices in attribute 1
Я пытался скрыть такие объекты, используя такой код перед каждым вызовом render
:
scene.traverse(function(obj) {
if ( !!obj && obj.geometry && obj.geometry.attributes && !obj.geometry.attributes.normal ) {
obj._visible = obj.visible;
obj.visible = false;
}
})
но я продолжаю получать те же ошибки и не знаю, как отследить объекты, которые их вызывают.
Итак, вот мой вопрос: Есть ли хороший способ отфильтровать объекты, у которых нет определенного атрибута (например, нормали), даже если некоторые из объектов имеют Mesh
es с Geometry
, а не BufferGeometry
?
Спасибо за вашу помощь!
Изменить: я удалил немного об альтернативном подходе и задал здесь отдельный вопрос: Render резкие края с помощью пользовательского шейдера
Код для NormalShader, для справки:
THREE.NormalShader = {
uniforms: {
},
vertexShader: [
"varying vec3 vNormal;",
"void main() {",
"vNormal = normalize(normal);",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"varying vec3 vNormal;",
"void main(void) {",
"gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, 1.0 );",
"}"
].join("\n")
};