Обнаружение края NPR с использованием пользовательского шейдера

Я пытаюсь реализовать обнаружение краев в шейдере для достижения нефотореалистичного эффекта «контура» в 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;
    } 
}) 

но я продолжаю получать те же ошибки и не знаю, как отследить объекты, которые их вызывают.

Итак, вот мой вопрос: Есть ли хороший способ отфильтровать объекты, у которых нет определенного атрибута (например, нормали), даже если некоторые из объектов имеют Meshes с 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")

};

person caseygrun    schedule 29.09.2014    source источник