package com.akjava.gwt.threejsexamples.client.examples.animation.cloth;
import java.util.List;
import com.akjava.gwt.lib.client.LogUtils;
import com.akjava.gwt.stats.client.Stats;
import com.akjava.gwt.three.client.gwt.GWTParamUtils;
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.utils.GWTThreeUtils;
import com.akjava.gwt.three.client.js.THREE;
import com.akjava.gwt.three.client.js.cameras.PerspectiveCamera;
import com.akjava.gwt.three.client.js.core.Geometry;
import com.akjava.gwt.three.client.js.extras.geometries.BoxGeometry;
import com.akjava.gwt.three.client.js.extras.geometries.CircleGeometry;
import com.akjava.gwt.three.client.js.extras.geometries.SphereGeometry;
import com.akjava.gwt.three.client.js.extras.helpers.ArrowHelper;
import com.akjava.gwt.three.client.js.lights.DirectionalLight;
import com.akjava.gwt.three.client.js.materials.MeshPhongMaterial;
import com.akjava.gwt.three.client.js.math.Matrix4;
import com.akjava.gwt.three.client.js.math.THREEMath;
import com.akjava.gwt.three.client.js.math.Vector3;
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.scenes.Scene;
import com.akjava.gwt.three.client.js.textures.Texture;
import com.akjava.gwt.threejsexamples.client.examples.animation.cloth.Cloth.Particle;
import com.akjava.gwt.threejsexamples.client.resources.Bundles;
import com.google.common.collect.Lists;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
/*
* TODO implement GUI
*/
public class ClothExample2 extends AbstractExample {
//Cloth cloth;
private FocusPanel container;
private Scene scene;
private PerspectiveCamera camera;
//private ParametricGeometry clothGeometry;
private Mesh sphere;
private ArrowHelper arrow;
private WebGLRenderer renderer;
private Stats stats;
private boolean rotate=true;
private List<ClothData> cloths=Lists.newArrayList();
public void init(){
container = createContainerPanel();
// scene
scene = THREE.Scene();
scene.setFog(THREE.Fog( 0xcce0ff, 500, 10000 ));
// camera
camera = THREE.PerspectiveCamera( 30, getWindowInnerWidth() / getWindowInnerHeight(), 1, 10000 );
camera.getPosition().setY(50) ;
camera.getPosition().setZ(1500);
scene.add( camera );
// lights
DirectionalLight light;
//materials;
scene.add(THREE.AmbientLight( 0x666666 ) );
light = THREE.DirectionalLight( 0xdfebff, 1.75 );
light.getPosition().set( 50, 200, 100 );
light.getPosition().multiplyScalar( 1.3 );
light.setCastShadow(true);
//light.shadowCameraVisible = true;
//light.setShadowMapWidth(1024);
light.getShadow().getMapSize().setWidth(1024);
//light.setShadowMapHeight(1024);
light.getShadow().getMapSize().setHeight(1024);
double d = 300;
//DirectionalLight return use OrthographicCamera;
light.getShadow().getCamera().gwtCastOrthographicCamera().setLeft(-d);
light.getShadow().getCamera().gwtCastOrthographicCamera().setRight(d);
light.getShadow().getCamera().gwtCastOrthographicCamera().setTop(d);
light.getShadow().getCamera().gwtCastOrthographicCamera().setBottom(-d);
light.getShadow().getCamera().gwtCastOrthographicCamera().setFar(1000);
scene.add( light );
// cloth material
Texture clothTexture = THREE.TextureLoader().load( "textures/patterns/circuit_pattern.png" );
clothTexture.setWrapS(THREE.RepeatWrapping);
clothTexture.setWrapT(THREE.RepeatWrapping);
clothTexture.setAnisotropy(16);
MeshPhongMaterial clothMaterial = THREE.MeshPhongMaterial(
GWTParamUtils.MeshPhongMaterial().alphaTest(0.5).color(0xffffff).specular(0x030303).emissive(0x111111).shininess(10)
.map(clothTexture).side(THREE.DoubleSide));
//shadow
Uniforms uniforms=Uniforms.create().setTypeAndValue("texture", clothTexture);
String vertexShader=Bundles.INSTANCE.vertexShaderDepth().getText();
String fragmentShader=Bundles.INSTANCE.fragmentShaderDepth().getText();
// cloth mesh
// sphere
int ballSize=120;
SphereGeometry ballGeo = THREE.SphereGeometry( ballSize, 20, 20 );//var ballGeo = new THREE.SphereGeometry( ballSize, 20, 20 );
MeshPhongMaterial ballMaterial = THREE.MeshPhongMaterial( GWTParamUtils.
MeshPhongMaterial().color(0x888888).side(THREE.DoubleSide)
.transparent(true).opacity(1).wireframe(true)
);// var ballMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff } );
CircleGeometry circle=THREE.CircleGeometry(ballSize, 4);
Mesh circleMesh=THREE.Mesh(circle,ballMaterial);
scene.add( circleMesh );
/*
for(int i=0;i<circleMesh.getGeometry().getVertices().length();i++){
LogUtils.log(ThreeLog.get(circleMesh.getGeometry().getVertices().get(i)));
}
*/
double angle = THREEMath.degToRad( -90 );
Matrix4 matrix=THREE.Matrix4().makeRotationFromEuler(THREE.Euler(angle, 0, 0));
circleMesh.getGeometry().applyMatrix(matrix);
//circleMesh.rotateX(angle);
//not same as segement ,therea are not way to just get circle points.
//LogUtils.log(circleMesh.getGeometry().getVertices().length());
//circleMesh.getPosition().setY(cloth.ballSize*2);
/*
LogUtils.log("converted");
for(int i=0;i<circleMesh.getGeometry().getVertices().length();i++){
LogUtils.log(ThreeLog.get(circleMesh.getGeometry().getVertices().get(i)));
}
*/
int cw=4;
int ch=5;
for(int i=0;i<circleMesh.getGeometry().getVertices().length();i++){
if(i==circleMesh.getGeometry().getVertices().length()-1){
continue;
}
int index1=i;
int index2=i+1;
Vector3 v1=circleMesh.getGeometry().getVertices().get(index1);
Vector3 v2=circleMesh.getGeometry().getVertices().get(index2);
double geometryW=v1.distanceTo(v2);
// cloth geometry
ClothData data=new ClothData(cw,ch,geometryW,100);
Cloth2 cloth=data.getCloth();
cloth.pins=cloth.pinsFormation.get(4);
data.getCloth().particles.get(0).getOriginal().copy(v1);
data.getCloth().particles.get(cw).getOriginal().copy(v2);
data.getCloth().ballSize=ballSize;
Mesh object = THREE.Mesh( data.getClothGeometry(), clothMaterial );
//object.getPosition().set( 0, 0, 0 );
object.setCastShadow(true);
object.setReceiveShadow(true);
object.setCustomDepthMaterial(THREE.ShaderMaterial(GWTParamUtils.ShaderMaterial().uniforms(uniforms).vertexShader(vertexShader).fragmentShader(fragmentShader)));
scene.add( object );
cloths.add(data);
}
sphere = THREE.Mesh( ballGeo, ballMaterial );// sphere = new THREE.Mesh( ballGeo, ballMaterial );
sphere.setCastShadow(true);// sphere.castShadow = true;
sphere.setReceiveShadow(true);// sphere.receiveShadow = true;
scene.add( sphere );
// arrow
arrow = THREE.ArrowHelper( THREE.Vector3( 0, 1, 0 ), THREE.Vector3( 0, 0, 0 ), 50, 0xff0000 );//arrow = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50, 0xff0000 );
arrow.getPosition().set( -200, 0, -200 );//arrow.position.set( -200, 0, -200 );
// scene.add( arrow );
// ground
Texture groundTexture = THREE.TextureLoader().load( "textures/terrain/grasslight-big.jpg" );//var groundTexture = THREE.ImageUtils.loadTexture( "textures/terrain/grasslight-big.jpg" );
groundTexture.setWrapS(THREE.RepeatWrapping);//groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.setWrapT(THREE.RepeatWrapping);
groundTexture.getRepeat().set( 25, 25 );//groundTexture.repeat.set( 25, 25 );
groundTexture.setAnisotropy(16);//groundTexture.anisotropy = 16;
MeshPhongMaterial groundMaterial = THREE.MeshPhongMaterial( GWTParamUtils.MeshPhongMaterial().color(0xffffff).specular(0x111111).map(groundTexture) );//var groundMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, map: groundTexture } );
Mesh mesh = THREE.Mesh( THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );//var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 20000, 20000 ), groundMaterial );
mesh.getPosition().setY(-250);//mesh.position.y = -250;
mesh.getRotation().setX(- Math.PI / 2);//mesh.rotation.x = - Math.PI / 2;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
scene.add( mesh );
// poles
BoxGeometry poleGeo = THREE.BoxGeometry( 5, 375, 5 );//var poleGeo = new THREE.BoxGeometry( 5, 375, 5 );
MeshPhongMaterial poleMat = THREE.MeshPhongMaterial( GWTParamUtils.MeshPhongMaterial().color(0xffffff).specular(0x111111).shininess(100) );//var poleMat = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, shiness: 100 } );
mesh = THREE.Mesh( poleGeo, poleMat );//var mesh = new THREE.Mesh( poleGeo, poleMat );
mesh.getPosition().setX(-125);//mesh.position.x = -125;
mesh.getPosition().setY(-62);//mesh.position.y = -62;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
mesh.setCastShadow(true);//mesh.castShadow = true;
scene.add( mesh );
mesh = THREE.Mesh( poleGeo, poleMat );//var mesh = new THREE.Mesh( poleGeo, poleMat );
mesh.getPosition().setX(125);//mesh.position.x = 125;
mesh.getPosition().setY(-62);//mesh.position.y = -62;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
mesh.setCastShadow(true);//mesh.castShadow = true;
scene.add( mesh );
mesh = THREE.Mesh( THREE.BoxGeometry( 255, 5, 5 ), poleMat );//var mesh = new THREE.Mesh( new THREE.BoxGeometry( 255, 5, 5 ), poleMat );
mesh.getPosition().setY(-250 + 750/2);//mesh.position.y = -250 + 750/2;
mesh.getPosition().setX(0);//mesh.position.x = 0;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
mesh.setCastShadow(true);//mesh.castShadow = true;
scene.add( mesh );
BoxGeometry gg = THREE.BoxGeometry( 10, 10, 10 );//var gg = new THREE.BoxGeometry( 10, 10, 10 );
mesh = THREE.Mesh( gg, poleMat );//var mesh = new THREE.Mesh( gg, poleMat );
mesh.getPosition().setY(-250);//mesh.position.y = -250;
mesh.getPosition().setX(125);//mesh.position.x = 125;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
mesh.setCastShadow(true);//mesh.castShadow = true;
scene.add( mesh );
mesh = THREE.Mesh( gg, poleMat );//var mesh = new THREE.Mesh( gg, poleMat );
mesh.getPosition().setY(-250);//mesh.position.y = -250;
mesh.getPosition().setX(-125);//mesh.position.x = -125;
mesh.setReceiveShadow(true);//mesh.receiveShadow = true;
mesh.setCastShadow(true);//mesh.castShadow = true;
scene.add( mesh );
//
renderer = THREE.WebGLRenderer( GWTParamUtils.WebGLRenderer().antialias(true) );//renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( GWTThreeUtils.getWindowDevicePixelRatio() );
renderer.setSize((int)getWindowInnerWidth() , (int)getWindowInnerHeight());
renderer.setClearColor( scene.getFog().getColor() );//renderer.setClearColor( scene.fog.color );
container.getElement().appendChild(renderer.getDomElement());
renderer.setGammaInput(true);//renderer.gammaInput = true;
renderer.setGammaOutput(true);//renderer.gammaOutput = true;
//renderer.setShadowMapEnabled(true);//renderer.shadowMapEnabled = true;
renderer.getShadowMap().setEnabled(true);
//
stats = Stats.create();
stats.setPosition(0, 0);
container.getElement().appendChild(stats.domElement());
/*
container.add(createAbsoluteHTML("Simple Cloth Simulation<br>Verlet integration with Constrains relaxation"
,100,10));
*/
//window.addEventListener( 'resize', onWindowResize, false );
sphere.setVisible(true);
//TODO create-gui
//setDebugAnimateOneTimeOnly(false);
createGUI();
}
public void createGUI(){
VerticalPanel gui=addResizeHandlerAndCreateGUIPanel();//need for window-resize
CheckBox lockCamera=new CheckBox("Lock Camera");
gui.add(lockCamera);
lockCamera.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
rotate=!event.getValue();
}
});
CheckBox wind=new CheckBox("Wind");
gui.add(wind);
wind.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
setWind(event.getValue());
}
});
wind.setValue(true);
CheckBox showSphere=new CheckBox("Show Ball");
gui.add(showSphere);
showSphere.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
sphere.setVisible(event.getValue());
}
});
final ListBox pinsBox=new ListBox();
pinsBox.addItem("Center only pin");
pinsBox.addItem("Top all pins");
pinsBox.addItem("First only pin");
pinsBox.addItem("No pin");
pinsBox.addItem("2 pins");
pinsBox.setSelectedIndex(1);//default
pinsBox.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
int selection=pinsBox.getSelectedIndex();
//cloth.pins=cloth.pinsFormation.get(selection);
}
});
//gui.add(pinsBox);
}
public void setWind(boolean value){
for(ClothData data:cloths){
data.getCloth().wind=value;
}
}
public void renderCloth(){
for(ClothData data:cloths){
Cloth2 cloth=data.getCloth();
Geometry clothGeometry=data.getClothGeometry();
List<Cloth2.Particle> p = cloth.particles;
for ( int i = 0, il = p.size(); i < il; i ++ ) {
clothGeometry.getVertices().get(i).copy( p.get(i).position);
}
clothGeometry.computeFaceNormals();
clothGeometry.computeVertexNormals();
clothGeometry.setNormalsNeedUpdate(true);//clothGeometry.normalsNeedUpdate = true;
clothGeometry.setVerticesNeedUpdate(true);//clothGeometry.verticesNeedUpdate = true;
//sphere.getPosition().copy( cloth.ballPosition );//sphere.position.copy( ballPosition );
}
}
public void render(double time){
double timer = time * 0.0002;
renderCloth();
if ( rotate ) {
camera.getPosition().setX(Math.cos( timer ) * 1500);//camera.position.x = Math.cos( timer ) * 1500;
camera.getPosition().setZ(Math.sin( timer ) * 1500);//camera.position.z = Math.sin( timer ) * 1500;
}
camera.lookAt( scene.getPosition() );
renderer.render( scene, camera );
}
@Override
public String getName() {
return "animation/cloth2";
}
public void animateCloth(double time){
for(ClothData data:cloths){
Cloth2 cloth=data.getCloth();
Geometry clothGeometry=data.getClothGeometry();
cloth.windStrength = Math.cos( time / 7000 ) * 20 + 40;
cloth.windForce.set( Math.sin( time / 2000 ), Math.cos( time / 3000 ), Math.sin( time / 1000 ) ).normalize().multiplyScalar( cloth.windStrength );
//arrow.setLength( cloth.windStrength );
//arrow.setDirection( cloth.windForce );
cloth.simulate(time,clothGeometry,sphere);//set otherwhere?
}
}
@Override
public void animate(double time) {
animateCloth(time);
render(time);
stats.update();//really deprecate?many still use this
}
@Override
public void onWindowResize() {
camera.setAspect(getWindowInnerWidth() / getWindowInnerHeight());
camera.updateProjectionMatrix();
renderer.setSize( (int)getWindowInnerWidth() , (int)getWindowInnerHeight() );
}
@Override
public String getTokenKey() {
return "cloth2";
}
}