ThreeJS Editor Transparent Background - three.js

I'm using the https://threejs.org/editor/ to export a webgl animation and I'm trying to figure out how to convert it to have a transparent background.
I'm essentially trying to put a div with text behind my animating threejs render.
I tried adding
renderer = new THREE.WebGLRenderer( { alpha: true,} );
renderer.setClearColor( 0xffffff, 0 );
but it doesn't seem to be working
I'm new to this so any help would be greatly appreciated!
Attached is my code so far
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="utf-8">
<meta name="generator" content="Three.js Editor">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: sans-serif;
font-size: 13px;
background-color: black;
margin: 0px;
overflow: hidden;
}
.text {
font-size: 30vw;
color: white;
font-family: helvetica;
position: absolute;
z-index: 0;
}
</style>
</head>
<body ontouchstart="">
<script src="js/three.min.js"></script>
<script src="js/app.js"></script>
<script>
var loader = new THREE.FileLoader();
loader.load( 'app.json', function ( text ) {
var player = new APP.Player();
player.load( JSON.parse( text ) );
player.setSize( window.innerWidth, window.innerHeight );
player.play();
document.body.appendChild( player.dom );
window.addEventListener( 'resize', function () {
player.setSize( window.innerWidth, window.innerHeight );
} );
} );
</script>
<div class="text">Text Here</div>
</body>
</html>
And .js file
var APP = {
Player: function () {
var loader = new THREE.ObjectLoader();
var camera, scene, renderer;
var events = {};
var dom = document.createElement( 'div' );
this.dom = dom;
this.width = 500;
this.height = 500;
this.load = function ( json ) {
renderer = new THREE.WebGLRenderer( { alpha: true,} );
renderer.setClearColor( 0xffffff, 0 );
renderer.gammaOutput = true;
renderer.setPixelRatio( window.devicePixelRatio );
var project = json.project;
if ( project.shadows ) renderer.shadowMap.enabled = true;
if ( project.vr ) renderer.vr.enabled = true;
dom.appendChild( renderer.domElement );
this.setScene( loader.parse( json.scene ) );
this.setCamera( loader.parse( json.camera ) );
events = {
init: [],
start: [],
stop: [],
keydown: [],
keyup: [],
mousedown: [],
mouseup: [],
mousemove: [],
touchstart: [],
touchend: [],
touchmove: [],
update: []
};
var scriptWrapParams = 'player,renderer,scene,camera';
var scriptWrapResultObj = {};
for ( var eventKey in events ) {
scriptWrapParams += ',' + eventKey;
scriptWrapResultObj[ eventKey ] = eventKey;
}
var scriptWrapResult = JSON.stringify( scriptWrapResultObj ).replace( /\"/g, '' );
for ( var uuid in json.scripts ) {
var object = scene.getObjectByProperty( 'uuid', uuid, true );
if ( object === undefined ) {
console.warn( 'APP.Player: Script without object.', uuid );
continue;
}
var scripts = json.scripts[ uuid ];
for ( var i = 0; i < scripts.length; i ++ ) {
var script = scripts[ i ];
var functions = ( new Function( scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';' ).bind( object ) )( this, renderer, scene, camera );
for ( var name in functions ) {
if ( functions[ name ] === undefined ) continue;
if ( events[ name ] === undefined ) {
console.warn( 'APP.Player: Event type not supported (', name, ')' );
continue;
}
events[ name ].push( functions[ name ].bind( object ) );
}
}
}
dispatch( events.init, arguments );
};
this.setCamera = function ( value ) {
camera = value;
camera.aspect = this.width / this.height;
camera.updateProjectionMatrix();
if ( renderer.vr.enabled ) {
dom.appendChild( THREE.WEBVR.createButton( renderer ) );
}
};
this.setScene = function ( value ) {
scene = value;
};
this.setSize = function ( width, height ) {
this.width = width;
this.height = height;
if ( camera ) {
camera.aspect = this.width / this.height;
camera.updateProjectionMatrix();
}
if ( renderer ) {
renderer.setSize( width, height );
}
};
function dispatch( array, event ) {
for ( var i = 0, l = array.length; i < l; i ++ ) {
array[ i ]( event );
}
}
var time, prevTime;
function animate() {
time = performance.now();
try {
dispatch( events.update, { time: time, delta: time - prevTime } );
} catch ( e ) {
console.error( ( e.message || e ), ( e.stack || "" ) );
}
renderer.render( scene, camera );
prevTime = time;
}
this.play = function () {
prevTime = performance.now();
document.addEventListener( 'keydown', onDocumentKeyDown );
document.addEventListener( 'keyup', onDocumentKeyUp );
document.addEventListener( 'mousedown', onDocumentMouseDown );
document.addEventListener( 'mouseup', onDocumentMouseUp );
document.addEventListener( 'mousemove', onDocumentMouseMove );
document.addEventListener( 'touchstart', onDocumentTouchStart );
document.addEventListener( 'touchend', onDocumentTouchEnd );
document.addEventListener( 'touchmove', onDocumentTouchMove );
dispatch( events.start, arguments );
renderer.setAnimationLoop( animate );
};
this.stop = function () {
document.removeEventListener( 'keydown', onDocumentKeyDown );
document.removeEventListener( 'keyup', onDocumentKeyUp );
document.removeEventListener( 'mousedown', onDocumentMouseDown );
document.removeEventListener( 'mouseup', onDocumentMouseUp );
document.removeEventListener( 'mousemove', onDocumentMouseMove );
document.removeEventListener( 'touchstart', onDocumentTouchStart );
document.removeEventListener( 'touchend', onDocumentTouchEnd );
document.removeEventListener( 'touchmove', onDocumentTouchMove );
dispatch( events.stop, arguments );
renderer.setAnimationLoop( null );
};
this.dispose = function () {
while ( dom.children.length ) {
dom.removeChild( dom.firstChild );
}
renderer.dispose();
camera = undefined;
scene = undefined;
renderer = undefined;
};
//
function onDocumentKeyDown( event ) {
dispatch( events.keydown, event );
}
function onDocumentKeyUp( event ) {
dispatch( events.keyup, event );
}
function onDocumentMouseDown( event ) {
dispatch( events.mousedown, event );
}
function onDocumentMouseUp( event ) {
dispatch( events.mouseup, event );
}
function onDocumentMouseMove( event ) {
dispatch( events.mousemove, event );
}
function onDocumentTouchStart( event ) {
dispatch( events.touchstart, event );
}
function onDocumentTouchEnd( event ) {
dispatch( events.touchend, event );
}
function onDocumentTouchMove( event ) {
dispatch( events.touchmove, event );
}
}
};

You might need to adjust the CSS z-index of the <canvas> that ThreeJS is creating.
Note that the WebGLRenderer constructor has an overload that lets you pass in a canvas, instead of letting ThreeJS create it. This might be a useful in your case, so that you can easily control where the element lives in your DOM.

Related

How to use OrbitControls in Three.js Editor project

Using the Three.js Editor, I exported a project with a simple scene (two boxes). Everything loads fine—I see the two boxes from my PerspectiveCamera that I added. I want to control my camera view with the mouse wheel. Here is the script in the index.html:
<script type="module">
import * as THREE from './js/three.module.js';
import { APP } from './js/app.js';
import {OrbitControls} from './js/OrbitControls.js'; // I added this part.
// OrbitControls here?
var loader = new THREE.FileLoader();
loader.load( 'app.json', function ( text ) {
var player = new APP.Player( THREE );
player.load( JSON.parse( text ) );
player.setSize( window.innerWidth, window.innerHeight );
player.play();
document.body.appendChild( player.dom );
window.addEventListener( 'resize', function () {
player.setSize( window.innerWidth, window.innerHeight );
} );
} );
</script>
How do I utilize OrbitControls for this? Everything I've attempted (based on similar threads) leads to errors of things being undefined (like "camera" or "controls" depending on where I put it).
Alternatively (and even more ideally), is there a way to define the camera behavior I want within the Three.js Editor itself? That would be extra awesome!
EDIT
Thanks to #Mugen87 's original answer (basically that this isn't possible without editing app.js) here is the status of the question now. I removed the OrbitControls import from my index.html (above) and added it to my app.js. So my app.js currently looks like this:
import {OrbitControls} from './OrbitControls.js';
var APP = {
Player: function ( THREE ) {
window.THREE = THREE; // FIX for editor scripts (they require THREE in global namespace)
var loader = new THREE.ObjectLoader();
var camera, scene, renderer;
var events = {};
var dom = document.createElement( 'div' );
dom.className = "threejs-app";
this.dom = dom;
this.width = 500;
this.height = 500;
this.load = function ( json ) {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.setClearColor( 0x000000 );
renderer.setPixelRatio( window.devicePixelRatio );
var project = json.project;
if ( project.shadows ) renderer.shadowMap.enabled = true;
if ( project.vr ) renderer.xr.enabled = true;
dom.appendChild( renderer.domElement );
this.setScene( loader.parse( json.scene ) );
this.setCamera( loader.parse( json.camera ) );
events = {
init: [],
start: [],
stop: [],
keydown: [],
keyup: [],
mousedown: [],
mouseup: [],
mousemove: [],
touchstart: [],
touchend: [],
touchmove: [],
update: []
};
var scriptWrapParams = 'player,renderer,scene,camera';
var scriptWrapResultObj = {};
for ( var eventKey in events ) {
scriptWrapParams += ',' + eventKey;
scriptWrapResultObj[ eventKey ] = eventKey;
}
var scriptWrapResult = JSON.stringify( scriptWrapResultObj ).replace( /\"/g, '' );
for ( var uuid in json.scripts ) {
var object = scene.getObjectByProperty( 'uuid', uuid, true );
if ( object === undefined ) {
console.warn( 'APP.Player: Script without object.', uuid );
continue;
}
var scripts = json.scripts[ uuid ];
for ( var i = 0; i < scripts.length; i ++ ) {
var script = scripts[ i ];
var functions = ( new Function( scriptWrapParams, script.source + '\nreturn ' + scriptWrapResult + ';' ).bind( object ) )( this, renderer, scene, camera );
for ( var name in functions ) {
if ( functions[ name ] === undefined ) continue;
if ( events[ name ] === undefined ) {
console.warn( 'APP.Player: Event type not supported (', name, ')' );
continue;
}
events[ name ].push( functions[ name ].bind( object ) );
}
}
}
dispatch( events.init, arguments );
};
this.setCamera = function ( value ) {
camera = value;
camera.aspect = this.width / this.height;
camera.updateProjectionMatrix();
};
this.setScene = function ( value ) {
scene = value;
};
this.setSize = function ( width, height ) {
this.width = width;
this.height = height;
if ( camera ) {
camera.aspect = this.width / this.height;
camera.updateProjectionMatrix();
}
if ( renderer ) {
renderer.setSize( width, height );
}
};
function dispatch( array, event ) {
for ( var i = 0, l = array.length; i < l; i ++ ) {
array[ i ]( event );
}
}
var time, prevTime;
function animate() {
time = performance.now();
try {
dispatch( events.update, { time: time, delta: time - prevTime } );
} catch ( e ) {
console.error( ( e.message || e ), ( e.stack || "" ) );
}
renderer.render( scene, camera );
prevTime = time;
}
this.play = function () {
prevTime = performance.now();
document.addEventListener( 'keydown', onDocumentKeyDown );
document.addEventListener( 'keyup', onDocumentKeyUp );
document.addEventListener( 'mousedown', onDocumentMouseDown );
document.addEventListener( 'mouseup', onDocumentMouseUp );
document.addEventListener( 'mousemove', onDocumentMouseMove );
document.addEventListener( 'touchstart', onDocumentTouchStart );
document.addEventListener( 'touchend', onDocumentTouchEnd );
document.addEventListener( 'touchmove', onDocumentTouchMove );
dispatch( events.start, arguments );
renderer.setAnimationLoop( animate );
};
this.stop = function () {
document.removeEventListener( 'keydown', onDocumentKeyDown );
document.removeEventListener( 'keyup', onDocumentKeyUp );
document.removeEventListener( 'mousedown', onDocumentMouseDown );
document.removeEventListener( 'mouseup', onDocumentMouseUp );
document.removeEventListener( 'mousemove', onDocumentMouseMove );
document.removeEventListener( 'touchstart', onDocumentTouchStart );
document.removeEventListener( 'touchend', onDocumentTouchEnd );
document.removeEventListener( 'touchmove', onDocumentTouchMove );
dispatch( events.stop, arguments );
renderer.setAnimationLoop( null );
};
this.dispose = function () {
while ( dom.children.length ) {
dom.removeChild( dom.firstChild );
}
renderer.dispose();
camera = undefined;
scene = undefined;
renderer = undefined;
};
//
function onDocumentKeyDown( event ) {
dispatch( events.keydown, event );
}
function onDocumentKeyUp( event ) {
dispatch( events.keyup, event );
}
function onDocumentMouseDown( event ) {
dispatch( events.mousedown, event );
}
function onDocumentMouseUp( event ) {
dispatch( events.mouseup, event );
}
function onDocumentMouseMove( event ) {
dispatch( events.mousemove, event );
}
function onDocumentTouchStart( event ) {
dispatch( events.touchstart, event );
}
function onDocumentTouchEnd( event ) {
dispatch( events.touchend, event );
}
function onDocumentTouchMove( event ) {
dispatch( events.touchmove, event );
}
}
};
export { APP };
Side note: I'm noticing there are already many event listeners that were already generated by the Three.js Editor. They currently don't seem to do anything, but maybe they're there to be called from outside the script, such as in my index.html???
Anyway, where and how in the app.js file do I need to put the OrbitControls, in order to control the Y-axis position of the PerspectiveCamera with the mousewheel?
Alternatively (and even more ideally), is there a way to define the camera behavior I want within the Three.js Editor itself?
Unfortunately no. You can only use the default controls which are defined by EditorControls, a class similar to OrbitControls but only used in the editor.
How do I utilize OrbitControls for this?
I'm afraid this is not possible without changing app.js. The camera and the renderer are created in within APP.Player and are not public accessible. Since you need both objects for creating OrbitControls, it's not possible to instantiate the controls in index.html.
If you decide to change app.js, use the following code to create the controls if you include OrbitControls via ES6 imports:
var controls = new OrbitControls( camera, renderer.domElement );
three.js R112

How to stop animation at a particular keyframe

I am very new to three.js and blender, I am trying to have a 3D image of a robot arm that rotates from 0 to 180 and vice versa,I have used blender2.8.1 for animation and have exported the glb file and called it in an html file with three.js module, till here things are fine but now I want to stop it at some degree let's say if I give in the value 30 then the robot arm should move by 30, and if the previous state was at 60 then it should add 30 and move to 90. The referred example is https://threejs.org/examples/#webgl_animation_skinning_morph
Can someone please help?
Thank you in advance.
Here is the code :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
<style>
body {
color: #222;
}
a {
color: #2fa1d6;
}
p {
max-width: 600px;
margin-left: auto;
margin-right: auto;
padding: 0 2em;
}
</style>
</head>
<body>
<script type="module">
import * as THREE from '../build/three.module.js';
import Stats from '../examples/jsm/libs/stats.module.js';
import { GUI } from '../examples/jsm/libs/dat.gui.module.js';
import { GLTFLoader } from '../examples/jsm/loaders/GLTFLoader.js';
var container, stats, clock, gui, mixer, actions, activeAction, previousAction;
var camera, scene, renderer, model, face;
var api = { state: 'middle' };
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 120, window.innerWidth / window.innerHeight, 0.25, 100 );
camera.position.set( 50, 30, -70 );
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0xe0e0e0 );
scene.fog = new THREE.Fog( 0xe0e0e0, 20, 100 );
clock = new THREE.Clock();
// lights
var light = new THREE.HemisphereLight( 0xffffff, 0x444444 );
light.position.set( 0, 20, 0 );
scene.add( light );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 20, 10 );
scene.add( light );
// ground
var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2000, 2000 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) );
mesh.rotation.x = - Math.PI / 2;
scene.add( mesh );
var grid = new THREE.GridHelper( 200, 40, 0x000000, 0x000000 );
grid.material.opacity = 0.2;
grid.material.transparent = true;
scene.add( grid );
// model
var loader = new GLTFLoader();
loader.load( 'robo.glb', function ( gltf ) {
model = gltf.scene;
scene.add( model );
createGUI( model, gltf.animations );
}, undefined, function ( e ) {
console.error( e );
} );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.gammaOutput = true;
renderer.gammaFactor = 2.2;
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
// stats
stats = new Stats();
//container.appendChild( stats.dom );
}
function createGUI( model, animations ) {
var states = [ 'negative', 'positive'];
gui = new GUI();
mixer = new THREE.AnimationMixer( model );
actions = {};
for ( var i = 0; i < animations.length; i ++ ) {
var clip = animations[ i ];
var action = mixer.clipAction( clip );
actions[ clip.name ] = action;
if ( states.indexOf( clip.name ) >= 4 ) {
action.clampWhenFinished = true;
action.loop = THREE.LoopOnce;
}
}
// states
var statesFolder = gui.addFolder( 'States' );
var clipCtrl = statesFolder.add( api, 'state' ).options( states );
clipCtrl.onChange( function () {
fadeToAction( api.state, 1 );
} );
statesFolder.close();
// emotes
//var emoteFolder = gui.addFolder( 'Emotes' );
}
function restoreState() {
mixer.removeEventListener( 'finished', restoreState );
fadeToAction( api.state, 0 );
}
face = model.getObjectByName( 'Head_2' );
var expressions = Object.keys( face.morphTargetDictionary );
var expressionFolder = gui.addFolder( 'Expressions' );
for ( var i = 0; i < expressions.length; i ++ ) {
expressionFolder.add( face.morphTargetInfluences, i, 0, 1, 0.01 ).name( expressions[ i ] );
}
activeAction = actions[ 'middle' ];
activeAction.play();
//expressionFolder.open();
function fadeToAction( name, duration ) {
previousAction = activeAction;
activeAction = actions[ name ];
if ( previousAction !== activeAction ) {
previousAction.fadeOut( duration );
}
activeAction
.reset()
.fadeIn( duration )
.setDuration(10)
.play();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
var dt = clock.getDelta();
if ( mixer ) mixer.update( dt );
requestAnimationFrame( animate );
renderer.render( scene, camera );
stats.update();
}
</script>
</body>
</html>

having trouble with Three.js .Json Loader (importing 3d models)

This is a skull i found on clara.io , i downloaded the .obj, and uploaded into the three.js editor, and proceeded to export it as Json.. Now I have been trying to add it to some of the three.js examples. What am I doing wrong. I notice the examples have different scripts linked, but most tutorials show people only linking the build. I love this stuff so much, I really wanna learn...
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - panorama fisheye demo</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
background-color: rgb(200,200,200);
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px; width: 100%;
color: #ffffff;
padding: 5px;
font-family:Monospace;
font-size:13px;
font-weight: bold;
text-align:center;
}
a {
color: #ffffff;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">three.js - panorama fisheye demo. cubemap by Jochum Skoglund. (mousewheel: change fov)</div>
<script src="../build/three.js"></script>
<script src="js/renderers/Projector.js"></script>
<script src="js/renderers/CanvasRenderer.js"></script>
<script>
var camera, scene, renderer;
var texture_placeholder,
isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 90, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0,
target = new THREE.Vector3();
init();
animate();
function init() {
var container, mesh;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
scene = new THREE.Scene();
texture_placeholder = document.createElement( 'canvas' );
texture_placeholder.width = 128;
texture_placeholder.height = 128;
var context = texture_placeholder.getContext( '2d' );
context.fillStyle = 'rgb( 200, 200, 200 )';
context.fillRect( 0, 0, texture_placeholder.width, texture_placeholder.height );
var materials = [
loadTexture( 'textures/cube/skybox/px.jpg' ), // right
loadTexture( 'textures/cube/skybox/nx.jpg' ), // left
loadTexture( 'textures/cube/skybox/py.jpg' ), // top
loadTexture( 'textures/cube/skybox/ny.jpg' ), // bottom
loadTexture( 'textures/cube/skybox/pz.jpg' ), // back
loadTexture( 'textures/cube/skybox/nz.jpg' ) // front
];
mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MultiMaterial( materials ) );
mesh.scale.x = - 1;
scene.add( mesh );
for ( var i = 0, l = mesh.geometry.vertices.length; i < l; i ++ ) {
var vertex = mesh.geometry.vertices[ i ];
vertex.normalize();
vertex.multiplyScalar( 550 );
}
var particleMaterial = new THREE.MeshBasicMaterial();
particleMaterial.map = THREE.ImageUtils.loadTexture ('');
particleMaterial.side = THREE.DoubleSide;
var itmArr = []
var loader = new THREE.JSONLoader();
loader.load('models/json/skull.json', function (geometry) {
for (var i = 0; i < 20; i++) {
var mesh = new THREE.Mesh(geometry, particleMaterial);
mesh.position.z = (Math.random()-Math.random())*100;
mesh.position.x = (Math.random()-Math.random())*100;
mesh.position.y = (Math.random()-Math.random())*100;
mesh.dir = (Math.random()-Math.random())*.01;
scene.add(mesh);
itmArr.push(mesh);
}
});
renderer = new THREE.CanvasRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'wheel', onDocumentMouseWheel, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function loadTexture( path ) {
var texture = new THREE.Texture( texture_placeholder );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var image = new Image();
image.onload = function () {
texture.image = this;
texture.needsUpdate = true;
};
image.src = path;
return material;
}
function onDocumentMouseDown( event ) {
event.preventDefault();
isUserInteracting = true;
onPointerDownPointerX = event.clientX;
onPointerDownPointerY = event.clientY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
function onDocumentMouseMove( event ) {
if ( isUserInteracting === true ) {
lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function onDocumentMouseUp( event ) {
isUserInteracting = false;
}
function onDocumentMouseWheel( event ) {
camera.fov += event.deltaY * 0.05;
camera.updateProjectionMatrix();
}
function onDocumentTouchStart( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
onPointerDownPointerX = event.touches[ 0 ].pageX;
onPointerDownPointerY = event.touches[ 0 ].pageY;
onPointerDownLon = lon;
onPointerDownLat = lat;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length == 1 ) {
event.preventDefault();
lon = ( onPointerDownPointerX - event.touches[0].pageX ) * 0.1 + onPointerDownLon;
lat = ( event.touches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
}
}
function animate() {
requestAnimationFrame( animate );
update();
}
function update() {
if ( isUserInteracting === false ) {
lon += 0.1;
}
lat = Math.max( - 85, Math.min( 85, lat ) );
phi = THREE.Math.degToRad( 90 - lat );
theta = THREE.Math.degToRad( lon );
target.x = 500 * Math.sin( phi ) * Math.cos( theta );
target.y = 500 * Math.cos( phi );
target.z = 500 * Math.sin( phi ) * Math.sin( theta );
camera.position.copy( target ).negate();
camera.lookAt( target );
renderer.render( scene, camera );
}
</script>
</body>
</html>

How to control the data.gui.js that do not affect the object(Three.js r66)

I write a trackball to control the object rotation, everything goes fine. However, when I add the gui component to the program, and when I put the mouse to change the gui, the object is moving. Because my trackball project the screen coordinate to the virtual ball, when my mouse is on the gui component, it is still in the screen, and it makes the object move. How to avoid that? I try t find the reason about the trackball three.js has, and do not find the a result. Why his trackball do not affact the gui object?
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/dat.gui.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var mouseDown = false;
var rotateStartP = new THREE.Vector3(0,0,1);
var rotateEndP = new THREE.Vector3(0,0,1);
var lastPosX;
var lastPosY;
var targetRotationY = 0;
var targetRotationX = 0;
var quater;
//var rotateQuaternion = new THREE.Quaternion();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//GUI
var controls = new function () {
this.xx = false;
this.yy = 512;
this.onChange = function () {
}
};
var gui = new dat.GUI();
gui.add(controls, 'xx').onChange(controls.onChange);
gui.add(controls, 'yy', 1, 10).step(1).onChange(controls.onChange);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = true;
rotateStartP = projectOnTrackball(event.clientX, event.clientY);
}
function onDocumentMouseMove( event ) {
if(!mouseDown)
{
return;
}
rotateEndP = projectOnTrackball(event.clientX, event.clientY);
}
function getMouseOnScreen( pageX, pageY) {
return new THREE.Vector2.set(pageX / window.innerWidth ,pageY / window.innerHeight);
}
function projectOnTrackball(pageX, pageY) // The screen coordinate[(0,0)on the left-top] convert to the
//trackball coordinate [(0,0) on the center of the page]
{
var mouseOnBall = new THREE.Vector3();
mouseOnBall.set(
( pageX - window.innerWidth * 0.5 ) / (window.innerWidth * .5),
( window.innerHeight * 0.5 - pageY ) / ( window.innerHeight * .5),
0.0
);
var length = mouseOnBall.length();
if (length > 1.0) {
mouseOnBall.normalize();
}
else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
return mouseOnBall;
}
function rotateMatrix(rotateStart, rotateEnd)
{
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
var angle = Math.acos( rotateStart.dot( rotateEnd ) / rotateStart.length() / rotateEnd.length() );
if ( angle )
{
axis.crossVectors( rotateStart, rotateEnd ).normalize();
angle *= 0.01; //Here we could define rotate speed
quaternion.setFromAxisAngle( axis, angle );
}
return quaternion;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
mouseDown = false;
rotateStartP = rotateEndP;
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDownX = targetRotationX;
mouseYOnMouseDown = event.touches[ 0 ].pageY - windowHalfY;
targetRotationOnMouseDownY = targetRotationY; */
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
/*
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotationX = targetRotationOnMouseDownX + ( mouseX - mouseXOnMouseDown ) * 0.05;
mouseY = event.touches[ 0 ].pageY - windowHalfY;
targetRotationY = targetRotationOnMouseDownY + ( mouseY - mouseYOnMouseDown ) * 0.05; */
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
//if(rotateStartP != rotateEndP) {
//rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
//quater=cube.quaternion;
//quater.multiplyQuaternions(rotateQuaternion, quater);
//quater.multiply(rotateQuaternion);
//quater.normalize();
var rotateQuaternion = rotateMatrix(rotateStartP, rotateEndP);
quater=cube.quaternion;
quater.multiplyQuaternions(rotateQuaternion,quater);
quater.normalize();
cube.setRotationFromQuaternion(quater);
// }
renderer.render( scene, camera );
}
</script>
</body>
</html>
Change my code to ObjectTrackball.js
The code is as follows:
TrackballControls = function ( object, domElement ) {
var _this = this;
_this.quater = object.quaternion;
_this.object = object;
_this.domElement = ( domElement !== undefined ) ? domElement : document;
_this.zoomValue = 0;
_this.mouseDown = true;
_this.rotateStartP = new THREE.Vector3();
_this.rotateEndP = new THREE.Vector3();
// events
var changeEvent = { type: 'change' };
// methods
this.handleEvent = function ( event ) {
if ( typeof this[ event.type ] == 'function' ) {
this[ event.type ]( event );
}
};
this.update = function () {
var rotateQuaternion = rotateMatrix(_this.rotateStartP, _this.rotateEndP);
_this.quater = _this.object.quaternion;
_this.quater.multiplyQuaternions(rotateQuaternion,_this.quater);
_this.quater.normalize();
_this.object.setRotationFromQuaternion(_this.quater);
_this.object.position.z += _this.zoomValue;
_this.zoomValue = 0;
};
function mousedown( event ) {
event.preventDefault();
_this.mouseDown = true;
_this.rotateStartP = projectOnTrackball(event.clientX, event.clientY);
document.addEventListener( 'mousemove', mousemove, false );
document.addEventListener( 'mouseup', mouseup, false );
}
function getMouseOnScreen( pageX, pageY) {
return new THREE.Vector2.set(pageX / window.innerWidth ,pageY / window.innerHeight);
}
function projectOnTrackball(pageX, pageY) // The screen coordinate[(0,0)on the left-top] convert to the
//trackball coordinate [(0,0) on the center of the page]
{
var mouseOnBall = new THREE.Vector3();
mouseOnBall.set(
( pageX - window.innerWidth * 0.5 ) / (window.innerWidth * .5),
( window.innerHeight * 0.5 - pageY ) / ( window.innerHeight * .5),
0.0
);
var length = mouseOnBall.length();
if (length > 1.0) {
mouseOnBall.normalize();
}
else {
mouseOnBall.z = Math.sqrt(1.0 - length * length);
}
return mouseOnBall;
}
function rotateMatrix(rotateStart, rotateEnd)
{
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
var angle = Math.acos( rotateStart.dot( rotateEnd ) / rotateStart.length() / rotateEnd.length() );
if ( angle )
{
axis.crossVectors( rotateStart, rotateEnd ).normalize();
angle *= 0.01; //Here we could define rotate speed
quaternion.setFromAxisAngle( axis, angle );
}
return quaternion;
}
function mousemove( event ) {
if(!_this.mouseDown)
{
return;
}
_this.rotateEndP = projectOnTrackball(event.clientX, event.clientY);
}
function mouseup( event ) {
_this.mouseDown = false;
_this.rotateStartP = _this.rotateEndP;
document.removeEventListener( 'mousemove', mousemove );
document.removeEventListener( 'mouseup', mouseup );
}
function mousewheel( event ) {
event.preventDefault();
event.stopPropagation();
var delta = 0;
if ( event.wheelDelta ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta / 40;
} else if ( event.detail ) { // Firefox
delta = - event.detail / 3;
}
_this.zoomValue += delta;
}
this.domElement.addEventListener( 'mousedown', mousedown, false );
this.domElement.addEventListener( 'mousewheel', mousewheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', mousewheel, false ); // firefox
};
TrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
Code of The Object control application (Three.js r66)
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js canvas - geometry - cube</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
</style>
</head>
<body>
<script src="../build/three.min.js"></script>
<script src="js/libs/dat.gui.min.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/controls/ObjectTrackballControl.js"></script>
<script>
var container, stats;
var camera, scene, renderer;
var cube, plane;
var control;
var mouseDown = false;
var rotateStartP = new THREE.Vector3(0,0,1);
var rotateEndP = new THREE.Vector3(0,0,1);
var lastPosX;
var lastPosY;
var targetRotationY = 0;
var targetRotationX = 0;
var quater;
//var rotateQuaternion = new THREE.Quaternion();
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var info = document.createElement( 'div' );
info.style.position = 'absolute';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = 'center';
info.innerHTML = 'Drag to spin the cube';
container.appendChild( info );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 150;
camera.position.z = 500;
scene = new THREE.Scene();
// Cube
var geometry = new THREE.CubeGeometry( 200, 200, 200 );
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var hex = Math.random() * 0xffffff;
geometry.faces[ i ].color.setHex( hex );
geometry.faces[ i + 1 ].color.setHex( hex );
}
var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, overdraw: 0.5 } );
cube = new THREE.Mesh( geometry, material );
cube.position.y = 150;
scene.add( cube );
control = new TrackballControls(cube);
// Plane
var geometry = new THREE.PlaneGeometry( 200, 200 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var material = new THREE.MeshBasicMaterial( { color: 0xe0e0e0, overdraw: 0.5 } );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//GUI
var controls = new function () {
this.xx = false;
this.yy = 512;
this.onChange = function () {
}
};
var gui = new dat.GUI();
gui.add(controls, 'xx').onChange(controls.onChange);
gui.add(controls, 'yy', 1, 10).step(1).onChange(controls.onChange);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
control.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>

THREE.js can not rotate object

I am attempting to rotate an object I uploaded along its y axis. The object uploads and the material is applied. I have used the same code to rotate a sphere but it does not seem to work with a custom object. If I un-comment the line at the bottom that is supposed to handle the actual rotation, the image no longer shows up as if there is an error.
Web GL Test
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
<script src="js/three.min.js"></script>
<script src="js/OBJLoader.js"></script>
<script type="text/javascript">
var container, stats;
var camera, scene, renderer;
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 200;
camera.position.z = 150;
scene = new THREE.Scene();
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
var geom = new THREE.SphereGeometry( 100, 50, 50 );
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material.map = texture;
}
} );
object.position.y = 150;
scene.add( object );
});
loader.load( 'Head.obj' );
var texture = THREE.ImageUtils.loadTexture('face.gif');
texture.needsUpdate = true;
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
document.addEventListener( 'touchstart', onDocumentTouchStart, false );
document.addEventListener( 'touchmove', onDocumentTouchMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
//
function onDocumentMouseDown( event ) {
event.preventDefault();
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mouseout', onDocumentMouseOut, false );
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove( event ) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
}
function onDocumentMouseUp( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentMouseOut( event ) {
document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
}
function onDocumentTouchStart( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove( event ) {
if ( event.touches.length === 1 ) {
event.preventDefault();
mouseX = event.touches[ 0 ].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
}
}
//
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
//object.rotation.y += ( targetRotation - object.rotation.y ) * 0.05;
renderer.render( scene, camera );
}
</script>
</body>
The problem is that you use the variable "object" in the animate function before it is initialized. Also the variable "object" has a scope limited to the callback function of the loader.
You might want to read something about javascript variable scope.
http://www.mredkj.com/tutorials/reference_js_intro_ex.html
To solve your problem you might to change a few things.
1) Make the variable "object" global
// Make object a global variable
var camera, scene, renderer, object;
2) Do not call the animate function before the object is initialized
init();
//animate();
3) Do not use "var" inside callback function of the loader
var loader = new THREE.OBJLoader();
loader.addEventListener( 'load', function ( event ) {
//var object = event.content;
object = event.content;
var geom = new THREE.SphereGeometry( 100, 50, 50 );
4) Call "animate" after "object" is initialized
object.position.y = 150;
scene.add( object );
// Call animate after object is loaded and added to the scene
animate();
5) Good luck ;)

Resources