Static Object in Scene - Three.js
Asked Answered
D

3

6

I have two objects in my scene. I am using the

 <script src="js/controls/LeapTrackballControls.js"  ></script>

for moving the camera, so it feels like the objects is rotating according to the movement of my hand.

The problem is that the other object is also moving, and I want it to remain always in front of me. I mean, that even if the camera moves, the object always is in the same place inside the canvas/explorer.

Sorry if I'm not explaining myself properly.

Any help is appreciated.

EDIT:

var controls = new THREE.LeapTrackballControls( camera , controller );

So, I have a sphere in the middle of the scene. I use the LeapTrackball library to move the camera around the center of the scene. This makes the user feel like the sphere is rotating around his center.

model = new THREE.Mesh(modelGeo, modelMat);
model.geometry.dynamic = true;
model.position.set(0, 0, 0);
scene.add(model);

My problem is that I have another shape:

myMesh = new THREE.Mesh(circleGeometry, material);
myMesh.position.set(0, 0, 10);
scene.add(myMesh);

that is also affected by the rotation of the camera. What I want is to keep the 'fake rotation' of the sphere, while the other mesh stays in the middle of the screen (0,0,10).

Ok, so this is my camera object.

var camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.1, 5000);

And my render function, which is used for update the control/movement of the camera.

   function render() {
        controls.update();
        renderer.render(scene, camera);
        doMouse();
        if(useOrbitControls){
            orbitControls.update();
        }
    }

I'm using a Leap controller, and this is the function that builds it up:

function leapMotion() {
                var controllerOptions = {
                    enableGestures: true
                    , background: true
            , frameEventName: 'animationFrame'
                , };

[...]

    controller.on('frame', onFrame);

Basically, this means that the onFrame function is done everytime that it receives a frame (60 per second aprox.)

    function onFrame(frame){
[...]
        }

There is not much more, all the magic comes from the library that you can find here:

https://leapmotion.github.io/Leap-Three-Camera-Controls/

Drake answered 5/8, 2015 at 11:37 Comment(3)
Well, you don't need a static object because from what you say your objects are already at a fixed position. If you move the camera of course both objects would move (it's your POV moving though), you should either actually rotate the object or move the fixed object with the camera, if you post some more code I could help you with that.Opportune
@Sosdoc edited! Do you need anything else?Drake
A bit more code (your camera object, requestAninationFrame function) would help, if you can put up a jsfiddle or something it would be even better.Opportune
M
16

If you want an object -- such as crosshairs -- to be fixed in front of the camera, you can do so by adding the object as a child of the camera. Use a pattern like this one:

scene.add( camera ); // required when the camera has a child
camera.add( object );
object.position.set( 0, 0, - 100 ); // or whatever distance you want

three.js r.71

Miscreance answered 5/8, 2015 at 14:26 Comment(1)
This works perfect! And I like that it is not declared inside the rendering function.Drake
O
0

The simple way of doing this is making your object track the camera's position.

Tracking means that, at each camera update, you'll move both the camera and the object by the same amount, while keeping a fixed distance between them.

For this to work you need to set a fixed position at which your object will always be viewed, in your sample it should be (0, 0, 10).

var fixedPosition = new THREE.Vector3(0, 0, 10);

Then, in your render() function you need to update the position of the object after the camera was moved, but before you render everything.

function render() {
        controls.update();

        // let's update the object's position now!
        myMesh.position.sub(camera.position, fixedPosition);
        // now camera and mesh are at the same distance
        renderer.render(scene, camera);
        //...
    }

In this case a vector subtraction works fine, we basically take the camera's position, subtract our fixed amount (10 on the Z-axis) and you'll have that your object's position will always be positioned 10 units away from the camera on the Z-axis

In general, many of the operations you'll be doing involve 3D vectors and some math, so it's useful to understand how these operations (basic addition, subtraction, multiplication, etc.) affect what you see on screen.

If you have more doubts I suggest reading a bit about vector math, it's not too hard and you don't need to memorize formulas (Three.js implements all the math you need already), but knowing what these operations do can be incredibly useful.

Opportune answered 5/8, 2015 at 14:1 Comment(3)
This works fine too, but I think that @WestLangley's answer is a bit easier, given that it doesn't need an extra call in each update.Drake
Yes, that's the better option since three allows you to have child objects attached. If that wasn't possible (like if you used webgl directly) your only option would be manipulating the object's position yourself like I did.Opportune
Looks like the sub method takes 1 argument, not 2.Gazelle
R
0

Hope this helps someone who uses @react-three/fiber

import {useFrame, useThree} from "@react-three/fiber";

const { gl } = useThree();

const [ vrEnabled, setVREnabled ] = useState(false);

useFrame(({camera}) => {
    setVREnabled(gl.xr.isPresenting);

    if (vrEnabled) {
        camera.add(ref.current);
        ref.current.position.set( 18, 0, 0 );
    }
});
Relativize answered 7/3, 2022 at 6:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.