conflict between dat.gui.js and trackballControl.js in three.js - javascript

When using three.js, I found a conflict between dat.gui.js and trackballControl.js. For example, after changing values by dat.gui, I can't rotate the camera with mousemove because the mouse can not move out from the area of GUI. Why and how to deal with it?

The trackballControls constructor allows for a second argument of a dom element.
This dom element is what the mouse event listeners for the controls will be added to. If you don't supply this argument, the mouse event listeners will be added to the document (which I believe is your problem).
It is hard to give you an example which will work for you, because you have not posted your code.
You should be able to send the renderer dom element to the trackballControls to fix your problem.
eg.
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
// send dom element to trackballControlls.
controls = new THREE.TrackballControls( camera, renderer.domElement );
Run snippet below for working example.
var camera, scene, renderer, mesh, material, controls, gui, directionalLight;
init();
render();
animate();
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 400;
// Add TrackballControls, sending dom element to attach mouseevent listeners to.
controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.addEventListener( 'change', render );
// Create scene.
scene = new THREE.Scene();
// Create material
material = new THREE.MeshPhongMaterial();
// Create cube and add to scene.
var geometry = new THREE.BoxGeometry(200, 200, 200);
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// Create ambient light and add to scene.
var light = new THREE.AmbientLight(0x404040); // soft white light
scene.add(light);
// Create directional light and add to scene.
directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
// Add GUI
var gui = new dat.GUI();
var lightFolder = gui.addFolder('Light');
lightFolder.add(directionalLight, 'intensity').onChange(function(){render()});
lightFolder.open();
}
function animate() {
requestAnimationFrame(animate);
controls.update();
}
// Only called by controls change or gui change.
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
controls.handleResize();
}
body {
margin: 0px;
}
<script src="https://cdn.rawgit.com/dataarts/dat.gui/v0.6.2/build/dat.gui.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/dev/examples/js/controls/TrackballControls.js"></script>

Related

Setting the position of a text geometry?

I have looked through stack overflow and google and I have found how to CENTER a text geometry but that is not what I want to do.
I have a scene that just has a block of text that says "Buy Here!". Using the documentation in the three.js website and examples here I was able to do that after some struggling. I had some trouble finding out how to refer to that mesh since I had created the geometry inside a function, and it took hours for me to know about setting a name for it as a string so it can be accessible from different parent/child levels.
What I am NOT able to do now is to offset the text by some arbitrary number of units. I tried shifting it down by 5 units. No matter how I try to do it it isn't working. I either manage to make the text geometry disappear OR my whole scene is black.
Here is my code...
I have the basic scene setup working properly and I'll include it here but feel free to skip since I'm pretty sure this has nothing to do with the issue...
import './style.css'
import * as THREE from 'three';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/three#0.117.0/examples/jsm/controls/OrbitControls.js';
import TWEEN from 'https://cdn.jsdelivr.net/npm/#tweenjs/tween.js#18.5.0/dist/tween.esm.js';
//BASIC SCENE SETUP
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
//LIGHTS (POINT AND AMBIENT)
const pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.set(5, 5, 5);
const ambientLight = new THREE.AmbientLight(0xFFFFFF);
scene.add(pointLight, ambientLight);
//RESIZE WINDOW
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}, false);
//ORBIT CONTROLS
const controls = new OrbitControls(camera, renderer.domElement);
controls.minDistance = 5;
controls.maxDistance = 70;
controls.enablePan = false;
controls.enableRotate = false;
controls.enableZoom = false;
controls.target.set(0,0,-1);
camera.position.setZ(25);
window.addEventListener("click", (event) => {
onClick(event);
})
window.addEventListener("mousemove", onMouseMove);
var animate = function() {
requestAnimationFrame(animate);
controls.update();
render();
TWEEN.update();
};
function render() {
renderer.render(scene, camera);
}
animate();
and here is my code for the text object....
var loaderF = new THREE.FontLoader();
loaderF.load( 'https://threejs.org/examples/fonts/optimer_regular.typeface.json', function ( font ) {
var geometry = new THREE.TextGeometry( 'Buy Here!', {
font: font,
size: 2.3,
height: 0.1,
curveSegments: 15,
bevelEnabled: true,
bevelThickness: 0.5,
bevelSize: 0.31,
bevelSegments: 7
} );
geometry.center();
var material = new THREE.MeshLambertMaterial({color: 0x686868});
var mesh = new THREE.Mesh( geometry, material );
mesh.name = "bhText"
scene.add( mesh );
mesh.userData = { URL: "http://google.com"};
} );
Here's what I have tried.....
under "var geometry ({...});" I typed....
geometry.position.setX(-5);
but the text object disappears completely so I tried
geometry.position.setX = -5;
but there was no difference so i tried taking out
geometry.center();
but it had the same results.
So then I tried using
mesh.position.x = -5;
with AND without
geometry.center();
but again, they all just make my text object disappear.
So now I tried to set the position from outside the function by typing the following code OUTSIDE of everything that is contained in
loaderF.load ('https.....', function (font){var geometry = .....})
using the reference I learned....
scene.getObjectByName("bhText").position.x(-5);
but this makes my entire scene go blank (black). So I tried variations of like
scene.getObjectByName("bhText").position.x = -5;
scene.getObjectByName("bhText").position.setX(-5);
scene.getObjectByName("bhText").position.setX = -5;
mesh.position.setX = -5;// I was pretty sure this wasn't going to work since I wasn't
//using the mesh name specifically for when it's inside something
//I can't reach because of parent-child relations
and again trying each of those with AND without
geometry.center();
but they all made my scene go black.
I just wanna move it down a couple of units. Sheesh.
Could anyone be kind enough to tell me WHERE in my code I can set the position of the text geometry? Thank you please.
I just wanna move it down a couple of units.
In this case use mesh.position.y = - 5;. Changing the x coordinate will move the mesh to the left or right. Here is a complete live example based on your code:
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set( 0, 0, 10 );
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
const pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.set(5, 5, 5);
const ambientLight = new THREE.AmbientLight(0xFFFFFF);
scene.add(pointLight, ambientLight);
const loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/optimer_regular.typeface.json', function(font) {
const geometry = new THREE.TextGeometry('Buy Here!', {
font: font,
size: 2,
height: 0.5
});
geometry.center();
const material = new THREE.MeshLambertMaterial({
color: 0x686868
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.y = - 1; // FIX
mesh.name = "bhText"
scene.add(mesh);
renderer.render(scene, camera);
});
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.130.1/build/three.min.js"></script>

How do i move three.js model to right side of screen?

I have just started learning three.js and I want to know if it is possible to move a 3d model to the right side of the screen instead of being centered in the middle.
Here is an image to help with the explanation of what I am trying to do.
(link to the image)
The three.js code looks like this:
<script>
let scene, carMesh, camera, renderer;
init();
animate();
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0xFFFFFF);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(25,window.innerWidth/window.innerHeight,1,5000);
camera.position.set(1500, 1200, 2000);
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.addEventListener('change', renderer);
hlight = new THREE.AmbientLight (0x404040,100);
scene.add(hlight);
directionalLight = new THREE.DirectionalLight(0xffffff,100);
directionalLight.position.set(0,1,0);
directionalLight.castShadow = true;
scene.add(directionalLight);
light = new THREE.PointLight(0xc4c4c4,10);
light.position.set(0,300,500);
scene.add(light);
light2 = new THREE.PointLight(0xc4c4c4,10);
light2.position.set(500,100,0);
scene.add(light2);
light3 = new THREE.PointLight(0xc4c4c4,10);
light3.position.set(0,100,-500);
scene.add(light3);
light4 = new THREE.PointLight(0xc4c4c4,10);
light4.position.set(-500,300,500);
scene.add(light4);
let loader = new THREE.GLTFLoader();
loader.load('scene.gltf', function(gltf){
scene.add(gltf.scene);
carMesh = gltf.scene.children[0];
carMesh.scale.set(0.5,0.5,0.5);
camera.lookAt(carMesh.position);
});
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene,camera);
controls.update(scene,);
}
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
</script>
Many thanks
Ollie
This has little to to with Three.js. Rather, it is a question of the page's layout, and the relative placement of the Three.js dom element in the dom tree.
In your code, the Three.js content is a child of the body element:
document.body.appendChild(renderer.domElement);
If you want to position it in a certain way, e.g. on the right side, you can position an element, typically a div, and use this as the parent element of the Three.js content.
A very simple solution is:
<div id="container" style="float: right"></div>
...
document.getElementById("container").appendChild(renderer.domElement);
Of course, to meet your needs, you may have to style/position other elements on your page as well, e.g. the element left of the Three.js div. This can be achieved by css, which you can define either inline in the elements via style, or in a separate section of your document (the preferred approach).

ThreeJS not rendering Cube with setAnimationLoop

So I'm working on a ThreeJS WebVR Page. (I'm quite new to three.js)
So I tired to make a basic scene to test some stuff. But when I load the page with renderer.setAnimationLoop(render) I get my green cube for 1 Frame and then it disappears.
(I got it working with requestAnimationFrame() but this will not work with WebVR)
This is my code for my test sandbox:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.vr.enabled = true;
document.body.appendChild(renderer.domElement);
var geometry = new THREE.BoxGeometry(1, 1, 1);
var material = new THREE.MeshBasicMaterial({
color: 0x00ff00
});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
function render() {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
function animate() {
renderer.setAnimationLoop(render);
}
animate();
//Button vor start VR Session
document.body.appendChild(WEBVR.createButton(renderer));
Not the problem with setAnimationLoop
The problem is you cannot set camera position when vr is enabled
check this stack overflow question
Unable to change camera position when using VRControls
Check this CodePen Link where i fixed your code by changing position of cube instead of camera
var cube = new THREE.Mesh(geometry, material);
cube.position.z = -5; //added this instead of camera.position.z = 5;
if you want to move the camera you need make it as child of another object and set the position to that object

Three.js ply colorless (all black)

I am trying to load my ply file using Three.js. It has worked but I almost don't see any colors. There are some glimpses here and there, but it's mostly black (the first image below). The image opens properly (with colors) in MeshLab (the second image below). I have tried vertexColors: THREE.VertexColors (as suggested in Three.js - ply files - why colorless?) and vertexColors: THREE.FaceColors but nothing seemed to help. I am a three.js newbie, so please tell me what am I doing wrong.
and my code:
<!doctype html>
<html lang="en">
<head>
<title>Icon 7</title>
<meta charset="utf-8">
</head>
<body style="margin: 0;">
<script src="js/three.min.js"></script>
<script src="js/PLYLoader.js"></script>
<script src="js/OrbitControls.js"></script>
<script>
// Set up the scene, camera, and renderer as global variables.
var scene, camera, renderer;
init();
animate();
// Sets up the scene.
function init() {
// Create the scene and set the scene size.
scene = new THREE.Scene();
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
// Create a renderer and add it to the DOM.
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(WIDTH, HEIGHT);
document.body.appendChild(renderer.domElement);
// Create a camera, zoom it out from the model a bit, and add it to the scene.
camera = new THREE.PerspectiveCamera(35, WIDTH / HEIGHT, 0.1, 100);
camera.position.set(0,0.15,3);
camera.lookAt(new THREE.Vector3(0,0,0));
scene.add(camera);
// Create an event listener that resizes the renderer with the browser window.
window.addEventListener('resize', function() {
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
});
// Set the background color of the scene.
renderer.setClearColor(0xd3d3d3, 1);
// Create a light, set its position, and add it to the scene.
var light = new THREE.PointLight(0xffffff);
light.position.set(0,200,100);
scene.add(light);
// Load in the mesh and add it to the scene.
var loader = new THREE.PLYLoader();
loader.load( './models/foot.ply', function ( geometry ) {
geometry.computeVertexNormals();
geometry.center();
var material = new THREE.MeshStandardMaterial ({ shininess: 1000,vertexColors: THREE.FaceColors } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.x = 0;
mesh.position.y = 0;
mesh.position.z = 0;
mesh.castShadow = false;
mesh.receiveShadow = false;
scene.add( mesh );
} );
// Add OrbitControls so that we can pan around with the mouse.
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.userPanSpeed = 0.05;
}
// Renders the scene and updates the render as needed.
function animate() {
// Read more about requestAnimationFrame at http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
requestAnimationFrame(animate);
// Render the scene.
renderer.render(scene, camera);
controls.update();
}
</script>
</body>
</html>
Edit: as I don't have separate textures, this is not a duplicate question.
Instead of using MeshStandardMaterial use MeshBasicMaterial

Object rotation using the Device Orientation Controls in Three.js

I am making my first steps coding with JavaScript and playing with Three.js.
I am experimenting with this example from threejs.org :http://threejs.org/examples/#misc_controls_deviceorientation
and this is the code that they have:
(function() {
"use strict";
window.addEventListener('load', function() {
var container, camera, scene, renderer, controls, geometry, mesh;
var animate = function(){
window.requestAnimationFrame( animate );
controls.update();
renderer.render(scene, camera);
};
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100);
controls = new THREE.DeviceOrientationControls( camera );
scene = new THREE.Scene();
var geometry = new THREE.SphereGeometry( 500, 16, 8 );
geometry.scale( - 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( {
map: new THREE.TextureLoader().load( 'textures/2294472375_24a3b8ef46_o.jpg' )
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var geometry = new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 );
var material = new THREE.MeshBasicMaterial( { color: 0xff00ff, side: THREE.BackSide, wireframe: true } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = 0;
container.appendChild(renderer.domElement);
window.addEventListener('resize', function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}, false);
animate();
}, false);
})();
I am trying to control an object that I made with the orientation of a mobile device. I can do it, is just change this line
controls = new THREE.DeviceOrientationControls( camera );
for this line: controls = new THREE.DeviceOrientationControls( object );
But now, my problem is that It changes the initial rotation of the object:
It should be like this:
And I see this in my desktop:
And this in a mobile device:
I tryied to change the DeviceOrientationControls file but is not the best way I think.
Then I found this in Stack Overflow Orbiting around the origin using a device's orientation and they said that is not possible to do it with control device orientation, its necessary to modify the Orbit Controls, and it is very complicated too.
So my question is: Is there a simple way to change the initial rotation of an object and to limit it too? Using DeviceOrientationControls.js
EDIT
I found a way to make it without using the device orientation controls. I used this:
window.addEventListener('deviceorientation', function(e) {
var gammaRotation = e.gamma ? e.gamma * (Math.PI / 600) : 0;
monogram.rotation.y = gammaRotation;
});
It works perfectly when I use my device in a vertical position,but when I use it in landscape position it doesn't work. Do you have a suggestion?

Categories

Resources