vagran / dxf-viewer

DXF 2D viewer written in JavaScript
Mozilla Public License 2.0
290 stars 86 forks source link

Question: All geometries use RawShaderMaterial ? #75

Closed ghost closed 5 months ago

ghost commented 1 year ago

in scene, I see all geometries use RawShaderMaterial. but I want use clipPlanes to cut geometry. but the implementation of this shader is not very clear.

file path: DxFViewer.js / _GenerateShaders function example:

vertex: `
  // other code
  ${fullInstanceAttr}
  ${pointInstanceAttr}

  // add new param
  out vec3 vPosition; 
  uniform mat4 modelViewMatrix;
  // other define param

  void main() {

   vec4 pos = vec4(position, 0.0, 1.0);
   // used by fragment Shader
   vPosition = vec3(position, 0.0);
   // other code
  }
`
fragment: `
// other code
out vec4 fragColor;
uniform vec4 clipPlanes[4];
out vec3 vPosition;

void main(){
  #if NUM_PLANES > 0 
    float distances[4];
    for (int i = 0; i < 4; i++) {
      distances[i] = dot(vPosition, clipPlanes[i].xyz) - clipPlanes[i].w;
    }
   if (distances[0] > 0.0 || distances[1] > 0.0 || distances[2] > 0.0 || distances[3] > 0.0) discard;
 #endif

  fragColor = vec4(color, 1.0);
}
`

but is not work。 I see three source code in path(src/renderers/shaders/ShaderChunk/clipping_planes_fragment.glsl).

Can you help me?

vagran commented 1 year ago

Hello, I would suggest you to simplify things and not rely on three.js built-in clipping planes functionality. First, it is 2D, so you can use clipping lines instead. I am not sure if NUM_PLANES preprocessor macro is properly defined when this shader is compiled (and you have hard-coded size 4 anyway, so it seems suspicious). Define you clip lines uniforms when material is created, and update them dynamically if needed.

        return {
            vertex: `

            precision highp float;
            precision highp int;
            in vec2 position;
            ${fullInstanceAttr}
            ${pointInstanceAttr}
            uniform mat4 modelViewMatrix;
            uniform mat4 projectionMatrix;
            ${pointSizeUniform}
            out out vec2 vPosition; // <<<< use 2D position

            void main() {
                vec4 pos = vec4(position, 0.0, 1.0);
                ${fullInstanceTransform}
                ${pointInstanceTransform}
                vPosition = pos.xy; // <<<< take it after instance transform is applied if any
                gl_Position = projectionMatrix * modelViewMatrix * pos;
                ${pointSizeAssigment}
            }
            `,
            fragment: `

            precision highp float;
            precision highp int;
            uniform vec3 color;
            out vec4 fragColor;
            uniform vec3 clipLines[4]; // <<< clip line is defined by normal vector in xy and distance in z

            void main() {

                bool clipped = true;
                #pragma unroll_loop_start
                for (int i = 0; i < 4; i++) {
                    vec3 line = clippingLines[i];
                    clipped = (dot(vPosition, line.xy) > line.z) && clipped;
                 }
                #pragma unroll_loop_end
                if (clipped) discard;

                fragColor = vec4(color, 1.0);
            }
            `
        }
    _CreateSimpleColorMaterial(instanceType = InstanceType.NONE) {
        const shaders = this._GenerateShaders(instanceType, false)
        return new three.RawShaderMaterial({
            uniforms: {
                color: {
                    value: new three.Color(0xff00ff)
                },
                clipLines: {
                    // put your clip lines here
                    value: [new three.Vector3(1,2,3), new three.Vector3(1,2,3), three.Vector3(1,2,3), three.Vector3(1,2,3)]
                }
            },
            vertexShader: shaders.vertex,
            fragmentShader: shaders.fragment,
            depthTest: false,
            depthWrite: false,
            glslVersion: three.GLSL3,
            side: three.DoubleSide
        })
    }

and similarly in _CreateSimplePointMaterial().