package com.akjava.gwt.threejsexamples.client.examples; import com.akjava.gwt.lib.client.JavaScriptUtils; 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.OrbitControls; import com.akjava.gwt.three.client.gwt.GWTParamUtils; import com.akjava.gwt.three.client.gwt.JSParameter; import com.akjava.gwt.three.client.gwt.core.Intersect; 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.Clock; import com.akjava.gwt.three.client.js.core.Geometry; import com.akjava.gwt.three.client.js.core.Object3D; import com.akjava.gwt.three.client.js.core.Raycaster; import com.akjava.gwt.three.client.js.extras.ImageUtils; import com.akjava.gwt.three.client.js.lights.DirectionalLight; 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.MeshPhongMaterial; import com.akjava.gwt.three.client.js.math.Euler; import com.akjava.gwt.three.client.js.math.Matrix4; import com.akjava.gwt.three.client.js.math.Vector2; import com.akjava.gwt.three.client.js.math.Vector3; import com.akjava.gwt.three.client.js.objects.Line; 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.LabeledInputRangeWidget; import com.google.gwt.core.client.JsArray; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseDownHandler; import com.google.gwt.event.dom.client.MouseMoveEvent; import com.google.gwt.event.dom.client.MouseMoveHandler; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.ui.Button; 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; public class DecalExample extends AbstractExample{ @Override public String getName() { return "decal"; } @Override public void animate(double timestamp) { render(timestamp); stats.update();//really deprecate?many still use this } private WebGLRenderer renderer; private Scene scene; private PerspectiveCamera camera; private Stats stats; double SCREEN_WIDTH; double SCREEN_HEIGHT; private int windowHalfX,windowHalfY; //private int mouseX,mouseY; Clock clock; double fov; Vector3 cameraTarget; private OrbitControls controls; private Line line; private Raycaster raycaster; private Mesh mouseHelper; private Vector2 mouse; private Mesh mesh; private JSParameter intersection; private JsArray<Mesh> decals; @Override public void init() { decals=JavaScriptUtils.createJSArray(); Texture decalDiffuse = ImageUtils.loadTexture( "textures/decal/decal-diffuse.png" ); Texture decalNormal = ImageUtils.loadTexture( "textures/decal/decal-normal.jpg" ); decalMaterial = THREE.MeshPhongMaterial( GWTParamUtils.MeshPhongMaterial().specular(0x444444).map(decalDiffuse).normalMap(decalNormal).normalScale(THREE.Vector2(1,1)).shininess(30).transparent(true).depthTest(true).depthWrite(false).polygonOffset(true).polygonOffsetFactor(- 4).wireframe(false) );//var decalMaterial = new THREE.MeshPhongMaterial( {specular: 0x444444,map: decalDiffuse,normalMap: decalNormal,normalScale: new THREE.Vector2( 1, 1 ),shininess: 30,transparent: true,depthTest: true,depthWrite: false,polygonOffset: true,polygonOffsetFactor: - 4,wireframe: false} ); p = THREE.Vector3( 0, 0, 0 ); r = THREE.Euler( 0, 0, 0 ); s = THREE.Vector3( 10, 10, 10 ); up = THREE.Vector3( 0, 1, 0 ); check = THREE.Vector3( 1, 1, 1 ); intersection=JSParameter.createParameter().set("intersects", false).set("point", THREE.Vector3()).set("normal", THREE.Vector3()); fov=45; mouse=THREE.Vector2(); clock=THREE.Clock(); SCREEN_WIDTH = getWindowInnerWidth(); SCREEN_HEIGHT = getWindowInnerHeight(); windowHalfX= (int)(SCREEN_WIDTH/2); windowHalfY= (int)(SCREEN_HEIGHT/2); FocusPanel container = createContainerPanel(); // renderer renderer = THREE.WebGLRenderer( GWTParamUtils.WebGLRenderer().antialias(true) );//THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio( GWTThreeUtils.getWindowDevicePixelRatio() ); renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); container.getElement().appendChild( renderer.getDomElement() ); // scene scene = THREE.Scene(); // camera camera = THREE.PerspectiveCamera(55, getWindowInnerWidth()/getWindowInnerHeight(), 1, 1000); camera.getPosition().set(0, 0, 100); cameraTarget=THREE.Vector3(); controls = THREEExp.OrbitControls( camera, renderer.getDomElement());//controls = new THREE.OrbitControls( camera, renderer.domElement ); controls.setMinDistance(50);//controls.minDistance = 50; controls.setMaxDistance(200);//controls.maxDistance = 200; scene.add( THREE.AmbientLight( 0x443333 ) );//scene.add( new THREE.AmbientLight( 0x443333 ) ); DirectionalLight light = THREE.DirectionalLight( 0xffddcc, 1 );//var light = new THREE.DirectionalLight( 0xffddcc, 1 ); light.getPosition().set( 1, 0.75, 0.5 );//light.position.set( 1, 0.75, 0.5 ); scene.add( light ); light = THREE.DirectionalLight( 0xccccff, 1 );//var light = new THREE.DirectionalLight( 0xccccff, 1 ); light.getPosition().set( -1, 0.75, -0.5 );//light.position.set( -1, 0.75, -0.5 ); scene.add( light ); Geometry geometry = THREE.Geometry();//var geometry = new THREE.Geometry(); geometry.getVertices().push( THREE.Vector3() );//geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() ); geometry.getVertices().push( THREE.Vector3() ); line = THREE.Line( geometry, THREE.LineBasicMaterial( GWTParamUtils.LineBasicMaterial().linewidth(4) ) );//line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { linewidth: 4 } ) ); scene.add( line ); loadLeePerrySmith(); raycaster = THREE.Raycaster();//raycaster = new THREE.Raycaster(); mouseHelper = THREE.Mesh( THREE.BoxGeometry( 1, 1, 10 ), THREE.MeshNormalMaterial() );//mouseHelper = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 10 ), new THREE.MeshNormalMaterial() ); mouseHelper.setVisible(false);//mouseHelper.visible = false; scene.add( mouseHelper ); container.addMouseDownHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { moved = false; } }); container.addMouseUpHandler(new MouseUpHandler() { @Override public void onMouseUp(MouseUpEvent event) { checkIntersection(); if ( ! moved ) shoot(); } }); container.addMouseMoveHandler(new MouseMoveHandler() { @Override public void onMouseMove(MouseMoveEvent event) { //clientX is not support frame int x=event.getX(); int y=event.getY(); mouse.setX(( x / getWindowInnerWidth() ) * 2 - 1);//mouse.x = ( x / window.innerWidth ) * 2 - 1; mouse.setY(- ( y / getWindowInnerHeight() ) * 2 + 1);//mouse.y = - ( y / window.innerHeight ) * 2 + 1; checkIntersection(); } }); //TODO //container.addTouchMoveHandler(new ) //todo change on UI //stats stats = Stats.create(); stats.setPosition(0, 0); container.getElement().appendChild(stats.domElement()); //add html info container.add(createAbsoluteHTML("<strong>Decal Splatter</strong><br />Click or tap to shoot.</p>" ,100,10)); //handle resize & gui initResizeHandlerAndGUI(); //setDebugAnimateOneTimeOnly(true); } boolean projectionCamera=false; private boolean isProjectionCamera(){ return projectionCamera; } private double getMaxScale(){ return maxScale; } private double getMinScale(){ return minScale; } private boolean isRotate(){ return rotate; } protected void shoot() { if ( isProjectionCamera()){//if ( params.projection == 'camera' ) { Vector3 dir = cameraTarget.clone();//var dir = camera.target.clone(); dir.sub( camera.getPosition());//dir.sub( camera.position ); p = intersection.getObject("point").cast(); Matrix4 m = THREE.Matrix4();//var m = new THREE.Matrix4(); Vector3 c = dir.clone(); c.negate(); c.multiplyScalar( 10 ); c.add( p ); m.lookAt( p, c, up ); m = m.extractRotation( m ); Object3D dummy = THREE.Object3D();//dummy = new THREE.Object3D(); dummy.getRotation().setFromRotationMatrix( m );//dummy.rotation.setFromRotationMatrix( m ); r.set( dummy.getRotation().getX(), dummy.getRotation().getY(), dummy.getRotation().getZ());//r.set( dummy.rotation.x, dummy.rotation.y, dummy.rotation.z ); } else { p = intersection.getObject("point").cast(); r.copy( mouseHelper.getRotation());//r.copy( mouseHelper.rotation ); } double scale = getMinScale() + Math.random() * (getMaxScale() -getMinScale());//var scale = params.minScale + Math.random() * ( params.maxScale - params.minScale ); s.set( scale, scale, scale ); if ( isRotate()) r.setZ(Math.random() * 2 * Math.PI);//if ( params.rotate ) r.z = Math.random() * 2 * Math.PI; MeshPhongMaterial material = decalMaterial.clone().cast(); material.getColor().setHex( (int)(Math.random() * 0xffffff) );//material.color.setHex( Math.random() * 0xffffff ); Mesh m = THREE.Mesh( THREEExp.DecalGeometry( mesh, p, r, s, check ), material );//var m = new THREE.Mesh( new THREE.DecalGeometry( mesh, p, r, s, check ), material ); decals.push( m ); scene.add( m ); } protected void checkIntersection() { if (mesh==null ) return;//not loaded raycaster.setFromCamera( mouse, camera ); JsArray<Mesh> array=JavaScriptUtils.createJSArray(mesh); JsArray<Intersect> intersects = raycaster.intersectObjects(array); if ( intersects.length() > 0 ) { Vector3 p = intersects.get(0).getPoint(); mouseHelper.getPosition().copy( p );//mouseHelper.position.copy( p ); Vector3 pt=intersection.getObject("point").cast(); pt.copy( p );//intersection.point.copy( p ); Vector3 n = intersects.get(0).getFace().getNormal().clone();//var n = intersects[ 0 ].face.normal.clone(); n.multiplyScalar( 10 ); n.add( p);//n.add( intersects[ 0 ].point ); Vector3 normal=intersection.getObject("normal").cast(); normal.copy( intersects.get(0).getFace().getNormal());//intersection.normal.copy( intersects[ 0 ].face.normal ); mouseHelper.lookAt( n ); line.getGeometry().getVertices().get(0).copy( pt);//line.geometry.vertices[ 0 ].copy( intersection.point ); line.getGeometry().getVertices().get(1).copy( n );//line.geometry.vertices[ 1 ].copy( n ); line.getGeometry().setVerticesNeedUpdate(true);//line.geometry.verticesNeedUpdate = true; intersection.set("intersects",true);//intersection.intersects = true; } else { intersection.set("intersects",false);//intersection.intersects = false; } } private boolean moved; private Vector3 up; private Euler r; private Vector3 p; private Vector3 s; private MeshPhongMaterial decalMaterial; private Vector3 check; private int maxScale=20; private int minScale=10; private boolean rotate=true; private void removeDecals(){ for(int i=0;i<decals.length();i++){ scene.remove(decals.get(i)); decals.set(i, null); } decals=JavaScriptUtils.createJSArray(); } private void loadLeePerrySmith() { JSONLoader loader=THREE.JSONLoader(); loader.load("obj/leeperrysmith/LeePerrySmith.js", new JSONLoadHandler() { @Override public void loaded(Geometry geometry, JsArray<Material> materials) { MeshPhongMaterial material = THREE.MeshPhongMaterial( GWTParamUtils.MeshPhongMaterial().specular(0x111111).map(ImageUtils.loadTexture( "obj/leeperrysmith/Map-COL.jpg" )).specularMap(ImageUtils.loadTexture( "obj/leeperrysmith/Map-SPEC.jpg" )).normalMap(ImageUtils.loadTexture( "obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg" )).normalScale(THREE.Vector2( 0.75,0.75)).shininess(25) );//var material = new THREE.MeshPhongMaterial( {specular: 0x111111,map: THREE.ImageUtils.loadTexture( 'obj/leeperrysmith/Map-COL.jpg' ),specularMap: THREE.ImageUtils.loadTexture( 'obj/leeperrysmith/Map-SPEC.jpg' ),normalMap: THREE.ImageUtils.loadTexture( 'obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg' ),normalScale: new THREE.Vector2( 0.75, 0.75 ),shininess: 25} ); mesh = THREE.Mesh( geometry, material );//mesh = new THREE.Mesh( geometry, material ); scene.add( mesh ); mesh.getScale().set( 10, 10, 10 );//mesh.scale.set( 10, 10, 10 ); } }); } private void initResizeHandlerAndGUI() { VerticalPanel gui=addResizeHandlerAndCreateGUIPanel(); gui.setWidth("200px");//some widget broke,like checkbox without parent size gui.setSpacing(2); final ListBox listBox=new ListBox(); gui.add(listBox); listBox.addItem("From cam to mesh"); listBox.addItem("Normal to mesh"); listBox.setSelectedIndex(1); listBox.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { projectionCamera=listBox.getSelectedIndex()==0; } }); LabeledInputRangeWidget minInput=new LabeledInputRangeWidget("minScale", 1, 30,1); gui.add(minInput); minInput.setValue(10); minInput.addtRangeListener(new ValueChangeHandler<Number>() { @Override public void onValueChange(ValueChangeEvent<Number> event) { minScale=event.getValue().intValue(); } }); gui.add(minInput); LabeledInputRangeWidget maxInput=new LabeledInputRangeWidget("maxScale", 1, 30,1); gui.add(maxInput); maxInput.setValue(20); maxInput.addtRangeListener(new ValueChangeHandler<Number>() { @Override public void onValueChange(ValueChangeEvent<Number> event) { maxScale=event.getValue().intValue(); } }); gui.add(maxInput); CheckBox rotateCheck=new CheckBox("rotate"); rotateCheck.addValueChangeHandler(new ValueChangeHandler<Boolean>() { @Override public void onValueChange(ValueChangeEvent<Boolean> event) { rotate=event.getValue(); } }); gui.add(rotateCheck); rotateCheck.setValue(true); Button clearBt=new Button("clear",new ClickHandler() { @Override public void onClick(ClickEvent event) { removeDecals(); } }); gui.add(clearBt); } public void onWindowResize() { SCREEN_WIDTH = getWindowInnerWidth(); SCREEN_HEIGHT = getWindowInnerHeight(); //re read because of double camera.setAspect(SCREEN_WIDTH / SCREEN_HEIGHT); camera.updateProjectionMatrix(); renderer.setSize( SCREEN_WIDTH , SCREEN_HEIGHT ); } public void render(double now) { renderer.render(scene, camera); } @Override public String getTokenKey() { return "decal"; } }