2

I am trying to implement edge detection in a shader to achieve a non-photorealistic "outline" effect in Three.js, following the approach here: http://ar3f.in/goochShading.html . I am mainly interested in the dark outlines, rather than the Gooch shading. I understand the approach taken in this code, which is to render the model first using object-space normals, then use Canny edge detection on that image (after some filtering), finally inverting to get an image of the outline. That outline image is then multiplied with a regular ("diffuse") rendering of the scene.

However, in this example, to implement the two renderings (one for the edges and one for the diffuse image), the author duplicates the main geometry and creates two meshes in two different scenes, in order to separately apply two different materials (one that just renders based on the normals, and one that renders using the Gooch shading). This approach is not terribly appealing in my application, because the geometries are quite large and are updated dynamically. No matter, I figured I'd just use an overrideMaterial on the RenderPass to draw all objects with a NormalShader(below). Unfortunately this didn't work since some of my objects are THREE.Lines or whatever and didn't have normal attributes, yielding errors like this:

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 

I tried hiding such objects using code like this before each render call:

scene.traverse(function(obj) {
    if ( !!obj && obj.geometry && obj.geometry.attributes && !obj.geometry.attributes.normal ) {
        obj._visible = obj.visible;
        obj.visible = false;
    } 
}) 

but I keep getting the same errors, and I don't know how to trace the objects that are causing them.

So here's my question: Is there a good way to filter out objects that don't have a particular attribute (e.g. normals), even if some of the objects are Meshes with Geometry rather than BufferGeometry?

Thanks for your help!

Edit: I've removed the bit about an alternative approach and started a separate question here: Render "hard" edges using custom shader


Code for the NormalShader, for reference:

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")

};
Community
  • 1
  • 1
caseygrun
  • 2,019
  • 1
  • 15
  • 21

0 Answers0