thothbot / parallax

Cross-platform Java 3D SDK
http://thothbot.github.io
MIT License
84 stars 26 forks source link

Rendering differences with transparency & fog #24

Open bartolomiew opened 9 years ago

bartolomiew commented 9 years ago

While trying to port this demo : http://stemkoski.github.io/Three.js/Translucence.html I can see several differences with Three.js. Fog doesn't work as expected so I've to add skybox to the scene, when looking at the scene in front rendering is almost the same, but behind doesn't work as expected either.

import thothbot.parallax.core.client.AnimatedScene;
import thothbot.parallax.core.client.controls.OrbitControls;
import thothbot.parallax.core.client.gl2.enums.TextureWrapMode;
import thothbot.parallax.core.client.textures.Texture;
import thothbot.parallax.core.shared.cameras.PerspectiveCamera;
import thothbot.parallax.core.shared.geometries.BoxGeometry;
import thothbot.parallax.core.shared.geometries.PlaneGeometry;
import thothbot.parallax.core.shared.geometries.SphereGeometry;
import thothbot.parallax.core.shared.lights.AmbientLight;
import thothbot.parallax.core.shared.lights.PointLight;
import thothbot.parallax.core.shared.materials.Material.BLENDING;
import thothbot.parallax.core.shared.materials.Material.SIDE;
import thothbot.parallax.core.shared.materials.MeshBasicMaterial;
import thothbot.parallax.core.shared.materials.MeshLambertMaterial;
import thothbot.parallax.core.shared.materials.MeshPhongMaterial;
import thothbot.parallax.core.shared.math.Color;
import thothbot.parallax.core.shared.math.Vector2;
import thothbot.parallax.core.shared.objects.Mesh;
import thothbot.parallax.core.shared.scenes.FogExp2;

public class Sample15Translucence extends AnimatedScene {

    // field of view
    private static final double VIEW_ANGLE = 45d;

    // near
    private static final double NEAR = 0.1d;

    // far
    private static final double FAR = 20000d;

    // camera
    private PerspectiveCamera camera;

    // control
    OrbitControls controls;

    private static final String texture_floor = "./static/textures/checkerboard.jpg";
    private static final String texture_moon = "./static/textures/moon.jpg";
    private static final String texture_redball = "./static/textures/redball.png";

    @Override
    protected void onStart() {

        // CAMERA
        camera = new PerspectiveCamera(VIEW_ANGLE, getRenderer()
                .getAbsoluteAspectRation(), NEAR, FAR);
        getScene().add(camera);
        camera.getPosition().set(0, 150, 400);
        camera.lookAt(getScene().getPosition());

        // CONTROLS
        controls = new OrbitControls(camera, getCanvas());

        // LIGHT
        PointLight light = new PointLight(0xffffff);
        light.getPosition().set(0,250,0);
        getScene().add(light);

        // FLOOR
        Texture floorTexture = new Texture(texture_floor);
        floorTexture.setWrapS(TextureWrapMode.REPEAT);
        floorTexture.setWrapT(TextureWrapMode.REPEAT);
        floorTexture.setRepeat(new Vector2(10, 10));
        MeshBasicMaterial floorMaterial = new MeshBasicMaterial();
        floorMaterial.setMap(floorTexture);
        floorMaterial.setSide(SIDE.DOUBLE);

        PlaneGeometry floorGeometry = new PlaneGeometry(1000, 1000, 10, 10);
        Mesh floor = new Mesh(floorGeometry, floorMaterial);
        floor.getPosition().setY(-0.5);
        floor.getRotation().setX(Math.PI / 2);
        getScene().add(floor);

        // SKYBOX/FOG
        BoxGeometry skyBoxGeometry = new BoxGeometry(10000, 10000, 10000);
        MeshBasicMaterial skyBoxMaterial = new MeshBasicMaterial();
        skyBoxMaterial.setColor(new Color(0x9999ff));
        skyBoxMaterial.setSide(SIDE.BACK);
        Mesh skyBox = new Mesh(skyBoxGeometry, skyBoxMaterial);
        getScene().add(skyBox);                                 // <---     
        getScene().setFog(new FogExp2( 0x9999ff, 0.00025 ));    // <---

        ////////////
        // CUSTOM //
        ////////////

        // radius, segments along width, segments along height
        SphereGeometry sphereGeom =  new SphereGeometry( 40, 32, 16 );

        // overlapping translucent red/green/blue spheres
        MeshBasicMaterial redMaterial = new MeshBasicMaterial();
        redMaterial.setColor(new Color(0xff0000));
        redMaterial.setTransparent(true);
        redMaterial.setOpacity(0.5); 
        Mesh sphere = new Mesh( sphereGeom.clone(), redMaterial );
        sphere.getPosition().set(-100, 50, 50);
        getScene().add( sphere );   

        MeshBasicMaterial greenMaterial = new MeshBasicMaterial();
        greenMaterial.setColor(new Color(0x00ff00));
        greenMaterial.setTransparent(true);
        greenMaterial.setOpacity(0.5); 
        sphere = new Mesh( sphereGeom.clone(), greenMaterial );
        sphere.getPosition().set(-100, 50, -50);
        getScene().add( sphere );   

        MeshBasicMaterial blueMaterial = new MeshBasicMaterial();
        blueMaterial.setColor(new Color(0x0000ff));
        blueMaterial.setTransparent(true);
        blueMaterial.setOpacity(0.5); 
        sphere = new Mesh( sphereGeom.clone(), blueMaterial );
        sphere.getPosition().set(-100, 50, -150);
        getScene().add( sphere );   

        // basic material translucence
        MeshBasicMaterial darkMaterial = new MeshBasicMaterial();
        darkMaterial.setColor(new Color(0x333333));
        darkMaterial.setTransparent(true);
        darkMaterial.setOpacity(0.95); 
        sphere = new Mesh( sphereGeom.clone(), darkMaterial );
        sphere.getPosition().set(0, 50, 0);
        getScene().add( sphere );       

        // phong material translucence
        MeshPhongMaterial darkMaterialPhong = new MeshPhongMaterial();
        darkMaterialPhong.setColor(new Color(0x333333));
        darkMaterialPhong.setTransparent(true);
        darkMaterialPhong.setOpacity(0.95); 
        sphere = new Mesh( sphereGeom.clone(), darkMaterialPhong );
        sphere.getPosition().set(100, 50, 0);
        getScene().add( sphere );

        // image material translucence
        Texture moonTexture = new Texture( texture_moon );
        MeshLambertMaterial moonMaterial = new MeshLambertMaterial();
        moonMaterial.setMap(moonTexture);
        moonMaterial.setTransparent(true);
        moonMaterial.setOpacity(0.75);
        Mesh moon = new Mesh( sphereGeom.clone(), moonMaterial );
        moon.getPosition().set(200, 50, 0);
        getScene().add( moon ); 

        // translucent blue sphere with additive blending for "glow" effect
        darkMaterial = new MeshBasicMaterial();
        darkMaterial.setColor(new Color(0x0000ff));
        darkMaterial.setTransparent(true);
        darkMaterial.setOpacity(0.8); 
        darkMaterial.setBlending(BLENDING.ADDITIVE);
        sphere = new Mesh( sphereGeom.clone(), darkMaterial );
        sphere.getPosition().set(0, 50, -100);
        getScene().add( sphere );   

        // translucent blue sphere with additive blending and phong shading
        // added ambient light and color for better results
        AmbientLight ambientLight = new AmbientLight(0x444444);
        getScene().add(ambientLight);

        darkMaterialPhong = new MeshPhongMaterial();
        darkMaterialPhong.setColor(new Color(0x0000ff));
        darkMaterialPhong.setAmbient(new Color(0xff0000));
        darkMaterialPhong.setTransparent(true);
        darkMaterialPhong.setBlending(BLENDING.ADDITIVE);
        sphere = new Mesh( sphereGeom.clone(), darkMaterialPhong );
        sphere.getPosition().set(100, 50, -100);
        getScene().add( sphere );   

        // image with transparency on a plane

        Texture ballTexture = new Texture( texture_redball );   // <--- look behind to see bug
        MeshBasicMaterial ballMaterial = new MeshBasicMaterial();
        ballMaterial.setMap(ballTexture);
        ballMaterial.setTransparent(true);
        ballMaterial.setSide(SIDE.DOUBLE);
        PlaneGeometry planeGeometry = new PlaneGeometry(100,100,1,1);
        Mesh plane = new Mesh( planeGeometry, ballMaterial );
        plane.getPosition().set( 200, 50, -100 );
        getScene().add(plane);      
    }

    @Override
    protected void onUpdate(double duration) {
        // Called when the animation should be updated.
        controls.update();
        getRenderer().render(getScene(), camera);
    }

}
thothbot commented 9 years ago

Let me check it, and I'll write you asap

thothbot commented 9 years ago

Looks like the issue is in blending mode for materials

bartolomiew commented 9 years ago

Nice to see you are able to find what's wrong so quickly

thothbot commented 9 years ago

But I need a time to figure it out. I think the issue somewhere in WebGLRenderer.setBlending() method, perhaps in caching..

thothbot commented 9 years ago

Ok, looks like I found an issue. It was more complex, than I thought.

  1. You should comment the following, as in original code:
//          getScene().add(skyBox);   
  1. In the original code - background is defined in the css for body element In the Parallax (in demo) I did the following
    @Override
    protected void loadRenderingPanelAttributes(RenderingPanel renderingPanel) 
    {
        super.loadRenderingPanelAttributes(renderingPanel);
        renderingPanel.setBackground(0xccccff);
    }
  1. In THREE.JS _clearAlpha = 0.0; in Parallax _clearAlpha = 1.0; that is why you need in the AnimatedScene do the following
getRenderer().setClearColor(0x000000, 0.0);

Hope it help, If you fine you can close the issue

bartolomiew commented 9 years ago

I've applyed all your changes, Front side the scene is now perfect but if you rotate the scene 180° on Z axis, looks at the sphere who is now behind the red ball. Thank's for the tip about _clearAlpha value.

thothbot commented 9 years ago

Yes, this is strange behavior. I'll take a look at it