How would you place hyperlinks on 3D Objects/Mesh using ThREE? - javascript

I am trying to create a simple box that can link when clicked.
It sounds simple but it didn't work for me so help is appreciated. I've been trying to find answers to this, I don't know what I did wrong. I found like only 2 questions about this on stackoverflow but they still didn't help me answer.
const coolTexture = new THREE.TextureLoader().load('cool.jpg');
const cool = new THREE.Mesh(
new THREE.BoxGeometry(3, 3, 3),
new THREE.MeshBasicMaterial({
color: Math.random() * 0xffffff
})
);
cool.userData = {
URL: "http://stackoverflow.com"
};
scene.add(cool);
function linki() {
if (intersects.length > 0) {
window.open(intersects[0].object.userData.URL);
}
}
document.body.onclick = linki

If it's going to be only one box then use window.open(object.URL); when pointerdown event is detected.
let scene, camera, renderer, cube;
window.addEventListener("pointerdown", () => {
window.open(cube.URL);
});
//
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf79862);
camera = new THREE.PerspectiveCamera(
90,
window.innerWidth / window.innerHeight,
1,
1000
);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
const geometry = new THREE.BoxGeometry(3, 3, 0.05);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 0, -2);
cube.URL = "http://stackoverflow.com";
scene.add(cube);
renderer.setAnimationLoop(loop);
}
function loop() {
renderer.render(scene, camera);
}
init();
body {
font-family: sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.145.0/three.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
<script src="src/index.js">
</script>
</body>
</html>
But if you plan to create more URLs you should use Raycaster and check which box was clicked.
let scene, camera, renderer;
let objsToTest = [];
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
mouse.x = mouse.y = null;
window.addEventListener("pointermove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});
let selectState = false;
window.addEventListener("pointerdown", () => {
selectState = true;
});
window.addEventListener("pointerup", () => {
selectState = false;
});
window.addEventListener("touchstart", (event) => {
selectState = true;
mouse.x = (event.touches[0].clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.touches[0].clientY / window.innerHeight) * 2 + 1;
});
window.addEventListener("touchend", () => {
selectState = false;
mouse.x = null;
mouse.y = null;
});
//
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf79862);
camera = new THREE.PerspectiveCamera(
90,
window.innerWidth / window.innerHeight,
1,
1000
);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
const geometry = new THREE.BoxGeometry(0.5, 0.3, 0.05);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.set(-0.5, 0, -2);
cube.URL = "url1";
scene.add(cube);
const material2 = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const cube2 = new THREE.Mesh(geometry, material2);
cube2.position.set(0.5, 0, -2);
cube2.URL = "url2";
scene.add(cube2);
objsToTest.push(cube, cube2);
renderer.setAnimationLoop(loop);
}
function loop() {
renderer.render(scene, camera);
updateButtons();
}
function updateButtons() {
let intersect;
if (mouse.x !== null && mouse.y !== null) {
raycaster.setFromCamera(mouse, camera);
intersect = raycast();
}
if (intersect && selectState) {
window.open(intersect.object.URL);
}
}
//
function raycast() {
return objsToTest.reduce((closestIntersection, obj) => {
const intersection = raycaster.intersectObject(obj, true);
if (!intersection[0]) return closestIntersection;
if (
!closestIntersection ||
intersection[0].distance < closestIntersection.distance
) {
intersection[0].object = obj;
return intersection[0];
}
return closestIntersection;
}, null);
}
init();
body {
font-family: sans-serif;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.145.0/three.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
<script src="src/index.js">
</script>
</body>
</html>

Related

three.js change same material texture multiple times

In three.js I would like to change the same object material texture multiple times.
After the page loaded the base 3D model rendered but already changed the left side of the furniture. (I made it on purpose). After 5 seconds it should change the texture again but the texture disappears. In the Network Activity tab the texture downloaded.
I would really appreciate it if somebody would give me a hint.
import * as THREE from 'three';
import {
OrbitControls
} from '../js/three/examples/jsm/controls/OrbitControls.js'
import {
GLTFLoader
} from '../js/three/examples/jsm/loaders/GLTFLoader.js'
const scene = new THREE.Scene();
const manager = new THREE.LoadingManager();
const renderer = new THREE.WebGLRenderer();
const loader = new GLTFLoader(manager);
const camera = new THREE.PerspectiveCamera(
30,
window.innerWidth / window.innerHeight,
0.1,
2000
)
camera.position.z = 3.5
camera.position.x = 0
camera.position.y = 1
const hemiLight = new THREE.HemisphereLight();
scene.add(hemiLight);
const light1 = new THREE.AmbientLight(0xFFFFFF, 0.3);
scene.add(light1);
const light2 = new THREE.DirectionalLight(0xFFFFFF, 0.8 * Math.PI);
light2.position.set(0.5, 1, 0.8);
scene.add(light2);
const light3 = new THREE.DirectionalLight(0xFFFFFF, 0.8 * Math.PI);
light3.position.set(-0.5, -1, -0.8);
scene.add(light3);
render.toneMapping = THREE.ACESFilmicToneMapping;
renderer.physicallyCorrectLights = true
renderer.shadowMap.enabled = true
renderer.outputEncoding = THREE.sRGBEncoding
renderer.setClearColor(0xcccccc);
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
const pmremGenerator = new THREE.PMREMGenerator(renderer);
pmremGenerator.compileEquirectangularShader();
const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
const loadElement = async (input, xinput, yinput, zinput, cb) => {
loader.load(input, async function (gltf) {
const box = new THREE.Box3().setFromObject(gltf.scene);
const center = box.getCenter(new THREE.Vector3());
gltf.scene.position.x += (gltf.scene.position.x - center.x + xinput);
gltf.scene.position.y += (gltf.scene.position.y - center.y + yinput);
gltf.scene.position.z += (gltf.scene.position.z - center.z + zinput);
cb(gltf.scene)
}),
function () {}, // onProgress function
function (error) {
console.log(error)
} // onError function
}
window.addEventListener('resize', onWindowResize, false)
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
renderer.setSize(window.innerWidth, window.innerHeight)
render()
}
function render() {
renderer.render(scene, camera)
}
function animate() {
requestAnimationFrame(animate)
controls.update()
render()
}
document.addEventListener("DOMContentLoaded", () => {
animate();
loadElement("../models/base/model.gltf", 0, -0.3, 0, (obj) => {
obj.name = "base";
scene.add(obj)
obj.traverse(child => {
if (child.material && child.material.name === 'dark_wood') {
child.material = new THREE.TextureLoader().load("../models/base/wood_color.png", (texture) => {
texture.flipY = false;
texture.encoding = THREE.sRGBEncoding;
texture.needsUpdate = true;
});
}
});
})
setTimeout(() => {
scene.getObjectByName('base').traverse(child => {
if (child.material && child.material.name === 'wood') {
child.material = new THREE.TextureLoader().load("../models/base/dark_wood_color.png", (texture) => {
texture.flipY = false;
texture.encoding = THREE.sRGBEncoding;
texture.needsUpdate = true;
});
}
});
}, 5000);
});

3D model not casting shadows in ThreeJS

I am importing a glTF model into ThreeJS and have a PlaneGeometry acting as a ground. I need the model to cast shadows onto the plane/ground.
I've tried enabling
renderer.shadowMap.enabled = true;
on
const renderer = new THREE.WebGLRenderer({ alpha: true });
I also have 2 lights:
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(0, 10, 0);
scene.add( hemiLight );
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(0, 0, 10);
dirLight.castShadow = true;
dirLight.shadow.camera.top = 200;
dirLight.shadow.camera.bottom = -200;
dirLight.shadow.camera.left = - 200;
dirLight.shadow.camera.right = 200;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 500;
scene.add( dirLight );
Final code
body
{
margin: 0px;
padding: 0px;
}
div#container canvas
{
cursor: grab;
}
div#container canvas:active
{
cursor: grabbing;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Import 3D Model into Three JS</title>
<script type="module" defer>
import * as THREE from 'https://cdn.skypack.dev/three#0.129.0/build/three.module.js';
import { GLTFLoader } from 'https://cdn.skypack.dev/three#0.129.0/examples/jsm/loaders/GLTFLoader.js'; // for .glb and .gltf.glb
// import { OBJLoader } from 'https://cdn.skypack.dev/three#0.129.0/examples/jsm/loaders/OBJLoader.js'; // for .obj
import { OrbitControls } from 'https://cdn.skypack.dev/three#0.129.0/examples/jsm/controls/OrbitControls.js';
const container = document.querySelector('div#container');
const path_to_model = './ImportModel/Mini-Game Variety Pack/Models/gltf/tree_forest.gltf.glb';
const loader = new GLTFLoader();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 500);
// Add lights
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(0, 10, 0);
scene.add( hemiLight );
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(0, 0, 10);
dirLight.castShadow = true;
dirLight.shadow.camera.top = 200;
dirLight.shadow.camera.bottom = -200;
dirLight.shadow.camera.left = - 200;
dirLight.shadow.camera.right = 200;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 500;
scene.add( dirLight );
// Make renderer
const renderer = new THREE.WebGLRenderer({
alpha: true
});
// Make transparent
renderer.setClearColor(0xffffff, 0);
// Set it to window size
renderer.setSize(window.innerWidth, window.innerHeight);
// Force shadows
renderer.shadowMap.enabled = true;
// Helper (optional)
// const camera_helper = new THREE.CameraHelper(dirLight.shadow.camera);
// scene.add(camera_helper);
// Double quality
const quality = 2;
renderer.setSize(window.innerWidth * quality, window.innerHeight * quality, false);
// Add mouse movement
const controls = new OrbitControls(camera, renderer.domElement);
// Add floor (plane)
const plane_geometry = new THREE.PlaneGeometry(10, 10);
const plane_material = new THREE.MeshPhongMaterial({
color: 0xffff00,
side: THREE.DoubleSide
});
const plane = new THREE.Mesh(
plane_geometry,
plane_material
);
plane.rotation.x = 1.5708;
plane.castShadow = true;
plane.receiveShadow = true;
scene.add(plane);
console.log(plane);
// Import glTF
loader.load(path_to_model, function (gltf)
{
//gltf.scene.position.y = -5;
//gltf.scene.center();
//gltf.scene.scale.set(0.1, 0.1, 0.1);
// Make it cast shadows
gltf.scene.castShadow = true;
gltf.scene.traverse(function(node)
{
if (node.isMesh)
{
node.castShadow = true;
//node.receiveShadow = true;
}
});
console.log(gltf);
console.log('Adding glTF model to scene...');
scene.add(gltf.scene);
console.log('Model added.');
console.log('Moving camera 5z...');
camera.position.z = 5;
console.log('Camera moved.');
}, undefined, function (error)
{
console.error(error);
});
container.appendChild(renderer.domElement);
function animate()
{
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>
Update: changed MeshBasicMaterial to MeshPhongMaterial in plane as suggested by #Justin.
The hemisphere light seems to be the main culprit. If you change the position of it you can start getting shadow. Most likely it was casting light everywhere thus drowning out any chance of shadows. Moving it away from the plane helped. Also the dirLight.shadow.camera.top/bottom/left/right are all too high. I used 2, vice 200, along with changing the hemi light and it seems to be working.
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Import 3D Model into Three JS</title>
</head>
<body>
<div id="container">
</div>
</body>
</html>
CSS
body
{
margin: 0px;
padding: 0px;
}
div#container canvas
{
cursor: grab;
}
div#container canvas:active
{
cursor: grabbing;
}
JS
import * as THREE from "https://cdn.skypack.dev/three#0.129.0/build/three.module.js";
import { GLTFLoader } from "https://cdn.skypack.dev/three#0.129.0/examples/jsm/loaders/GLTFLoader.js"; // for .glb and .gltf.glb
// import { OBJLoader } from 'https://cdn.skypack.dev/three#0.129.0/examples/jsm/loaders/OBJLoader.js'; // for .obj
import { OrbitControls } from "https://cdn.skypack.dev/three#0.129.0/examples/jsm/controls/OrbitControls.js";
const container = document.querySelector("div#container");
const path_to_model =
"https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/stacy_lightweight.glb";
const loader = new GLTFLoader();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.01,
500
);
// Add lights
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(20, 20, 10);
scene.add(hemiLight);
const dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(-10, 20, 6);
dirLight.castShadow = true;
dirLight.shadow.camera.top = 2;
dirLight.shadow.camera.bottom = -2;
dirLight.shadow.camera.left = -2;
dirLight.shadow.camera.right = 2;
dirLight.shadow.camera.near = 0.1;
dirLight.shadow.camera.far = 500;
scene.add(dirLight);
// Make renderer
const renderer = new THREE.WebGLRenderer({
alpha: true
});
// Make transparent
renderer.setClearColor(0xffffff, 0);
// Set it to window size
renderer.setSize(window.innerWidth, window.innerHeight);
// Force shadows
renderer.shadowMap.enabled = true;
// Helper (optional)
// const camera_helper = new THREE.CameraHelper(dirLight.shadow.camera);
// scene.add(camera_helper);
// Double quality
const quality = 2;
renderer.setSize(
window.innerWidth * quality,
window.innerHeight * quality,
false
);
// Add mouse movement
const controls = new OrbitControls(camera, renderer.domElement);
// Add floor (plane)
const plane_geometry = new THREE.PlaneGeometry(10, 10);
const plane_material = new THREE.MeshPhongMaterial({
color: 0xffff00,
side: THREE.DoubleSide
});
const plane = new THREE.Mesh(plane_geometry, plane_material);
plane.rotation.x = 1.5708;
plane.castShadow = true;
plane.receiveShadow = true;
scene.add(plane);
console.log(plane);
//scene.add(box)
// Import glTF
loader.load(
path_to_model,
function (gltf) {
//gltf.scene.position.y = -5;
//gltf.scene.center();
//gltf.scene.scale.set(0.1, 0.1, 0.1);
// Make it cast shadows
gltf.scene.castShadow = true;
gltf.scene.traverse(function (node) {
if (node.isMesh) {
node.castShadow = true;
//node.receiveShadow = true;
}
});
console.log(gltf);
console.log("Adding glTF model to scene...");
scene.add(gltf.scene);
console.log("Model added.");
console.log("Moving camera 5z...");
camera.position.z = 5;
console.log("Camera moved.");
},
undefined,
function (error) {
console.error(error);
}
);
container.appendChild(renderer.domElement);
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();

How to animate objects different with three.js

I just wanted to create a very simple scene with 2 different objects that move
differently.
But my sphere isnt moving at all.
When I change the line:
scene.add(obj2)
to:
obj.add(obj2)
the sphere is moving exactly as the box
what can I change to just let the sphere rotate?
//set up the scene
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer();
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
const light = new THREE.DirectionalLight();
scene.background = new THREE.Color("white");
renderer.setSize((3 * window.innerWidth) / 4, (3 * window.innerHeight) / 4);
document.body.appendChild(renderer.domElement);
camera.position.z = 17;
light.position.set(-1, 1, 1);
//-----GEOMETRY VARIABLES------//
let box = new THREE.BoxGeometry(1, 1, 1);
let sphere = new THREE.SphereGeometry(0.5, 32, 32);
//-----MATERIAL VARIABLES------//
let phong = new THREE.MeshPhongMaterial({
color: "pink",
emissive: 0,
specular: 0x070707,
shininess: 100,
});
//-----FUNCTIONALITY------//
//make the objects and add them to the scene
let obj, currentShape, currentMesh, obj2;
currentShape = box;
currentMesh = phong;
obj = new THREE.Mesh(currentShape, currentMesh);
scene.add(light);
scene.add(obj);
obj2 = new THREE.Mesh(sphere, currentMesh);
obj2.position.set(3, 0, 0);
scene.add(obj2);
//methods for making the objects move
let up = true;
function animate() {
requestAnimationFrame(animate);
obj.rotation.y += 0.01;
obj2.rotation.x += 0.02;
if (up) {
obj.translateOnAxis(new THREE.Vector3(0, 1, 0).normalize(), 0.1);
if (obj.position.y > 3.4) {
up = false;
}
} else if (!up) {
obj.translateOnAxis(new THREE.Vector3(0, 1, 0).normalize(), -0.1);
if (obj.position.y < -3.4) {
up = true;
}
}
renderer.render(scene, camera);
}
window.onload = () => {
document.getElementById("shape-form").onchange = evt => {
switch (evt.target.value) {
case "box":
currentShape = box;
break;
}
obj.geometry = currentShape;
obj.geometry.buffersNeedUpdate = true;
};
document.getElementById("mesh-form").onchange = evt => {
switch (evt.target.value) {
case "phong":
currentMesh = phong;
break;
}
obj.material = currentMesh;
obj.material.needsUpdate = true;
};
animate();
};
It's just hard to see a sphere rotating :)
Here's a simplified version of your example - I made both the cube and the sphere rotate and float around in gentle waves.
const renderer = new THREE.WebGLRenderer();
renderer.setSize((3 * window.innerWidth) / 4, (3 * window.innerHeight) / 4);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color("white");
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 17;
const light = new THREE.DirectionalLight();
light.position.set(-1, 1, 1);
scene.add(light);
const phong = new THREE.MeshPhongMaterial({
color: "pink",
emissive: 0,
specular: 0x070707,
shininess: 100,
});
const boxGeom = new THREE.BoxGeometry(1, 1, 1);
const boxObj = new THREE.Mesh(boxGeom, phong);
scene.add(boxObj);
const sphereGeom = new THREE.SphereGeometry(0.5, 32, 32);
const sphereObj = new THREE.Mesh(sphereGeom, phong);
scene.add(sphereObj);
function animate() {
const time = +new Date() / 1000;
requestAnimationFrame(animate);
boxObj.rotation.y += 0.01;
sphereObj.rotation.x += 0.02;
boxObj.position.x = Math.sin(time * .2) * 3.4;
sphereObj.position.x = Math.cos(time * .3) * 3.4;
boxObj.position.y = Math.sin(time) * 3.4;
sphereObj.position.y = Math.cos(time) * 3.4;
renderer.render(scene, camera);
}
animate();
<script src="https://threejs.org/build/three.min.js"></script>

when I switch camera,camera control is bing valid

I want to swith camera type in my threejs Demo,so I read an official demo :https://threejs.org/examples/#webgl_camera
But some errors occur when I test my demo. When I press P to use cameraPerspective,it works well;But when I use O to switch cameraOrtho,cameracontrol doesn't work——I cannot rotate or move my model sample.
There is my code:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>3D-earth</title>
<script src="JSandCSS/jquery-2.2.4.min.js"></script>
<script src="JSandCSS/three.min.js"></script>
<script src="JSandCSS/OrbitControls.js"></script>
<script src="JSandCSS/OBJLoader.js"></script>
<script type="text/javascript" src="JSandCSS/jquery.qrcode.min.js"></script>
<script type="text/javascript" src="JSandCSS/qrcode.js"></script>
<script src="JSandCSS/bootstrap.min.js"></script>
<script type="text/javascript" src="JSandCSS/CanvasRenderer.js"></script>
<script src="JSandCSS/Projector.js"></script>
<link href="JSandCSS/bootstrap.min.css" rel="stylesheet" type="text/css">
</head>
<body>
<div style="width: 50%;">
<script>
var scene = new THREE.Scene();
var group = new THREE.Group;
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var objects = [];
init();
var container, stats, titleinfo;
scene.add(group);
var textureLoader = new THREE.TextureLoader();
var mat = new THREE.MeshLambertMaterial({
/* Roushness:1,
Metalness:0,*/
map: textureLoader.load("model/earth/texture.jpg"),
/* normalMap:textureLoader.load("model/earth/normal.jpg"),*/
specularMap: textureLoader.load("model/earth/specular.jpg"),
lightMap: textureLoader.load("model/earth/light.jpg"),
side:THREE.DoubleSide,
});
var loader = new THREE.OBJLoader();
loader.load('model/earth/earth.obj', function(obj) {
obj.traverse(function(child) {
if(child instanceof THREE.Mesh) {
child.material = mat;
}
});
mesh = obj;
obj.scale.set(2, 2, 2);
group.add(obj);
});
var light = new THREE.PointLight(0xffffff);
light.position.set(300, 400, 200);
light.intensity.set = 0.1;
scene.add(light);
scene.add(new THREE.AmbientLight(0x333333));
var cameraPerspective = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
cameraPerspective.position.set(200, 200, 200);
cameraPerspective.lookAt(scene.position);
cameraOrtho = new THREE.OrthographicCamera(window.innerWidth / -4, window.innerWidth / 4, window.innerHeight / 4, window.innerHeight / -4, -10000, 10000);
ActiveCamera = cameraPerspective;
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.render(scene, ActiveCamera);
renderer.setClearColor(0x808080, 0.5);
var controls = new THREE.OrbitControls(ActiveCamera);
controls.minDistance = 200;
controls.maxDistance = 400;
controls.autoRotate = true;
controls.addEventListener('change', render);
animate();
window.addEventListener('resize', handleWindowResize, false);
document.addEventListener('keydown', onKeyDown, false);
function render() {
/*group.rotation.y -= 0.004;*/
renderer.render(scene, ActiveCamera);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function onKeyDown(event) {
switch(event.keyCode) {
case 79:
ActiveCamera = cameraOrtho;
case 80:
ActiveCamera = cameraPerspective;
}
}
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
ActiveCamera.aspect = WIDTH / HEIGHT;
ActiveCamera.updateProjectionMatrix();
}
</script>
</div>
</body>
try with single camera object of CombinedCamera and
to switch between Perspective and Ortho use below code.
//initial
var camera = new THREE.CombinedCamera($(canvasHold).innerWidth(), $(canvasHold).innerHeight(), 75, .1, 3e3, -5e3, 5e3);
camera.toOrthographic();
function switchCamera()
{
if(ortho) // Add condition
{
camera.toOrthographic();
camera.position.set(0, 0, 0);
camera.zoom = .5;
camera.up = new THREE.Vector3(0, 0, 0);
camera.lookAt(scene.position);
camera.setFov(75);
}
else
{
camera.toPerspective();
camera.zoom = 1;
camera.setFov(45);
}
}
Note: Please change variables and values according to your requirements.

Why raycaster.intersectObjects work fine with Geometry built in scene but work bad with model loaded form exterior?

I wanna make a measure tool in three.js,and I use reycaster function to do it.
When I use it with Geometry built in scene,it was fine.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ytest</title>
<script src="JSandCSS/three.js"></script>
<script src="JSandCSS/OrbitControls.js"></script>
<script src="JSandCSS/OBJLoader.js"></script>
<script src="JSandCSS/Raycaster.js"></script>
</head>
<body>
<script>
var scene = new THREE.Scene();
var group = new THREE.Group;
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var objects = [];
var particleMaterial;
particlecount = 0;
var container, stats, titleinfo;
scene.add(group);
var geometry = new THREE.SphereGeometry(5, 32, 32);
geometry.scale(10, 10, 10);
var material = new THREE.MeshBasicMaterial({
color: 0xffff00
});
var sphere = new THREE.Mesh(geometry, material);
group.add(sphere);
objects.push(sphere);
var light = new THREE.PointLight(0xffffff);
light.position.set(300, 400, 200);
light.intensity.set = 0.1;
scene.add(light);
scene.add(new THREE.AmbientLight(0x333333));
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(200, 200, 200);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.render(scene, camera);
renderer.setClearColor(0x808080, 0.5);
render();
var controls = new THREE.OrbitControls(camera);
controls.addEventListener('change', render);
animate();
window.addEventListener('resize', handleWindowResize, false);
window.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event) {
event.preventDefault();
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
var PI2 = Math.PI * 2;
var pointLoader = new THREE.TextureLoader();
particleMaterial = new THREE.SpriteMaterial({
map: pointLoader.load("pic/measurepoint.png"),
});
if(intersects.length > 0) {
if(particlecount == 0) {
var particle1 = new THREE.Sprite(particleMaterial);
particle1.name = 'particle1';
particle1.position.copy(intersects[0].point);
particle1.scale.x = particle1.scale.y = 5;
scene.add(particle1);
particlecount = 1;
} else {
if(particlecount !== 2) {
var particle2 = new THREE.Sprite(particleMaterial);
particle2.name = 'particle2';
particle2.position.copy(intersects[0].point);
particle2.scale.x = particle2.scale.y = 5;
scene.add(particle2);
particlecount = 2;
a = scene.getObjectByName('particle1');
b = scene.getObjectByName('particle2');
var dis = a.position.distanceTo(b.position);
alert('distance between two point is' + dis);
scene.remove(a);
scene.remove(b);
particlecount = 0;
}
}
}
}
function render() {
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
</script>
</body>
</html>
enter image description here
But When I loaded a model,it doesn't work.As you see result of "alert(intersects.length)" is 0.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ytest</title>
<script src="JSandCSS/three.js"></script>
<script src="JSandCSS/OrbitControls.js"></script>
<script src="JSandCSS/OBJLoader.js"></script>
<script src="JSandCSS/Raycaster.js"></script>
</head>
<body>
<script>
var scene = new THREE.Scene();
var group = new THREE.Group;
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var objects = [];
var particleMaterial;
particlecount = 0;
var container, stats, titleinfo;
scene.add(group);
var textureLoader = new THREE.TextureLoader();
var mat = new THREE.MeshLambertMaterial({
map: textureLoader.load("model/earth/texture.jpg"),
specularMap: textureLoader.load("model/earth/specular.jpg"),
lightMap: textureLoader.load("model/earth/light.jpg")
});
var loader = new THREE.OBJLoader();
loader.load('model/earth/earth.obj',
function chuanzhi(obj) {
obj.traverse(function(child) {
if(child instanceof THREE.Mesh) {
child.material = mat;
}
});
Mesh = obj;
obj.scale.set(2, 2, 2);
group.add(obj);
objects.push(Mesh);
});
var light = new THREE.PointLight(0xffffff);
light.position.set(300, 400, 200);
light.intensity.set = 0.1;
scene.add(light);
scene.add(new THREE.AmbientLight(0x333333));
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(200, 200, 200);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.render(scene, camera);
renderer.setClearColor(0x808080, 0.5);
render();
var controls = new THREE.OrbitControls(camera);
controls.addEventListener('change', render);
animate();
window.addEventListener('resize', handleWindowResize, false);
window.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event) {
event.preventDefault();
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
var PI2 = Math.PI * 2;
var pointLoader = new THREE.TextureLoader();
particleMaterial = new THREE.SpriteMaterial({
map: pointLoader.load("pic/measurepoint.png"),
});
alert(intersects.length);
if(intersects.length > 0) {
if(particlecount == 0) {
var particle1 = new THREE.Sprite(particleMaterial);
particle1.name = 'particle1';
particle1.position.copy(intersects[0].point);
particle1.scale.x = particle1.scale.y = 5;
scene.add(particle1);
particlecount = 1;
} else {
if(particlecount !== 2) {
var particle2 = new THREE.Sprite(particleMaterial);
particle2.name = 'particle2';
particle2.position.copy(intersects[0].point);
particle2.scale.x = particle2.scale.y = 5;
scene.add(particle2);
particlecount = 2;
a = scene.getObjectByName('particle1');
b = scene.getObjectByName('particle2');
var dis = a.position.distanceTo(b.position);
alert('distance between two point is' + dis);
scene.remove(a);
scene.remove(b);
particlecount = 0;
}
}
}
}
function render() {
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
</script>
</body>
</html>
I wanna know why it happened,and how I can use it correctly.Could you help me ?

Categories

Resources