set camera relative to point collection - three.js

I'm trying to set the camera to be 3 units away from a collection of points I would like this to be relative to the group of points since the points will change later on.
So far I can retrieve x,y,z coordinates from the database and are returned using djangos {{coord_x}} I will have to return the correct length, (I could do this on the python side - len()) for now the database query is limited to 20 rows. These points are brought into three.js using a for loop.
How do I set a camera relative to the objects? Do I need to calculate a bounding box?
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.001, 100000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// allow resizing of the window
window.addEventListener('resize', function()
{
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
//Controls
controls = new THREE.OrbitControls(camera, renderer.domElement)
//create the shape
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({color: 0x007654, wireframe: false});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
var numpoints = 20;
var dots = []; //If you want to use for other task
for (var i = 0 ; i < numpoints ; i++) {
var x = "{{coord_x}}";
var y = "{{coord_y}}";
var z = "{{coord_z}}";
// var x = Math.random() * (0 - 1) + 1
// var y = Math.random() * (0 - 1) + 1
// var z = Math.random() * (0 - 1) + 1
var dotGeometry = new THREE.Geometry();
dots.push(dotGeometry);
dotGeometry.vertices.push(new THREE.Vector3(x, y, z));
var dotMaterial = new THREE.PointsMaterial( { size: 3, sizeAttenuation: false, color: 0xFF0000 });
var dot = new THREE.Points( dotGeometry, dotMaterial);
scene.add(dot);
}
camera.position.z = 30
//game logic, allow rotation
var update = function()
{
//cube.rotation.x += 0.00;
//cube.rotation.y += 0.0025;
//dot.rotation.x += 0.00;
//dot.rotation.y += 0.005;
};
// draw scene
var render = function()
{
renderer.render(scene, camera);
};
// run game loop (update, render, repeat)
var GameLoop = function()
{
requestAnimationFrame(GameLoop);
update();
render();
};
GameLoop();
</script>

That's how you can work with THREE.Sphere() object to set the position of your camera:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var geom = new THREE.Geometry();
for (let i = 0; i < 100; i++) {
geom.vertices.push(
new THREE.Vector3(
Math.random() - 0.5,
Math.random() - 0.5,
Math.random() - 0.5
).multiplyScalar(10)
);
}
var points = new THREE.Points(geom, new THREE.PointsMaterial({
size: 0.25,
color: "aqua"
}));
scene.add(points);
var sphere = new THREE.Sphere().setFromPoints(geom.vertices);
console.log(sphere);
camera.position.copy(sphere.center);
camera.position.z += sphere.radius / Math.sin(THREE.Math.degToRad(camera.fov / 2));
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Related

I am having a problem with three.js collision detection

We are creating a three.js based game where players can eat food, currently we have a collision script but it is not working properly. Any help to get it working so our players can eat would be greatly appreciated.
The code is below.
Code snippet:
//sorry in advance for the crazy code structure o.o
//variables
var scene, renderer, rayCaster;
var WORLD, floor, FOOD, MWORLD;
var plr, camera, controls;
function debugupdate()
{
window.plr = plr
window.floor = floor
window.WORLD = WORLD
window.camera = camera
window.controls = controls
window.scene = scene
window.FOOD = FOOD
}
setInterval(debugupdate, 1000)
//setup scene for gameplay
function InitGame()
{
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
rayCaster = new THREE.Raycaster();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.y = 8;
camera.position.z = 8;
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.autoRotate = false;
controls.enablePan = false;
//controls.update() must be called after any manual changes to the camera's transform
//camera.position.set( 0, 20, 100 );
//controls.update();
//MWORLD = stuff mouse can detect
MWORLD = new THREE.Object3D();
MWORLD.name = 'MWORLD'
var floorgeo = new THREE.BoxGeometry(30, 0.5, 30);
var floormat = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
floor = new THREE.Mesh( floorgeo, floormat );
MWORLD.add(floor)
WORLD = new THREE.Object3D();
WORLD.add( MWORLD );
WORLD.name = 'WORLD';
scene.add(WORLD);
}
InitGame();
//Mouse Stuff
var MousePos;
var PlrTarget;
document.addEventListener('mousemove', MouseToWorld, false);
function MouseToWorld(event) {
event.preventDefault();
var mouse = {};
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
vector.unproject( camera );
var dir = vector.sub( camera.position ).normalize();
var distance = - camera.position.z / dir.z;
MousePos = camera.position.clone().add( dir.multiplyScalar( distance ) );
//console.log(MousePos)
rayCaster.setFromCamera(mouse, camera);
var intersects = rayCaster.intersectObjects(WORLD.getObjectByName('MWORLD').children, true);
if (intersects.length > 0)
// console.log(intersects[0].point);
PlrTarget = intersects[0].point
// Make the sphere follow the mouse
// mouseMesh.position.set(event.clientX, event.clientY, 0);
};
//Food Parent
FOOD = new THREE.Object3D();
FOOD.name = 'FOOD'
WORLD.add(FOOD)
var fid = -1
//Add Food Object should this be different?
function AddFood()
{
fid = fid + 1
var colors = ['red', 'blue', 'orange', 'yellow', 'pink', 'cyan'];
var geometry = new THREE.SphereGeometry( 0.05 * 1.5, 32 / 4, 32 / 4 );
var material = new THREE.MeshBasicMaterial( {color: colors[Math.floor(Math.random() * colors.length)]} );
var sphere = new THREE.Mesh( geometry, material );
var geometry = new THREE.BoxGeometry( 0.1 * 1.5, 10, 0.1 * 1.5);//BoxGeometry for collision detection spheres were lagging like crazy :(
var material = new THREE.MeshBasicMaterial( {color: 'red'} );
material.transparent = true
material.opacity = 0.2
var cube = new THREE.Mesh( geometry, material );
var foodrange = 15
cube.add(sphere);
cube.position.y = 0.25
cube.position.z = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));
cube.position.x = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));
cube.name = 'f' + fid
WORLD.getObjectByName('FOOD').add(cube)
}
//adds lots of food
function InitFood()
{
var i
for(i = 0; i < 150; i++)
{
AddFood();
}
}
InitFood();
//Eats the food working I think...
function ConsumeFood(fid)
{
FOOD.remove(FOOD.getObjectByName(fid))
plr.scale.x = plr.scale.x + 0.01
plr.scale.y = plr.scale.y + 0.01
plr.scale.z = plr.scale.z + 0.01
}
//Creates Player
function CreatePlr()
{
var geometry = new THREE.SphereGeometry( 0.5, 32, 32);//32 / 2
var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
var sphere = new THREE.Mesh( geometry, material );
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {color: 'blue'} );
material.transparent = true
material.opacity = 0.2
var cube = new THREE.Mesh( geometry, material );
plr = new THREE.Object3D();
plr.add(sphere);
plr.add(cube);
scene.add(plr)
controls.target = plr.position
}
CreatePlr();
setTimeout(Eat, 1500)
//DETECT FOOD PLEASE HELP :(
//sometimes works ok you have to have the food fairly deep within the player to detect
//never eats as soon as you touch it
//sometimes totally fails to detect piece of food until you go over it multiple times
//sometimes random pieces of food are eaten even though they are not touched
function Eat() {
var originPoint = plr.position.clone();
for (var vertexIndex = 0; vertexIndex < plr.children[1].geometry.vertices.length; vertexIndex++)
{
var localVertex = plr.children[1].geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4( plr.children[1].matrix );
var directionVector = globalVertex.sub( plr.position );
var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
var collisionResults = ray.intersectObjects( FOOD.children );
if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() ) //if your touching the food or its in your player eat it
collisionResults.forEach(function(food){
console.log(food.object)//shows in console that food was detected and what piece of food it was
ConsumeFood(food.object.name)//consume food based on name (f1, f2, f3)
})
}
setTimeout(Eat, 50)
}
var Time = new THREE.Clock();
function PlrLerpSpeed(speed)
{
var distance = plr.position.distanceTo(PlrTarget);
var finalSpeed = (distance / speed);
return Time.deltaTime / finalSpeed
}
var animate = function () {
requestAnimationFrame( animate );
if(PlrTarget){
plr.lookAt(PlrTarget)
//plr.position.lerp(PlrTarget, PlrLerpSpeed(1));
plr.position.lerp(PlrTarget, 0.01 / (plr.position.distanceTo(PlrTarget) / 2));
}
controls.update();
//plr.position = MousePos
/*var speed = 5; // units a second, the speed we want
var currentPoint = new THREE.Vector3(); // we will re-use it
// this part is in a function of event listener of, for example, a button
currentPoint.copy(plr.position); // cube is the object to move
var distance = currentPoint.distanceTo(MousePos)
var duration = (distance / speed) * 1000; // in milliseconds
new TWEEN.Tween(plr.position)
.to(MousePos, duration) // destinationPoint is the object of destination
.start();
*/
renderer.render( scene, camera );
};
animate();
body { margin: 0; }
canvas { display: block; }
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
Since your player and food objects are basically spheres, you can implement a super fast and accurate collision detection with bounding spheres. Try it like so:
//variables
var scene, renderer, rayCaster;
var WORLD, floor, FOOD, MWORLD;
var plr, camera, controls;
function debugupdate() {
window.plr = plr
window.floor = floor
window.WORLD = WORLD
window.camera = camera
window.controls = controls
window.scene = scene
window.FOOD = FOOD
}
setInterval(debugupdate, 1000)
//setup scene for gameplay
function InitGame() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
rayCaster = new THREE.Raycaster();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.y = 8;
camera.position.z = 8;
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.autoRotate = false;
controls.enablePan = false;
//controls.update() must be called after any manual changes to the camera's transform
//camera.position.set( 0, 20, 100 );
//controls.update();
//MWORLD = stuff mouse can detect
MWORLD = new THREE.Object3D();
MWORLD.name = 'MWORLD'
var floorgeo = new THREE.BoxGeometry(30, 0.5, 30);
var floormat = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
floor = new THREE.Mesh(floorgeo, floormat);
MWORLD.add(floor)
WORLD = new THREE.Object3D();
WORLD.add(MWORLD);
WORLD.name = 'WORLD';
scene.add(WORLD);
}
InitGame();
//Mouse Stuff
var MousePos;
var PlrTarget;
document.addEventListener('mousemove', MouseToWorld, false);
function MouseToWorld(event) {
event.preventDefault();
var mouse = {};
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
vector.unproject(camera);
var dir = vector.sub(camera.position).normalize();
var distance = -camera.position.z / dir.z;
MousePos = camera.position.clone().add(dir.multiplyScalar(distance));
//console.log(MousePos)
rayCaster.setFromCamera(mouse, camera);
var intersects = rayCaster.intersectObjects(WORLD.getObjectByName('MWORLD').children, true);
if (intersects.length > 0)
// console.log(intersects[0].point);
PlrTarget = intersects[0].point
// Make the sphere follow the mouse
// mouseMesh.position.set(event.clientX, event.clientY, 0);
};
//Food Parent
FOOD = new THREE.Object3D();
FOOD.name = 'FOOD'
WORLD.add(FOOD)
var fid = -1
//Add Food Object should this be different?
function AddFood() {
fid = fid + 1
var colors = ['red', 'blue', 'orange', 'yellow', 'pink', 'cyan'];
var geometry = new THREE.SphereGeometry(0.05 * 1.5, 32 / 4, 32 / 4);
var material = new THREE.MeshBasicMaterial({
color: colors[Math.floor(Math.random() * colors.length)]
});
var sphere = new THREE.Mesh(geometry, material);
var foodrange = 15
sphere.position.y = 0.25
sphere.position.z = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));
sphere.position.x = ((Math.random() * foodrange + 1) * (Math.round(Math.random()) * 2 - 1));
sphere.name = 'f' + fid
WORLD.getObjectByName('FOOD').add(sphere)
}
//adds lots of food
function InitFood() {
var i
for (i = 0; i < 150; i++) {
AddFood();
}
}
InitFood();
//Eats the food working I think...
function ConsumeFood(fid) {
FOOD.remove(FOOD.getObjectByName(fid))
plr.scale.x = plr.scale.x + 0.01
plr.scale.y = plr.scale.y + 0.01
plr.scale.z = plr.scale.z + 0.01
}
//Creates Player
function CreatePlr() {
var geometry = new THREE.SphereGeometry(0.5, 32, 32); //32 / 2
var material = new THREE.MeshBasicMaterial({
color: 0xffff00
});
plr = new THREE.Mesh(geometry, material);
scene.add(plr)
controls.target = plr.position
}
CreatePlr();
setTimeout(Eat, 1500)
var spherePlayer = new THREE.Sphere();
var sphereFood = new THREE.Sphere();
//DETECT FOOD PLEASE HELP :(
//sometimes works ok you have to have the food fairly deep within the player to detect
//never eats as soon as you touch it
//sometimes totally fails to detect piece of food until you go over it multiple times
//sometimes random pieces of food are eaten even though they are not touched
function Eat() {
spherePlayer.copy( plr.geometry.boundingSphere ).applyMatrix4( plr.matrixWorld );
for ( var i = 0; i < FOOD.children.length; i ++ ) {
var food = FOOD.children[ i ];
sphereFood.copy( food.geometry.boundingSphere ).applyMatrix4( food.matrixWorld );
if ( spherePlayer.intersectsSphere( sphereFood ) === true ) {
ConsumeFood(food.name);
}
}
setTimeout(Eat, 50)
}
var Time = new THREE.Clock();
function PlrLerpSpeed(speed) {
var distance = plr.position.distanceTo(PlrTarget);
var finalSpeed = (distance / speed);
return Time.deltaTime / finalSpeed
}
var animate = function() {
requestAnimationFrame(animate);
if (PlrTarget) {
plr.lookAt(PlrTarget)
//plr.position.lerp(PlrTarget, PlrLerpSpeed(1));
plr.position.lerp(PlrTarget, 0.01 / (plr.position.distanceTo(PlrTarget) / 2));
}
controls.update();
//plr.position = MousePos
/*var speed = 5; // units a second, the speed we want
var currentPoint = new THREE.Vector3(); // we will re-use it
// this part is in a function of event listener of, for example, a button
currentPoint.copy(plr.position); // cube is the object to move
var distance = currentPoint.distanceTo(MousePos)
var duration = (distance / speed) * 1000; // in milliseconds
new TWEEN.Tween(plr.position)
.to(MousePos, duration) // destinationPoint is the object of destination
.start();
*/
renderer.render(scene, camera);
};
animate();
body { margin: 0; }
canvas { display: block; }
<script src="https://cdn.jsdelivr.net/npm/three#0.116.1/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.116.1/examples/js/controls/OrbitControls.js"></script>

How do you plot elliptic paraboloid in ThreeJS

I am trying to create a elliptic paraboloid in threeJS using parametric curves. Here is the link to what I am looking to plot:
https://mathinsight.org/level_sets.
Here is what I have right now:
Here is the current function definition, however it seems to be producing a different result.
let planeCreator = function(u,v,w){
var height = 15;
var size = 20;
var u = u * height;
var v = (v * 2 * Math.PI);
var x = size * Math.sqrt(u) * Math.cos(v);
var y = u;
var z = size * Math.sqrt(u) * Math.sin(v);
w.set(x,-y,z);
};
let geometry = new THREE.ParametricBufferGeometry( planeCreator, 50, 50 );
geometry.center();
let material = new THREE.MeshPhongMaterial( {
color: 0xff0000,
side: THREE.DoubleSide,
wireframe: true
} );
let object = new THREE.Mesh( geometry, material );
scene.add( object );
Here is what is currently plotted:
As an option (without parametric geometries):
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-4, 2, 5);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var planeGeom = new THREE.PlaneBufferGeometry(4, 4, 20, 20);
planeGeom.rotateX(-Math.PI * 0.5);
var v = new THREE.Vector3();
var positions = planeGeom.attributes.position;
for (var i = 0; i < positions.count; i++) {
v.fromBufferAttribute(positions, i);
positions.setY(i, (-(v.x * v.x) - (2 * v.z * v.z)) * 0.25);
}
planeGeom.center();
planeGeom.computeVertexNormals();
var ellipticParaboloidSurface = new THREE.Mesh(planeGeom, new THREE.MeshNormalMaterial({
side: THREE.DoubleSide
}));
scene.add(ellipticParaboloidSurface);
var boxHelper = new THREE.BoxHelper(ellipticParaboloidSurface, "yellow");
scene.add(boxHelper);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
})
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Three.js, moving a partical along an EllipseCurve

I know questions related to my problem have been asked and answered before but three.js changed a lot in the last couple years and I'm having trouble finding what I need in the currently available examples.
I have an elliptical curve that I'd like to run particles along. My code runs without error but it doesn't actually move the particle anywhere. What am I missing?
var t = 0;
var curve = new THREE.EllipseCurve( .37, .15, .35, .25, 150, 450, false, 0 );
var points = curve.getPoints( 50 );
var curveGeometry = new THREE.BufferGeometry().setFromPoints( points );
var particleGeometry = new THREE.Geometry();
var particleMap = new THREE.TextureLoader().load( "/img/spark.png" );
var vertex = new THREE.Vector3();
vertex.x = points[0].x;
vertex.y = points[0].y;
vertex.z = 0;
particleGeometry.vertices.push(vertex);
particleMaterial = new THREE.PointsMaterial({
size: .05,
map: particleMap,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent : true
});
particles = new THREE.Points( particleGeometry, particleMaterial );
scene.add(particles);
animate();
function animate() {
if (t <= 1) {
particles.position = curveGeometry.getPointAt(t)
t += 0.005
} else {
t = 0;
}
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
Just a rough concept of how you can do it, using THREE.Geometry():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 0, 50);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor(0x404040);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var grid = new THREE.GridHelper(40, 40, "white", "gray");
grid.rotation.x = Math.PI * -0.5;
scene.add(grid);
var curve = new THREE.EllipseCurve(0, 0, 20, 20, 0, Math.PI * 2, false, 0);
// using of .getPoints(division) will give you a set of points of division + 1
// so, let's get the points manually :)
var count = 10;
var inc = 1 / count;
var pointAt = 0;
var points = [];
for (let i = 0; i < count; i++) {
let point = curve.getPoint(pointAt); // get a point of THREE.Vector2()
point.z = 0; // geometry needs points of x, y, z; so add z
point.pointAt = pointAt; // save position along the curve in a custom property
points.push(point);
pointAt += inc; // increment position along the curve for next point
}
var pointsGeom = new THREE.Geometry();
pointsGeom.vertices = points;
console.log(points);
var pointsObj = new THREE.Points(pointsGeom, new THREE.PointsMaterial({
size: 1,
color: "aqua"
}));
scene.add(pointsObj);
var clock = new THREE.Clock();
var time = 0;
render();
function render() {
requestAnimationFrame(render);
time = clock.getDelta();
points.forEach(p => {
p.pointAt = (p.pointAt + time * 0.1) % 1; // it always will be from 0 to 1
curve.getPoint(p.pointAt, p); //re-using of the current point
});
pointsGeom.verticesNeedUpdate = true;
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

shadowMap cant detect all instances on THREE.InstancedBufferGeometry

I'm implementing something similar to the buffer geometry instancing dynamic example.
Basically the idea is having one bufferGeometry duplicated and having an attribute array with the offsets of my objects (like they have in the above example).
If I try to add shadows, I only get shadows on 1 object, which I assume is because we only have 1 geometry.
Is there a way of adding shadows to all my objects?
var scene, camera, renderer, controls;
var offsets;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 250, 1000);
renderer = new THREE.WebGLRenderer();
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.gammaInput = true
renderer.gammaOutput = true
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
controls = new THREE.OrbitControls(camera, renderer.domElement);
// Lights
var ambient = new THREE.AmbientLight(0xcccccc);
scene.add(ambient);
var spot = new THREE.SpotLight(0x999999, 1, 0, Math.PI / 2, 1);
spot.position.set(700, 700, 700)
spot.target.position.set(0, 0, 0);
spot.castShadow = true
spot.angle = Math.PI / 4
spot.penumbra = 0.05
spot.decay = 2
spot.distance = 10000
spot.shadow.mapSize.width = 1024
spot.shadow.mapSize.height = 1024
spot.shadow.camera.near = 1
spot.shadow.camera.far = 10000
scene.add(spot);
var spotHelper = new THREE.SpotLightHelper(spot)
scene.add(spotHelper);
// Floor
var geometry = new THREE.PlaneGeometry(3000, 3000, 10, 10);
var material = new THREE.MeshPhongMaterial({
color: new THREE.Color(0x777777),
shininess: 5
});
var ground = new THREE.Mesh(geometry, material);
ground.rotation.x = -1.57;
ground.receiveShadow = true;
scene.add(ground);
// instanced geometry
var instances = 10;
var geometry = new THREE.InstancedBufferGeometry();
var icosahedron = new THREE.BufferGeometry().fromGeometry(new THREE.IcosahedronGeometry(200, 3));
geometry.addAttribute('position', icosahedron.attributes.position);
geometry.addAttribute('normal', icosahedron.attributes.normal);
geometry.addAttribute('uv', icosahedron.attributes.uv);
geometry.setIndex(icosahedron.index);
offsets = new THREE.InstancedBufferAttribute(new Float32Array(instances * 3), 3, 1);
var vector = new THREE.Vector3();
for (var i = 0; i < offsets.count; i++) {
var x = Math.random() * 1000 - 500;
var y = Math.random() * 1000 - 500;
var z = Math.random() * 1000 - 500;
vector.set(x, y, z).normalize();
offsets.setXYZ(i, x + vector.x * 5, y + vector.y * 5, z + vector.z * 5);
}
geometry.addAttribute('offset', offsets);
var material = new THREE.ShaderMaterial({
uniforms: {},
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
side: THREE.DoubleSide,
});
var mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
Example JsFiddle

Three.js: Add different images to each side of cylinder

I am trying to add different image to each face of a cylinder in three.js, basically I want the top, bottom and side to be different images.
This is code where I have added one image which wraps the complete cylinder.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.CylinderGeometry(0.9,1,0.5,32,1, false);
var material = new THREE.MeshPhongMaterial({color: 0xffffff, side:THREE.DoubleSide, map: THREE.ImageUtils.loadTexture('cake-texture-nice-golden-ginger-33420104.jpg')});
var cone = new THREE.Mesh(geometry, material);
scene.add(cone);
var width = window.innerWidth; var height = window.innerHeight; var screenW = window.innerWidth; var screenH = window.innerHeight; /*SCREEN*/ var spdx = 0, spdy = 0; mouseX = 0, mouseY = 0, mouseDown = false; /*MOUSE*/ document.body.addEventListener("mousedown", function(event) { mouseDown = true }, false); document.body.addEventListener("mouseup", function(event) { mouseDown = false }, false); function animate() { spdy = (screenH / 2 - mouseY) / 40; spdx = (screenW / 2 - mouseX) / 40; if (mouseDown){ cone.rotation.x = spdy; cone.rotation.y = spdx; } requestAnimationFrame( animate ); render(); } // create a point light var pointLight = new THREE.PointLight( 0xFFFF8F ); // set its position pointLight.position.x = 10; pointLight.position.y = 50; pointLight.position.z = 130; // add to the scene scene.add(pointLight); camera.position.z = 5; var render = function () { requestAnimationFrame(render); //cone.rotation.x += 0.01; //cone.rotation.y += 0.001; //cone.rotation.z -= 0.02; window.addEventListener('mousemove', function (e) { var mouseX = ( e.clientX - width / 2 ); var mouseY = ( e.clientY - height / 2 ); cone.rotation.x = mouseY * 0.005; cone.rotation.y = mouseX * 0.005; cone.rotation.y += mouseY; //console.log(mouseY); }, false); renderer.render(scene, camera); }; render();
This is the pen for the cylinder: http://codepen.io/dilipmerani/pen/XmWNdV
Update-25Sep
var materialTop = new THREE.MeshPhongMaterial({color: 0xffffff, side:THREE.DoubleSide, map: THREE.ImageUtils.loadTexture('chocolate_brown_painted_textured_wall_tileable.jpg')});
var materialSide = new THREE.MeshPhongMaterial({color: 0xffffff, side:THREE.DoubleSide, map: THREE.ImageUtils.loadTexture('cake-texture-nice-golden-ginger-33420104.jpg')});
var materialBottom = new THREE.MeshPhongMaterial({color: 0xffffff, side:THREE.DoubleSide, map: THREE.ImageUtils.loadTexture('cake-texture-nice-golden-ginger-33420104.jpg')});
var materialsArray = [];
materialsArray.push(materialTop); //materialindex = 0
materialsArray.push(materialSide); // materialindex = 1
materialsArray.push(materialBottom); // materialindex = 2
var material = new THREE.MeshFaceMaterial(materialsArray);
var geometry = new THREE.CylinderGeometry(0.9,1,0.5,3,1, false);
var aFaces = geometry.faces.length;
console.log(aFaces);
for(var i=0;i<aFaces;i++) {
geometry.faces[i].materialindex;
}
var cone = new THREE.Mesh(geometry, material);
scene.add(cone);
Thanks
Create MeshFaceMaterial:
var materialTop = new THREE.MeshPhongMaterial(...);
var materialSide = new THREE.MeshPhongMaterial(...);
var materialBottom = new THREE.MeshPhongMaterial(...);
var materialsArray = [];
materialsArray.push(materialTop); //materialindex = 0
materialsArray.push(materialSide); // materialindex = 1
materialsArray.push(materialBottom); // materialindex = 2
var material = new THREE.MeshFaceMaterial(materialsArray);
Update geometry:
var geometry = new THREE.CylinderGeometry(0.9,1,0.5,32,1, false);
faces you can get from geometry.faces
Loop faces and change materialindex: geometry.faces[faceIndex].materialindex
Print geometry.faces to console and check what it has.
var aFaces = geometry.faces.length;
for(var i=0;i<aFaces;i++) {
if(i < 64){
geometry.faces[i].materialIndex = 0;
}else if(i > 63 && i < 96){
geometry.faces[i].materialIndex = 1;
}else{
geometry.faces[i].materialIndex = 2;
}
}
Build your cone
var cone = new THREE.Mesh(geometry, material);
Example of your updated code
You should create faces in mesh's geometry with some materialindex. So you'll have 3 surfaces. And than use MeshFaceMaterial(array of material for each surface).

Resources