14

I'm drawing two geometries next to each other and have them rotate. The problem is that the first drawn one is obstructing the second one, where transparency should take effect. The two objects should have the same transparency, regardless of who was drawn first. That's why blending is turned on and depth test is off. Here are the images:

Both geometries are point cloud using THREE.ShaderMaterial as followed:

var shaderMaterial = new THREE.ShaderMaterial({
                uniforms: uniforms,
                attributes: attributes,
                vertexShader: document.getElementById('vertexshader').textContent,
                fragmentShader: document.getElementById('fragmentshader').textContent,
                blending: THREE.NormalBlending,
                depthTest: false,
                transparent: true
            });

where

// attributes
attributes = {
                size: { type: 'f', value: null },
                alpha: { type: 'f', value: [] },
                customColor: { type: 'c', value: null }
            };

 // uniforms
uniforms = {
             color: { type: "c", value: new THREE.Color(0x00ff00) },
             texture: { type: "t", value: THREE.ImageUtils.loadTexture("../textures/sprites/circle.png") }
            };

and

<script type="x-shader/x-vertex" id="vertexshader">
        attribute float alpha;
        attribute float size;
        attribute vec3 customColor;        
        varying float vAlpha;
        varying vec3 vColor;
        void main() {
        vAlpha = alpha;
        vColor = customColor;
        vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
        gl_PointSize =  size * ( 120.0 / length( mvPosition.xyz ));
        gl_Position = projectionMatrix * mvPosition;
        }
    </script>
<script type="x-shader/x-fragment" id="fragmentshader">
        uniform vec3 color;
        uniform sampler2D texture;
        varying float vAlpha;
        varying vec3 vColor;
        void main() {
        gl_FragColor = vec4( vColor, vAlpha );
        gl_FragColor = gl_FragColor * texture2D( texture, gl_PointCoord );
        }
    </script>
Eyal Shacham
  • 139
  • 1
  • 1
  • 7
  • Try `material.alphaTest = 0.5`. If that does not work, can you provide a _simple_ live link? – WestLangley Jan 18 '15 at 16:59
  • Where do I add the material.alphaTest = 0.5 to? – Eyal Shacham Jan 18 '15 at 17:29
  • 2
    Sorry. Since you are are using `ShaderMaterial`, you have to handle that yourself: `if ( gl_FragColor.a < 0.5 ) discard;` – WestLangley Jan 18 '15 at 17:39
  • Thanks, but this change just discards some vertices, making the object more see-thru like as the point cloud objects are less 'crowded'. – Eyal Shacham Jan 18 '15 at 22:37
  • Where would I host it? Do you know of a site where I can upload the code? Thanks! – Eyal Shacham Jan 24 '15 at 18:54
  • OK, I was able to load it to JSFiddle at http://jsfiddle.net/e8h7k520/5/. – Eyal Shacham Jan 24 '15 at 20:15
  • The JSFiddle example is not using an image (png) as the texture for the shader but it demonstrates the issue. – Eyal Shacham Jan 24 '15 at 20:16
  • You have many, many overlapping particles and the blue ones are rendered last, since they are at the end of the buffer. Blending is not commutative. Study the blending math to see what happens. Study this simpler example: http://jsfiddle.net/e8h7k520/6/. – WestLangley Jan 25 '15 at 04:25
  • Even with your version of the example, where you have much less particles, overlapping occurs when the objects rotates, and blending is correct for one color but not for the other one. I even tried to add the particles from both objects to the buffer array, one at the time from each object, and the results got worsen, so no matter how I codes it, one color will always be dominant. I thought I could model real life situation where two semi-transparent object rotates around each-other the front object becomes the dominant. Is that even possible? – Eyal Shacham Jan 25 '15 at 15:16
  • Remember, blending is not commutative. For comparison, google "order independent transparency". `PointCloud` particles are not sorted. You can try with two separate point clouds, as long as they have different `position`s, and the clouds are disjoint. – WestLangley Jan 25 '15 at 18:51

1 Answers1

14

Example code with 2 textures, but can be made to work with one as well:

<script id="fragmentShaderLoader" type="x-shader/x-fragment">
        uniform float percent;

        uniform sampler2D texture1;
        uniform sampler2D texture2;

        varying vec2 vUv;

        void main() {
            gl_FragColor = texture2D( texture1, vUv);
            vec4 tex2 = texture2D( texture2, vUv );
            if(tex2.a - percent < 0.0) {
                gl_FragColor.a = 0.0;
                //or without transparent = true use
                //discard; 
            }

        }

    </script>

    <script id="vertexShaderLoader" type="x-shader/x-vertex">
        varying vec2 vUv;

        void main()
        {
            vUv = uv;

            vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
            gl_Position = projectionMatrix * mvPosition;
        }
    </script>

Then for init:

uniformsMove = {
                    percent: { type: "f", value: 1.0 },
                    texture1: { type: "t", value: (new THREE.TextureLoader()).load( "govr/loader-test.png" ) },
                    texture2: { type: "t", value: (new THREE.TextureLoader()).load( "govr/loader-mask2.png" ) } 
                };

            material = new THREE.ShaderMaterial( {
                uniforms: uniformsMove,
                vertexShader: document.getElementById( 'vertexShaderLoader' ).textContent,
                fragmentShader: document.getElementById( 'fragmentShaderLoader' ).textContent

            } );
material.transparent = true;
Evalds Urtans
  • 6,436
  • 1
  • 41
  • 31