Selecting FBX with raycaster

Hi Every one,

i try use raycaster make,

I try to change raycaster scene.children to my model object meshobj,but error

before:
var intersects = raycaster.intersectObjects(scene.children, true);

after:
var intersects = raycaster.intersectObjects(meshobj, true);

this is my code:

let container, stats, controls;

let camera, scene, renderer, light, mesh, grid, meshobj;

let mixer;

let composer, outlinePass;

init();

animate();

function init() {

    //選擇容器

    const canvas = document.querySelector('#infoe');

    //建立相機

    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 5000);

    camera.position.set(200, 500, 700);

    //建立場景

    scene = new THREE.Scene();

    scene.background = new THREE.Color(0xffffff);

    // scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);

    //建立燈光(半球光)

    light = new THREE.HemisphereLight(0x999999, 0x000000);

    light.position.set(0, 200, 0);

    scene.add(light);

    //建立燈光(定向光)

    light = new THREE.DirectionalLight(0x999999);

    light.position.set(0, 200, 100);

    light.castShadow = true;

    light.shadow.camera.top = 180;

    light.shadow.camera.bottom = - 100;

    light.shadow.camera.left = - 120;

    light.shadow.camera.right = 120;

    scene.add(light);

    // model 載入進度

    const onProgress = function (xhr) {

        if (xhr.lengthComputable) {

            const percentComplete = (xhr.loaded / xhr.total) * 100;

            console.log(Math.round(percentComplete, 2) + '% downloaded');

        }

    };

    const onError = function () { };

    const manager = new THREE.LoadingManager();

    // model 3D (FBX)

    var loader = new THREE.FBXLoader(manager);

    loader.load('models/fbx/national-museum-finish-5.fbx', function (object) {

        object.scale.multiplyScalar(1); //模型大小縮放

        meshobj = object

        meshobj.position.y = 100;

        scene.add(meshobj);

    }, onProgress, onError);

    //render 渲染彩現

    renderer = new THREE.WebGLRenderer({

        canvas,

        antialias: true,

        alpha: true

    });

    //OrbitControls 滑鼠拖曳旋轉控制器

    controls = new THREE.OrbitControls(camera, canvas);

    controls.enableDamping = false; //拖拉慣性

    controls.campingFactor = 0.25;  //拖拉慣性阻尼參數搭配enableDamping使用

    controls.enableZoom = true; //相機變焦移動

    controls.enablePan = false; //相機平移

    controls.target.set(0, 100, 0);

    controls.update();

}

//canvas 畫面自訂義

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;

}

//raycaster

let raycaster = new THREE.Raycaster();

let mouse = new THREE.Vector2(), INTERSECTED;

let selection = null;

function onMouseClick(event) {

    event.preventDefault();

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;

    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

}

function render() {

    //通過相機和滑鼠位置更新射線

    raycaster.setFromCamera(mouse, camera);

    // 計算物體和射線的焦點

    var intersects = raycaster.intersectObjects(scene.children, true);

    if (intersects.length > 0) {

        if (INTERSECTED != intersects[0].object) {

            selection = intersects[0].object;

            // 當點擊其他地方回復顏色

            if (selection) selection.material.color.set(selection.currentHex);

            // 設定新的顏色

            selection.material.color.set(0xff0000);

            container.style.cursor = "pointer";

            console.log('點到你了');

        }

    } else {

        if (selection) selection.material.color.set(0x000000);

        selection = null;

        container.style.cursor = "default";

    }

    renderer.render(scene, camera);

}

//動畫執行

function animate() {

    requestAnimationFrame(animate);

    if (resizeRendererToDisplaySize(renderer)) {

        const canvas = renderer.domElement;

        camera.aspect = canvas.clientWidth / canvas.clientHeight;

        camera.updateProjectionMatrix();

    }

    if (meshobj) {

        // meshobj.rotation.y += 0.002;

    }

    renderer.render(scene, camera);

    window.addEventListener('click', onMouseClick, false);

    window.requestAnimationFrame(render);

}

Your console is telling you that you are not passing an array to raycaster.intersectObjects.
If you must raycast only with a single object, either do raycaster.intersectObject (with no “s”)
either do raycaster.intersectObjects( [yourSingleObject] )

See the difference here : https://threejs.org/docs/#api/en/core/Raycaster.intersectObject

felixmariotto thanks u replay.

I try raycaster.intersectObject , But the screen still has an error.XD,
Although can choose the model color

var intersects = raycaster.intersectObject(meshobj, true);

As your console is saying, it seems that selection.material.color is undefined at line 132…

Try console.log( selection ) at line 130, and see what is happening with your material. Is selection what you expected it to be ? Is selection.material what you expected it to be ? Not all three.js materials have a color property.

1 Like

Hi, i console.log after,generate some parameters.
How can I change it so that my model can change colors?

Are you logging right before the line 132 ?
If so honestly I don’t know what’s happening, it looks like there is a PhongMaterial as material property, so I don’t know why it’s claiming it’s undefined line 132.

How are you loading this model ? Do you manually set its material at some point ? It could be a synchronicity issue, raycasting maybe occur before your model is assigned a material.

You could try checking for the material existence every time you will update it, like so :
if (selection && selection.material)

Yes, I has before the line 183 logging right,
I want to click on Block1 on the right, and then change the material color of the model.
Thank you for your reply

console.log(): 181

loading models:

Error:

This is my code:
let container, stats, controls;

let camera, scene, renderer, light, mesh, grid, meshobj;

let mixer;

let composer, outlinePass;

init();

animate();

function init() {

    //選擇容器

    const canvas = document.querySelector('#infoe');

    //建立相機

    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 5000);

    camera.position.set(200, 500, 700);

    //建立場景

    scene = new THREE.Scene();

    scene.background = new THREE.Color(0xffffff);

    // scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);

    //建立燈光(半球光)

    light = new THREE.HemisphereLight(0x999999, 0x000000);

    light.position.set(0, 200, 0);

    scene.add(light);

    //建立燈光(定向光)

    light = new THREE.DirectionalLight(0x999999);

    light.position.set(0, 200, 100);

    light.castShadow = true;

    light.shadow.camera.top = 180;

    light.shadow.camera.bottom = - 100;

    light.shadow.camera.left = - 120;

    light.shadow.camera.right = 120;

    scene.add(light);

    // model 載入進度

    const onProgress = function (xhr) {

        if (xhr.lengthComputable) {

            const percentComplete = (xhr.loaded / xhr.total) * 100;

            console.log(Math.round(percentComplete, 2) + '% downloaded');

        }

    };

    const onError = function () { };

    const manager = new THREE.LoadingManager();

    // model 3D (FBX)

    var loader = new THREE.FBXLoader(manager);

    loader.load('models/fbx/national-museum-finish-5.fbx', function (object) {

        object.scale.multiplyScalar(1); //模型大小縮放

        meshobj = object

        meshobj.position.y = 100;

        scene.add(meshobj);

    }, onProgress, onError);

    //render 渲染彩現

    renderer = new THREE.WebGLRenderer({

        canvas,

        antialias: true,

        alpha: true

    });

    //OrbitControls 滑鼠拖曳旋轉控制器

    controls = new THREE.OrbitControls(camera, canvas);

    controls.enableDamping = false; //拖拉慣性

    controls.campingFactor = 0.25;  //拖拉慣性阻尼參數搭配enableDamping使用

    controls.enableZoom = true; //相機變焦移動

    controls.enablePan = false; //相機平移

    controls.target.set(0, 100, 0);

    controls.update();

}

//canvas 畫面自訂義

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;

}

//raycaster

let raycaster = new THREE.Raycaster();

let mouse = new THREE.Vector2(), INTERSECTED;

let selection = null;

function onMouseClick(event) {

    event.preventDefault();

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;

    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

}

function render() {

    //通過相機和滑鼠位置更新射線

    raycaster.setFromCamera(mouse, camera);

    // 計算物體和射線的焦點

    var intersects = raycaster.intersectObject(meshobj, true);

    if (intersects.length > 0) {

        if (INTERSECTED != intersects[0].object) {

            selection = intersects[0].object;

            // 當點擊其他地方回復顏色

            console.log( selection )

            if (selection) selection.material.color.set(selection.currentHex);

            // 設定新的顏色

            selection.material.color.set(0xff0000);

            // container.style.cursor = "pointer";

            console.log('點到你了');

        }

    } else {

        if (selection) selection.material.color.set(0x000000);

        selection = null;

        container.style.cursor = "default";

    }

    renderer.render(scene, camera);

}

//動畫執行

function animate() {

    requestAnimationFrame(animate);

    if (resizeRendererToDisplaySize(renderer)) {

        const canvas = renderer.domElement;

        camera.aspect = canvas.clientWidth / canvas.clientHeight;

        camera.updateProjectionMatrix();

    }

    if (meshobj) {

        // meshobj.rotation.y += 0.002;

    }

    renderer.render(scene, camera);

    window.addEventListener('click', onMouseClick, false);

    window.requestAnimationFrame(render);

}

mh the only issue I can see is that raycasting occurs on the variable meshobj even when it’s undefined (model is not yet loaded).

I also see that you call requestAnimationFrame on two functions :

requestAnimationFrame(animate);

window.requestAnimationFrame(render);

Just remove the latter and put the render() call in your conditional block :

if (meshobj) {

    render()

    // meshobj.rotation.y += 0.002;

}

I copied you code and made these changes, for me it worked :

Here is my code :

Summary
import * as THREE from '../build/three.module.js';

import Stats from './jsm/libs/stats.module.js';

import { OrbitControls } from './jsm/controls/OrbitControls.js';
import { FBXLoader } from './jsm/loaders/FBXLoader.js';

let container, stats, controls;
let camera, scene, renderer, light, mesh, grid, meshobj;

let mixer;

let composer, outlinePass;

init();

animate();

function init() {

    //選擇容器

    const canvas = document.querySelector('#infoe');

    //建立相機

    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 5000);

    camera.position.set(200, 500, 700);

    //建立場景

    scene = new THREE.Scene();

    scene.background = new THREE.Color(0xffffff);

    // scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000);

    //建立燈光(半球光)

    light = new THREE.HemisphereLight(0x999999, 0x000000);

    light.position.set(0, 200, 0);

    scene.add(light);

    //建立燈光(定向光)

    light = new THREE.DirectionalLight(0x999999);

    light.position.set(0, 200, 100);

    light.castShadow = true;

    light.shadow.camera.top = 180;

    light.shadow.camera.bottom = - 100;

    light.shadow.camera.left = - 120;

    light.shadow.camera.right = 120;

    scene.add(light);

    // model 載入進度

    const onProgress = function (xhr) {

        if (xhr.lengthComputable) {

            const percentComplete = (xhr.loaded / xhr.total) * 100;

            console.log(Math.round(percentComplete, 2) + '% downloaded');

        }

    };

    const onError = function () { };

    const manager = new THREE.LoadingManager();

    // model 3D (FBX)

    var loader = new FBXLoader(manager);

    loader.load('models/fbx/Samba Dancing.fbx', function (object) {

        object.scale.multiplyScalar(1); //模型大小縮放

        meshobj = object

        meshobj.position.y = 100;

        scene.add(meshobj);

    }, onProgress, onError);

    //render 渲染彩現

    renderer = new THREE.WebGLRenderer({

        antialias: true,

        alpha: true

    });

    renderer.setSize( window.innerWidth, window.innerHeight )

    document.body.appendChild( renderer.domElement );

    //OrbitControls 滑鼠拖曳旋轉控制器

    controls = new OrbitControls(camera, document.body);

    controls.enableDamping = false; //拖拉慣性

    controls.campingFactor = 0.25;  //拖拉慣性阻尼參數搭配enableDamping使用

    controls.enableZoom = true; //相機變焦移動

    controls.enablePan = false; //相機平移

    controls.target.set(0, 100, 0);

    controls.update();

}

//canvas 畫面自訂義

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;

}

//raycaster

let raycaster = new THREE.Raycaster();

let mouse = new THREE.Vector2(), INTERSECTED;

let selection = null;

function onMouseClick(event) {

    event.preventDefault();

    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;

    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

}

function render() {

    //通過相機和滑鼠位置更新射線

    raycaster.setFromCamera(mouse, camera);

    // 計算物體和射線的焦點

    var intersects = raycaster.intersectObject(meshobj, true);

    if (intersects.length > 0) {

        if (INTERSECTED != intersects[0].object) {

            selection = intersects[0].object;

            // 當點擊其他地方回復顏色

            console.log( selection )

            if (selection) selection.material.color.set(selection.currentHex);

            // 設定新的顏色

            selection.material.color.set(0xff0000);

            // container.style.cursor = "pointer";

            console.log('點到你了');

        }

    } else {

        if (selection) selection.material.color.set(0x000000);

        selection = null;

        // container.style.cursor = "default";

    }

    renderer.render(scene, camera);

}

//動畫執行

function animate() {

    requestAnimationFrame(animate);

    if (resizeRendererToDisplaySize(renderer)) {

        const canvas = renderer.domElement;

        camera.aspect = canvas.clientWidth / canvas.clientHeight;

        camera.updateProjectionMatrix();

    }

    if (meshobj) {

    	render();
        // meshobj.rotation.y += 0.002;

    }

    renderer.render(scene, camera);

    window.addEventListener('click', onMouseClick, false);

}

If it still doesn’t work for you, you will have to make a fiddle to demonstrate the issue.
You can use this fiddle as a template : https://jsfiddle.net/ofa7bj8x/

1 Like

felixmariotto
thank you very much for your help normally successfulI , I tested my model and found that the model produced borwser error…

02

Excuse me, Is import loading useful for webpack or npm?

1 Like