Im trying to roatate this space ship that i created, the rotation itself works the problem is that whenever i rotate it with the left and right arrow keys i want the spaceship to rotate just like with cartesian coordinates the problem is that whenever the objects rotates around the planet, the spaceship inclination doesnt change at all, like it would with cartesian coordinates and i dont get why really because the rotation around the planet itself works.
Sorry if the code is too long most of it is just to create the spaceship itself, i think the problem itself is in the update function itself.
Program:
/*global THREE*/
var camera = [];
var scene, renderer, currentCamera = 0;
var viewSize = 40;
var aspectRatio;
var geometry, material, mesh;
var wiredObjects = [];
var leftArrow, rightArrow, upArrow, downArrow;
var clock = new THREE.Clock();
//!!var controls;
var defaultScale = 1;
var planetRadius = 12;
var rocketHeight = planetRadius/12;
var rocketPartHeight = rocketHeight/2;
var rocketInfRadius = rocketPartHeight;
var rocketMidRadius = rocketPartHeight/2;
var rocketSupRadius = 0;
var boosterRadius = rocketInfRadius/5;
var boosterHeight = rocketInfRadius/4;
var rocketTrashDistance = 1.2 * planetRadius;
var objPositions = [];
var objAngles = [];
var nrTrash = 20;
var floatingTrash = [];
var trashSizes = [];
var minTrashSize = planetRadius/24;
var maxTrashSize = planetRadius/20;
var trashGeometries = [];
var copyVideo;
var universe;
var planet;
var rocket;
var loader = new THREE.TextureLoader();
var space_texture = new THREE.TextureLoader().load(
"https://wallpaperaccess.com/full/1268183.jpg"
);
'use strict';
function addObjPart(obj, geometry, mater, hex, x, y, z, rotX, rotY, rotZ) {
material = (mater != null)? mater : new THREE.MeshBasicMaterial({color: hex, wireframe: wires});
mesh = new THREE.Mesh(geometry, material);
mesh.rotateX(rotX);
mesh.rotateY(rotY);
mesh.rotateZ(rotZ);
mesh.position.set(x, y, z);
obj.add(mesh);
wiredObjects.push(mesh);
return mesh;
}
function getObjPositions() {
var i;
var nrObj = nrTrash+1;
var angleTheta, anglePhi;
var objX, objY, objZ;
var posVector = new THREE.Vector3(0,0,0); // spherical coordinates vector
var angleVector = new THREE.Vector2(0,0); // angles Theta and Phi for spherical coordinates
for (i = 0; i < nrObj; i++) {
angleTheta = Math.random() * 2*Math.PI;
anglePhi = Math.random() * 2*Math.PI;
angleVector.set(angleTheta, anglePhi);
objAngles.push(angleVector);
objX = rocketTrashDistance * Math.sin(angleTheta) * Math.sin(anglePhi);
objY = rocketTrashDistance * Math.cos(angleTheta);
objZ = rocketTrashDistance * Math.sin(angleTheta) * Math.cos(anglePhi);
posVector.set(objX, objY, objZ);
objPositions.push(posVector);
}
}
function createUniverse(x, y, z, scale) {
wires = true;
universe = new THREE.Object3D();
universe.scale.set(scale, scale, scale);
var rocketPos = objPositions[0];
addPlanet(universe, 0, 0, 0);
addRocket(universe, rocketPos.x, rocketPos.y, rocketPos.z);
addAux(universe);
universe.position.set(x, y, z);
scene.add(universe);
return universe;
}
function addPlanet(obj, x, y, z) {
planet = new THREE.Object3D();
geometry = new THREE.SphereGeometry(planetRadius);
var planetTexture = new THREE.TextureLoader().load(
"https://st2.depositphotos.com/5171687/44380/i/450/depositphotos_443805316-stock-photo-equirectangular-map-clouds-storms-earth.jpg"
);
var planetMaterial = new THREE.MeshBasicMaterial( {
map: planetTexture,
transparent:true,
side:THREE.DoubleSide,
} );
addObjPart(obj, geometry, planetMaterial, 0x0000ff, x, y, z, 0, 0, 0);
}
function addRocket(obj, x, y, z) {
rocket = new THREE.Group();
var n_rocket = new THREE.Object3D();
addRocketTop(n_rocket, 0, 0, -rocketPartHeight/2);
addRocketBottom(n_rocket, 0, 0, rocketPartHeight/2);
addRocketBooster(n_rocket, 0, rocketInfRadius-boosterRadius, rocketPartHeight+0.5*boosterHeight);
addRocketBooster(n_rocket, 0, -rocketInfRadius+boosterRadius,rocketPartHeight+0.5*boosterHeight);
addRocketBooster(n_rocket, rocketInfRadius-boosterRadius, 0, rocketPartHeight+0.5*boosterHeight);
addRocketBooster(n_rocket, -rocketInfRadius+boosterRadius, 0, rocketPartHeight+0.5*boosterHeight);
rocket.add(n_rocket);
rocket.position.set(x, y, z);
obj.add(rocket);
return rocket;
}
function addRocketTop(obj, x, y, z) {
geometry = new THREE.CylinderGeometry(rocketMidRadius, rocketSupRadius, rocketPartHeight, 41,1);
addObjPart(obj, geometry, null, 0xff0000, x, y, z, Math.PI/180*90, 0, 0);
}
function addRocketBottom(obj, x, y, z) {
geometry = new THREE.CylinderGeometry(rocketInfRadius, rocketMidRadius, rocketPartHeight, 41,1);
addObjPart(obj, geometry, null, 0x000fff, x, y, z, Math.PI/180*90, 0, 0);
}
function addRocketBooster(obj, x, y, z) {
geometry = new THREE.CapsuleGeometry(boosterRadius, boosterHeight, 0.5, 20);
addObjPart(obj, geometry, null, 0xff0000, x, y, z, Math.PI/180*90, 0, 0);
}
function addTrash(x, y, z) {
}
function render() {
renderer.render(scene, camera[currentCamera]); // tells 3js renderer to draw scene visualization based on camera
}
function onResize() {
if (window.innerWidth > 0 && window.innerHeight > 0){
var i;
var val = 2;
aspectRatio = window.innerWidth / window.innerHeight;
renderer.setSize(window.innerWidth, window.innerHeight);
var nrCameras = camera.length;
for (i = 0; i < 1; i++) { // Ortographic Cameras
camera[i].left = -viewSize * aspectRatio / val;
camera[i].right = viewSize * aspectRatio / val;
camera[i].top = viewSize / val;
camera[i].bottom = viewSize / -val;
camera[i].updateProjectionMatrix();
}
for (i=1; i < nrCameras; i++) { // Perspective cameras
camera[i].aspect = aspectRatio;
camera[i].updateProjectionMatrix();
}
}
}
function update()
{
var timeOccurred = clock.getDelta();
var rocketSpeed = Math.PI/180 * 40;
if (rightArrow || leftArrow || upArrow || downArrow) { // rocket movement flags
var rocketTheta = objAngles[0].x;
var rocketPhi = objAngles[0].y;
var rocketX, rocketY, rocketZ;
if (leftArrow){
rocketPhi += rocketSpeed * timeOccurred;
}
if (rightArrow){
//n_rocket.rotation.x += - rocketSpeed * timeOccurred;
rocketPhi += - rocketSpeed * timeOccurred;
}
if (upArrow){
//n_rocket.rotation.z += - rocketSpeed * timeOccurred;
rocketTheta += -rocketSpeed * timeOccurred;
}
if (downArrow){
//n_rocket.rotation.z += rocketSpeed * timeOccurred;
rocketTheta += rocketSpeed * timeOccurred;
}
rocketX = rocketTrashDistance * Math.sin(rocketTheta) * Math.sin(rocketPhi);
rocketY = rocketTrashDistance * Math.cos(rocketTheta);
rocketZ = rocketTrashDistance * Math.sin(rocketTheta) * Math.cos(rocketPhi);
rocket.position.set(rocketX, rocketY, rocketZ);
objAngles[0].set(rocketTheta, rocketPhi);
objPositions[0].set(rocketX, rocketY, rocketZ);
}
}
function animate() {
update();
requestAnimationFrame(animate);
// controls.update();
render();
}
function addAux(obj) {
geometry = new THREE.SphereGeometry(5);
addObjPart(obj, geometry, null, 0xffc0cb, 15, 0, 0);
addObjPart(obj, geometry, null, 0xffff00, 15, 0, 0);
addObjPart(obj, geometry, null, 0x0000ff, 15, 0, 0);
}
function createScene() {
scene = new THREE.Scene();
scene.add(new THREE.AxesHelper(100));
scene.background = space_texture;
getObjPositions();
universe = createUniverse(0, 0, 0, defaultScale);
}
function createOrtographicCamera(x, y, z) {
var val = 2;
aspectRatio = window.innerWidth / window.innerHeight;
var camera = new THREE.OrthographicCamera( viewSize * aspectRatio/-val,
viewSize * aspectRatio / val,
viewSize / val,
viewSize / -val,
1,
1000);
camera.position.x = x;
camera.position.y = y;
camera.position.z = z;
camera.lookAt(scene.position);
return camera;
}
function onKeyDown(e) {
var keyName = e.keyCode;
switch (keyName) {
case 49://1
currentCamera = 0;
break;
case 37 : // left arrow key
leftArrow = true;
break;
case 38: // up arrow key
upArrow = true;
break;
case 39: // right arrow key
rightArrow = true;
break;
case 40: // down arrow key
downArrow = true;
break;
default:
break;
}
}
function onKeyUp(e) {
var keyName = e.keyCode;
switch (keyName) {
case 37 : // left arrow key
leftArrow = false;
break;
case 38: // up arrow key
upArrow = false;
break;
case 39: // right arrow key
rightArrow = false;
break;
case 40: // down arrow key
downArrow = false;
break;
default:
break;
}
}
function init() {
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
createScene();
camera[0] = createOrtographicCamera(viewSize, 0, 0);
//!! controls = new THREE.OrbitControls(camera[0], renderer.domElement);
animate();
window.addEventListener("resize", onResize);
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
}
Related
I looked at this example with three js to draw particles with images and works perfectly but i want to change the image with a switch when click a button (calls this function):
const changeImg = function(num) {
switch (num)
{
case 0:
imgData ="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA....";
break;
case 1:
imgData = "data:image/png;base64,iVBORw0KGgoAAAAN..."
break;
}
img.src = imgData;
}
And works but when you click multiple times website becomes slow.
How can I update just the image without slowing down the website?
EDIT 1
I change the code like this:
var renderer, scene, camera, ww, wh, particles, mw, mh, mz, numState;
numState = 0;
mz = 6; // Matrerial size
ww = document.getElementById('map-container').offsetWidth,
wh = 450;
mw = ww * 2;
mh = wh * 2;
var centerVector = new THREE.Vector3(0, 0, 0);
var previousTime = 0
speed = 10
isMouseDown = false;
// Render
renderer = new THREE.WebGLRenderer({
canvas: document.getElementById("map"),
antialias: true
});
renderer.setSize(mw, mh);
renderer.setClearColor(0x12347C);
// Scence
scene = new THREE.Scene();
// Camera
camera = new THREE.OrthographicCamera( ww / - 2, ww / 2, wh / 2, wh / - 2, 1, 1000 );
camera.position.set(7, 0, 4);
camera.lookAt(centerVector);
scene.add(camera);
camera.zoom = 4;
camera.updateProjectionMatrix();
// Geometry
var geometry = new THREE.Geometry();
var material = new THREE.PointsMaterial({
size: mz,
color: 0xFFFFFF,
sizeAttenuation: false
});
// Particle
particles = new THREE.Points();
var getImageData = function(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
return ctx.getImageData(0, 0, image.width, image.height);
}
var drawTheMap = function() {
geometry.dispose();
particles.material.dispose();
particles.geometry.dispose();
for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {
var vertex = new THREE.Vector3();
vertex.x = x - imagedata.width / 2;
vertex.y = -y + imagedata.height / 2;
vertex.z = -Math.random()*500;
vertex.speed = Math.random() / speed + 0.015;
geometry.vertices.push(vertex);
}
}
}
particles.material = material;
particles.geometry = geometry;
scene.add(particles);
requestAnimationFrame(render);
};
var init = function() {
imagedata = getImageData(image);
drawTheMap();
onResize();
window.addEventListener('mousemove', onMousemove, false);
window.addEventListener('mousedown', onMousedown, false);
window.addEventListener('mouseup', onMouseup, false);
window.addEventListener('resize', onResize, false);
};
var onResize = function(){
var mov1, mov2;
ww = document.getElementById('map-container').offsetWidth;
wh = 450;
if (window.innerWidth > 850) {
mw = ww * 2;
mh = wh * 2;
mz = 6;
mov1 = 2.2;
mov2 = 1.9;
particles.material.size = mz;
} else {
mw = ww;
mh = wh;
mz = 3;
mov1 = 2;
mov2 = 2;
particles.material.size = mz;
}
renderer.setSize(mw, mh);
camera.left = ww / - mov1;
camera.right = ww / 2;
camera.top = wh / mov2;
camera.bottom = wh / - 2;
camera.updateProjectionMatrix();
};
var onMouseup = function(){
isMouseDown = false;
}
var onMousedown = function(e){
isMouseDown = true;
lastMousePos = {x:e.clientX, y:e.clientY};
};
var onMousemove = function(e){
if(isMouseDown){
camera.position.x += (e.clientX-lastMousePos.x)/100;
camera.position.y -= (e.clientY-lastMousePos.y)/100;
camera.lookAt(centerVector);
lastMousePos = {x:e.clientX, y:e.clientY};
}
};
var render = function(a) {
requestAnimationFrame(render);
particles.geometry.verticesNeedUpdate = true;
if(!isMouseDown){
camera.position.x += (0-camera.position.x)*0.06;
camera.position.y += (0-camera.position.y)*0.06;
camera.lookAt(centerVector);
}
renderer.render(scene, camera);
};
var imgData;
var image;
imgData ="data:image/png;base64,iVBORw0KGgoAAA...";
const changeState = function(state, num) {
document.getElementById('dropbox-choose').innerHTML = state;
numState = num;
switch (numState)
{
case 0:
imgData ="data:image/png;base64,iVBORw0KGgoAAA...";
break;
case 1:
imgData = "data:image/png;base64,iVBORw0KGgoI..."
break;
}
image.src = imgData;
}
image = document.createElement("img");
image.onload = init;
image.src = imgData;
And the THREE.WebGLRenderer is only applied once but when I click to change the image, it does not update and also I still have the problem that the website slows down
it's my first time using three js and i don't know if i'm applying well what it says in the documentation
EDIT 2
var renderer, scene, camera, ww, wh, particles, mw, mh, mz, numState;
numState = 0;
mz = 6;
ww = document.getElementById('map-container').offsetWidth,
wh = 450;
mw = ww * 2;
mh = wh * 2;
var centerVector = new THREE.Vector3(0, 0, 0);
var previousTime = 0
speed = 10
isMouseDown = false;
// Render
renderer = new THREE.WebGLRenderer({
canvas: document.getElementById("map"),
antialias: true
});
renderer.setSize(mw, mh);
renderer.setClearColor(0x12347C);
// Scence
scene = new THREE.Scene();
// Camera
camera = new THREE.OrthographicCamera( ww / - 2, ww / 2, wh / 2, wh / - 2, 1, 1000 );
camera.position.set(7, 0, 4);
camera.lookAt(centerVector);
scene.add(camera);
camera.zoom = 4;
camera.updateProjectionMatrix();
// Geometry
//var geometry = new THREE.Geometry();
var material = new THREE.PointsMaterial({
size: mz,
color: 0xFFFFFF,
sizeAttenuation: false
});
// Particle
particles = new THREE.Points();
particles.material = material
scene.add(particles);
var getImageData = function(image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
return ctx.getImageData(0, 0, image.width, image.height);
}
var drawTheMap = function() {
let vertices = particles.geometry; // this acts as a REFERENCE!
vertices.length = 0; // clears the vertices array
for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {
var vertex = new THREE.Vector3();
vertex.x = x - imagedata.width / 2;
vertex.y = -y + imagedata.height / 2;
vertex.z = -Math.random()*500;
vertex.speed = Math.random() / speed + 0.015;
vertices.vertices.push(vertex);
}
}
}
particles.geometry.verticesNeedUpdate = true; // Inform three.js of the update
requestAnimationFrame(render);
};
var init = function() {
imagedata = getImageData(image);
drawTheMap();
onResize();
window.addEventListener('mousemove', onMousemove, false);
window.addEventListener('mousedown', onMousedown, false);
window.addEventListener('mouseup', onMouseup, false);
window.addEventListener('resize', onResize, false);
};
var onResize = function(){
var mov1, mov2;
ww = document.getElementById('map-container').offsetWidth;
wh = 450;
if (window.innerWidth > 850) {
mw = ww * 2;
mh = wh * 2;
mz = 6;
mov1 = 2.2;
mov2 = 1.9;
particles.material.size = mz;
} else {
mw = ww;
mh = wh;
mz = 3;
mov1 = 2;
mov2 = 2;
particles.material.size = mz;
}
renderer.setSize(mw, mh);
camera.left = ww / - mov1;
camera.right = ww / 2;
camera.top = wh / mov2;
camera.bottom = wh / - 2;
camera.updateProjectionMatrix();
};
var onMouseup = function(){
isMouseDown = false;
}
var onMousedown = function(e){
isMouseDown = true;
lastMousePos = {x:e.clientX, y:e.clientY};
};
var onMousemove = function(e){
if(isMouseDown){
camera.position.x += (e.clientX-lastMousePos.x)/100;
camera.position.y -= (e.clientY-lastMousePos.y)/100;
camera.lookAt(centerVector);
lastMousePos = {x:e.clientX, y:e.clientY};
}
};
var render = function(a) {
requestAnimationFrame(render);
particles.geometry.verticesNeedUpdate = true;
if(!isMouseDown){
camera.position.x += (0-camera.position.x)*0.06;
camera.position.y += (0-camera.position.y)*0.06;
camera.lookAt(centerVector);
}
renderer.render(scene, camera);
};
var imgData;
var image;
imgData ="data:image/png;base64,iVBORw0KGgoAAA...";
const changeState = function(state, num) {
document.getElementById('dropbox-choose').innerHTML = state;
numState = num;
switch (numState)
{
case 0:
imgData ="data:image/png;base64,iVBORw0KGgoAAA...";
break;
case 1:
imgData = "data:image/png;base64,iVBORw0KGgoAAA..."
break;
}
image.src = imgData;
}
image = document.createElement("img");
image.onload = init;
image.src = imgData;
When I click to change the image, it does not update and also I still have the problem that the website slows down. I cahaged vertcies.push to vertices.vertices.push()
I know I mentioned disposal in a previous version of my answer, but let's instead consider re-using all of your objects.
particles - Add it to the scene immediately after creation.
material - Assign it to particles immediately; No need to re-assign it every time.
geometry - Don't create it globally, we'll let it work from within particles.
Now what we're going to do is replace the vertices and tell three.js that there are new vertices to upload to the GPU.
var drawTheMap = function() {
let vertices = particles.geometry; // this acts as a REFERENCE!
vertices.length = 0; // clears the vertices array
for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {
var vertex = new THREE.Vector3();
vertex.x = x - imagedata.width / 2;
vertex.y = -y + imagedata.height / 2;
vertex.z = -Math.random()*500;
vertex.speed = Math.random() / speed + 0.015;
vertices.push(vertex);
}
}
}
particles.geometry.verticesNeedUpdate = true; // Inform three.js of the update
requestAnimationFrame(render);
};
The important part here (other than replacing the contents of the vertices array) is setting particles.geometry.verticesNeedUpdate = true;. This is what triggers three.js to replace the vertices on the GPU. Everything else is re-used, not recreated, so it should run fairly smooth.
The solution is change THREE.geometry to THREE.BufferGeometry
var drawTheMap = function() {
particles.geometry = new THREE.BufferGeometry();
var positions = [];
for (var y = 0, y2 = imagedata.height; y < y2; y += 2) {
for (var x = 0, x2 = imagedata.width; x < x2; x += 2) {
if (imagedata.data[(x * 4 + y * 4 * imagedata.width)] < 128) {
positions.push(x - imagedata.width / 2);
positions.push(-y + imagedata.height / 2);
positions.push(-Math.random()*500);
particles.geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
}
}
}
particles.geometry.verticesNeedUpdate = true;
requestAnimationFrame(render);
};
This code should produce a mesh of a torus in three js. I'm pretty sure the maths are correct. However it renders only a piece of torus, or stranger things if I change some parameters. Is there something bad with my practice of THREE.Mesh ?
// the vertices of the mesh and the vertex normals ----------------
var nx = 64;
var ny = 32;
var R = 10; var r = 3;
var Vertices = new Array(nx);
var Normals = new Array(nx);
for (var i = 0; i < nx; i++) {
Vertices[i] = new Array(ny);
Normals[i] = new Array(ny);
var u = i / nx * 2 * Math.PI;
var cos_u = Math.cos(u);
var sin_u = Math.sin(u);
var cx = R * cos_u;
var cy = R * sin_u;
for (var j = 0; j < ny; j++) {
var v = j / ny * 2 * Math.PI;
var rcos_v = r * Math.cos(v);
var rsin_v = r * Math.sin(v);
Vertices[i][j] = new THREE.Vector3(
cx + rcos_v * cos_u,
cy + rcos_v * sin_u,
rsin_v
);
Normals[i][j] = new THREE.Vector3(
rcos_v * cos_u,
rcos_v * sin_u,
rsin_v
);
}
}
// vertices as a dot cloud ----------------------------------------
var dotGeometry = new THREE.Geometry();
for (var i = 0; i < nx; i++) {
for (var j = 0; j < ny; j++) {
dotGeometry.vertices.push(Vertices[i][j]);
}
}
var dotMaterial =
new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
var cloud = new THREE.Points(dotGeometry, dotMaterial);
// mesh -----------------------------------------------------------
var geom = new THREE.Geometry();
for (var i = 0; i < nx; i++) {
var ip1 = (i == nx - 1 ? 0 : i + 1);
for (var j = 0; j < ny; j++) {
var jp1 = (j == ny - 1 ? 0 : j + 1);
geom.vertices.push(Vertices[i][j]);
geom.vertices.push(Vertices[i][jp1]);
geom.vertices.push(Vertices[ip1][j]);
var vnormals1 =
[Normals[i][j], Normals[i][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
i * ny + j,
i * ny + jp1,
ip1 * ny + j,
vnormals1
));
geom.vertices.push(Vertices[i][jp1]);
geom.vertices.push(Vertices[ip1][jp1]);
geom.vertices.push(Vertices[ip1][j]);
var vnormals2 =
[Normals[i][jp1], Normals[ip1][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
i * ny + jp1,
ip1 * ny + jp1,
ip1 * ny + j,
vnormals2
));
}
}
var torusMesh = new THREE.Mesh(
geom,
new THREE.MeshNormalMaterial({ wireframe: false }));
// three js scene -------------------------------------------------
var scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(50, aspect, 1, 10000);
camera.position.z = 30;
scene.add(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var object = new THREE.Object3D();
object.add(torusMesh);
object.add(cloud);
scene.add(object);
renderer.render(scene, camera);
// animation ---------------------------------------------------------
var isDragging = false;
var previousMousePosition = {
x: 0,
y: 0
};
$(renderer.domElement).on('mousedown', function (e) {
isDragging = true;
}).on('mousemove', function (e) {
var deltaMove = {
x: e.offsetX - previousMousePosition.x,
y: e.offsetY - previousMousePosition.y
};
if (isDragging) {
var deltaRotationQuaternion = new THREE.Quaternion()
.setFromEuler(new THREE.Euler(
Math.PI / 180 * (deltaMove.y * 1),
Math.PI / 180 * (deltaMove.x * 1),
0,
'XYZ'
));
object.quaternion.multiplyQuaternions(deltaRotationQuaternion,
object.quaternion);
}
previousMousePosition = {
x: e.offsetX,
y: e.offsetY
};
});
$(document).on('mouseup', function (e) {
isDragging = false;
});
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function render() {
renderer.render(scene, camera);
requestAnimFrame(render);
}
render();
canvas {
width: 100%;
height: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
I think there were two problems with your code:
When using Geometry, you define faces just by adding objects of type Face3 to the faces array. The vertices of the geometry are defined just once. In your case, you can just do this:
geom.vertices = dotGeometry.vertices;
Besides, the winding order of your faces was not correct. You have to switch the first and third index.
// the vertices of the mesh and the vertex normals ----------------
var nx = 64;
var ny = 32;
var R = 10; var r = 3;
var Vertices = new Array(nx);
var Normals = new Array(nx);
for (var i = 0; i < nx; i++) {
Vertices[i] = new Array(ny);
Normals[i] = new Array(ny);
var u = i / nx * 2 * Math.PI;
var cos_u = Math.cos(u);
var sin_u = Math.sin(u);
var cx = R * cos_u;
var cy = R * sin_u;
for (var j = 0; j < ny; j++) {
var v = j / ny * 2 * Math.PI;
var rcos_v = r * Math.cos(v);
var rsin_v = r * Math.sin(v);
Vertices[i][j] = new THREE.Vector3(
cx + rcos_v * cos_u,
cy + rcos_v * sin_u,
rsin_v
);
Normals[i][j] = new THREE.Vector3(
rcos_v * cos_u,
rcos_v * sin_u,
rsin_v
);
}
}
// vertices as a dot cloud ----------------------------------------
var dotGeometry = new THREE.Geometry();
for (var i = 0; i < nx; i++) {
for (var j = 0; j < ny; j++) {
dotGeometry.vertices.push(Vertices[i][j]);
}
}
var dotMaterial =
new THREE.PointsMaterial({ size: 1, sizeAttenuation: false });
var cloud = new THREE.Points(dotGeometry, dotMaterial);
// mesh -----------------------------------------------------------
var geom = new THREE.Geometry();
geom.vertices = dotGeometry.vertices;
for (var i = 0; i < nx; i++) {
var ip1 = (i == nx - 1 ? 0 : i + 1);
for (var j = 0; j < ny; j++) {
var jp1 = (j == ny - 1 ? 0 : j + 1);
var vnormals1 =
[Normals[i][j], Normals[i][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
ip1 * ny + j,
i * ny + jp1,
i * ny + j,
vnormals1
));
var vnormals2 =
[Normals[i][jp1], Normals[ip1][jp1], Normals[ip1][j]];
geom.faces.push(new THREE.Face3(
ip1 * ny + j,
ip1 * ny + jp1,
i * ny + jp1,
vnormals2
));
}
}
var torusMesh = new THREE.Mesh(
geom,
new THREE.MeshNormalMaterial({ wireframe: false }));
// three js scene -------------------------------------------------
var scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(50, aspect, 1, 10000);
camera.position.z = 30;
scene.add(camera);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var object = new THREE.Object3D();
object.add(torusMesh);
object.add(cloud);
scene.add(object);
renderer.render(scene, camera);
// animation ---------------------------------------------------------
var isDragging = false;
var previousMousePosition = {
x: 0,
y: 0
};
$(renderer.domElement).on('mousedown', function (e) {
isDragging = true;
}).on('mousemove', function (e) {
var deltaMove = {
x: e.offsetX - previousMousePosition.x,
y: e.offsetY - previousMousePosition.y
};
if (isDragging) {
var deltaRotationQuaternion = new THREE.Quaternion()
.setFromEuler(new THREE.Euler(
Math.PI / 180 * (deltaMove.y * 1),
Math.PI / 180 * (deltaMove.x * 1),
0,
'XYZ'
));
object.quaternion.multiplyQuaternions(deltaRotationQuaternion,
object.quaternion);
}
previousMousePosition = {
x: e.offsetX,
y: e.offsetY
};
});
$(document).on('mouseup', function (e) {
isDragging = false;
});
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
function render() {
renderer.render(scene, camera);
requestAnimFrame(render);
}
render();
canvas {
width: 100%;
height: 100%
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/98/three.js"></script>
<script
src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
crossorigin="anonymous"></script>
Besides, consider to use the approach of TorusBufferGeometry. Moreover, it's much faster to generate a geometry with BufferGeometry than with Geometry.
I started my first Three.js project. A solar system which you can see here.
I have a function addCelestrialObject() where I create the planets and I want this function to automatically create the orbit circles what it does for the planets but I want it also for moons.
So every Planet (mesh) becomes a name and I want to access this object to get its center position so I can add a circle to this position if I have a moon.
My problem is that the function scene.getObjectByName(parent,true); always delivers an undefined. You can see the console.log(scene) on my example when you inspect the site.
function addCelestrialObject(name, type, parent, surface, bump, specular,
positionX, positionY, positionZ, size, clouds, drawcircle
) {
var loader = new THREE.TextureLoader();
var group = new THREE.Group();
loader.load(surface, function (texture) {
var geometry = new THREE.SphereGeometry(size, 32, 32);
if (type == "sun") {
var material = new THREE.MeshBasicMaterial({ map: texture });
material.shading = true;
} else {
var material = new THREE.MeshPhongMaterial({ map: texture, overdraw: 0.5 });
material.shading = true;
if (bump) {
material.bumpMap = THREE.ImageUtils.loadTexture(bump);
material.bumpScale = 0.5;
}
if (specular) {
material.specularMap = THREE.ImageUtils.loadTexture(specular);
material.specular = new THREE.Color(0x222222);
}
}
var mesh = new THREE.Mesh(geometry, material);
mesh.name = name;
mesh.position.x = positionX;
mesh.position.y = positionY;
mesh.position.z = positionZ;
objectControls.add(mesh);
mesh.select = function () {
var position = { x: controls.target.x, y: controls.target.y, z: controls.target.z };
var target = { x: this.position.x, y: this.position.y, z: this.position.z };
var tween = new TWEEN.Tween(position).to(target, 500);
tween.easing(TWEEN.Easing.Exponential.InOut)
tween.onUpdate(function () {
controls.target.x = position.x;
controls.target.y = position.y;
controls.target.z = position.z;
controls.dollyIn(2);
});
tween.start();
controls.minDistance = size * 5;
}
onRenderFcts.push(function (delta, now) {
mesh.rotateY(1 / 32 * delta)
});
group.add(mesh);
});
if (clouds == true) {
var canvasResult = document.createElement('canvas')
canvasResult.width = 1024
canvasResult.height = 512
var contextResult = canvasResult.getContext('2d')
// load earthcloudmap
var imageMap = new Image();
imageMap.addEventListener("load", function () {
// create dataMap ImageData for earthcloudmap
var canvasMap = document.createElement('canvas')
canvasMap.width = imageMap.width
canvasMap.height = imageMap.height
var contextMap = canvasMap.getContext('2d')
contextMap.drawImage(imageMap, 0, 0)
var dataMap = contextMap.getImageData(0, 0, canvasMap.width, canvasMap.height)
// load earthcloudmaptrans
var imageTrans = new Image();
imageTrans.addEventListener("load", function () {
// create dataTrans ImageData for earthcloudmaptrans
var canvasTrans = document.createElement('canvas')
canvasTrans.width = imageTrans.width
canvasTrans.height = imageTrans.height
var contextTrans = canvasTrans.getContext('2d')
contextTrans.drawImage(imageTrans, 0, 0)
var dataTrans = contextTrans.getImageData(0, 0, canvasTrans.width, canvasTrans.height)
// merge dataMap + dataTrans into dataResult
var dataResult = contextMap.createImageData(canvasMap.width, canvasMap.height)
for (var y = 0, offset = 0; y < imageMap.height; y++) {
for (var x = 0; x < imageMap.width; x++, offset += 4) {
dataResult.data[offset + 0] = dataMap.data[offset + 0]
dataResult.data[offset + 1] = dataMap.data[offset + 1]
dataResult.data[offset + 2] = dataMap.data[offset + 2]
dataResult.data[offset + 3] = 255 - dataTrans.data[offset + 0]
}
}
// update texture with result
contextResult.putImageData(dataResult, 0, 0)
material.map.needsUpdate = true;
})
imageTrans.src = 'textures/earthcloudmaptrans.jpg';
}, false);
imageMap.src = 'textures/earthcloudmap.jpg';
var geometry = new THREE.SphereGeometry(size + 0.5, 32, 32)
var material = new THREE.MeshPhongMaterial({
map: new THREE.Texture(canvasResult),
side: THREE.DoubleSide,
transparent: true,
opacity: 1,
shading: true,
})
var cloudMesh = new THREE.Mesh(geometry, material);
cloudMesh.position.x = positionX;
cloudMesh.position.y = positionY;
cloudMesh.position.z = positionZ;
group.add(cloudMesh);
onRenderFcts.push(function (delta, now) {
cloudMesh.rotateY(1 / 16 * delta)
});
}
if (drawcircle == true) {
//circle
var radius = Math.abs(distance(0, positionX, 0, positionZ));
segments = 64;
materialLine = new THREE.LineBasicMaterial({ color: 0x00a8ff });
geometry = new THREE.CircleGeometry(radius, segments);
// Remove center vertex
geometry.vertices.shift();
circle = new THREE.Line(geometry, materialLine);
circle.rotation.x = 1.571;
if (parent) {
var object = scene.getObjectByName(parent, true);
//circle.position.x=object.position.x;
//circle.position.y=object.position.y;
//circle.position.z=object.position.z;
}
group.add(circle);
}
scene.add(group);
}
I would like to set object at the end of sphere radius based on object.position.set (x,y,z)
In typical mathematic formula for coordinates of the point on sphere we have:
var x = radius * Math.cos(phi) * Math.cos(theta);
var y = radius * Math.cos(phi) * Math.sin(theta);
var z = radius * Math.cos(phi);
I use
var x = radius * Math.cos(angleZ) * Math.cos(angleX);
var y = radius * Math.cos(angleZ) * Math.sin(angleX);
var z = radius * Math.cos(angleZ);
I know that this is wrong becasue thete and phi are not this angles
How can i connect this 3 angles angleX, angleY, angleZ to transformt it to phi and theta
In Three js i have :
cylinderX.rotation.x = degToRad(angleX);
cylinderX.rotation.y = degToRad(angleY);
cylinderX.rotation.z = degToRad(angleZ);
degToRad - function which change deg to radians
where
angleX is angle between y plane and z plane
angleY is angle between z plane and x plane
angleZ is angle between x plane and y plane
phi and theta are difrrent angles becasue theta is angle between radius and plane
I run animation and position of object ( x,y,z) and itts location on sphere plane is wrong
How can i resolved this problem ?
To be more specific , here below is my code and example:
http://newdesignlive.neomedia.info/index.html
I would like to set this green cube at the end of this red cuboid when car is rotating in all angles on all axis x,y,z
In arrays : x[...], y[...], z[...] you have values of angles how car (object) is rotating on all axis (X, Y, Z);
I do not know how to connect angleX, angleZ, angleY to "phi" and "theta" to set "green cube" on correct position x,y,z depend on radius = 100 for example;
In animate.js here is all code I add it here bellow to
var container, stats, camera, scene, renderer, object;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
var angleX=0, angleY=0, angleZ=0, G=0;
var x; var y; var z;
var times = [];
x = ["0", "10", "20","30", "40", "50" ];
y = ["0", "20", "40","60", "70", "80" ];
z = ["0", "30", "60","90", "120", "150" ];
gX = ["1", "1.4", "0.7", "0.4", "1", "1.2", "0.5", "1.2", "1.4", "1.3", "1", "0.7" ];
gY = ["1", "2", "1", "2", "1", "2", "3", "1.2", "1.4", "1.3", "1", "2" ];
gZ = ["1", "2", "1", "2", "1", "2", "3", "1.2", "1.4", "1.3", "1", "2" ];
generateTimesForAngles();
generateTimesForG();
var currentTransform = 0;
var currentStep = 0;
var intervalTime = 20;
var intervalTimeG = 50
setInterval(transformAngleX,intervalTime);
setInterval(transformAngleY,intervalTime);
setInterval(transformAngleZ,intervalTime);
setInterval(transformGX,intervalTimeG);
setInterval(transformGY,intervalTimeG);
setInterval(transformGZ,intervalTimeG);
init();
animate();
function setVectorDirection (position, gValue)
{
var gValue = document.getElementById('g').value;
gValue = gValue*10;
var direction = document.getElementById("VectorDirection");
var position = direction.options[direction.selectedIndex].value;
var darkMaterial = new THREE.MeshBasicMaterial( { color: 0x222222 } );
var wireframeMaterial = new THREE.MeshBasicMaterial( { color: 0x222222, wireframe: true, transparent: true } ); var multiMaterial = [ darkMaterial, wireframeMaterial ];
var x;
var y;
x = 120 + gValue - gValue/2;
y = 110;
}
function init(objectfilename, materialfilename) {
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xDEDEDE, 1 );
container = document.createElement('div');
document.body.appendChild(container);
container.appendChild( renderer.domElement )
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.y = 200;
camera.position.z = 0;
camera.position.x = 400;
controls = new THREE.OrbitControls( camera );
controls.addEventListener( 'change', render );
scene = new THREE.Scene();
var gridHelper = new THREE.GridHelper( 500, 100 );
gridHelper.setColors(0xFFFFFF, 0xFFFFFF);
scene.add(gridHelper);
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var initColor = new THREE.Color( 0xFFFFFF );
var initTexture = THREE.ImageUtils.generateDataTexture( 1, 1, initColor );
var groundMaterial = new THREE.MeshPhongMaterial
(
{
color: 0xEDEDED,
specular: 0xEDEDED,
map: initTexture }
);
var groundTexture = THREE.ImageUtils.loadTexture
(
"red.jpg",
undefined,
function()
{
groundMaterial.map = groundTexture
}
);
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
groundTexture.repeat.set( 25, 25 );
groundTexture.anisotropy = 16;
var backgroundmesh = new THREE.Mesh( new THREE.PlaneGeometry( 20000, 20000 ), groundMaterial );
backgroundmesh.position.y = -200;
backgroundmesh.rotation.x = - Math.PI / 2;
backgroundmesh.receiveShadow = true;
scene.add( backgroundmesh );
setVectorDirection();
light = new THREE.DirectionalLight(0xffffff);
light.position.set(0, 100, 60);
light.castShadow = true;
light.shadowCameraLeft = -60;
light.shadowCameraTop = -60;
light.shadowCameraRight = 60;
light.shadowCameraBottom = 60;
light.shadowCameraNear = 1;
light.shadowCameraFar = 10000;
light.shadowBias = -.0001
light.shadowMapWidth = light.shadowMapHeight = 1024;
light.shadowDarkness = .7;
scene.add(light);
mesh1 = new THREE.Mesh( geometry, material );
mesh1.position.set(100,100,100);
scene.add( mesh1 );
var geometry;
loader = new THREE.JSONLoader();
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('gtare.jpg'),
colorAmbient: [0.480000026226044, 0.480000026226044, 0.480000026226044],
colorDiffuse: [0.480000026226044, 0.480000026226044, 0.480000026226044],
colorSpecular: [0.8999999761581421, 0.8999999761581421, 0.8999999761581421]
});
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
grotX = new THREE.Mesh( new THREE.CylinderGeometry( 0.4, 8, 8, 40, 1 ),new THREE.MeshBasicMaterial( { color: 0x458B00 } ));
cylinderX = new THREE.Mesh(new THREE.BoxGeometry(10,10,10)/*THREE.CylinderGeometry(4, 4, 300, 50, 50, false)*/,new THREE.MeshBasicMaterial( { color: 0x458B00 } ));
cylinderY = new THREE.Mesh(new THREE.BoxGeometry(10,10,10/*4, 4, 300, 50, 50, false*/),new THREE.MeshBasicMaterial( { color: 0x01C5BB } ));
cylinderZ = new THREE.Mesh(new THREE.BoxGeometry(10,200,10/*4, 4, 300, 50, 50, false*/),new THREE.MeshBasicMaterial( { color: 0xFF0000 } ));
scene.add(cylinderX);
scene.add(cylinderY);
scene.add(cylinderZ);
loader.load('car.js', function (geometry, materials) {
var material = new THREE.MeshLambertMaterial({
map: THREE.ImageUtils.loadTexture('gtare.jpg'),
colorAmbient: [0.480000026226044, 0.480000026226044, 0.480000026226044],
colorDiffuse: [0.480000026226044, 0.480000026226044, 0.480000026226044],
colorSpecular: [0.8999999761581421, 0.8999999761581421, 0.8999999761581421]
});
mesh = new THREE.Mesh( geometry, material );
mesh.receiveShadow = true;
scene.add(mesh);
render();
});
}
function degToRad(degrees) {
return degrees * Math.PI / 180.0;
}
function radToDeg(radians) {
return parseInt(radians * 180.0 / Math.PI);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
function generateTimesForAngles() {
var baseTime360 = 10000;
for(i=0;i<z.length-1;i++) {
var timeMiddle = 10000;
times.push(timeMiddle);
}
}
function generateTimesForG() {
var baseTimeallG = 5000;
for(i=0;i<g.length-1;i++) {
var timeMiddleG = 240;
times.push(timeMiddleG);
}
}
function transformGX() {
var steps = times[currentTransform] / intervalTime;
var singleStepGX = (gX[currentTransform+1]-gX[currentTransform]) / steps;
if(currentStep<steps) {
currentStep++;
GX = +gX[currentTransform] + (+currentStep * +singleStepGX);
} else if(currentTransform<times.length){
currentStep = 0;
currentTransform++;
GX = gX[currentTransform];
} else {
}
}
function transformGY() {
var steps = times[currentTransform] / intervalTime;
var singleStepGY = (gY[currentTransform+1]-gY[currentTransform]) / steps;
if(currentStep<steps) {
currentStep++;
GY = +gY[currentTransform] + (+currentStep * +singleStepGY);
} else if(currentTransform<times.length){
currentStep = 0;
currentTransform++;
GY = gY[currentTransform];
} else {
}
}
function transformGZ() {
var steps = times[currentTransform] / intervalTime;
var singleStepGZ = (gZ[currentTransform+1]-gZ[currentTransform]) / steps;
if(currentStep<steps) {
currentStep++;
GZ = +gZ[currentTransform] + (+currentStep * +singleStepGZ); // Pamiętaj o plusach!!!
} else if(currentTransform<times.length){
currentStep = 0;
currentTransform++;
GZ = gZ[currentTransform];
} else {
}
}
function transformAngleX() {
var steps = times[currentTransform] / intervalTime;
var singleStepAngle = (x[currentTransform+1]-x[currentTransform]) / steps;
if(currentStep<steps) {
currentStep++;
angleX = +x[currentTransform] + (+currentStep * +singleStepAngle);
} else if(currentTransform<times.length){
currentStep = 0;
currentTransform++;
angleX = x[currentTransform];
} else {
}
}
function transformAngleY() {
var steps = times[currentTransform] / intervalTime;
var singleStepAngle = (y[currentTransform+1]-y[currentTransform]) / steps;
if(currentStep<steps) {
currentStep++;
angleY = +y[currentTransform] + (+currentStep * +singleStepAngle);
} else if(currentTransform<times.length){
currentStep = 0;
currentTransform++;
angleY = y[currentTransform];
} else {
}
}
function transformAngleZ() {
var steps = times[currentTransform] / intervalTime;
var singleStepAngle = (z[currentTransform+1]-z[currentTransform]) / steps;
if(currentStep<steps) {
currentStep++;
angleZ = +z[currentTransform] + (+currentStep * +singleStepAngle); // Pamiętaj o plusach!!!
} else if(currentTransform<times.length){
currentStep = 0;
currentTransform++;
angleZ = z[currentTransform];
} else {
}
}
var i = 0;
function animate() {
i++;
requestAnimationFrame( animate );
var x = 100 * Math.sin(degToRad(angleX))* Math.cos(degToRad(angleY));
var y = 100 * Math.sin(degToRad(angleX))* Math.sin(degToRad(angleY));
var z = 100 * Math.cos(degToRad(angleX));
z = -z;
cylinderX.position.set(x,y,z);
cylinderY.position.set(0, 0, 0);
cylinderX.rotation.x = degToRad(angleX);
cylinderX.rotation.y = degToRad(angleY);
cylinderX.rotation.z = degToRad(angleZ);
cylinderZ.rotation.x = degToRad(angleX);
cylinderZ.rotation.y = degToRad(angleY);
cylinderZ.rotation.z = degToRad(angleZ-90);
mesh.rotation.x = degToRad(angleX);
mesh.rotation.y = degToRad(angleY);
mesh.rotation.z = degToRad(angleZ);
render();
}
//renderowanie obiektów
function render() {
renderer.render( scene, camera );
}
I think the easiest way is to add the object to a parent Object3D, and move the object the appropriate distance (radius of the sphere you want to match the surface of) on one of the x, y or z axis. Add the parent to the scene and position it on the centre of the sphere you want to match (the child object should now fall on the sphere where that intersects the axis you used). With that set up like this, you can rotate the parent to position your object on the sphere.
I am making a go of three.js and cannon.js, but am stuck with being able to make walls solid, or anything solid that doesn't move and does hold the player back.
http://www.trepaning.com/3js/SEA3d/elvisCollideWalls.html
Here is the code I have thus far. Any insight appreciated. I prefer figuring stuff out on my own, but this one thing of making walls solid is holding me back at the moment, and I appreciate any info to get me over this hump.
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var initScene;
var MARGIN = 10;
var MARGINSIDE = 0;
var WIDTH = window.innerWidth || ( 2 + 2 * MARGINSIDE );
//var WIDTH = window.innerWidth/3 || ( 2 + 2 * MARGINSIDE );
//var HEIGHT = window.innerHeight/3 || ( 2 + 2 * MARGIN );
var HEIGHT = window.innerHeight || ( 2 + 2 * MARGIN );
var SCREEN_WIDTH = WIDTH -2 * MARGINSIDE;
var SCREEN_HEIGHT = HEIGHT -2 * MARGIN;
var FAR = 10000;
var DAY = 0;
var stats, camera, scene, renderer;
var mesh, geometry;
var sunLight, pointLight, ambientLight, hemiLight;
var parameters
var clock = new THREE.Clock();
var inRender = true;
var inResize = false;
// cannon physics
var world;
var worldScale = 100;
var timeStep = 1/60;
var walls=[], balls=[], ballMeshes=[], boxes=[], boxMeshes=[];
var solidMaterial;
var playerMaterialPhy;
var playerRigid;
var playerPhysicsMesh;
var UNITSIZE = 250
var WALLHEIGHT = UNITSIZE / 3;
var map = [ // 1 2 3 4 5 6 7 8 9
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], // 0
[1, 1, 0, 0, 0, 0, 0, 1, 1, 1,], // 1
[1, 1, 0, 0, 2, 0, 0, 0, 0, 1,], // 2
[1, 0, 0, 1, 0, 2, 0, 0, 0, 1,], // 3
[1, 0, 0, 2, 0, 0, 2, 1, 0, 1,], // 4
[1, 0, 0, 0, 2, 0, 0, 0, 0, 1,], // 5
[1, 1, 1, 0, 0, 0, 0, 0, 1, 1,], // 6
[1, 1, 1, 0, 0, 0, 0, 0, 1, 1,], // 7
[1, 1, 1, 1, 1, 1, 0, 0, 1, 1,], // 8
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], // 9
], mapW = map.length, mapH = map[0].length;
// player
var loader;
var player;
var playerMaterial;
var playerMap = { map:undefined, normal:undefined};
var players=[];
var playerName = "LegoElvis";
var scaleFactor = 5;
var velocity = {x : 0, z : 0};
var playerControls = {
moveForward: false,
moveBackward: false,
moveLeft: false,
moveRight: false,
bodyOrientation: 0,
maxSpeed: 275,
maxReverseSpeed: -275,
frontAcceleration: 600,
backAcceleration: 600,
frontDecceleration: 600,
angularSpeed: 2.5,
speed: 0
};
var shadowConfig = {
Visible: false,
Near: 750,
Far: 4000,
Fov: 75,
Bias: -0.0002,
Darkness: 0.5,
Resolution:1024
};
var playerConfig = {
name: "",
loading: 0,
scale: 1,
CloneNumber: 30,
Clone: false
};
var LightConfig = {
Ambient: 0x554b3b,
Fog : 0x00283f
};
var MaterialConfig = {
shininess : 0,
specular: 1,
normalScaleX: 0,
normalScaleY: 0,
bias:0,
bumpScale: 2,
metal:false
};
var sky;
var skyCubeNight, skyCubeDay;
var skyShader;
initScene = function () {
// RENDERER
renderer = new THREE.WebGLRenderer( { clearColor: LightConfig.Fog, clearAlpha: 1, antialias: true } );
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
renderer.setClearColor( LightConfig.Fog, 1 );
renderer.domElement.style.position = "absolute";
document.getElementById( 'viewport' ).appendChild( renderer.domElement );
renderer.shadowMapEnabled = true;
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.physicallyBasedShading = true;
// SCENE
scene = new THREE.Scene();
scene.fog = new THREE.Fog( LightConfig.Fog , 1000, FAR );
// CAMERA
camera = new THREE.PerspectiveCamera( 45, SCREEN_WIDTH / SCREEN_HEIGHT, 2, FAR );
camera.position.set( 50, 300, 350 );
// CAMERA CONTROL
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.center.set( 0, 0, 0 );
controls.keys = [];
controls.maxPolarAngle = toRad(90);
controls.userRotateSpeed = 1.8;
controls.zoomSpeed = 1.6;
controls.userPanSpeed = 0.8;
// GROUND
var mapGround = THREE.ImageUtils.loadTexture( "images/legoElvis.jpg" );
mapGround.anisotropy = renderer.getMaxAnisotropy();
mapGround.repeat.set( 100, 100 );
mapGround.wrapS = mapGround.wrapT = THREE.RepeatWrapping;
mapGround.magFilter = THREE.NearestFilter;
mapGround.format = THREE.RGBFormat;
var groundMaterial = new THREE.MeshPhongMaterial( { shininess: 10, ambient: 0x444444, color: 0xffffff, specular: 0xffffff, map: mapGround, metal: false } );
var planeGeometry = new THREE.PlaneGeometry( 100, 100 );
var ground = new THREE.Mesh( planeGeometry, groundMaterial );
ground.position.set( 0, 0, 0 );
ground.rotation.x = - Math.PI / 2;
ground.scale.set( 1000, 1000, 1000 );
ground.receiveShadow = true;
scene.add( ground );
initLights();
initPhysics();
loadSea3dModel();
stats = new Stats();
document.getElementById('my-stat').appendChild(stats.domElement);
// LISTENERS
window.addEventListener( 'resize', onWindowResize, false );
document.addEventListener( 'keydown', onKeyDown, false );
document.addEventListener( 'keyup', onKeyUp, false );
// TWEEN
parameters = { control: 0 };
animate();
}
//-----------------------------------------------------
// LIGHT
//-----------------------------------------------------
function initLights() {
var sunIntensity = 0.8;
var pointIntensity = 0.3;
var pointColor = 0xffffff;
var skyIntensity = 1;
ambientLight = new THREE.AmbientLight( LightConfig.Ambient );
scene.add( ambientLight );
hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
hemiLight.color.setHSL( 0.63, 0.05, 0 );
hemiLight.groundColor.setHex( 0xe4c8a0 );
hemiLight.position.set( 0, 400, 0 );
scene.add( hemiLight );
pointLight = new THREE.PointLight( LightConfig.Moon, pointIntensity, 5000 );
pointLight.position.set( -1000, 0, -1000 );
scene.add( pointLight );
sunLight = new THREE.SpotLight( LightConfig.Sun, sunIntensity, 0, Math.PI/2, 1 );
sunLight.position.set( 1000, 2000, 1000 );
sunLight.castShadow = true;
sunLight.shadowCameraVisible = shadowConfig.Visible;
sunLight.shadowCameraNear = shadowConfig.Near;
sunLight.shadowCameraFar = shadowConfig.Far;
sunLight.shadowCameraFov = shadowConfig.Fov;
sunLight.shadowBias = shadowConfig.Bias;
sunLight.shadowDarkness = shadowConfig.Darkness * sunIntensity;
sunLight.shadowMapWidth = shadowConfig.Resolution;
sunLight.shadowMapHeight = shadowConfig.Resolution;
scene.add( sunLight );
}
function enableCascadeShadow() {
renderer.shadowMapCascade = true;
sunLight.shadowCascade = true;
sunLight.shadowCascadeCount = 3;
sunLight.shadowCascadeNearZ = [ -1.000, 0.995, 0.998 ];
sunLight.shadowCascadeFarZ = [ 0.995, 0.998, 1.000 ];
sunLight.shadowCascadeWidth = [ shadowConfig.Resolution, shadowConfig.Resolution, shadowConfig.Resolution ];
sunLight.shadowCascadeHeight = [ shadowConfig.Resolution, shadowConfig.Resolution, shadowConfig.Resolution ];
}
//-----------------------------------------------------
// RESIZE
//-----------------------------------------------------
function onWindowResize( event ) {
inResize = true;
//document.getElementById("viewport").style.background = '#222222';
SCREEN_WIDTH = window.innerWidth - 2 * MARGINSIDE;
SCREEN_HEIGHT = window.innerHeight - 2 * MARGIN;
camera.aspect = SCREEN_WIDTH / SCREEN_HEIGHT;
camera.updateProjectionMatrix();
renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
}
//-----------------------------------------------------
// KEYBOARD
//-----------------------------------------------------
function onKeyDown ( event ) {
switch ( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/
case 90: /*Z*/ playerControls.moveForward = true; break;
case 40: /*down*/
case 83: /*S*/ playerControls.moveBackward = true; break;
case 37: /*left*/
case 65: /*A*/
case 81: /*Q*/ playerControls.moveLeft = true; break;
case 39: /*right*/
case 68: /*D*/ playerControls.moveRight = true; break;
}
}
function onKeyUp ( event ) {
switch( event.keyCode ) {
case 38: /*up*/
case 87: /*W*/
case 90: /*Z*/ playerControls.moveForward = false; break;
case 40: /*down*/
case 83: /*S*/ playerControls.moveBackward = false; break;
case 37: /*left*/
case 65: /*A*/
case 81: /*Q*/ playerControls.moveLeft = false; break;
case 39: /*right*/
case 68: /*D*/ playerControls.moveRight = false; break;
}
};
//-----------------------------------------------------
// SEA3D
//-----------------------------------------------------
function loadSea3dModel() {
loader = new THREE.SEA3D( false );
//loader.matrixAutoUpdate = true;
//loader.invertCamera = true;
loader.onComplete = function( e ) {
player = loader.getMesh(playerName);
player.play("idle");
player.scale.set( playerConfig.scale*3, playerConfig.scale*3, -playerConfig.scale*3 );
scene.add( player );
creatPlayerPhysics();
};
//loader.load( 'folder/'+playerName+'.sea' );
loader.load( 'models/legoElvis.sea' );
}
// PLAYER ANIMATION
function updatePlayer(delta) {
if (playerControls.moveForward){
if (player.currentAnimation.name == "idle") player.play("walk");
} else if (playerControls.moveBackward){
if (player.currentAnimation.name == "idle") player.play("walk");
}
else {
if(player.currentAnimation.name == "walk") player.play("idle");
}
THREE.AnimationHandler.update( delta );
updatePlayerMove(delta);
}
// PLAYER MOVE
function updatePlayerMove( delta ) {
playerControls.maxReverseSpeed = -playerControls.maxSpeed;
if ( playerControls.moveForward ) playerControls.speed = THREE.Math.clamp( playerControls.speed + delta * playerControls.frontAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
if ( playerControls.moveBackward ) playerControls.speed = THREE.Math.clamp( playerControls.speed - delta * playerControls.backAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
// orientation based on controls
// (don't just stand while turning)
var dir = 1;
if ( playerControls.moveLeft ) {
playerControls.bodyOrientation += delta * playerControls.angularSpeed;
playerControls.speed = THREE.Math.clamp( playerControls.speed + dir * delta * playerControls.frontAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
}
if ( playerControls.moveRight ) {
playerControls.bodyOrientation -= delta * playerControls.angularSpeed;
playerControls.speed = THREE.Math.clamp( playerControls.speed + dir * delta * playerControls.frontAcceleration, playerControls.maxReverseSpeed, playerControls.maxSpeed );
}
// speed decay
if ( ! ( playerControls.moveForward || playerControls.moveBackward ) ) {
if ( playerControls.speed > 0 ) {
var k = exponentialEaseOut( playerControls.speed / playerControls.maxSpeed );
playerControls.speed = THREE.Math.clamp( playerControls.speed - k * delta * playerControls.frontDecceleration, 0, playerControls.maxSpeed );
} else {
var k = exponentialEaseOut( playerControls.speed / playerControls.maxReverseSpeed );
playerControls.speed = THREE.Math.clamp( playerControls.speed + k * delta * playerControls.backAcceleration, playerControls.maxReverseSpeed, 0 );
}
}
// displacement
var forwardDelta = playerControls.speed * delta;
velocity.x = Math.sin( playerControls.bodyOrientation ) * forwardDelta;
velocity.z = Math.cos( playerControls.bodyOrientation ) * forwardDelta;
player.position.x += velocity.x;
player.position.z += velocity.z;
player.position.y = playerConfig.scale*scaleFactor;
// steering
player.rotation.y = playerControls.bodyOrientation;
if(controls){
//controls.target.set( player.position.x, player.position.y, player.position.z );
camera.position.x += velocity.x;
camera.position.z += velocity.z;
controls.center.set( player.position.x, player.position.y, player.position.z );
}
if(playerRigid){
//playerRigid.position.set(player.position.x, player.position.y+3, player.position.z );
playerRigid.position.set(player.position.x, player.position.y+80, player.position.z+15 );
playerRigid.quaternion.setFromAxisAngle(new CANNON.Vec3(0,1,0),player.rotation.y);
}
};
function exponentialEaseOut( k ) { return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1; };
//-----------------------------------------------------
// RENDER LOOP
//-----------------------------------------------------
function animate() {
requestAnimationFrame( animate );
if(inRender || inResize){
//if(isPad)PadTest();
//updateCamera();
var delta = clock.getDelta();
if(player!=null)updatePlayer(delta);
updatePhysics();
render();
stats.update();
}
inResize = false;
}
function render() {
TWEEN.update();
controls.update();
scene.fog.color.setHSL( 0.63, 0.05, parameters.control );
renderer.setClearColor( scene.fog.color, 1 );
pointLight.intensity = - parameters.control * 0.5 + 1;
hemiLight.color.setHSL( 0.63, 0.05, parameters.control )
sunLight.shadowDarkness = shadowConfig.Darkness * sunLight.intensity;
renderer.render( scene, camera );
}
function tell(s){
document.getElementById("debug").innerHTML = s;
}
//-----------------------------------------------------
// PHYSICS
//-----------------------------------------------------
function initPhysics() {
world = new CANNON.World();
world.quatNormalizeSkip = 0;
world.quatNormalizeFast = false;
var solver = new CANNON.GSSolver();
world.defaultContactMaterial.contactEquationStiffness = 1e9;
world.defaultContactMaterial.contactEquationRegularizationTime = 4;
solver.iterations = 3;
solver.tolerance = 0.1;
world.gravity.set(0,-9.82*worldScale,0);//world.gravity.set(0,-9.82,0); // m/s²
world.broadphase = new CANNON.NaiveBroadphase();
// Create a slippery material (friction coefficient = 0.0)
physicsMaterial = new CANNON.Material("slipperyMaterial");
solidMaterial = new CANNON.Material("solidMaterial");
playerMaterialPhy = new CANNON.Material("playerMat");
var physicsContactMaterial = new CANNON.ContactMaterial(physicsMaterial, physicsMaterial, 0.0, 0.3 );
var playerContactMaterial = new CANNON.ContactMaterial(playerMaterialPhy, playerMaterialPhy, 0.0, 0.3 );
var solidContactMaterial = new CANNON.ContactMaterial(solidMaterial, solidMaterial, 0.2, 0.6 );
world.addContactMaterial(physicsContactMaterial);
world.addContactMaterial(playerContactMaterial);
world.addContactMaterial(solidContactMaterial);
// Create infinie plane
var groundShape = new CANNON.Plane();
var groundBody = new CANNON.RigidBody(0,groundShape,physicsMaterial);
groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0),-Math.PI/2);
world.add(groundBody);
createBoxeObject();
createBallObject();
}
function creatPlayerPhysics() {
if(playerPhysicsMesh){
scene.remove(playerPhysicsMesh);
playerPhysicsMesh.geometry.dispose();
}
if(playerRigid)world.remove(playerRigid);
//player body
var halfExtents = new CANNON.Vec3(0.5*worldScale,playerConfig.scale*80, 0.25*worldScale);
var playerShape = new CANNON.Box(halfExtents);
playerRigid = new CANNON.RigidBody(0,playerShape, playerMaterialPhy);
world.add(playerRigid);
playerRigid.linearDamping=0.01;
playerRigid.angularDamping=0.01;
var boxGeometry = new THREE.CubeGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2);
playerPhysicsMesh = new THREE.Mesh( boxGeometry );
scene.add(playerPhysicsMesh);
playerPhysicsMesh.useQuaternion = true;
playerPhysicsMesh.castShadow = false;
playerPhysicsMesh.receiveShadow = false;
showPlayerPhysics();
}
function showPlayerPhysics() {
//if(OptionConfig.ShowPlayerHitBox)playerPhysicsMesh.visible = true;
//else playerPhysicsMesh.visible = true;
playerPhysicsMesh.visible = true;
}
function createBallObject() {
var s = worldScale;
var mat = new THREE.MeshLambertMaterial( { color: 0xdddddd } );
var radius;
var mass = 4;
var sphereShape;
for(var i=0; i<5; i++){
radius = (0.2+(Math.random()*0.8))*s;
sphereShape = new CANNON.Sphere(radius);
ballGeometry = new THREE.SphereGeometry(radius, 32, 32 );
var sphereBody = new CANNON.RigidBody(mass,sphereShape,physicsMaterial);
//sphereBody.linearDamping = 0.9;
var x = ((Math.random()-0.5)*20)*s;
var y = (1 + (Math.random()-0.5)*1)*s;
var z = ((Math.random()-0.5)*20)*s;
sphereBody.position.set(x,y,z);
sphereBody.linearDamping=0.03;
sphereBody.angularDamping=0.03;
world.add(sphereBody);
var ballMesh = new THREE.Mesh( ballGeometry, mat );
scene.add(ballMesh);
ballMesh.useQuaternion = true;
ballMesh.castShadow = true;
ballMesh.receiveShadow = true;
// add to array
balls.push(sphereBody);
ballMeshes.push(ballMesh);
}
}
function createBoxeObject() {
var s = worldScale;
var material = new THREE.MeshLambertMaterial( { color: 0x222222 } );
// Add boxes
var sx, xy, xz;
var halfExtents = new CANNON.Vec3(1*s,1*s,1*s);
var boxShape = new CANNON.Box(halfExtents);
var boxGeometry = new THREE.CubeGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2);
for(var i=0; i<5; i++){
sx= 0.2+(Math.random()*0.8);
sy= 0.2+(Math.random()*0.8);
sz= 0.2+(Math.random()*0.8);
halfExtents = new CANNON.Vec3(sx*s,sy*s,sz*s);
boxShape = new CANNON.Box(halfExtents);
boxGeometry = new THREE.CubeGeometry(halfExtents.x*2,halfExtents.y*2,halfExtents.z*2);
var x = ((Math.random()-0.5)*20)*s;
var y = (1 + (Math.random()-0.5)*1)*s;
var z = ((Math.random()-0.5)*20)*s;
var boxBody = new CANNON.RigidBody(9,boxShape, solidMaterial);
var boxMesh = new THREE.Mesh( boxGeometry, material );
world.add(boxBody);
scene.add(boxMesh);
boxBody.position.set(x,y,z);
//boxMesh.position.set(x,y,z);
boxBody.quaternion.setFromAxisAngle(new CANNON.Vec3(0,0,0),toRad(Math.random()*360));
boxMesh.castShadow = true;
boxMesh.receiveShadow = true;
boxMesh.useQuaternion = true;
boxes.push(boxBody);
boxMeshes.push(boxMesh);
}
function createObstacle() {
obstacleMesh = new THREE.CubeGeometry(150, 50, 50)
obstacleMaterial = new THREE.MeshLambertMaterial( { color: 0x666666 } );
obstacleObject = new THREE.Mesh(obstacleMesh, obstacleMaterial);
obstacleObject.position.set(0, 26, 200);
obstacleObject.castShadow = true;
obstacleObject.receiveShadow = true;
scene.add(obstacleObject);
}
createObstacle();
function setupScene() {
var units = mapW;
// Geometry: walls
var cube = new THREE.CubeGeometry(UNITSIZE, WALLHEIGHT, UNITSIZE);
var materials = [
new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture('images/legoElvisR.jpg')}), //wall 1
new THREE.MeshLambertMaterial({map: THREE.ImageUtils.loadTexture('images/legoElvisG.jpg')}), //wall 2
];
for (var i = 0; i < mapW; i++) {
for (var j = 0, m = map[i].length; j < m; j++) {
if (map[i][j]) {
var wall = new THREE.Mesh(cube, materials[map[i][j]-1]);
wall.position.x = (i - units/2) * UNITSIZE;
wall.position.y = WALLHEIGHT/2;
wall.position.z = (j - units/2) * UNITSIZE;
wall.castShadow = true;
wall.receiveShadow = true;
scene.add(wall);
}
}
}
}
setupScene();
// Add linked boxes
var size = 0.5*s;
var he = new CANNON.Vec3(size,size,size*0.1);
var boxShape = new CANNON.Box(he);
var mass = 0;
var space = 0.1*size;
var N=5, last;
var boxGeometry = new THREE.CubeGeometry(he.x*2,he.y*2,he.z*2);
for(var i=0; i<N; i++){
var boxbody = new CANNON.RigidBody(mass,boxShape, solidMaterial);
var boxMesh = new THREE.Mesh( boxGeometry, material );
boxbody.position.set(5*s,((N-i)*(size*2+2*space) + size*2+space)-150,0);
boxbody.linearDamping=0.01;
boxbody.angularDamping=0.01;
boxMesh.useQuaternion = true;
boxMesh.castShadow = true;
boxMesh.receiveShadow = true;
world.add(boxbody);
scene.add(boxMesh);
boxes.push(boxbody);
boxMeshes.push(boxMesh);
if(i!=0){
// Connect this body to the last one
var c1 = new CANNON.PointToPointConstraint(boxbody,new CANNON.Vec3(-size,size+space,0),last,new CANNON.Vec3(-size,-size-space,0));
var c2 = new CANNON.PointToPointConstraint(boxbody,new CANNON.Vec3(size,size+space,0),last,new CANNON.Vec3(size,-size-space,0));
world.addConstraint(c1);
world.addConstraint(c2);
} else {
mass=0.3;
}
last = boxbody;
}
}
function updatePhysics() {
if(!world) return;
world.step(timeStep);
// update player mesh test
if(playerRigid !== undefined){
playerRigid.position.copy(playerPhysicsMesh.position);
playerRigid.quaternion.copy(playerPhysicsMesh.quaternion);
}
// Update ball positions
for(var i=0; i<balls.length; i++){
balls[i].position.copy(ballMeshes[i].position);
balls[i].quaternion.copy(ballMeshes[i].quaternion);
}
// Update box positions
for(var i=0; i<boxes.length; i++){
boxes[i].position.copy(boxMeshes[i].position);
boxes[i].quaternion.copy(boxMeshes[i].quaternion);
}
}
//-----------------------------------------------------
// MATH
//-----------------------------------------------------
function toRad(Value) {
return Value * Math.PI / 180;
}
window.onload = initScene;
When you update your physics in updatePlayerMove, you set the position of the corresponding Cannon.js body. This body will never have a chance to update its position by itself since you override its position all the time.
Setting the position of bodies like this makes the physics unstable. You'll get large and buggy overlaps. And, of course, the player will be able to walk through walls.
Try controlling the player body via velocity instead. Cannon.js will then provide the response on the player for you, and the physics will become stable:
playerRigid.velocity.set(vx,vy,vz);