0

I add a json model with glow effect into the scene.

As follows: enter image description here

I try to rotate the json model automatically. However, it looks weird when it is rotating. The glow effect of the model does not work. enter image description here enter image description here

I assume that the position of the json model does not be changed when this model is rotating. As the result, the viewVector.value of the ShaderMaterial is constant when this model is rotating(I do not change position of the camera).

if(jsonMesh){
    jsonMesh.rotation.y += 0.1;
    jsonMesh.material.uniforms.viewVector.value =
        new THREE.Vector3().subVectors( camera.position, jsonMesh.position );

}

This is the Three.ShaderMaterial.

VertexShader and FragmentShader

<script id="vertexShader" type="x-shader/x-vertex">
    uniform vec3 viewVector;
    uniform float c;
    uniform float p;
    varying float intensity;
    void main()
    {
        vec3 vNormal = normalize( normalMatrix * normal );
        vec3 vNormel = normalize( normalMatrix * viewVector );
        intensity = pow( c - dot(vNormal, vNormel), p );

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

<script id="fragmentShader" type="x-shader/x-fragment"> 
    uniform vec3 glowColor;
    varying float intensity;
    void main() 
    {
        vec3 glow = glowColor * intensity;
        gl_FragColor = vec4( glow, 1.0 );
    }
</script>

Three.ShaderMaterial.

var customMaterial = new THREE.ShaderMaterial( 
{
    uniforms: 
    { 
        "c":   { type: "f", value: 1.0 },
        "p":   { type: "f", value: 1.4 },
        glowColor: { type: "c", value: new THREE.Color(0xffff00) },
        viewVector: { type: "v3", value: camera.position }
    },
    vertexShader:   document.getElementById( 'vertexShader'   ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
    side: THREE.FrontSide,
    blending: THREE.AdditiveBlending,
    transparent: true
}
);

How should I modify the code in this case? Here is the Demo and source code.

Kevin Hsiao
  • 2,281
  • 2
  • 10
  • 18

1 Answers1

1

You can use built in three.js functions for this. Instead of using the camera position, I chose to show you how to set a light source position in the world. That way you can match the light source on your custom shader to any light sources you plan to add later to your 3d world. Feel free to change the worldLightPoint value to camera.position instead of new THREE.Vector3(100,100,100). and in that case the effect will remain constant with the camera position.

var v = new THREE.Vector3();
//var worldLightPoint =  camera.position;
var worldLightPoint = new THREE.Vector3(100,100,100);
function update()
{
    controls.update();
    stats.update();
    if(jsonMesh){
        jsonMesh.rotation.y += 0.1;
        jsonMesh.material.uniforms.viewVector.value = jsonMesh.worldToLocal(v.copy(worldLightPoint));
    }
}
Radio
  • 2,810
  • 1
  • 21
  • 43
  • Tip: Do not call `new` or `clone()` in the animation loop. Create an instance and reuse it. Use `copy()`. – WestLangley Dec 27 '16 at 17:59
  • @WestLangley Changed per recommendation, as I understand it. – Radio Dec 27 '16 at 18:10
  • Granted, there is no "right way", but I would use this pattern: `viewVector.value.copy( v )`. It is up to you. :-) – WestLangley Dec 27 '16 at 18:47
  • @WestLangley Makes total sense. Your way is less calls in our calls, when we call our calls. :) – Radio Dec 27 '16 at 19:04
  • Thank you all ! It does work!! Actually I still do not know what "worldToLocal" means. But I will try my best to understand how to use ".worldToLocal()". Thank you so much. This is an amazing solution! – Kevin Hsiao Dec 28 '16 at 04:33
  • Every object has its own cartesian space. The world has its cartesian space. When you rotate the obejct, the world's space is not affected. The camera exists in world space. The shader exists in the object's space. You need to translate the world position of the camera to the local cartesian space of the object. – Radio Dec 28 '16 at 17:00