Mouseover doesn't work properly compared to Click event in Threejs - javascript

I’m kind of new to Three.js
I’m trying to load GLTF model, add mouseover and mouseout events, where first will change the GLTF color, while the second will revert it back to the original.
So far I have been able to achieve it - partially, as it appear in this video, it doesn’t change anything, unless the mouse pointer come from (out of focus maybe?) directly into the GLTF model without going through the black background.
The code I’m using:
const loader = new GLTFLoader();
loader.load('models/box.glb', function (gltf) {
gltf.scene.traverse(function (child) {
if (child.isMesh) {
let m = child;
m.receiveShadow = true;
m.castShadow = true;
m.material.flatShading = true;
sceneMeshes.push(m);
}
if (child.isLight) {
let l = child;
l.castShadow = true;
l.shadow.bias = -.003;
l.shadow.mapSize.width = 2048;
l.shadow.mapSize.height = 2048;
}
});
scene.add(gltf.scene);
console.log(gltf.scene);
}, (xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
}, (error) => {
console.log(error);
});
const raycaster = new THREE.Raycaster();
const sceneMeshes = new Array();
renderer.domElement.addEventListener('mouseover', onMouseMove, false);
renderer.domElement.addEventListener('mouseout', onMouseOut, false);
function onMouseMove(event) {
const mouse = {
x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
};
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(sceneMeshes, false);
if (intersects.length > 0) {
intersects[0].object.material.color.set(0xffff00);
}
}
function onMouseOut(event) {
const mouse = {
x: (event.clientX / renderer.domElement.clientWidth) * 2 - 1,
y: -(event.clientY / renderer.domElement.clientHeight) * 2 + 1
};
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(sceneMeshes, false);
if (intersects.length > 0) {
intersects[0].object.material.color.set(0xff0000);
}
}
Any idea what i might be done wrong?

Try it with this simplified code:
let camera, scene, renderer, mesh;
let raycaster, mouse;
let currentIntersection = null;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 4;
raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
scene = new THREE.Scene();
const geometry = new THREE.BoxBufferGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.domElement.addEventListener('pointermove', onMouseMove, false);
}
function animate() {
requestAnimationFrame(animate);
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render(scene, camera);
}
function onMouseMove(event) {
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(scene, true);
if (intersects.length > 0) {
currentIntersection = intersects[0].object;
currentIntersection.material.color.set(0xffff00);
} else {
if (currentIntersection !== null) {
currentIntersection.material.color.set(0xff0000);
currentIntersection = null;
}
}
}
body {
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.120.1/build/three.js"></script>
You normally only need a pointermove event listener to implement a "hover" effect.

I got it solved by using mousemove event, and the following code inside onMouseMove event:
if (intersects.length > 0) {
INTERSECTED = intersects[0].object;
if (intersects[0].object) {
INTERSECTED.material.color.set(0xff0000);
console.log("Touching")
}
} else {
INTERSECTED.material.color.set(0xfff000);
console.log("Not touching")
}
Basically i was using the else statement in the wrong place - right after the if (intersects[0].object)

Related

How to drag a scene with three.js?

In the following html page I create a scene with some points, in which you can zoom comfortably by using the mouse wheel.
But what I want to do is to drag that scene after I have zoomed in. I want to press the left mouse button, keep it pressed and then move the mouse. I want the scene to move accordingly (e.g. by changing the x/y coordinates of the camera).
I tried to create a listener to listen to clicks, but when I click somewhere I do not see any console output.
I also searched and found the suggestion to use DragControls, but this does not seem to be defined in THREE. At least I get an error when I uncomment these lines.
So how to implement something so I can drag the whole scene (or the camera)?
Code:
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script>
<title>Test</title>
</head>
<body>
<script>
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 0, 150);
scene = new THREE.Scene();
scene.add(camera);
renderer = new THREE.WebGLRenderer({
clearAlpha: 1
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x228B22, 1);
document.body.appendChild(renderer.domElement);
// Define a standard Circle
circle = new THREE.CircleGeometry(1, 20);
var max = 50;
var min = -50;
for (var i = 0; i < 100; i++) {
var object = new THREE.Mesh( circle.clone(), new THREE.MeshBasicMaterial( { color: new THREE.Color('yellow'), opacity: 0.5 } ) );
object.position.x = Math.random() * (max - min) + min;
object.position.y = Math.random() * (max - min) + min;
object.position.z = 0;
scene.add( object );
}
document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
function onDocumentMouseWheel( event ) {
var fovMAX = 100;
var fovMIN = 1;
camera.fov -= event.wheelDeltaY * 0.05;
camera.fov = Math.max( Math.min( camera.fov, fovMAX ), fovMIN );
camera.projectionMatrix = new THREE.Matrix4().makePerspective(camera.fov, window.innerWidth / window.innerHeight, camera.near, camera.far);
}
document.addEventListener( 'mouseclick', onDocumentMouseClick, false );
function onDocumentMouseClick( event ) {
console.log("mouseclick! " + event.offsetX + "-" + event.offsetY, );
}
animate();
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
//// undefined:
//var controls = new THREE.DragControls( objects, camera, renderer.domElement );
//controls.addEventListener( 'dragstart', function ( event ) {
// event.object.material.emissive.set( 0xaaaaaa );
//} );
//
//controls.addEventListener( 'dragend', function ( event ) {
// event.object.material.emissive.set( 0x000000 );
//} );
</script>
</body>
</html>
Maybe there is a better way to do this, but I found a way (see below). The trick is to have a flag that tells if the mouse button is pressed, and then you have an algorithm to determine the difference on the previous position, and move the camera accordingly.
var mouseDown = false;
var mousePos = [0,0];
var cameraPos = 0;
document.addEventListener('mousedown', onMouseDown, false);
function onMouseDown( event ) {
mouseDown = true;
mousePos = [event.offsetX, event.offsetY];
cameraPos = camera.position;
}
document.addEventListener('mouseup', onMouseUp, false);
function onMouseUp( event ) {
mouseDown = false;
}
document.addEventListener('mousemove', onMouseMove, false);
function onMouseMove( event ) {
if (mouseDown) {
// scale factor takes into account the current FOV
scale = Math.tan(camera.fov/2 * Math.PI / 180)/1.5;
dx = mousePos[0] - event.offsetX;
dy = mousePos[1] - event.offsetY;
x = cameraPos.x + scale*dx;
y = cameraPos.y - scale*dy;
camera.position.x = x;
camera.position.y = y;
mousePos = [event.offsetX, event.offsetY];
cameraPos = camera.position;
}
}

Best way to show and hide GUI when click occurs

I want a dat.GUI() instance to show up when a click occurs inside a mesh, and when its clicked again to disapear.
Obviosouly, when it is reclicked, i want to it reapper.
I tried many different things but i cannot get the behaviour i want...
For example chick this code:
function onDocumentMouseClick(event) //if we detect a click event
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
// update the mouse variable
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
//if mouse is on top of the mesh when the click occurs, change color of mesh and render GUI
if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === false)
{
isClicked = true;
cube.material.color.set( 0xF7F7F7 );
var params = {
textField: "Enter value:"
}
var item = gui.add(params, "textField").onFinishChange(function (value) {
//Do something with the new value
console.log(value);
});
}
//if mouse is on top of the mesh when the click occurs, but it already marked as 'clicked', now mark it as 'unclicked'
else if ( intersects.length > 0 && intersects[ 0 ].object === cube && isClicked === true)
{
isClicked = false;
cube.material.color.set( cube.userData.originalColor );
dat.GUI.toggleHide();
//gui.toggleHide()
}
}
Now when i click the mesh, the GUi is created, when i reclick it dissaperas, but when i click again weird stuff happens.
Sometimes the hide button does not work, but ultimately i end up with many different GUIS, where i only want one.
And have the option to make it appear / dissapear.
You can do it this way:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry();
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
params = {
zAxis: "1"
}
var gui = new dat.GUI();
gui.add(params, "zAxis").onFinishChange(val => {
cube.scale.z = parseFloat(val);
});
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var intersects;
window.addEventListener("click", event => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObject(cube);
if (intersects.length > 0) {
let vis = gui.domElement.style.visibility;
gui.domElement.style.visibility = vis == "" ? "hidden" : "";
}
});
var animate = function() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/libs/dat.gui.min.js"></script>

Why do I get these white lines when I render a 3d obj using three.js?

I am unsure why I get these white lines when I render my 3d model using three.js. Are they part of the wireframe? I know some of the meshes weren't separated like they should have been. I am also unsure of how to remove the wireframe if that is the case and could use some guidance. I couldn't find examples that I could follow.
Here is a screen show of the issue.
Here is my three.js code for reference-
import * as THREE from '../dap/three.js-master/build/three.module.js';
import { DDSLoader } from '../dap/three.js-master/examples/jsm/loaders/DDSLoader.js';
import { MTLLoader } from '../dap/three.js-master/examples/jsm/loaders/MTLLoader.js';
import { OBJLoader } from '../dap/three.js-master/examples/jsm/loaders/OBJLoader.js';
import { OrbitControls } from '../dap/three.js-master/examples/jsm/controls/OrbitControls.js';
function main() {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer2 = new THREE.WebGLRenderer({canvas});
var kitchenCameraActive = false;
document.getElementById("roomSelect").addEventListener("change", changeIt);
function changeIt(e) {
//e.target.value
document.getElementById(e.target.value).click();
console.log(e);
}
var fov = 45;
var aspect = 2; // the canvas default
var near = 0.1;
var far = 100;
var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(-97.570, 5.878, -5.289);
camera.rotation.set(0,0,0);
var controls;
controls = new OrbitControls( camera, canvas );
//var controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 5, 0);
controls.update();
document.getElementById("kitchen").addEventListener("click", changeCamera);
document.getElementById("bathroom").addEventListener("click", changeCamera);
document.getElementById("deck").addEventListener("click", changeCamera);
document.getElementById("livingRoom").addEventListener("click", changeCamera);
document.getElementById("bedRoom").addEventListener("click", changeCamera);
document.getElementById("walkway").addEventListener("click", changeCamera);
document.getElementById("sideHouse").addEventListener("click", changeCamera);
document.getElementById("frontPorch").addEventListener("click", changeCamera);
document.getElementById("garageDoor").addEventListener("click", changeCamera);
document.getElementById("insideGarage").addEventListener("click", changeCamera);
function changeCamera(e) {
camera.rotation.set(e.toElement.attributes[5].nodeValue, e.toElement.attributes[6].nodeValue, e.toElement.attributes[7].nodeValue);
camera.fov = e.toElement.attributes[4].nodeValue;
camera.position.set(e.toElement.attributes[1].nodeValue, e.toElement.attributes[2].nodeValue, e.toElement.attributes[3].nodeValue);
camera.updateProjectionMatrix();
if (e.target.id == "walkway" || e.target.id == "frontPorch" || e.target.id == "garageDoor" || e.target.id == "insideGarage")
{
controls.target.set(0, 5, 0);
controls.update();
}
if(e.target.id == "kitchen"){
controls.target.set(7, 6, 7);
}
if(e.target.id == "bathroom"){
controls.target.set(-9,15,-7);
}
if(e.target.id == "deck"){
controls.target.set(31, 7, 1);
}
if(e.target.id == "livingRoom"){
controls.target.set(-12.5, 1.5, -18.5);
}
if(e.target.id == "bedRoom"){
controls.target.set(-15.7, 14, -21);
}
if(e.target.id == "insideGarage"){
controls.target.set(24.405, 6.733, -6.425);
}
controls.update();
console.log(e);
}
const scene = new THREE.Scene();
scene.background = new THREE.Color('black');
{
const planeSize = 40;
}
{
const skyColor = 0xB1E1FF; // light blue
const groundColor = 0xB97A20; // brownish orange
const intensity = 1;
const light = new THREE.HemisphereLight(skyColor, groundColor, intensity);
scene.add(light);
}
var light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
var onProgress = function ( xhr ) {
if ( xhr.lengthComputable ) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log( Math.round( percentComplete, 2 ) + '% downloaded' );
}
};
var onError = function () { };
var manager = new THREE.LoadingManager();
manager.addHandler( /\.dds$/i, new DDSLoader() );
new MTLLoader( manager )
.setPath( '' )
.load( 'dapHouseGood5.mtl', function ( materials ) {
materials.preload();
new OBJLoader( manager )
.setMaterials( materials )
.setPath( '' )
.load( 'dapHouseGood5.obj', function ( object ) {
//object.position.y = - 95;
scene.add( object );
}, onProgress, onError );
} );
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function onPositionChange(o) {
console.log("position changed in object");
console.log(o);
console.log('camera_default: '+camera.position.x+', '+camera.position.y+', '+camera.position.z);
console.log('camera_default: '+camera.rotation.x+', '+camera.rotation.y+', '+camera.rotation.z);
console.log(camera.fov);
console.log('quaternion_default: '+camera.quaternion.x+', '+
camera.quaternion.y+', '+camera.quaternion.z+', '+camera.quaternion.w);
}
controls.addEventListener('change', onPositionChange);
var mouse = new THREE.Vector2();
var raycaster, mouse = { x : 0, y : 0};
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//raycaster.setFromCamera( mouse3D, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ].object.name );
}
}
}
main();
</script>
It looks like the lines were defined as segments (two vertices per line), but the loader created them as a continuous line.
Line
LineSegments
I'm not sure whether it's better to tweak the loader output, or just copy and modify the loader. But for the tweak angle, try this:
scene.traverse( node => {
if ( node.isLine ) {
node.isLineSegments = true;
}
} );
// re-render the scene
That should set the draw mode for the lines to be segments, rather than continuous, without rebuilding the objects.
(three.js r113)
Might be a stray wireframe material, or the geometry might not have exported correctly.
after loading, you can try:
scene.traverse( (e)=>{ if(e.isMesh && e.material && e.material.wireframe)e.material.wireframe = false });
and see if that "fixes" it.

Cant seem to add my obj to the scene: THREE.Object3D.add: object not an instance of THREE.Object3D

I am new to using three.js. I used to use a JSON file as my 3D model but the actual 3D file has some issues when I export it from Blender so I am switching to obj. The actual model is fine now but I have no idea how to switch from JSON to obj. This is as far as I can get but I keep getting the error: THREE.Object3D.add: object not an instance of THREE.Object3D.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
10,
1000
);
camera.position.z = 100;
camera.position.y = 10;
var renderer = new THREE.WebGLRenderer({
alpha: true
});
var manager = new THREE.LoadingManager(loadModel);
manager.onProgress = function(item, loaded, total) {
console.log(item, loaded, total);
};
var wrapper = new THREE.Object3D();
var textureloader = new THREE.TextureLoader();
renderer.setSize(window.innerWidth, window.innerHeight);
var light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(100, 100, 100);
scene.add(light);
var light2 = new THREE.DirectionalLight(0xffffff, 1.0);
light2.position.set(-100, 100, -100);
scene.add(light2);
function onError() {}
function onProgress(xhr) {
if (xhr.lengthComputable) {
var percentComplete = (xhr.loaded / xhr.total) * 100;
console.log("model " + Math.round(percentComplete, 2) + "% downloaded");
}
}
var head;
var loader = new THREE.OBJLoader2(manager);
loader.load(
"http://trhidouan309.barzalou.com/site_web/js/profil.obj",
function(obj) {
head = obj;
},
onProgress,
onError
);
function loadModel() {
setTimeout(function() {
wrapper.add(head);
scene.add(wrapper);
}, 10);
}
material.opacity = 0.6;
var hiddenPlane = new THREE.Mesh(planeGeometry, material);
hiddenPlane.position.set(0, 0, 50);
scene.add(hiddenPlane);
var mouse = new THREE.Vector2(0, 0);
var point = new THREE.Vector3(0, 0, 0);
var raycaster = new THREE.Raycaster();
camera.lookAt(scene.position);
window.addEventListener("mousemove", onMouseMove, false);
window.addEventListener("resize", onWindowResize, false);
function onMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(hiddenPlane);
if (intersects.length > 0) {
point = intersects[0].point;
}
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
wrapper.lookAt(point);
renderer.render(scene, camera);
}
window.onload = function() {
document.getElementById("scene3d").appendChild(renderer.domElement);
};
animate();
<script src="js/LoaderSupport.js"></script>
<script src="js/OBJLoader2.js"></script>
<script src="js/index.js"></script>
The 3D model seems to load but I don't think its able to be added in the scene
You are having issues with the timing of the calls to load the obj file and render it.
You are calling loadModel through the loading manager which contains a call to the object named head before it is initialized by loader.load() function. Additionally you are calling loader.load() asynchronously which would cause further timing issues.
One way to fix this would be calling loader.load() synchronously by passing the correct arguments as mentioned in the docs OBJLoader2 ThreeJS (see below) and moving the call to loader.load to be before the loading manager so that it would load before the object named head gets used.
From objloader2 doc setting useAsync to false causes the loader to load synchronously:
.load ( url : String, onLoad : Function, onProgress : Function, onError : Function, onMeshAlter : Function, useAsync : boolean ) : null
This way ensures the obj object is not used before the .obj file is loaded.
See code snippet below:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 10, 1000);
camera.position.z = 100;
camera.position.y = 10;
var renderer = new THREE.WebGLRenderer({
alpha: true
});
//Moved loader.load and passed correct sync args
var head;
var loader = new THREE.OBJLoader2(manager);
loader.load('http://trhidouan309.barzalou.com/site_web/js/profil.obj', function (obj) {
head = obj;
}, onProgress, onError, null, false);
var manager = new THREE.LoadingManager(loadModel);
manager.onProgress = function (item, loaded, total) {
console.log(item, loaded, total);
};
var wrapper = new THREE.Object3D;
var textureloader = new THREE.TextureLoader();
renderer.setSize(window.innerWidth, window.innerHeight);
var light = new THREE.DirectionalLight(0xffffff, 1.0);
light.position.set(100, 100, 100);
scene.add(light);
var light2 = new THREE.DirectionalLight(0xffffff, 1.0);
light2.position.set(-100, 100, -100);
scene.add(light2);
function onError() {}
function onProgress(xhr) {
if (xhr.lengthComputable) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log('model ' + Math.round(percentComplete, 2) + '% downloaded');
}
}
function loadModel() {
setTimeout(function () {
wrapper.add(head);
scene.add(wrapper);
}, 10);
}
material.opacity = 0.6;
var hiddenPlane = new THREE.Mesh(planeGeometry, material);
hiddenPlane.position.set(0, 0, 50);
scene.add(hiddenPlane);
var mouse = new THREE.Vector2(0, 0);
var point = new THREE.Vector3(0, 0, 0);
var raycaster = new THREE.Raycaster();
camera.lookAt(scene.position);
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('resize', onWindowResize, false);
function onMouseMove(event) {
event.preventDefault();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(hiddenPlane);
if (intersects.length > 0) {
point = intersects[0].point;
}
};
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
wrapper.lookAt(point);
renderer.render(scene, camera);
}
window.onload = function () {
document.getElementById("scene3d").appendChild(renderer.domElement);
}
animate();
PS: there seems to be another issue with material.opacity = 0.6; lacking correct declaration that might cause the scene to not render properly.

threejs, adding points to scene and not seeing them

Hello I have one doubt:
I have studied:
https://threejs.org/docs/#api/materials/PointsMaterial
And I have adapted the example to work with my existing code.
The aim is to render points on top of the model which we have loaded on click position.
Here we have the code, the important part is onDocumentMouseDown(), the file, logic.js:
if (!Detector.webgl) Detector.addGetWebGLMessage();
// global variables for this scripts
let OriginalImg,
SegmentImg;
var mouse = new THREE.Vector2();
var raycaster = new THREE.Raycaster();
var mousePressed = false;
var clickCount = 0;
init();
animate();
// initilize the page
function init() {
let filename = "models/nrrd/columna01.nrrd"; // change your nrrd file
let idDiv = 'original';
OriginalImg = new InitCanvas(idDiv, filename);
OriginalImg.init();
console.log(OriginalImg);
filename = "models/nrrd/columnasegmentado01.nrrd"; // change your nrrd file
idDiv = 'segment';
SegmentImg = new InitCanvas(idDiv, filename);
SegmentImg.init();
}
let originalCanvas = document.getElementById('original');
originalCanvas.addEventListener('mousedown', onDocumentMouseDown, false);
originalCanvas.addEventListener('mouseup', onDocumentMouseUp, false);
function onDocumentMouseDown(event) {
mousePressed = true;
clickCount++;
mouse.x = ( ( event.clientX - OriginalImg.renderer.domElement.offsetLeft ) / OriginalImg.renderer.domElement.clientWidth ) * 2 - 1;
mouse.y = -( ( event.clientY - OriginalImg.renderer.domElement.offsetTop ) / OriginalImg.renderer.domElement.clientHeight ) * 2 + 1
console.log('Mouse x position is: ', mouse.x, 'the click number was: ', clickCount);
console.log('Mouse Y position is: ', mouse.y);
raycaster.setFromCamera(mouse.clone(), OriginalImg.camera);
var objects = raycaster.intersectObjects(OriginalImg.scene.children);
var pointGeometry = new THREE.Geometry();
var position = new THREE.Vector3();
position.x = objects[0].point.x;
position.y = objects[0].point.y;
position.z = objects[0].point.z;
pointGeometry.vertices.push(position);
var pointMaterial = new THREE.PointsMaterial({color: 0x888888});
var point = new THREE.Points(pointGeometry, pointMaterial);
OriginalImg.scene.add(point);
console.log(objects);
}
function onDocumentMouseUp(event) {
mousePressed = false
}
function animate() {
requestAnimationFrame(animate);
OriginalImg.animate();
SegmentImg.animate();
}
And we do add the points to the scene, but in fact they do not render, they do not show, and I wonder why?:
As you could see in the image we see that the raycaster intercepts those new created points, however the do not get drawn.
I wonder if they are too small, or just the color hides them with the background.
Could you help me please?.
Additional code:
// this class handles the load and the canva for a nrrd
// Using programming based on prototype: https://javascript.info/class
// This class should be improved:
// - Canvas Width and height
InitCanvas = function (IdDiv, Filename) {
this.IdDiv = IdDiv;
this.Filename = Filename
}
InitCanvas.prototype = {
constructor: InitCanvas,
init: function () {
this.container = document.getElementById(this.IdDiv);
// this should be changed.
debugger;
this.container.innerHeight = 600;
this.container.innerWidth = 800;
//These statenments should be changed to improve the image position
this.camera = new THREE.PerspectiveCamera(60, this.container.innerWidth / this.container.innerHeight, 0.01, 1e10);
this.camera.position.z = 300;
let scene = new THREE.Scene();
scene.add(this.camera);
// light
let dirLight = new THREE.DirectionalLight(0xffffff);
dirLight.position.set(200, 200, 1000).normalize();
this.camera.add(dirLight);
this.camera.add(dirLight.target);
// read file
let loader = new THREE.NRRDLoader();
loader.load(this.Filename, function (volume) {
//z plane
let sliceZ = volume.extractSlice('z', Math.floor(volume.RASDimensions[2] / 4));
debugger;
this.container.innerWidth = sliceZ.iLength;
this.container.innerHeight = sliceZ.jLength;
sliceZ.mesh.material.color.setRGB(0,1,1);
console.log('Our slice is: ', sliceZ);
scene.add(sliceZ.mesh);
}.bind(this));
this.scene = scene;
// renderer
this.renderer = new THREE.WebGLRenderer({alpha: true});
this.renderer.setPixelRatio(this.container.devicePixelRatio);
debugger;
this.renderer.setSize(this.container.innerWidth, this.container.innerHeight);
// add canvas in container
this.container.appendChild(this.renderer.domElement);
},
animate: function () {
this.renderer.render(this.scene, this.camera);
}
}
I wonder about the point size because if we see this example they are made with 0.05 of size:
https://github.com/mrdoob/three.js/blob/master/examples/webgl_interactive_raycasting_points.html
And in the example we see the camera being quite far away from the points being generated and they are visible:
https://threejs.org/examples/webgl_interactive_raycasting_points.html
What do you think?
You can use THREE.BufferGeometry() with .setDrawRange():
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(1, 5, 5);
camera.lookAt(scene.position);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
var mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(3, 32, 24), new THREE.MeshBasicMaterial({
wireframe: true,
color: "red"
}));
scene.add(mesh);
var idx = 0;
var maxIdx = 10;
var points = [];
for (let i = 0; i < maxIdx; i++) {
points.push(new THREE.Vector3());
}
var geometry = new THREE.BufferGeometry().setFromPoints(points);
geometry.setDrawRange(0, idx);
var points = new THREE.Points(geometry, new THREE.PointsMaterial({
size: 0.125,
color: "yellow"
}));
scene.add(points);
window.addEventListener("mousemove", onMouseMove, false);
window.addEventListener("mousedown", onMouseDown, false);
var raycaster = new THREE.Raycaster();
var mouse = new THREE.Vector2();
var intersects = [];
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function onMouseDown(event) {
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObject(mesh);
if (intersects.length === 0) return;
if (idx == maxIdx) return;
let p = intersects[0].point;
geometry.attributes.position.setXYZ(idx, p.x, p.y, p.z);
geometry.attributes.position.needsUpdate = true;
idx++;
geometry.setDrawRange(0, idx);
}
render();
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Categories