How to animate objects different with three.js - javascript

I just wanted to create a very simple scene with 2 different objects that move
differently.
But my sphere isnt moving at all.
When I change the line:
scene.add(obj2)
to:
obj.add(obj2)
the sphere is moving exactly as the box
what can I change to just let the sphere rotate?
//set up the scene
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer();
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
const light = new THREE.DirectionalLight();
scene.background = new THREE.Color("white");
renderer.setSize((3 * window.innerWidth) / 4, (3 * window.innerHeight) / 4);
document.body.appendChild(renderer.domElement);
camera.position.z = 17;
light.position.set(-1, 1, 1);
//-----GEOMETRY VARIABLES------//
let box = new THREE.BoxGeometry(1, 1, 1);
let sphere = new THREE.SphereGeometry(0.5, 32, 32);
//-----MATERIAL VARIABLES------//
let phong = new THREE.MeshPhongMaterial({
color: "pink",
emissive: 0,
specular: 0x070707,
shininess: 100,
});
//-----FUNCTIONALITY------//
//make the objects and add them to the scene
let obj, currentShape, currentMesh, obj2;
currentShape = box;
currentMesh = phong;
obj = new THREE.Mesh(currentShape, currentMesh);
scene.add(light);
scene.add(obj);
obj2 = new THREE.Mesh(sphere, currentMesh);
obj2.position.set(3, 0, 0);
scene.add(obj2);
//methods for making the objects move
let up = true;
function animate() {
requestAnimationFrame(animate);
obj.rotation.y += 0.01;
obj2.rotation.x += 0.02;
if (up) {
obj.translateOnAxis(new THREE.Vector3(0, 1, 0).normalize(), 0.1);
if (obj.position.y > 3.4) {
up = false;
}
} else if (!up) {
obj.translateOnAxis(new THREE.Vector3(0, 1, 0).normalize(), -0.1);
if (obj.position.y < -3.4) {
up = true;
}
}
renderer.render(scene, camera);
}
window.onload = () => {
document.getElementById("shape-form").onchange = evt => {
switch (evt.target.value) {
case "box":
currentShape = box;
break;
}
obj.geometry = currentShape;
obj.geometry.buffersNeedUpdate = true;
};
document.getElementById("mesh-form").onchange = evt => {
switch (evt.target.value) {
case "phong":
currentMesh = phong;
break;
}
obj.material = currentMesh;
obj.material.needsUpdate = true;
};
animate();
};

It's just hard to see a sphere rotating :)
Here's a simplified version of your example - I made both the cube and the sphere rotate and float around in gentle waves.
const renderer = new THREE.WebGLRenderer();
renderer.setSize((3 * window.innerWidth) / 4, (3 * window.innerHeight) / 4);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color("white");
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 17;
const light = new THREE.DirectionalLight();
light.position.set(-1, 1, 1);
scene.add(light);
const phong = new THREE.MeshPhongMaterial({
color: "pink",
emissive: 0,
specular: 0x070707,
shininess: 100,
});
const boxGeom = new THREE.BoxGeometry(1, 1, 1);
const boxObj = new THREE.Mesh(boxGeom, phong);
scene.add(boxObj);
const sphereGeom = new THREE.SphereGeometry(0.5, 32, 32);
const sphereObj = new THREE.Mesh(sphereGeom, phong);
scene.add(sphereObj);
function animate() {
const time = +new Date() / 1000;
requestAnimationFrame(animate);
boxObj.rotation.y += 0.01;
sphereObj.rotation.x += 0.02;
boxObj.position.x = Math.sin(time * .2) * 3.4;
sphereObj.position.x = Math.cos(time * .3) * 3.4;
boxObj.position.y = Math.sin(time) * 3.4;
sphereObj.position.y = Math.cos(time) * 3.4;
renderer.render(scene, camera);
}
animate();
<script src="https://threejs.org/build/three.min.js"></script>

Related

Optimising three.js for multiple elements/scenes with varying animations and colours

I'm running a small web page where a few animated gradient blobs are positioned throughout the page, attached to existing elements, each with a slightly different colour and animation.
$(".blob").each(function(){
let scene = new THREE.Scene();
let lightTop = new THREE.DirectionalLight(0xFFFFFF, .7);
lightTop.position.set(0, 500, 200);
lightTop.castShadow = true;
scene.add(lightTop);
let lightBottom = new THREE.DirectionalLight(0x000000, .95);
lightBottom.position.set(0, -500, 400);
lightBottom.castShadow = true;
scene.add(lightBottom);
let ambientLight = new THREE.AmbientLight(0x798296);
scene.add(ambientLight);
camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
var material = new THREE.MeshPhongMaterial({
vertexColors: THREE.VertexColors,
shininess: 100
});
var geometry = new THREE.SphereGeometry(.8, 128, 128);
var speedSlider = $(this).data('speed'),
spikesSlider = $(this).data('spikes'),
processingSlider = $(this).data('processing'),
color1 = $(this).data('color-1');
color2 = $(this).data('color-2');
color3 = $(this).data('color-3');
var $canvas = $(this).children('canvas'),
canvas = $canvas[0],
renderer = new THREE.WebGLRenderer({
canvas: canvas,
context: canvas.getContext('webgl2'),
antialias: false,
alpha: false
}),
simplex = new SimplexNoise();
renderer.setSize($canvas.width(), $canvas.height());
renderer.setPixelRatio(window.devicePixelRatio * 1 || 1);
camera.position.z = 5;
var sphere = new THREE.Mesh(geometry, material);
var rev = true;
var color_parsed_1 = hexToRgb(color1);
var color_parsed_2 = hexToRgb(color2);
var color_parsed_3 = hexToRgb(color3);
var cols = [{
stop: 0,
color: new THREE.Color(color_parsed_1)
}, {
stop: .55,
color: new THREE.Color(color_parsed_2)
}, {
stop: 1,
color: new THREE.Color(color_parsed_3)
}];
setGradient(geometry, cols, 'y', rev);
scene.add(sphere);
var update = () => {
var time = performance.now() * 0.00001 * speedSlider * Math.pow(processingSlider, 3),
spikes = spikesSlider * processingSlider;
for(var i = 0; i < sphere.geometry.vertices.length; i++) {
var p = sphere.geometry.vertices[i];
p.normalize().multiplyScalar(1 + 0.3 * simplex.noise3D(p.x * spikes, p.y * spikes, p.z * spikes + time));
}
sphere.geometry.computeVertexNormals();
sphere.geometry.normalsNeedUpdate = true;
sphere.geometry.verticesNeedUpdate = true;
}
function animate() {
update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
});
jsfiddle:
https://jsfiddle.net/cdigitalig/Lqdr7825/18/
I'm guessing my approach is abysmal for performance - for each individual '.blob' element, a new canvas and scene are rendered, and the number of elements varies on page length. You'll also see a lot of variables, like the lighting, repeat unnecessarily for each '.blob' - but setting these before the .each loop results in no colours showing.
I'm struggling to keep all these individual blobs within one canvas, or within one scene - the positioning of blobs varies and so they have to render wherever the element is currently on the page.
What would be the optimal solution here, performance-wise, and how do I make sure this entire layout is part of a single canvas/scene while maintaining different animations/colours per each blob?
$(".blob").each(function(){
let scene = new THREE.Scene();
let lightTop = new THREE.DirectionalLight(0xFFFFFF, .7);
lightTop.position.set(0, 500, 200);
lightTop.castShadow = true;
scene.add(lightTop);
let lightBottom = new THREE.DirectionalLight(0x000000, .95);
lightBottom.position.set(0, -500, 400);
lightBottom.castShadow = true;
scene.add(lightBottom);
let ambientLight = new THREE.AmbientLight(0x798296);
scene.add(ambientLight);
camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
var material = new THREE.MeshPhongMaterial({
vertexColors: THREE.VertexColors,
shininess: 100
});
var geometry = new THREE.SphereGeometry(.8, 128, 128);
var speedSlider = $(this).data('speed'),
spikesSlider = $(this).data('spikes'),
processingSlider = $(this).data('processing'),
color1 = $(this).data('color-1');
color2 = $(this).data('color-2');
color3 = $(this).data('color-3');
var $canvas = $(this).children('canvas'),
canvas = $canvas[0],
renderer = new THREE.WebGLRenderer({
canvas: canvas,
context: canvas.getContext('webgl2'),
antialias: false,
alpha: false
}),
simplex = new SimplexNoise();
renderer.setSize($canvas.width(), $canvas.height());
renderer.setPixelRatio(window.devicePixelRatio * 1 || 1);
camera.position.z = 5;
var sphere = new THREE.Mesh(geometry, material);
var rev = true;
var color_parsed_1 = hexToRgb(color1);
var color_parsed_2 = hexToRgb(color2);
var color_parsed_3 = hexToRgb(color3);
var cols = [{
stop: 0,
color: new THREE.Color(color_parsed_1)
}, {
stop: .55,
color: new THREE.Color(color_parsed_2)
}, {
stop: 1,
color: new THREE.Color(color_parsed_3)
}];
setGradient(geometry, cols, 'y', rev);
scene.add(sphere);
var update = () => {
var time = performance.now() * 0.00001 * speedSlider * Math.pow(processingSlider, 3),
spikes = spikesSlider * processingSlider;
for(var i = 0; i < sphere.geometry.vertices.length; i++) {
var p = sphere.geometry.vertices[i];
p.normalize().multiplyScalar(1 + 0.3 * simplex.noise3D(p.x * spikes, p.y * spikes, p.z * spikes + time));
}
sphere.geometry.computeVertexNormals();
sphere.geometry.normalsNeedUpdate = true;
sphere.geometry.verticesNeedUpdate = true;
}
function animate() {
update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
});

Creating same circles with PointsMaterial and CircleGeometry

I would like to create circles in two different ways:
With a circle sprite, then draw it with Points and PointsMaterial
With basic circle buffer geometries
However, I cannot make them match together because of PointsMaterial size.
const width = window.innerWidth;
const height = window.innerHeight;
const fov = 40;
const near = 10;
const far = 200;
const camera = new THREE.PerspectiveCamera(fov, width / height, near, far);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
const circle_sprite = new THREE.TextureLoader().load(
'https://fastforwardlabs.github.io/visualization_assets/circle-sprite.png'
);
const factor = 280;
const positions = [
{ x: 100, y: -5 },
{ x: 6, y: 50 }
];
const circleRadius = 20;
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xefefef);
/* First method */
const pointsGeometry = new THREE.Geometry();
const colors = [];
for (const position of positions) {
// Set vector coordinates from data
const vertex = new THREE.Vector3(position.x, position.y, 0);
pointsGeometry.vertices.push(vertex);
const color = new THREE.Color(0xff0000);
colors.push(color);
}
pointsGeometry.colors = colors;
const pointsMaterial = new THREE.PointsMaterial({
size: (factor * circleRadius) / fov,
sizeAttenuation: false,
vertexColors: true,
map: circle_sprite,
transparent: true,
opacity: 0.5
});
const firstPoints = new THREE.Points(pointsGeometry, pointsMaterial);
scene.add(firstPoints);
/* Second method */
const circleGeometry = new THREE.CircleBufferGeometry(circleRadius, 32);
const circleMaterial = new THREE.MeshBasicMaterial({
color: 0xffff00,
transparent: true,
opacity: 0.5
});
positions.forEach((position) => {
const circleMesh = new THREE.Mesh(circleGeometry, circleMaterial);
circleMesh.position.set(position.x, position.y, 0);
scene.add(circleMesh);
});
/* Render loop */
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
camera.position.set(0, 0, far);
I try to find the factor variable value but I also discovered that width or height are involved in this factor.
How can I draw same circles with PointsMaterial?
Having this: https://github.com/mrdoob/three.js/issues/12150#issuecomment-327874431, you can compute the size of points.
body {
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, innerWidth / innerHeight, 1, 100);
camera.position.set(0, 0, 10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
var grid = new THREE.GridHelper(10, 10);
grid.rotation.x = Math.PI * 0.5;
scene.add(grid);
// geometry
var cGeom = new THREE.CircleBufferGeometry(1, 32);
var cMat = new THREE.MeshBasicMaterial({
color: "magenta"
});
var circle = new THREE.Mesh(cGeom, cMat);
circle.position.set(0, 3, 0);
scene.add(circle);
// points
var g = new THREE.BufferGeometry().setFromPoints([new THREE.Vector3()]);
var c = document.createElement("canvas");
c.width = 128;
c.height = 128;
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, 128, 128);
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(64, 64, 64, 0, 2 * Math.PI);
ctx.fill();
var tex = new THREE.CanvasTexture(c);
var desiredSize = 2;
var pSize = desiredSize / Math.tan( THREE.Math.degToRad( camera.fov / 2 ) );
var m = new THREE.PointsMaterial({
size: pSize,
color: "aqua",
map: tex,
alphaMap: tex,
alphaTest: 0.5
});
var p = new THREE.Points(g, m);
scene.add(p);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera)
});
</script>

How can I detect the intersection of two sphere objects to avoid overlapping one another?

I am trying to create spheres and assign them a random color at the vertices of the rectangle (It can be other geometrical from like triangles or hexagons and so forth, for simplicity in this example I want to use a rectangle). http://jsfiddle.net/ElmerCC/ja6zL0k1/
let scene, camera, renderer;
let controls;
let widthWindow = window.innerWidth;
let heightWindow = window.innerHeight;
let aspect = widthWindow / heightWindow;
let mouse = new THREE.Vector2();
let raycaster = new THREE.Raycaster();
let intersect;
let elements = [];
let elementsNew = [];
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 10000);
camera.up.set(0, 0, 1);
camera.position.set(-500, -500, 400);
scene.add(camera);
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(widthWindow, heightWindow);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
let p = [];
p[0] = new THREE.Vector3(-100, -100, 0);
p[1] = new THREE.Vector3(100, -100, 0);
p[2] = new THREE.Vector3(100, 100, 0);
p[3] = new THREE.Vector3(-100, 100, 0);
//dibujar los nodos
for (let cont = 0; cont < 4; cont++) {
let obj = drawJoint(p[cont], 10, 0x666666, 0, true);
elements.push(obj);
scene.add(obj);
}
var geometry = new THREE.PlaneGeometry(200, 200);
var material = new THREE.MeshBasicMaterial({
color: 0x666666,
side: THREE.DoubleSide
});
var plane = new THREE.Mesh(geometry, material);
scene.add(plane);
//document.addEventListener("mousemove", moveMouse);
document.addEventListener("mousedown", downMouse);
}
function downMouse(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
let intersected = raycaster.intersectObjects(elements);
if (intersected.length > 0) {
intersect = intersected[0].object;
let center = intersect.position;
let n = drawJoint(center, 15, Math.random() * 0xffffff, 1, true);
elementsNew.push(n);
scene.add(n);
}
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
controls.update();
renderer.render(scene, camera);
}
function drawJoint(
JtCenter,
JtRadius,
Jtcolor,
JtOpacity,
JtTransparency
) {
let JtMaterial = new THREE.MeshBasicMaterial({
color: Jtcolor,
opacity: JtOpacity,
transparent: JtTransparency
});
let JtGeom = new THREE.SphereGeometry(JtRadius, 10, 10);
let Joint = new THREE.Mesh(JtGeom, JtMaterial);
JtGeom .computeBoundingSphere();
Joint.position.copy(JtCenter);
return Joint;
}
How can I detect the intersection of two sphere objects to avoid overlapping one another?
Spheres are the easiest objects for which you can test intersection.
Note that a Sphere is a mathematical representation, and is different than a Mesh with sphere geometry. (You can still get the mathematical bounding sphere of a Mesh with the boundingSphere property.)
Here is how you'd check if two spheres touch/intersect (you can send this function two boundingSphere properties to check other non-sphere objects).
function spheresIntersect(sphere1, sphere1position, sphere2, sphere2position){
return sphere1position.distanceTo(sphere2position) <= (sphere1.radius + sphere2.radius)
}

threejs: Move camera to position inside another object

I'm trying to move the camera controlled by trackballControl into the position of an object.
Right now it's working but as you can see in my fiddle, each time the camera changes position it also changes the z which isn't what I want.
I'm trying to keep the same position but only rotate the globe into the position of the cube.
Here is my code so far
var camera, scene, renderer, controls, cubeMesh;
document.querySelector('button').onclick = function () {
camera.position.copy(cubeMesh.position);
camera.lookAt(controls.target);
};
var initLights = function () {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
var light = new THREE.DirectionalLight(0x002288);
light.position.set(-1, -1, -1);
scene.add(light);
var light = new THREE.AmbientLight(0x222222);
scene.add(light);
};
var init = function () {
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 300;
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera);
controls.target.set(0, 0, 0);
controls.rotateSpeed = 2;
document.body.appendChild(renderer.domElement);
var sphereGeom = new THREE.SphereGeometry(100, 32, 32);
var sphereMat = new THREE.MeshPhongMaterial({
color: 0xfb3550,
flatShading: true
});
var sphereMesh = new THREE.Mesh(sphereGeom, sphereMat);
//cube
var cubeDim = 20;
var cubeGeom = new THREE.BoxGeometry(cubeDim, cubeDim, cubeDim);
var cubeMat = new THREE.MeshPhongMaterial({
color: 0x7cf93e,
flatShading: true
});
cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
var spherical = new THREE.Spherical();
spherical.set(100 + cubeDim / 2, 0.4, 0);
cubeMesh.position.setFromSpherical(spherical);
var zero = new THREE.Vector3(0, 0, 0);
cubeMesh.lookAt(zero);
scene.add(sphereMesh);
sphereMesh.add(cubeMesh);
initLights();
};
var render = function () {
renderer.render(scene, camera);
};
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
};
init();
animate()
You can test it in my fiddle here
Here is a fiddle where the camera is zoomed a little bit out by clicking the button.
JS Fiddle
var camera, scene, renderer, controls, cubeMesh;
document.querySelector('button').onclick = function () {
let x = cubeMesh.position.x
let y = cubeMesh.position.y
let z = cubeMesh.position.z
camera.position.x = 0
camera.position.y = y + 200
camera.position.z = z + 100
camera.lookAt(controls.target);
};
var initLights = function () {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
var light = new THREE.DirectionalLight(0x002288);
light.position.set(-1, -1, -1);
scene.add(light);
var light = new THREE.AmbientLight(0x222222);
scene.add(light);
};
var init = function () {
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 300;
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera);
controls.target.set(0, 0, 0);
controls.rotateSpeed = 2;
document.body.appendChild(renderer.domElement);
var sphereGeom = new THREE.SphereGeometry(100, 32, 32);
var sphereMat = new THREE.MeshPhongMaterial({
color: 0xfb3550,
flatShading: true
});
var sphereMesh = new THREE.Mesh(sphereGeom, sphereMat);
//cube
var cubeDim = 20;
var cubeGeom = new THREE.BoxGeometry(cubeDim, cubeDim, cubeDim);
var cubeMat = new THREE.MeshPhongMaterial({
color: 0x7cf93e,
flatShading: true
});
cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
var spherical = new THREE.Spherical();
spherical.set(100 + cubeDim / 2, 0.4, 0);
cubeMesh.position.setFromSpherical(spherical);
var zero = new THREE.Vector3(0, 0, 0);
cubeMesh.lookAt(zero);
scene.add(sphereMesh);
sphereMesh.add(cubeMesh);
initLights();
};
var render = function () {
console.log(camera.position)
renderer.render(scene, camera);
};
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
};
init();
animate()
You have to set the camera target to the position where you want to look at.
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
camera.lookAt(newTarget);
and the THREE.TrackballControls has to be notified to update from the camera THREE.TrackballControls.update:
document.querySelector('button').onclick = function () {
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
If the current camera position should be kept and not be reseted, then the position has to be read form the world matrix of the camera and the initial position of the camera has to be set to its current position:
document.querySelector('button').onclick = function ()
var newPosition = new THREE.Vector3(0, 0, 0);
newPosition.applyMatrix4( camera.matrixWorld );
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.position.copy(newPosition);
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
See the example:
var camera, scene, renderer, controls, cubeMesh;
document.getElementById('reset').onclick = function () {
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
document.getElementById('target').onclick = function () {
var newPosition = new THREE.Vector3(0, 0, 0);
newPosition.applyMatrix4( camera.matrixWorld );
var newTarget = new THREE.Vector3(0, 0, 0);
newTarget.copy(cubeMesh.position);
controls.reset();
camera.position.copy(newPosition);
camera.lookAt(newTarget)
camera.updateProjectionMatrix();
controls.update();
};
var initLights = function () {
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(1, 1, 1);
scene.add(light);
var light = new THREE.DirectionalLight(0x002288);
light.position.set(-1, -1, -1);
scene.add(light);
var light = new THREE.AmbientLight(0x222222);
scene.add(light);
};
var init = function () {
renderer = new THREE.WebGLRenderer({antialias: false});
renderer.setSize(window.innerWidth, window.innerHeight);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 300;
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera);
controls.target.set(0, 0, 0);
controls.rotateSpeed = 2;
document.body.appendChild(renderer.domElement);
var sphereGeom = new THREE.SphereGeometry(100, 32, 32);
var sphereMat = new THREE.MeshPhongMaterial({
color: 0xfb3550,
flatShading: true
});
var sphereMesh = new THREE.Mesh(sphereGeom, sphereMat);
//cube
var cubeDim = 20;
var cubeGeom = new THREE.BoxGeometry(cubeDim, cubeDim, cubeDim);
var cubeMat = new THREE.MeshPhongMaterial({
color: 0x7cf93e,
flatShading: true
});
cubeMesh = new THREE.Mesh(cubeGeom, cubeMat);
var spherical = new THREE.Spherical();
spherical.set(100 + cubeDim / 2, 0.4, 0);
cubeMesh.position.setFromSpherical(spherical);
var zero = new THREE.Vector3(0, 0, 0);
cubeMesh.lookAt(zero);
scene.add(sphereMesh);
sphereMesh.add(cubeMesh);
initLights();
};
var render = function () {
renderer.render(scene, camera);
};
var animate = function () {
requestAnimationFrame(animate);
controls.update();
render();
};
init();
animate();
button {
position : absolute;
top : 0;
right : 0;
}
.button2 {
position : absolute;
top : 0;
left : 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/TrackballControls.js"></script>
<button id="reset" class="button2">
reset camera
</button>
<button id="target">
look at target
</button>

Using three.js and tween.js to rotate object in 90 degree increments to create a 360 loop

I have a working animation, just not the way I would like.
I would like the object to rotate 90 degrees with a delay (works) then continue to rotate 90 degrees, ultimately looping forever. No matter what I do, it always resets. Even if I set up 4 tweens taking me to 360, the last tween that resets back zero makes the whole object spin in the opposite direction.
Thanks
var width = 1000;
var height = 600;
var scene = new THREE.Scene();
var group = new THREE.Object3D(); //create an empty container
var camera = new THREE.OrthographicCamera(width / -2, width / 2, height / 2, height / -2, -500, 1000);
camera.position.x = 180;
camera.position.y = 180;
camera.position.z = 200;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.setClearColor(0xf0f0f0);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(300, 300, 300);
var material = new THREE.MeshLambertMaterial({
color: 0xffffff,
shading: THREE.SmoothShading,
overdraw: 0.5
});
var cube = new THREE.Mesh(geometry, material);
group.add(cube);
var canvas1 = document.createElement('canvas');
canvas1.width = 1000;
canvas1.height = 1000;
var context1 = canvas1.getContext('2d');
context1.font = "Bold 20px Helvetica";
context1.fillStyle = "rgba(0,0,0,0.95)";
context1.fillText('Text bit', 500, 500);
// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1)
texture1.needsUpdate = true;
var material1 = new THREE.MeshBasicMaterial({
map: texture1,
side: THREE.DoubleSide
});
material1.transparent = true;
var mesh1 = new THREE.Mesh(
new THREE.PlaneBufferGeometry(2000, 2000),
material1
);
mesh1.position.set(-150, 150, 151);
group.add(mesh1);
directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 0, 0)
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0x888888);
directionalLight.position.set(0, 1, 0)
scene.add(directionalLight);
directionalLight = new THREE.DirectionalLight(0xcccccc);
directionalLight.position.set(0, 0, 1)
scene.add(directionalLight);
scene.add(group)
// with help from https://github.com/tweenjs/tween.js/issues/14
var tween = new TWEEN.Tween(group.rotation).to({ y: -(90 * Math.PI / 180)}, 1000).delay(1000);
tween.onComplete(function() {
group.rotation.y = 0;
});
tween.chain(tween);
tween.start();
camera.lookAt(scene.position);
var render = function() {
requestAnimationFrame(render);
TWEEN.update();
renderer.render(scene, camera);
};
render();
=====EDIT=====
I got it working, not sure if this is the most efficient approach but I'm satisfied:
var start = {}
start.y = 0;
var targ = {};
targ.y = 90*Math.PI/180
function rot(s,t) {
start["y"] = s;
targ["y"] = t;
}
var cnt1 = 1;
var cnt2 = 2;
rot(0,90*Math.PI/180);
var tween = new TWEEN.Tween(start).to(targ, 1000).delay(1000);
tween.onUpdate(function() {
group.rotation.y = start.y;
})
tween.onComplete(function() {
_c = cnt1++;
_d = cnt2++;
rot((_c*90)*Math.PI/180,(_d*90)*Math.PI/180)
});
tween.chain(tween);
tween.start();
Simple call setTimeout when tween is end
( http://jsfiddle.net/bhpf4zvy/ ):
function tRotate( obj, angles, delay, pause ) {
new TWEEN.Tween(group.rotation)
.delay(pause)
.to( {
x: obj.rotation._x + angles.x,
y: obj.rotation._y + angles.y,
z: obj.rotation._z + angles.z
}, delay )
.onComplete(function() {
setTimeout( tRotate, pause, obj, angles, delay, pause );
})
.start();
}
tRotate(group, {x:0,y:-Math.PI/2,z:0}, 1000, 500 );
Upd: pfff, what nonsense am I??? Simple use relative animation (http://jsfiddle.net/vv06u6rs/7/):
var tween = new TWEEN.Tween(group.rotation)
.to({ y: "-" + Math.PI/2}, 1000) // relative animation
.delay(1000)
.onComplete(function() {
// Check that the full 360 degrees of rotation,
// and calculate the remainder of the division to avoid overflow.
if (Math.abs(group.rotation.y)>=2*Math.PI) {
group.rotation.y = group.rotation.y % (2*Math.PI);
}
})
.start();
tween.repeat(Infinity)

Categories

Resources