I'm trying to create a simple app where I can move a cube either left or right. I've got that part figured out. Now I'm trying to make it so that the cube cannot leave the plane. What's the easiest way to go about this?
Below is the code I currently have.
<html>
<head>
<title>Time Car</title>
<style>
body {
width: 100%;
height: 100%;
margin: 0;
padding 0;
}
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/Detector.js"></script>
<script>
var scene, camera, renderer, object, raycaster, board1, board2, board3, board4;
var vy = 0,
vx = 0,
direction = "",
gravity = 0.3;
function init() {
if (!Detector.webgl) Detector.addGetWebGLMessage();
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0xCCFFFF);
document.body.appendChild(renderer.domElement);
var light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(1, 1, 1).normalize();
scene.add(light);
var light = new THREE.DirectionalLight(0xffffff);
light.position.set(-1, -1, -1).normalize();
scene.add(light);
var geometry = new THREE.BoxGeometry(20, 10, 10);
object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0x3333FF
}));
scene.add(object);
var geometry = new THREE.BoxGeometry(80, 160, 10);
board1 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xCC0000
}));
board1.position.set(0, 0, -200);
scene.add(board1);
var geometry = new THREE.BoxGeometry(80, 160, 10);
board2 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xCC0000
}));
board2.position.set(400, 0, -200);
scene.add(board2);
var geometry = new THREE.BoxGeometry(80, 160, 10);
board3 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xCC0000
}));
board3.position.set(800, 0, -200);
scene.add(board3);
var geometry = new THREE.BoxGeometry(80, 160, 10);
board4 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xCC0000
}));
board4.position.set(1200, 0, -200);
scene.add(board4);
geometry = new THREE.PlaneGeometry(5000, 800, 800);
var plane = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0x99FF66
}));
plane.rotation.x = -Math.PI / 2;
plane.position.set(0, -20, 0);
scene.add(plane);
camera.position.set(0, 100, 100);
raycaster = new THREE.Raycaster();
raycaster.ray.direction.set(0, -1, 0);
render();
}
function render() {
requestAnimationFrame(render);
if (direction == "left") {
vx = -2;
}
if (direction == "right") {
vx = 2;
}
object.position.x += vx;
vx = vx * 0.95;
camera.lookAt(object.position);
camera.position.x += (((object.position.x - 20) - camera.position.x)) * 0.03;
camera.position.y += (((object.position.y + 50) - camera.position.y));
renderer.render(scene, camera);
}
window.addEventListener('keydown', function (e) {
switch (e.keyCode) {
case 65: //left
direction = "left";
break;
break;
case 68: //right
direction = "right";
break;
};
}, false);
window.addEventListener('keyup', function (e) {
switch (e.keyCode) {
case 65: //left
direction = "";
break;
case 68: //right
direction = "";
break;
};
}, false);
init();
</script>
</body>
</html>
If I got you right. You set the plane as
geometry = new THREE.PlaneGeometry(5000, 800, 800);
...
plane.position.set(0, -20, 0);
Here you can compute its bounding box
plane.geometry.computeBoundingBox();
Its size along x-axis is 5000 and you don't translate it along this axis, so plane.geometry.boundingBox.min.x is -2500, plane.geometry.boundingBox.max.x is 2500. Then in your animation loop you can check the object's position. Something like this
object.position.x += vx;
var objHalfWidth = object.geometry.parameters.width / 2;
if (object.position.x + objHalfWidth >= plane.geometry.boundingBox.max.x){
object.position.x = plane.geometry.boundingBox.max.x - objHalfWidth;
}
if (object.position.x - objHalfWidth <= plane.geometry.boundingBox.min.x){
object.position.x = plane.geometry.boundingBox.min.x + objHalfWidth;
}
Related
I discovered three.js which I love to use now, but I built a rotating car animation with keyboard arrows to control it, but I can't find out how to make a sliding animation (e.g.,
-> -> ->
) Instead of a rotation animation. I tried searching but I don't even know how to explain it other than a sliding animation. Does someone know how / if you can do this?
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ThreeJS Animation</title>
<style>
body {
margin: 0;
font-weight: 100;
float: none;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script src="https://threejs.org/build/three.js"></script>
<script>
let carBottomColor = "#999";
let carTopColor = "#FFF";
let carWindowColor = "#666";
const scene = new THREE.Scene();
scene.background = new THREE.Color("#f1f1f1");
const car = createCar();
scene.add(car);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(200, 500, 300);
scene.add(dirLight);
const aspectRatio = window.innerWidth / window.innerHeight;
const cameraWidth = 300;
const cameraHeight = cameraWidth / aspectRatio;
const camera = new THREE.OrthographicCamera(
cameraWidth / -2, // left
cameraWidth / 2, // right
cameraHeight / 2, // top
cameraHeight / -2, // bottom
200, // near plane
800 // far plane
);
camera.position.set(200, 200, 200);
camera.lookAt(0, 10, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
let x = 0;
let y = 0;
let keydown = '';
document.body.addEventListener('keydown', e => {
keydown = e.key;
});
document.body.addEventListener('keyup', e => {
keydown = '';
});
const update = () => {
switch (keydown) {
case 'ArrowUp':
x -= 0.1;
car.rotation.x = x;
break;
case 'ArrowDown':
x += 0.1;
car.rotation.x = x;
break;
case 'ArrowLeft':
y -= 0.1;
car.rotation.y = y;
break;
case 'ArrowRight':
y += 0.1;
car.rotation.y = y;
break;
}
window.requestAnimationFrame(update);
}
window.requestAnimationFrame(update);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
document.body.appendChild(renderer.domElement);
function createCar() {
const car = new THREE.Group();
const backWheel = createWheels();
backWheel.position.y = 6;
backWheel.position.x = -18;
car.add(backWheel);
const frontWheel = createWheels();
frontWheel.position.y = 6;
frontWheel.position.x = 18;
car.add(frontWheel);
const main = new THREE.Mesh(
new THREE.BoxGeometry(60, 15, 30),
new THREE.MeshLambertMaterial({ color: carBottomColor })
);
main.position.y = 12;
car.add(main);
const carFrontTexture = getCarFrontTexture();
const carBackTexture = getCarFrontTexture();
const carRightSideTexture = getCarSideTexture();
const carLeftSideTexture = getCarSideTexture();
carLeftSideTexture.center = new THREE.Vector2(0.5, 0.5);
carLeftSideTexture.rotation = Math.PI;
carLeftSideTexture.flipY = false;
const cabin = new THREE.Mesh(new THREE.BoxGeometry(33, 12, 24), [
new THREE.MeshLambertMaterial({ map: carFrontTexture }),
new THREE.MeshLambertMaterial({ map: carBackTexture }),
new THREE.MeshLambertMaterial({ color: carTopColor }), // top
new THREE.MeshLambertMaterial({ color: carTopColor }), // bottom
new THREE.MeshLambertMaterial({ map: carRightSideTexture }),
new THREE.MeshLambertMaterial({ map: carLeftSideTexture })
]);
cabin.position.x = -6;
cabin.position.y = 25.5;
car.add(cabin);
return car;
}
function createWheels() {
const geometry = new THREE.BoxGeometry(12, 12, 33);
const material = new THREE.MeshLambertMaterial({ color: "#333" });
const wheel = new THREE.Mesh(geometry, material);
return wheel;
}
function getCarFrontTexture() {
const canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = 32;
const context = canvas.getContext("2d");
context.fillStyle = "#ffffff";
context.fillRect(0, 0, 64, 32);
context.fillStyle = carWindowColor || carBaseColor; // Wheel color
context.fillRect(8, 8, 48, 24);
return new THREE.CanvasTexture(canvas);
}
function getCarSideTexture() {
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 32;
const context = canvas.getContext("2d");
context.fillStyle = "#ffffff";
context.fillRect(0, 0, 128, 32);
context.fillStyle = carWindowColor || carBaseColor; // Wheel color
context.fillRect(10, 8, 38, 24);
context.fillRect(58, 8, 60, 24);
return new THREE.CanvasTexture(canvas);
}
</script>
</body>
</html>
I made some assumptions, but I think what you're trying to do is rotate the car along the y-axis when pressing left/right arrows, and you're trying to move the card forward when pressing up/down arrows. If that's the case, then you can do car.translateX() to create that forward/backward motion, and car.rotation.y to make the car turn.
Here's the modified example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ThreeJS Animation</title>
<style>
body {
margin: 0;
font-weight: 100;
float: none;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script src="https://threejs.org/build/three.js"></script>
<script>
let carBottomColor = "#999";
let carTopColor = "#FFF";
let carWindowColor = "#666";
const scene = new THREE.Scene();
scene.background = new THREE.Color("#f1f1f1");
const car = createCar();
scene.add(car);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(200, 500, 300);
scene.add(dirLight);
const aspectRatio = window.innerWidth / window.innerHeight;
const cameraWidth = 300;
const cameraHeight = cameraWidth / aspectRatio;
const camera = new THREE.OrthographicCamera(
cameraWidth / -2, // left
cameraWidth / 2, // right
cameraHeight / 2, // top
cameraHeight / -2, // bottom
200, // near plane
800 // far plane
);
camera.position.set(200, 200, 200);
camera.lookAt(0, 10, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.render(scene, camera);
let x = 0;
let y = 0;
let keydown = '';
document.body.addEventListener('keydown', e => {
e.preventDefault();
keydown = e.key;
});
document.body.addEventListener('keyup', e => {
keydown = '';
});
const update = () => {
switch (keydown) {
case 'ArrowUp':
car.translateX(1.0);
break;
case 'ArrowDown':
car.translateX(-1.0);
break;
case 'ArrowLeft':
y += 0.1;
car.rotation.y = y;
break;
case 'ArrowRight':
y -= 0.1;
car.rotation.y = y;
break;
}
window.requestAnimationFrame(update);
}
window.requestAnimationFrame(update);
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
document.body.appendChild(renderer.domElement);
function createCar() {
const car = new THREE.Group();
const backWheel = createWheels();
backWheel.position.y = 6;
backWheel.position.x = -18;
car.add(backWheel);
const frontWheel = createWheels();
frontWheel.position.y = 6;
frontWheel.position.x = 18;
car.add(frontWheel);
const main = new THREE.Mesh(
new THREE.BoxGeometry(60, 15, 30),
new THREE.MeshLambertMaterial({ color: carBottomColor })
);
main.position.y = 12;
car.add(main);
const carFrontTexture = getCarFrontTexture();
const carBackTexture = getCarFrontTexture();
const carRightSideTexture = getCarSideTexture();
const carLeftSideTexture = getCarSideTexture();
carLeftSideTexture.center = new THREE.Vector2(0.5, 0.5);
carLeftSideTexture.rotation = Math.PI;
carLeftSideTexture.flipY = false;
const cabin = new THREE.Mesh(new THREE.BoxGeometry(33, 12, 24), [
new THREE.MeshLambertMaterial({ map: carFrontTexture }),
new THREE.MeshLambertMaterial({ map: carBackTexture }),
new THREE.MeshLambertMaterial({ color: carTopColor }), // top
new THREE.MeshLambertMaterial({ color: carTopColor }), // bottom
new THREE.MeshLambertMaterial({ map: carRightSideTexture }),
new THREE.MeshLambertMaterial({ map: carLeftSideTexture })
]);
cabin.position.x = -6;
cabin.position.y = 25.5;
car.add(cabin);
return car;
}
function createWheels() {
const geometry = new THREE.BoxGeometry(12, 12, 33);
const material = new THREE.MeshLambertMaterial({ color: "#333" });
const wheel = new THREE.Mesh(geometry, material);
return wheel;
}
function getCarFrontTexture() {
const canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = 32;
const context = canvas.getContext("2d");
context.fillStyle = "#ffffff";
context.fillRect(0, 0, 64, 32);
context.fillStyle = carWindowColor || carBaseColor; // Wheel color
context.fillRect(8, 8, 48, 24);
return new THREE.CanvasTexture(canvas);
}
function getCarSideTexture() {
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 32;
const context = canvas.getContext("2d");
context.fillStyle = "#ffffff";
context.fillRect(0, 0, 128, 32);
context.fillStyle = carWindowColor || carBaseColor; // Wheel color
context.fillRect(10, 8, 38, 24);
context.fillRect(58, 8, 60, 24);
return new THREE.CanvasTexture(canvas);
}
</script>
</body>
</html>
I've created a 3D marquee by bending two meshes into a circle, however I'm having trouble getting them to center to the camera.
Please reference https://jsfiddle.net/siiiick/1jh49e1u/
var text = "EXPRESS FREE SHIPPING WORLDWIDE OVER 200€ / 200% 150$ ";
var geoParams = {
size: 208,
height: 1,
curveSegments: 4,
font: "junicode",
// bevelEnabled: false,
// bevelThickness: 1,
// bevelSize: 1,
}
var textMaterial = new THREE.MeshPhongMaterial({
color: 0x000000
});
var deg = Math.PI / 4.8;
var geoTop = new THREE.TextGeometry(text, geoParams);
var textTop = new THREE.Mesh(geoTop, textMaterial);
geoTop.computeBoundingBox();
textWidth = geoTop.boundingBox.max.x - geoTop.boundingBox.min.x;
controls.target.set(-textWidth * .1 - 10, 0, -textWidth / 3.8);
textTop.rotation.y = Math.PI;
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textTop.geometry);
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textTop.geometry);
textTop.position.set(-0.5 * textWidth + textWidth * .867, 0, -textWidth * .577);
var geoBot = new THREE.TextGeometry(text, geoParams);
var textBot = new THREE.Mesh(geoBot, textMaterial);
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textBot.geometry);
modifier.set(new THREE.Vector3(0, 0, -1), new THREE.Vector3(0, 1, 0), deg).modify(textBot.geometry);
textBot.position.set(-0.5 * textWidth, 0, 0);
scene.add(textTop);
scene.add(textBot);
As you can see after a few seconds the the marquee isn't centered. Do you think it's as a result of the camera positioning or the mesh positioning?
Thanks
//Testing some easy camera centering code...
var renderer = new THREE.WebGLRenderer();
var w = 300;
var h = 200;
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
45, // Field of view
w / h, // Aspect ratio
0.1, // Near
10000 // Far
);
camera.position.set(15, 10, 15);
camera.lookAt(scene.position);
controls = new THREE.OrbitControls(camera, renderer.domElement);
var light = new THREE.PointLight(0xFFFF00);
light.position.set(20, 20, 20);
scene.add(light);
var light1 = new THREE.AmbientLight(0x808080);
light1.position.set(20, 20, 20);
scene.add(light1);
var light2 = new THREE.PointLight(0x00FFFF);
light2.position.set(-20, 20, -20);
scene.add(light2);
var light3 = new THREE.PointLight(0xFF00FF);
light3.position.set(-20, -20, -20);
scene.add(light3);
var sphereGeom = new THREE.SphereGeometry(5, 16, 16);
var material = new THREE.MeshLambertMaterial({
color: 0x808080
});
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
var mesh1 = new THREE.Mesh(sphereGeom, material);
mesh1.position.x += 5;
mesh.add(mesh1);
var mesh2 = new THREE.Mesh(sphereGeom, material);
mesh2.position.y += 5;
mesh2.position.x += 9;
mesh.add(mesh2);
var grp0 = mesh;
var mesh = new THREE.Mesh(sphereGeom, material);
scene.add(mesh);
mesh.position.x += 30;
var mesh1 = new THREE.Mesh(sphereGeom, material);
mesh1.position.x += 15;
mesh.add(mesh1);
var mesh2 = new THREE.Mesh(sphereGeom, material);
mesh2.position.y += 12;
mesh2.position.x += 9;
mesh.add(mesh2);
renderer.setClearColor(0xdddddd, 1);
var grp1 = mesh;
var curGrp;
var targPos;
var targLook;
var tmp = new THREE.Vector3();
var vbox;
function focusCam(targ) {
const boundingBox = new THREE.Box3();
boundingBox.setFromObject(targ)
var center = boundingBox.getCenter(new THREE.Vector3())
var sz = boundingBox.getSize(new THREE.Vector3());
var minZ = sz.length() + camera.near;
var lookOffset = new THREE.Vector3(0, 0, 1);
lookOffset.applyQuaternion(camera.quaternion);
lookOffset.multiplyScalar(minZ)
targLook = center.clone();
targPos = new THREE.Vector3().copy(center).add(lookOffset)
if (!vbox) {
vbox = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), material.clone())
vbox.material.transparent = true;
vbox.material.opacity = 0.15;
scene.add(vbox)
}
vbox.scale.copy(sz);
vbox.position.copy(center);
}
renderer.domElement.onclick = (evt) => {
if (!curGrp) {
curGrp = grp0;
} else if (curGrp === grp0) {
curGrp = grp1
} else if (curGrp === grp1) {
curGrp = grp0
}
focusCam(curGrp);
}
(function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
if (targPos) {
tmp.copy(targPos).sub(camera.position).multiplyScalar(0.01)
if (tmp.length() > 0.01) {
camera.position.add(tmp)
controls.target.add(tmp);//copy(targLook);
//camera.lookAt(targLook);
} else targPos = undefined;
}
})();
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
Here is my code which has embedded html page in three.js . I want to click the html page and make a popup. So is there any way i can do that because i think ray casting can only be done to three.js elements and not the html one.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ADN CSS3D Demo</title>
<style>
body {
background-color: #ffffff;
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/renderers/CSS3DRenderer.js"></script>
<script>
var controls, camera, glScene, cssScene, glRenderer, cssRenderer;
///////////////////////////////////////////////////////////////////
// Creates WebGL Renderer
//
///////////////////////////////////////////////////////////////////
function createGlRenderer() {
var glRenderer = new THREE.WebGLRenderer({alpha:true});
glRenderer.setClearColor(0xECF8FF);
glRenderer.setPixelRatio(window.devicePixelRatio);
glRenderer.setSize(window.innerWidth, window.innerHeight);
glRenderer.domElement.style.position = 'absolute';
glRenderer.domElement.style.zIndex = 1;
glRenderer.domElement.style.top = 0;
return glRenderer;
}
///////////////////////////////////////////////////////////////////
// Creates CSS Renderer
//
///////////////////////////////////////////////////////////////////
function createCssRenderer() {
var cssRenderer = new THREE.CSS3DRenderer();
cssRenderer.setSize(window.innerWidth, window.innerHeight);
cssRenderer.domElement.style.position = 'absolute';
glRenderer.domElement.style.zIndex = 0;
cssRenderer.domElement.style.top = 0;
return cssRenderer;
}
///////////////////////////////////////////////////////////////////
// Creates plane mesh
//
///////////////////////////////////////////////////////////////////
function createPlane(w, h, position, rotation) {
var material = new THREE.MeshBasicMaterial({
color: 0x000000,
opacity: 0.0,
side: THREE.DoubleSide
});
var geometry = new THREE.PlaneGeometry(w, h);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = position.x;
mesh.position.y = position.y;
mesh.position.z = position.z;
mesh.rotation.x = rotation.x;
mesh.rotation.y = rotation.y;
mesh.rotation.z = rotation.z;
return mesh;
}
///////////////////////////////////////////////////////////////////
// Creates CSS object
//
///////////////////////////////////////////////////////////////////
function createCssObject(w, h, position, rotation, url) {
var html = [
'<div style="width:' + w + 'px; height:' + h + 'px;">',
'<iframe src="' + url + '" width="' + w + '" height="' + h + '">',
'</iframe>',
'</div>'
].join('\n');
var div = document.createElement('div');
$(div).html(html);
var cssObject = new THREE.CSS3DObject(div);
cssObject.position.x = position.x;
cssObject.position.y = position.y;
cssObject.position.z = position.z;
cssObject.rotation.x = rotation.x;
cssObject.rotation.y = rotation.y;
cssObject.rotation.z = rotation.z;
return cssObject;
}
///////////////////////////////////////////////////////////////////
// Creates 3d webpage object
//
///////////////////////////////////////////////////////////////////
function create3dPage(w, h, position, rotation, url) {
var plane = createPlane(
w, h,
position,
rotation);
glScene.add(plane);
var cssObject = createCssObject(
w, h,
position,
rotation,
url);
cssScene.add(cssObject);
}
///////////////////////////////////////////////////////////////////
// Creates material with random color
//
///////////////////////////////////////////////////////////////////
function createColoredMaterial() {
var material = new THREE.MeshBasicMaterial({
color: Math.floor(Math.random() * 16777215),
shading: THREE.FlatShading,
side: THREE.DoubleSide
});
return material;
}
///////////////////////////////////////////////////////////////////
// Creates 3D geometry to place in the scene
//
///////////////////////////////////////////////////////////////////
function create3dGeometry() {
var mesh1 = new THREE.Mesh(
new THREE.CylinderGeometry(0, 200, 300, 20, 4),
createColoredMaterial());
mesh1.position.x = 0;
mesh1.position.y = -300;
mesh1.position.z = 400;
glScene.add(mesh1);
var mesh2 = new THREE.Mesh(
new THREE.BoxGeometry(200, 200, 200),
createColoredMaterial());
mesh2.position.x = -300;
mesh2.position.y = -300;
mesh2.position.z = 400;
glScene.add(mesh2);
var mesh3 = new THREE.Mesh(
new THREE.SphereGeometry(100, 128, 128),
createColoredMaterial());
mesh3.position.x = 500;
mesh3.position.y = -300;
mesh3.position.z = 400;
glScene.add(mesh3);
}
///////////////////////////////////////////////////////////////////
// Initializes scene
//
///////////////////////////////////////////////////////////////////
function initialize() {
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
10000);
camera.position.set(0, 100, 3000);
controls = new THREE.TrackballControls(camera);
glRenderer = createGlRenderer();
cssRenderer = createCssRenderer();
//document.body.appendChild(glRenderer.domElement);
document.body.appendChild(cssRenderer.domElement);
cssRenderer.domElement.appendChild(glRenderer.domElement);
glScene = new THREE.Scene();
cssScene = new THREE.Scene();
var ambientLight = new THREE.AmbientLight(0x555555);
glScene.add(ambientLight);
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set( -.5, .5, -1.5 ).normalize();
glScene.add(directionalLight);
create3dPage(
1000, 1000,
new THREE.Vector3(-1050, 0, 400),
new THREE.Vector3(0, 45 * Math.PI / 180, 0),
'http://viewer.autodesk.io/node/ng-gallery/#/home');
create3dPage(
900, 1000,
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(0, 0, 0),
'http://adndevblog.typepad.com/cloud_and_mobile');
create3dPage(
1000, 1000,
new THREE.Vector3(1050, 0, 400),
new THREE.Vector3(0, -45 * Math.PI / 180, 0),
'http://mongo.autodesk.io');
create3dGeometry();
update();
}
///////////////////////////////////////////////////////////////////
// Updates scene
//
///////////////////////////////////////////////////////////////////
function update() {
controls.update();
glRenderer.render(glScene, camera);
cssRenderer.render(cssScene, camera);
requestAnimationFrame(update);
}
///////////////////////////////////////////////////////////////////
// On document ready
//
///////////////////////////////////////////////////////////////////
$(document ).ready(function() {
initialize();
});
</script>
</body>
</html>
I have tried raycasting using the description given on three.js site but the browser is not showing an results. Can somebody help me with my code
Okay. I'm clearly missing something here. I'm simply trying to get this code to cast shadows. I've turned on receive shadows and cast shadows for the cube and the floor but it still isn't showing. This shouldn't be this hard. I've used casting shadows before however I'm clearing missing something here. Any ideas would help. I'm at a loss because I know casting shadows isn't that hard. I must be missing something obvious.
Thanks in advance.
var camera, scene, renderer;
var RED = 0xff3300;
init();
render();
function init() {
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
-
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 15000);
camera.position.set(1000, 500, 1000);
camera.lookAt(new THREE.Vector3(0, 200, 0));
scene = new THREE.Scene();
scene.background = new THREE.Color(0xcccccc);
var light = new THREE.SpotLight(0xdddddd, 1);
light.position.set(50, 600, 50);
scene.add(light);
var coloredCube = createCube(100, 100, 100, 0, 300, 0, 0, RED);
coloredCube.castShadow = true;
coloredCube.receiveShadow = true;
scene.add(coloredCube);
//create floor
var planeFloor = createSizedPlane(1000, 1000);
planeFloor = preparePlaneForScene(planeFloor, Math.PI / -2, 0, 0, 0, 0, 0);
planeFloor.castShadow = true;
planeFloor.receiveShadow = true;
scene.add(planeFloor);
}
function render() {
renderer.render(scene, camera);
}
function createSizedPlane(xSize, zSize, numberOfSegments) {
var planeGeometry = new THREE.PlaneGeometry(xSize, zSize, numberOfSegments);
planeGeometry.receiveShadow = true;
planeGeometry.castShadow = true;
var material = new THREE.MeshStandardMaterial({
roughness: 0.8,
color: 0xffffff,
metalness: 0.2,
bumpScale: 0.0005,
opacity: 1, transparent: false
}
);
return new THREE.Mesh(planeGeometry, material);
}
function preparePlaneForScene(plane, xRotation, yRotation, zRotation, xPosition, yPosition, zPosition) {
plane.rotation.x = xRotation;
plane.rotation.y = yRotation;
plane.rotation.z = zRotation;
plane.position.x = xPosition;
plane.position.y = yPosition;
plane.position.z = zPosition;
return plane;
}
function createCube(xSize, ySize, zSize, xPosition, yPosition, zPosition, yRotation, color) {
var cubeGeometry = new THREE.BoxGeometry(xSize, ySize, zSize);
var cubeMaterial = new THREE.MeshLambertMaterial({color: color});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = xPosition;
cube.position.y = yPosition;
cube.position.z = zPosition;
cube.rotation.y = yRotation;
cube.castShadow = true;
cube.receiveShadow = true;
return cube;
}
Enable shadowMap for renderer and casting shadow for light:
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
spotLight.castShadow = true;
spotLight.shadow = new THREE.LightShadow(new THREE.PerspectiveCamera(60, 1, 1, 2500));
spotLight.shadow.bias = 0.0001;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
THREE.SpotLightShadow should work too.
For directional light you would need orthographic projection (or use THREE.DirectionalLightShadow).
Screenshot 1
Screenshot 2
I have some models(STL) turn to pure black while other models get color(from lights) correctly.
As you can see in Screenshot 1 and 2,the fighter got a nice color but the miku is totally black. It seems no light illuminates her or she behaves like being applied with black BasicMaterial.
The 2 models are applied with PhongMaterial. And I tried several combnations of lights with different position/type/parameter but it didn't work.
I'm sure about that the model of miku is normal. I just downloaded the fighter and miku from the same website,where they both displays with color. I also have some models which turn to pure black in my scene ,though they're normal STL model.
There must be some mistakes in my scene.
Here is my code:
<script>
var renderer;
function initThree() {
width = document.getElementById('canvas-frame').clientWidth;
height = document.getElementById('canvas-frame').clientHeight;
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(width, height);
document.getElementById('canvas-frame').appendChild(renderer.domElement);
}
var camera;
function initCamera() {
camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
camera.position.x = 50;
camera.position.y = 0;
camera.position.z = 0;
camera.lookAt({
x: 0,
y: 0,
z: 0
});
}
var scene;
function initScene() {
scene = new THREE.Scene();
}
//光源1
var light;
function initLight() {
light = new THREE.DirectionalLight(0xfefff7, 2.0, 0);
light.position.set(0, 500, 0);
scene.add(light);
}
//光源2
var light2;
function initLight2() {
light2 = new THREE.DirectionalLight(0x414141, 1.0, 0);
light2.position.set(0, -500, 0);
scene.add(light2);
}
//此光源暂时无用
var light3;
function initLight3() {
light3 = new THREE.SpotLight(0xffffff, .7, 0);
light3.spotLight = new THREE.SpotLight(0xffffff, .7, 0);
light3.position.set(-700, 1000, 1000);
light3.castShadow = true;
scene.add(light3);
}
//此光源暂时无用
var light4;
function initLight4() {
light4 = new THREE.PointLight(0xffffff, 0.7, 0);
light4.position.set(3200, -3900, 3500);
light4.castShadow = true;
scene.add(light4);
}
//
//创造木星
var sphere;
function initSphere() {
var bitmap = new Image();
bitmap.src = 'img/jupiter.jpg';
var texture = THREE.ImageUtils.loadTexture(bitmap.src);
var material = new THREE.MeshPhongMaterial({
map: texture
});
var geometry = new THREE.SphereGeometry(50, 64, 64);
sphere = new THREE.Mesh(geometry, material);
sphere.position.set(0, 17, -120);
scene.add(sphere);
}
//加载模型文件
var loader = new THREE.STLLoader();
function initLoad() {
loader.addEventListener('load', function (event) {
var geometryOfFiles = event.content;
var materialOfFiles = new THREE.MeshPhongMaterial({
wrapAround: true,
wrapRGB: new THREE.Vector3(0, 1, 1),
color: 0xFFFFFF,
specular: 0xFFFFFF,
shading: THREE.SmoothShading,
shininess: 630,
fog: false,
side: THREE.DoubleSide
});
var object = new THREE.Mesh(geometryOfFiles, materialOfFiles);
object.position.set(0, 0, 0);
object.rotation.set(-Math.PI / 2, 0, Math.PI / 111);
object.scale.set(2, 2, 2);
scene.add(object);
});
loader.load('miku.stl');
}
var loader1 = new THREE.STLLoader();
function initLoad1() {
loader1.addEventListener('load', function (event) {
var geometryOfFiles = event.content;
var materialOfFiles = new THREE.MeshPhongMaterial({
wrapAround: true,
wrapRGB: new THREE.Vector3(0, 1, 1),
color: 0xFFFFFF,
specular: 0xFFFFFF,
shading: THREE.SmoothShading,
shininess: 230,
fog: false,
side: THREE.DoubleSide
});
var object = new THREE.Mesh(geometryOfFiles, materialOfFiles);
object.position.set(0, 20, 50);
object.rotation.set(-Math.PI / 2, 0, Math.PI / 111);
object.scale.set(0.5, 0.5, 0.5);
scene.add(object);
});
loader1.load('f35.stl');
}
var controls;
function setControl() {
controls = new THREE.TrackballControls(camera);
/*
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.panSpeed = 2;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = false;
controls.dynamicDampingFactor = 0.3;*/
}
function animate() {
controls.update();
renderer.clear();
renderer.render(scene, camera);
requestAnimationFrame(animate);
sphere.position.x -= 0.1;
sphere.rotation.y += -0.005;
}
function threeStart() {
initThree();
initCamera();
initScene();
initLight3();
initLight4();
initSphere();
setControl();
animate();
initLoad();
initLoad1();
}
</script>
seeing that adding an AmbientLight helped it will probably be normals calculated incorrectly or missing altogether check them here
geometry.faces[0].normal;
and to calculate the correct values call
geometry.computeFaceNormals()
To answer your question about how thingiverse shows them correct: after looking at their code I noticed they dont actually use those STL files they provide, but have a JSON file to load from (using THREE.JSONLoader)
these files have normals correct(they might have done some precalculations on files uploaded by users) but you would have to check the STL yourself
the miku JSON file can be found at http://thingiverse-production-new.s3.amazonaws.com/threejs_json/51/67/c8/34/6d/293cd764miku.js
don't know if computeFaceNormals() is outdated, but in my case i had to do:
const caseGeometry = useLoader(STLLoader, CaseObject)
caseGeometry.computeVertexNormals()
works like a charm, though 👍