How to rotate an object to face the camera? [duplicate] - javascript

guys I know this question has been asked several times, several different ways, but I just can get it to work. Basically I have 2d clouds, but I want the camera to rotate around an object floating above the clouds. The problem is, when im not looking a the face of the clouds u can tell that they are 2d. Soooo i want the the clouds to "look" at the camera where ever it is. I believe my problem stems from how the cloud geometry is called on to the planes, but here take a look. I put the a lookAt function with in my animate function. I hope you can point me in the right direction at least.
Three.js rev. 70...
container.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 0, 100);
scene.add(camera);
controls = new THREE.OrbitControls( camera );
controls.target.copy( new THREE.Vector3( 0, 0,475) );
controls.minDistance = 50;
controls.maxDistance = 200;
controls.autoRotate = true;
controls.autoRotateSpeed = .2; // 30 seconds per round when fps is 60
controls.minPolarAngle = Math.PI/4; // radians
controls.maxPolarAngle = Math.PI/2; // radians
controls.enableDamping = true;
controls.dampingFactor = 0.25;
clock = new THREE.Clock();
cloudGeometry = new THREE.Geometry();
var texture = THREE.ImageUtils.loadTexture('img/cloud10.png', null, animate);
texture.magFilter = THREE.LinearMipMapLinearFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
var fog = new THREE.Fog(0x4584b4, -100, 3000);
cloudMaterial = new THREE.ShaderMaterial({
uniforms: {
"map": {
type: "t",
value: texture
},
"fogColor": {
type: "c",
value: fog.color
},
"fogNear": {
type: "f",
value: fog.near
},
"fogFar": {
type: "f",
value: fog.far
},
},
vertexShader: document.getElementById('vs').textContent,
fragmentShader: document.getElementById('fs').textContent,
depthWrite: false,
depthTest: false,
transparent: true
});
var plane = new THREE.Mesh(new THREE.PlaneGeometry(64, 64));
for (var i = 0; i < 8000; i++) {
plane.position.x = Math.random() * 1000 - 500;
plane.position.y = -Math.random() * Math.random() * 200 - 15;
plane.position.z = i;
plane.rotation.z = Math.random() * Math.PI;
plane.scale.x = plane.scale.y = Math.random() * Math.random() * 1.5 + 0.5;
plane.updateMatrix();
cloudGeometry.merge(plane.geometry, plane.matrix);
}
cloud = new THREE.Mesh(cloudGeometry, cloudMaterial);
scene.add(cloud);
cloud = new THREE.Mesh(cloudGeometry, cloudMaterial);
cloud.position.z = -8000;
scene.add(cloud);
var radius = 100;
var xSegments = 50;
var ySegments = 50;
var geo = new THREE.SphereGeometry(radius, xSegments, ySegments);
var mat = new THREE.ShaderMaterial({
uniforms: {
lightPosition: {
type: 'v3',
value: light.position
},
textureMap: {
type: 't',
value: THREE.ImageUtils.loadTexture("img/maps/moon.jpg")
},
normalMap: {
type: 't',
value: THREE.ImageUtils.loadTexture("img/maps/normal.jpg")
},
uvScale: {
type: 'v2',
value: new THREE.Vector2(1.0, 1.0)
}
},
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent
});
mesh = new THREE.Mesh(geo, mat);
mesh.geometry.computeTangents();
mesh.position.set(0, 50, 0);
mesh.rotation.set(0, 180, 0);
scene.add(mesh);
}
function onWindowResize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
light.orbit(mesh.position, clock.getElapsedTime());
cloud.lookAt( camera );
controls.update(camera);
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', onWindowResize, false);

just a first guess:
the lookAt function needs Vector3 as parameter. try to use camera.position in the animate function.
cloud.lookAt( camera.position );

first of all, to build 2D objects in a scene that always faces towards the camera, you should use Sprite object, so you don't have to do anything to get this effect. (and have better performance :))
Definition from THREE.org: Sprite - a sprite is a plane in an 3d scene which faces always towards the camera.
var map = THREE.ImageUtils.loadTexture( "sprite.png" );
var material = new THREE.SpriteMaterial( { map: map, color: 0xffffff, fog: true } );
var sprite = new THREE.Sprite( material );
scene.add( sprite );
Please check this example: http://threejs.org/examples/#webgl_points_sprites

I would absolutely agree, I would use Sprite, or even Points, but then, if assign a texture to it, it will render it square-sized. My sprites are animated, and frames cannot be packed in square tiles, cause it would take a lot of space. I might make a mesh and use this lookAt function.

Related

How to tween/animate fog three.js

So i am trying to change the fog density by tweening it is this possible because it doesn't seem to change here's my defaults:
var camera, densityFog, colorFog2;
colorFog2 = 0xfee2ed;
densityFog = 0.25;
scene.fog = new THREE.FogExp2(colorFog2, densityFog);
and here is what I've tried using the libs GSAP and tweenjs:
tween = new TWEEN.Tween(scene.fog)
.to({densityFog: 0.02}, 1000 )
.easing(TWEEN.Easing.Exponential.InOut)
.onComplete(function() { }).start();
gsap.to(scene.fog, {
duration: 2,
densityFog: 0.02,
onUpdate: function () {
controls.update();
isZoomed = 0;
controls.enabled = false;
},
});
can anyone point me in the right direction?
This answer uses gsap
Use an object eg. myfog = { value: .5 } and tween its value property to what you desire.
Then in onUpdate, set scene.fog to a new THREE.FogExp2 with the current myfog.value as a parameter.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
camera.position.y = 2;
// Init the object and fog here
var myfog = { value: .5 }
scene.fog = new THREE.FogExp2(0x00ff00, myfog.value);
var geometry = new THREE.BoxGeometry(1, 1, 5);
var mat = new THREE.MeshBasicMaterial({
color: 0xff0000
});
var mesh = new THREE.Mesh(geometry, mat);
scene.add(mesh);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x00ff00);
document.body.appendChild(renderer.domElement);
function render() {
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
}
animate();
// This animates the fog
gsap.to(myfog, {
duration: 2,
value: 0.002, // The end value
onUpdate: function() {
// New fog with current myfog value
scene.fog = new THREE.FogExp2(0x00ff00, myfog.value);
},
// These just infinitely repeat the animation
yoyo: true,
repeat: -1,
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r127/three.min.js"></script>

Three.js rotate a sphere that's followed by a camera

I'm working on a toy Three.js scene in which I want to follow a sphere with a camera [demo]. Right now, though, I can't figure out how to make the sphere "roll" without also rotating the camera.
Here's the code I use to update the sphere's position each frame:
function moveSphere() {
var delta = clock.getDelta(); // seconds
var moveDistance = 200 * delta; // 200 pixels per second
var rotateAngle = Math.PI / 2 * delta; // pi/2 radians (90 deg) per sec
// move forwards/backwards/left/right
if ( pressed['W'] ) {
sphere.translateZ( -moveDistance );
}
if ( pressed['S'] )
sphere.translateZ( moveDistance );
if ( pressed['Q'] )
sphere.translateX( -moveDistance );
if ( pressed['E'] )
sphere.translateX( moveDistance );
// rotate left/right/up/down
var rotation_matrix = new THREE.Matrix4().identity();
if ( pressed['A'] )
sphere.rotateOnAxis(new THREE.Vector3(0,1,0), rotateAngle);
if ( pressed['D'] )
sphere.rotateOnAxis(new THREE.Vector3(0,1,0), -rotateAngle);
if ( pressed['R'] )
sphere.rotateOnAxis(new THREE.Vector3(1,0,0), rotateAngle);
if ( pressed['F'] )
sphere.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle);
}
And the code to follow the sphere each tick of time:
function moveCamera() {
var relativeCameraOffset = new THREE.Vector3(0,50,200);
var cameraOffset = relativeCameraOffset.applyMatrix4(sphere.matrixWorld);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(sphere.position);
}
Is there an easy way to make the ball roll without making the camera spiral all over the place? Inside of the if (pressed['W']) block, I tried various permutations of sphere.rotateOnAxis(new THREE.Vector3(0,0,1), rotateAngle); but haven't found a natural way to make the ball roll. I would be very grateful for any advice others can offer on this!
Your issue is this line:
var cameraOffset = relativeCameraOffset.applyMatrix4(sphere.matrixWorld);
This takes the offset you specify and applies not only the sphere position, but it's rotation as well. For example, if your sphere is rotated 180 degrees on the Y-axis, the resulting vector is (0, 50, -200) + (sphere position).
You need to extract the translation component from the sphere matrix, and apply it to the offset. The code below uses an intermediate matrix to store the position of the sphere.
/**
* Follow the sphere
**/
var sphereTranslation = new THREE.Matrix4(); // only make it once to reduce overhead
function moveCamera() {
var relativeCameraOffset = new THREE.Vector3(0,50,200);
sphereTranslation.copyPosition(sphere.matrixWorld); // get sphere position only
var cameraOffset = relativeCameraOffset.applyMatrix4(sphereTranslation);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(sphere.position);
}
The key here was to create a sphere, then add that sphere to a group, so that I could translate and rotate the group (which controls the ball's position) while also rotating the sphere inside the group (which allows the ball to "roll"). Separating these entities out allows the camera to follow the sphere group just as before while allowing the ball to rotate independently of the sphere group's movement [updated demo]:
/**
* Generate a scene object with a background color
**/
function getScene() {
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
return scene;
}
/**
* Generate the camera to be used in the scene. Camera args:
* [0] field of view: identifies the portion of the scene
* visible at any time (in degrees)
* [1] aspect ratio: identifies the aspect ratio of the
* scene in width/height
* [2] near clipping plane: objects closer than the near
* clipping plane are culled from the scene
* [3] far clipping plane: objects farther than the far
* clipping plane are culled from the scene
**/
function getCamera() {
var aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspectRatio, 0.1, 10000);
camera.position.set(0,150,400);
camera.lookAt(scene.position);
return camera;
}
/**
* Generate the light to be used in the scene. Light args:
* [0]: Hexadecimal color of the light
* [1]: Numeric value of the light's strength/intensity
* [2]: The distance from the light where the intensity is 0
* #param {obj} scene: the current scene object
**/
function getLight(scene) {
var lights = [];
lights[0] = new THREE.PointLight( 0xffffff, 0.6, 0 );
lights[0].position.set( 100, 200, 100 );
scene.add( lights[0] );
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
return light;
}
/**
* Generate the renderer to be used in the scene
**/
function getRenderer() {
// Create the canvas with a renderer
var renderer = new THREE.WebGLRenderer({antialias: true});
// Add support for retina displays
renderer.setPixelRatio(window.devicePixelRatio);
// Specify the size of the canvas
renderer.setSize(window.innerWidth, window.innerHeight);
// Add the canvas to the DOM
document.body.appendChild(renderer.domElement);
return renderer;
}
/**
* Generate the controls to be used in the scene
* #param {obj} camera: the three.js camera for the scene
* #param {obj} renderer: the three.js renderer for the scene
**/
function getControls(camera, renderer) {
var controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.zoomSpeed = 0.4;
controls.panSpeed = 0.4;
return controls;
}
/**
* Get grass
**/
function getPlane(scene, loader) {
var texture = loader.load('grass.jpg');
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 10, 10 );
var material = new THREE.MeshBasicMaterial({
map: texture, side: THREE.DoubleSide
});
var geometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
var plane = new THREE.Mesh(geometry, material);
plane.position.y = -0.5;
plane.rotation.x = Math.PI / 2;
scene.add(plane);
return plane;
}
/**
* Add background
**/
function getBackground(scene, loader) {
var imagePrefix = 'sky-parts/';
var directions = ['right', 'left', 'top', 'bottom', 'front', 'back'];
var imageSuffix = '.bmp';
var geometry = new THREE.BoxGeometry( 1000, 1000, 1000 );
var materialArray = [];
for (var i = 0; i < 6; i++)
materialArray.push( new THREE.MeshBasicMaterial({
map: loader.load(imagePrefix + directions[i] + imageSuffix),
side: THREE.BackSide
}));
var sky = new THREE.Mesh( geometry, materialArray );
scene.add(sky);
}
/**
* Add a character
**/
function getSphere(scene) {
var geometry = new THREE.SphereGeometry( 30, 12, 9 );
var material = new THREE.MeshPhongMaterial({
color: 0xd0901d,
emissive: 0xaf752a,
side: THREE.DoubleSide,
flatShading: true
});
var sphere = new THREE.Mesh( geometry, material );
// create a group for translations and rotations
var sphereGroup = new THREE.Group();
sphereGroup.add(sphere)
sphereGroup.position.set(0, 24, 100);
scene.add(sphereGroup);
return [sphere, sphereGroup];
}
/**
* Store all currently pressed keys
**/
function addListeners() {
window.addEventListener('keydown', function(e) {
pressed[e.key.toUpperCase()] = true;
})
window.addEventListener('keyup', function(e) {
pressed[e.key.toUpperCase()] = false;
})
}
/**
* Update the sphere's position
**/
function moveSphere() {
var delta = clock.getDelta(); // seconds
var moveDistance = 200 * delta; // 200 pixels per second
var rotateAngle = Math.PI / 2 * delta; // pi/2 radians (90 deg) per sec
// move forwards/backwards/left/right
if ( pressed['W'] ) {
sphere.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle)
sphereGroup.translateZ( -moveDistance );
}
if ( pressed['S'] )
sphereGroup.translateZ( moveDistance );
if ( pressed['Q'] )
sphereGroup.translateX( -moveDistance );
if ( pressed['E'] )
sphereGroup.translateX( moveDistance );
// rotate left/right/up/down
var rotation_matrix = new THREE.Matrix4().identity();
if ( pressed['A'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(0,1,0), rotateAngle);
if ( pressed['D'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(0,1,0), -rotateAngle);
if ( pressed['R'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(1,0,0), rotateAngle);
if ( pressed['F'] )
sphereGroup.rotateOnAxis(new THREE.Vector3(1,0,0), -rotateAngle);
}
/**
* Follow the sphere
**/
function moveCamera() {
var relativeCameraOffset = new THREE.Vector3(0,50,200);
var cameraOffset = relativeCameraOffset.applyMatrix4(sphereGroup.matrixWorld);
camera.position.x = cameraOffset.x;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(sphereGroup.position);
}
// Render loop
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
moveSphere();
moveCamera();
};
// state
var pressed = {};
var clock = new THREE.Clock();
// globals
var scene = getScene();
var camera = getCamera();
var light = getLight(scene);
var renderer = getRenderer();
// add meshes
var loader = new THREE.TextureLoader();
var floor = getPlane(scene, loader);
var background = getBackground(scene, loader);
var sphereData = getSphere(scene);
var sphere = sphereData[0];
var sphereGroup = sphereData[1];
addListeners();
render();
body { margin: 0; overflow: hidden; }
canvas { width: 100%; height: 100%; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>

Disappearing line object in Three.js

I have a strange problem, which can be a three.js bug, but it also can be my curve hands.
I have a scene with some meshes (in example below I used several transparent cubes and small spheres) and one line object (can be Line or LineSegments - doesn't matter) based on buffer geometry. While I rotating the camera line object sometimes disappears form view like it's covered by another object. It seems it also disappears if I cannot see the start point (if rotate camera to a degree where start point is offscreen, even without additional meshes) of the line while 90% of the line object should be in view.
The question is: Why does the line disappear and how should I prevent such its behavior?
This is how it looks on screencast:
http://screencast.com/t/HLC99OMmDdK
And this is an example of the problem:
http://jsfiddle.net/exiara/sa4bxhc3/
You should be able to see how line disappears when camera rotates.
The code of jsfiddle example:
var camera, controls, scene, renderer, dummy, projector,
stats, fps = 30, fpsTimeout = 1000 / fps,
linesGeometry,globalLine;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor(0xFFFFeF, 1);
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xFFFFeF, 100, 2500 );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 50000 );
camera.position.set(-450, 300, 650);
camera.target = new THREE.Vector3(0,0,0);
controls = new THREE.OrbitControls( camera );
controls.addEventListener('change', render );
// ------------ MAIN PART START ------------ //
var lines = 1000;
linesGeometry = new THREE.BufferGeometry();
var positions = new Float32Array( lines * 6 );
for ( var i = 0, j, ll = lines; i < ll; i++ ) {
j=i*6;
positions[j] = Math.random()*100;
positions[j+1] = Math.random()*100;
positions[j+2] = Math.random()*100;
positions[j+3] = Math.random()*100;
positions[j+4] = Math.random()*100;
positions[j+5] = Math.random()*100;
}
linesGeometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
globalLine = new THREE.Line( linesGeometry, new THREE.LineBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.8
} ));
scene.add( globalLine );
// ------------ MAIN PART END ------------ //
// add cubes
var step = 400;
var gridSize = 4;
var offset = step*gridSize/2;
var cubeGeometry = new THREE.BoxGeometry(step, step, step);
var cubeMaterial = new THREE.MeshBasicMaterial({ color:0xFF0000, ambient: 0xCCCCCC, transparent: true, opacity: 0 });
var testCube, edge;
for (var x = -offset; x <= offset; x+=step) {
for (var y = -offset; y <= offset; y+=step) {
for (var z = -offset; z <= offset; z+=step) {
testCube = new THREE.Mesh(cubeGeometry,cubeMaterial);
testCube.position.set(x, y, z);
edge = new THREE.EdgesHelper( testCube, 0x000000 );
scene.add(testCube);
scene.add(edge);
}
}
}
// spheres
var sphereGeometry = new THREE.SphereGeometry( 10,32,16),
sphere;
var spheres = [
[0xff0000, 0, 0, 0 ], // red
[0x0000ff, 200, 0, 0 ], // blue
[0x00FF00, -200, 0, 0 ], // green
[0xFF00ff, 0, 200, 0 ], // magenta
[0x00ffff, 0, -200, 0 ], // aqua
[0xFFff00, 0, 0, 200 ], // lime
[0x000000, 0, 0, -200] // black
];
for (var i = 0, sl = spheres.length; i <sl; i++) {
sphere = new THREE.Mesh(sphereGeometry, new THREE.MeshBasicMaterial({color: spheres[i][0]}));
sphere.position.set(spheres[i][1], spheres[i][2], spheres[i][3]);
scene.add(sphere);
}
/* Stats */
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
document.body.appendChild( stats.domElement );
/* window observers */
window.addEventListener( 'resize', onWindowResize, false );
window.addEventListener( 'load', render, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function degInRad(deg) {
return deg * Math.PI / 180;
}
function animate()
{
setTimeout(function() {
requestAnimationFrame(animate);
}, fpsTimeout );
render();
}
function render() {
camera.lookAt(camera.target);
renderer.render( scene, camera );
stats.update();
}
The problem is that you are drawing multiple levels of opacity on top of each other and webgl needs to sort them. So the short answer is to add depthTest: false to your cube material.
var cubeMaterial = new THREE.MeshBasicMaterial({ color:0xFF0000, ambient: 0xCCCCCC, transparent: true, opacity: 0, depthTest: false });
But I would like to mention that what you are doing is inefficient. You should not be drawing a grid that way. Use lines instead.

Light Not showing on object

so Ive been messing with this, and Ive finally gotten everything to kind of work for me. I'm a beginner at any type of javascript so I don't know if this is a simple fix. Basically I cant get the light to show up on the moon like how it does in the original.
Well here is what I have thus far.
<script type="text/javascript" id="mainCode">
var container,
renderer,
scene,
camera,
mesh,
light = {
speed: 0.1,
distance: 1000,
position: new THREE.Vector3(0, 0, 0),
orbit: function (center, time) {
this.position.x =
(center.x + this.distance) * Math.sin(time * -this.speed);
this.position.z =
(center.z + this.distance) * Math.cos(time * this.speed);
}
},
clock,
controls;
init();
function init() {
// grab the container from the DOM
container = document.getElementById( "container" );
scene = new THREE.Scene();
var fov = 35,
aspect = window.innerWidth / window.innerHeight,
near = 1,
far = 65536;
renderer = new THREE.WebGLRenderer({antialias: true, preserveDrawingBuffer: true});
renderer.setClearColor(0x000000, 1);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(0, 0, 800);
scene.add(camera);
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 0.5;
controls.dynamicDampingFactor = 0.5;
clock = new THREE.Clock();
var radius = 100;
var xSegments = 50;
var ySegments = 50;
var geo = new THREE.SphereGeometry(radius, xSegments, ySegments);
var mat = new THREE.ShaderMaterial({
uniforms: {
lightPosition: {
type: 'v3',
value: light.position
},
textureMap: {
type: 't',
value: THREE.ImageUtils.loadTexture( "img/maps/moon.jpg" )
},
normalMap: {
type: 't',
value: THREE.ImageUtils.loadTexture( "img/maps/normal.jpg" )
},
uvScale: {
type: 'v2',
value: new THREE.Vector2(1.0, 1.0)
}
},
vertexShader:document.getElementById('vertexShader').textContent,
fragmentShader:document.getElementById('fragmentShader').textContent
});
mesh = new THREE.Mesh(geo, mat);
mesh.geometry.computeTangents();
mesh.position.set(0, 0, 0);
mesh.rotation.set(0, 180, 0);
scene.add(mesh);
}
function onWindowResize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
light.orbit(mesh.position, clock.getElapsedTime());
controls.update(camera);
renderer.render(scene, camera);
}
animate();
window.addEventListener('resize', onWindowResize, false);
</script>
You never add any lights to your scene. The moon example uses a custom shader which is more complicated than what you need right now. You need to create a regular Three light and add it to your scene, for example
http://threejs.org/docs/#Reference/Lights/PointLight
var light = new THREE.PointLight( 0xff0000, 1, 100 );
light.position.set( 50, 50, 50 );
scene.add( light );

How can I print text along an arc using Three.js?

I'm trying to print text along an arc using Three.js. With help from this post, I was able to get the math for the rotation. But, as you'll see, the text is all jumbled on top of itself. How can I get it to correctly space itself out? Codepen is here.
var container, camera, scene, renderer;
function init() {
container = document.getElementById( 'canvas' );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 1, 100000);
camera.position.z = 500;
scene.add(camera);
var loader = new THREE.FontLoader();
loader.load( 'https://raw.githubusercontent.com/mrdoob/three.js/master/examples/fonts/helvetiker_bold.typeface.json', function ( font ) {
var theText = "This is some text."
var numRadsPerChar = 2*Math.PI/theText.length;
for (var i = 0; i < theText.length; i++){
var char = theText[i]
var geometry = new THREE.TextBufferGeometry( char, {
font: font,
size: 60,
height: 60,
curveSegments: 20
});
var materials = [
new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, overdraw: 0.5 } ),
new THREE.MeshBasicMaterial( { color: 0x000000, overdraw: 0.5 } )
];
var mesh = new THREE.Mesh( geometry, materials );
mesh.rotation.z = (i * numRadsPerChar);
//mesh.position.x = i * 20;
group = new THREE.Group();
group.add( mesh );
scene.add( group );
};
} );
renderer = new THREE.WebGLRenderer({alpha: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
animate();
} init();
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Had some help figuring this out, but here's the portion that needed to be edited to work:
mesh.rotation.z = (i * numRadsPerChar);
Needed to be:
mesh.position.x = 100 * Math.sin(i * numRadsPerChar);
mesh.position.y = 100 * Math.cos(i * numRadsPerChar);
mesh.rotation.z = Math.PI/2 -(i * numRadsPerChar);
Basically, I needed to add a constant (Math.PI/2) for the rotation. For the x and y positions, I had to take the sin and cosine, respectively, to get the letters to be placed properly around the arc. Here's a working codepen.
Another way to do this would be to draw your text on a canvas and use the canvas in a texture with texture.wrapS and .wrapT set to THREE.RepeatWrapping.. then put that texture on a material.. then make a path with the extruded path geometry and set it's material. The you can move the text by setting the texture.offset.x or y each frame in your render loop.

Categories

Resources