package com.akjava.gwt.threejsexamples.client.examples.shadowmap;
import java.util.List;
import com.akjava.gwt.lib.client.GWTUtils;
import com.akjava.gwt.lib.client.LogUtils;
import com.akjava.gwt.stats.client.Stats;
import com.akjava.gwt.three.client.examples.js.THREEExp;
import com.akjava.gwt.three.client.examples.js.controls.FirstPersonControls;
import com.akjava.gwt.three.client.examples.js.shaders.ExampleShaders;
import com.akjava.gwt.three.client.gwt.GWTParamUtils;
import com.akjava.gwt.three.client.gwt.extras.Shader;
import com.akjava.gwt.three.client.gwt.extras.Uniforms;
import com.akjava.gwt.three.client.java.ui.example.AbstractExample;
import com.akjava.gwt.three.client.java.ui.example.Example;
import com.akjava.gwt.three.client.java.utils.GWTThreeUtils;
import com.akjava.gwt.three.client.js.THREE;
import com.akjava.gwt.three.client.js.animation.AnimationMixer;
import com.akjava.gwt.three.client.js.cameras.OrthographicCamera;
import com.akjava.gwt.three.client.js.cameras.PerspectiveCamera;
import com.akjava.gwt.three.client.js.core.Clock;
import com.akjava.gwt.three.client.js.core.Geometry;
import com.akjava.gwt.three.client.js.extras.geometries.PlaneBufferGeometry;
import com.akjava.gwt.three.client.js.extras.geometries.TextGeometry;
import com.akjava.gwt.three.client.js.lights.AmbientLight;
import com.akjava.gwt.three.client.js.lights.SpotLight;
import com.akjava.gwt.three.client.js.loaders.JSONLoader;
import com.akjava.gwt.three.client.js.loaders.JSONLoader.JSONLoadHandler;
import com.akjava.gwt.three.client.js.materials.Material;
import com.akjava.gwt.three.client.js.materials.MeshLambertMaterial;
import com.akjava.gwt.three.client.js.materials.MeshPhongMaterial;
import com.akjava.gwt.three.client.js.materials.ShaderMaterial;
import com.akjava.gwt.three.client.js.objects.Mesh;
import com.akjava.gwt.three.client.js.renderers.WebGLRenderer;
import com.akjava.gwt.three.client.js.renderers.shaders.WebGLShaders.ShaderChunk.UniformsUtils;
import com.akjava.gwt.three.client.js.scenes.Scene;
import com.google.common.collect.Lists;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
public class ShadowmapExample extends AbstractExample{
@Override
public String getName() {
return "shadowmap";
}
@Override
public void animate(double timestamp) {
render(timestamp);
stats.update();//really deprecate?many still use this
}
//don't set value here,because of abstract class
private WebGLRenderer renderer;
private Scene scene;
private PerspectiveCamera camera;
private Stats stats;
int WIDTH;
int HEIGHT;
private int windowHalfX,windowHalfY;
//private int mouseX,mouseY;
Clock clock;
private double NEAR,FAR;
private FirstPersonControls controls;
private SpotLight light;
private int SHADOW_MAP_WIDTH,SHADOW_MAP_HEIGHT;
private OrthographicCamera cameraOrtho;
private Mesh hudMesh;
private Scene sceneHUD;
private double HUD_MARGIN;
private double FLOOR;
private List<MeshData> morphs;
private boolean showHUD=false;//for test
@Override
public void init() {
NEAR=10;
FAR=3000;
SHADOW_MAP_WIDTH=2048;
SHADOW_MAP_HEIGHT=1024;
HUD_MARGIN=0.05;
FLOOR=-250;
clock=THREE.Clock();
WIDTH = (int)getWindowInnerWidth();
HEIGHT = (int)getWindowInnerHeight();
windowHalfX=(int) (getWindowInnerWidth()/2);
windowHalfY=(int) (getWindowInnerHeight()/2);
morphs=Lists.newArrayList();
// scene
scene = THREE.Scene();
scene.setFog(THREE.Fog( 0x59472b, 1000, FAR ));//scene.fog = new THREE.Fog( 0x59472b, 1000, FAR );
// renderer
FocusPanel container = createContainerPanel();
renderer = THREE.WebGLRenderer( GWTParamUtils.WebGLRenderer().antialias(true) );//renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( scene.getFog().getColor());//renderer.setClearColor( scene.fog.color );
renderer.setPixelRatio( GWTThreeUtils.getWindowDevicePixelRatio() );//renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( WIDTH, HEIGHT );
renderer.setAutoClear(false);//renderer.autoClear = false;
container.getElement().appendChild( renderer.getDomElement() );
renderer.getShadowMap().setEnabled(true);//renderer.shadowMap.enabled = true;
renderer.getShadowMap().setType(THREE.PCFShadowMap);//renderer.shadowMap.type = THREE.PCFShadowMap;
// camera
camera = THREE.PerspectiveCamera(23, getWindowInnerWidth()/getWindowInnerHeight(), NEAR, FAR);
camera.getPosition().set(700, 50, 1900);
//controls
controls = THREEExp.FirstPersonControls( camera);//controls = new THREE.FirstPersonControls( camera );
controls.setLookSpeed(0.0125);//controls.lookSpeed = 0.0125;
controls.setMovementSpeed(500);//controls.movementSpeed = 500;
//controls.setNoFly(false);//controls.noFly = false;
controls.setLookVertical(true);//controls.lookVertical = true;
controls.setConstrainVertical(true);//controls.constrainVertical = true;
controls.setVerticalMin(1.5);//controls.verticalMin = 1.5;
controls.setVerticalMax(2.0);//controls.verticalMax = 2.0;
controls.setLon(250);//controls.lon = 250;
controls.setLat(30);//controls.lat = 30;
//lights
AmbientLight ambient = THREE.AmbientLight( 0x444444 );//var ambient = new THREE.AmbientLight( 0x444444 );
scene.add( ambient );
light = THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 2, 1 );//light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 2, 1 );
light.getPosition().set( 0, 1500, 1000 );//light.position.set( 0, 1500, 1000 );
light.getTarget().getPosition().set( 0, 0, 0 );//light.target.position.set( 0, 0, 0 );
light.setCastShadow(true);//light.castShadow = true;
light.setShadowCameraNear(1200);//light.shadowCameraNear = 1200;
light.setShadowCameraFar(2500);//light.shadowCameraFar = 2500;
light.setShadowCameraFov(50);//light.shadowCameraFov = 50;
//light.setShadowCameraVisible(true);////light.shadowCameraVisible = true;
light.setShadowBias(0.0001);//light.shadowBias = 0.0001;
light.setShadowMapWidth(SHADOW_MAP_WIDTH);//light.shadowMapWidth = SHADOW_MAP_WIDTH;
light.setShadowMapHeight(SHADOW_MAP_HEIGHT);//light.shadowMapHeight = SHADOW_MAP_HEIGHT;
scene.add( light );
//stats
stats = Stats.create();
stats.setPosition(0, 0);
container.getElement().appendChild(stats.domElement());
//add html info
container.add(createAbsoluteHTML("<div style='text:white'><a href='http://threejs.org' target='_blank'>three.js</a> - test</div> shadowmap - models by <a href=\"http://mirada.com/\">mirada</a> from <a href=\"http://ro.me\">rome</a></br>move camera with WASD / RF + mouse<br/>"
,100,10));
//handle resize & gui
initResizeHandlerAndGUI();
//setDebugAnimateOneTimeOnly(true);
createHUD();
createScene();
GWTUtils.addKeyDownHandlerToDocument(new KeyDownHandler() {
@Override
public void onKeyDown(KeyDownEvent event) {
//LogUtils.log("key"+event.getNativeKeyCode());
if(event.getNativeKeyCode() ==84){// t
showHUD=!showHUD;
}
}
});
}
private void createScene() {
// GROUND
PlaneBufferGeometry geometry = THREE.PlaneBufferGeometry( 100, 100 );//var geometry = new THREE.PlaneBufferGeometry( 100, 100 );
MeshPhongMaterial planeMaterial = THREE.MeshPhongMaterial( GWTParamUtils.MeshPhongMaterial().color(0xffdd99) );//var planeMaterial = new THREE.MeshPhongMaterial( { color: 0xffdd99 } );
Mesh ground = THREE.Mesh( geometry, planeMaterial );//var ground = new THREE.Mesh( geometry, planeMaterial );
ground.getPosition().set( 0, FLOOR, 0 );//ground.position.set( 0, FLOOR, 0 );
ground.getRotation().setX(- Math.PI / 2);//ground.rotation.x = - Math.PI / 2;
ground.getScale().set( 100, 100, 100 );//ground.scale.set( 100, 100, 100 );
ground.setCastShadow(false);//ground.castShadow = false;
ground.setReceiveShadow(true);//ground.receiveShadow = true;
scene.add( ground );
// TEXT
TextGeometry textGeo = THREEExp.TextGeometry( "THREE.JS", GWTParamUtils.TextGeometry().size(200).height(50).curveSegments(12).font("helvetiker").weight("bold").style("normal").bevelThickness(2).bevelSize(5).bevelEnabled(true));//var textGeo = new THREE.TextGeometry( "THREE.JS", {size: 200,height: 50,curveSegments: 12,font: "helvetiker",weight: "bold",style: "normal",bevelThickness: 2,bevelSize: 5,bevelEnabled: true});
textGeo.computeBoundingBox();
double centerOffset = -0.5 * ( textGeo.getBoundingBox().getMax().getX() - textGeo.getBoundingBox().getMin().getX());//var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
MeshPhongMaterial textMaterial = THREE.MeshPhongMaterial( GWTParamUtils.MeshPhongMaterial().color(0xff0000).specular(0xffffff) );//var textMaterial = new THREE.MeshPhongMaterial( { color: 0xff0000, specular: 0xffffff } );
Mesh mesh = THREE.Mesh( textGeo, textMaterial );//var mesh = new THREE.Mesh( textGeo, textMaterial );
mesh.getPosition().setX(centerOffset);//mesh.position.x = centerOffset;
mesh.getPosition().setY(FLOOR + 67);//mesh.position.y = FLOOR + 67;
mesh.setCastShadow(true);//mesh.castShadow = true;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
scene.add( mesh );
// CUBE
mesh = THREE.Mesh( THREE.BoxGeometry( 1500, 220, 150 ), planeMaterial );//var mesh = new THREE.Mesh( new THREE.BoxGeometry( 1500, 220, 150 ), planeMaterial );
mesh.getPosition().setY(FLOOR - 50);//mesh.position.y = FLOOR - 50;
mesh.getPosition().setZ(20);//mesh.position.z = 20;
mesh.setCastShadow(true);//mesh.castShadow = true;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
scene.add( mesh );
mesh = THREE.Mesh( THREE.BoxGeometry( 1600, 170, 250 ), planeMaterial );//var mesh = new THREE.Mesh( new THREE.BoxGeometry( 1600, 170, 250 ), planeMaterial );
mesh.getPosition().setY(FLOOR - 50);//mesh.position.y = FLOOR - 50;
mesh.getPosition().setZ(20);//mesh.position.z = 20;
mesh.setCastShadow(true);//mesh.castShadow = true;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
scene.add( mesh );
JSONLoader loader=THREE.JSONLoader();
loader.load("models/animated/horse.js", new JSONLoadHandler() {
@Override
public void loaded(Geometry geometry, JsArray<Material> materials) {
addMorph( geometry, 550, 1, 100 - Math.random() * 1000, FLOOR, 300, true );
addMorph( geometry, 550, 1, 100 - Math.random() * 1000, FLOOR, 450, true );
addMorph( geometry, 550, 1, 100 - Math.random() * 1000, FLOOR, 600, true );
addMorph( geometry, 550, 1, 100 - Math.random() * 1000, FLOOR, -300, true );
addMorph( geometry, 550, 1, 100 - Math.random() * 1000, FLOOR, -450, true );
addMorph( geometry, 550, 1, 100 - Math.random() * 1000, FLOOR, -600, true );
}
});
loader.load("models/animated/flamingo.js", new JSONLoadHandler() {
@Override
public void loaded(Geometry geometry, JsArray<Material> materials) {
addMorph( geometry, 500, 1, 500 - Math.random() * 500, FLOOR + 350, 40 ,false);
}
});
loader.load("models/animated/stork.js", new JSONLoadHandler() {
@Override
public void loaded(Geometry geometry, JsArray<Material> materials) {
addMorph( geometry, 350, 1, 500 - Math.random() * 500, FLOOR + 350, 340,false );
}
});
loader.load("models/animated/parrot.js", new JSONLoadHandler() {
@Override
public void loaded(Geometry geometry, JsArray<Material> materials) {
addMorph( geometry, 450, 0.5, 500 - Math.random() * 500, FLOOR + 300, 700,false );
}
});
}
private void createHUD() {
double aspect = (double)WIDTH / HEIGHT;
//LogUtils.log(aspect);
cameraOrtho = THREE.OrthographicCamera( - aspect, aspect, 1, - 1, 1, 10 );//cameraOrtho = new THREE.OrthographicCamera( - aspect, aspect, 1, - 1, 1, 10 );
cameraOrtho.getPosition().setZ(5);//cameraOrtho.position.z = 5;
Shader shader = ExampleShaders.UnpackDepthRGBAShader();
Uniforms uniforms = UniformsUtils.clone( shader.uniforms());//var uniforms = new THREE.UniformsUtils.clone( shader.uniforms );
//there are no shadowmap
//uniforms.set("tDiffuse",light.getShadowMap());//uniforms.tDiffuse.value = light.shadowMap;
ShaderMaterial hudMaterial = THREE.ShaderMaterial( GWTParamUtils.ShaderMaterial().uniforms(uniforms).vertexShader(shader.vertexShader()).fragmentShader(shader.fragmentShader()) );//ShaderMaterial hudMaterial = THREE.ShaderMaterial( {uniforms: uniforms,vertexShader: shader.vertexShader,fragmentShader: shader.fragmentShader} );
double hudHeight = 2.0 / 3;//watch out original integer value make problem.
double hudWidth = hudHeight * SHADOW_MAP_WIDTH / SHADOW_MAP_HEIGHT;
PlaneBufferGeometry hudGeo = THREE.PlaneBufferGeometry( hudWidth, hudHeight );//var hudGeo = new THREE.PlaneBufferGeometry( hudWidth, hudHeight );
hudGeo.translate( hudWidth / 2, hudHeight / 2, 0 );
hudMesh = THREE.Mesh( hudGeo, hudMaterial );//hudMesh = new THREE.Mesh( hudGeo, hudMaterial );
hudMesh.getPosition().setX(cameraOrtho.getLeft() + HUD_MARGIN);//hudMesh.position.x = cameraOrtho.left + HUD_MARGIN;
hudMesh.getPosition().setY(cameraOrtho.getBottom() + HUD_MARGIN);//hudMesh.position.y = cameraOrtho.bottom + HUD_MARGIN;
sceneHUD = THREE.Scene();//sceneHUD = new THREE.Scene();
sceneHUD.add( hudMesh );
cameraOrtho.lookAt( sceneHUD.getPosition());//cameraOrtho.lookAt( sceneHUD.position );
}
private void initResizeHandlerAndGUI() {
VerticalPanel gui=addResizeHandlerAndCreateGUIPanel();
gui.setWidth("200px");//some widget broke,like checkbox without parent size
gui.setSpacing(2);
}
private class MeshData{
private Mesh mesh;
public MeshData(Mesh mesh, double speed, AnimationMixer mixer) {
super();
this.mesh = mesh;
this.speed = speed;
this.mixer = mixer;
}
public Mesh getMesh() {
return mesh;
}
public double getSpeed() {
return speed;
}
public AnimationMixer getMixer() {
return mixer;
}
private double speed;
private AnimationMixer mixer;
}
private void addMorph(Geometry geometry,double speed, double duration, double x,double y,double z,boolean fudgeColor ){
MeshLambertMaterial material = THREE.MeshLambertMaterial( GWTParamUtils.MeshLambertMaterial().color(0xffaa55).morphTargets(true).vertexColors(THREE.FaceColors) );//var material = new THREE.MeshLambertMaterial( { color: 0xffaa55, morphTargets: true, vertexColors: THREE.FaceColors } );
if ( fudgeColor ) {
material.getColor().offsetHSL( 0, Math.random() * 0.5 - 0.25, Math.random() * 0.5 - 0.25 );//material.color.offsetHSL( 0, Math.random() * 0.5 - 0.25, Math.random() * 0.5 - 0.25 );
}
Mesh mesh = THREE.Mesh( geometry, material );//var mesh = new THREE.Mesh( geometry, material );
//mesh.setSpeed(speed);//mesh.speed = speed;
AnimationMixer mixer = THREE.AnimationMixer( mesh );//var mixer = new THREE.AnimationMixer( mesh );
mixer.clipAction( geometry.getAnimations().get(0) ).setDuration( duration ).play();//mixer.addAction( new THREE.AnimationAction( geometry.animations[0] ).warpToDuration( duration ) );
mixer.update( 600 * Math.random() );
//mesh.setMixer(mixer);//mesh.mixer = mixer;
mesh.getPosition().set( x, y, z );//mesh.position.set( x, y, z );
mesh.getRotation().setY(Math.PI/2);//mesh.rotation.y = Math.PI/2;
mesh.setCastShadow(true);//mesh.castShadow = true;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
scene.add( mesh );
MeshData data=new MeshData(mesh, speed, mixer);
morphs.add( data );
}
public void onWindowResize() {
camera.setAspect(getWindowInnerWidth() / getWindowInnerHeight());
camera.updateProjectionMatrix();
renderer.setSize( (int)getWindowInnerWidth() , (int)getWindowInnerHeight() );
windowHalfX=(int) (getWindowInnerWidth()/2);
windowHalfY=(int) (getWindowInnerHeight()/2);
double aspect = getWindowInnerWidth() / getWindowInnerHeight();
cameraOrtho.setLeft(- aspect);//cameraOrtho.left = - aspect;
cameraOrtho.setRight(aspect);//cameraOrtho.right = aspect;
cameraOrtho.setTop(1);//cameraOrtho.top = 1;
cameraOrtho.setBottom(- 1);//cameraOrtho.bottom = - 1;
cameraOrtho.updateProjectionMatrix();
hudMesh.getPosition().setX(cameraOrtho.getLeft() + HUD_MARGIN);//hudMesh.position.x = cameraOrtho.left + HUD_MARGIN;
hudMesh.getPosition().setY(cameraOrtho.getBottom() + HUD_MARGIN);//hudMesh.position.y = cameraOrtho.bottom + HUD_MARGIN;
controls.handleResize();
}
public void render(double now) {
double delta=clock.getDelta();
//do something
for ( int i = 0; i < morphs.size(); i ++ ) {
Mesh morph = morphs.get(i).getMesh();
morphs.get(i).getMixer().update( delta );
morph.getPosition().gwtIncrementX(morphs.get(i).getSpeed() * delta);//morph.position.x += morph.speed * delta;
if ( morph.getPosition().getX() > 2000 ) {//if ( morph.position.x > 2000 ) {
morph.getPosition().setX(-1000 - Math.random() * 500);//morph.position.x = -1000 - Math.random() * 500;
}
}
controls.update( delta );
renderer.clear();
renderer.render( scene, camera );
// Render debug HUD with shadow map
if ( showHUD ) {
//LogUtils.log("showHUD");
renderer.clearDepth();
renderer.render( sceneHUD, cameraOrtho );
}
}
@Override
public String getTokenKey() {
return "shadowmap";
}
}