Rotate sphere by clicking on link in three.js - javascript

I have created a sphere and I have a set of link. I want to change the position of sphere or rotate the sphere by clicking any of the link. I have tried to search a lot but can't find any example similar to this.

It's just a matter of creating an HTML element and associate a JS function to its "onclick" event. Here's quick implementation on a basic scene, using a button (you can replace it with a link or whatever you like):
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<title>Rotate Mesh On Button Clicked</title>
</head>
<body>
<button onclick="myFunction()">Rotate</button>
<script type="text/javascript" src="three.min.js"></script>
<script type="text/javascript" src="OrbitControls.js"></script>
<script type="text/javascript" src="scene.js"></script>
</body>
</html>
JavaScript
var container, camera, scene, renderer;
var geometry, material, mesh;
var cameraControls;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xdbdbdb );
container.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 3, 0.5, 40 );
scene.add( camera );
// controls
cameraControls = new THREE.OrbitControls( camera, renderer.domElement );
// lights
scene.add( new THREE.AmbientLight( 0x222222 ) );
var light = new THREE.PointLight( 0xffffff, 0.8 );
camera.add( light );
// objects
geometry = new THREE.CylinderGeometry( 5, 5, 5, 5 );
material = new THREE.MeshPhongMaterial( {color: 0x00aafa} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
window.addEventListener( 'resize', onWindowResize, false );
}
function myFunction() {
mesh.rotateX(90);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
cameraControls.update();
}
function render() {
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
As you can see when the button is clicked it calls "myFunction", which rotates the Mesh by 90°, pretty simple.

Related

Three.js - Need to update camera position live based on updated sql code

I have a mysql code that updates values live from a .php file and I have a three.js model viewer that I want to be able to rotate live based on the updated sql input. The code below shows it in the camera.position.set tag My page does show the numbers updated every second, but I need the model to update as well. I've tried various types of animate(), settimeout, etc. but don't really know the best way to do this.
Here's my existing three.js code. Note, the result WORKS, it just doesn't update unless I refresh the page.
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var camera, scene, renderer;
init();
function init() {
scene = new THREE.Scene();
scene.add( new THREE.AmbientLight( 0x999999 ) );
var pointLight = new THREE.PointLight( 0xffffff, 0.6 );
pointLight.position.set(80, 80, 90);
scene.add( pointLight );
camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 1, 500 );
// Z is up for objects intended to be 3D printed.
camera.up.set( 0, 0, 1 );
camera.position.set( <?php echo $xaxis; ?>, <?php echo $yaxis; ?>, <?php echo $zaxis; ?> );
//camera.add( new THREE.PointLight( 0xffffff, 0.8 ) );
scene.add( camera );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setClearColor( 0x333333 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
var loader = new THREE.ThreeMFLoader();
loader.load( './models/3mf/cube_gears.3mf', function ( object ) {
scene.add( object );
render();
} );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.target.set( 80, 65, 35 );
controls.update();
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
The thing is that you draw only one time on your scene.
You should just call a method that does something like this :
function animate() {
requestAnimationFrame( animate );
/* update your information*/
render()
}
If you want more information you can find it there with a good exemple on the animation and how it works : https://threejs.org/docs/#manual/en/introduction/Creating-a-scene
Moreover you should not render inside your init() method.

Can't use MeshLambertMaterial with custom BufferGeometry

I just wrote a simple program to generate pyramidal roof shapes in Three.js (actuall this is part of a bigger project, so I can't show you all the code). So these shapes should be rendered in the scene as well as other objects like extrusions, cubes, etc. , all in BufferGeometry and with a MeshLambertMaterial. However, the roofs I generated look as if they were generated with a MeshBasicMaterial, and I don't know why...
This is a minimal version of my code, so that you can test it :
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script src="three.min.js"></script>
<script src="OrbitControls.js"></script>
<style type="text/css">
body{margin:0;}
</style>
</head>
<body>
<script>
var camera, SCENE, renderer, controls, SUN, OBJ;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 1000 );
SCENE = new THREE.Scene();
SCENE.background = new THREE.Color( 0xBBDDFF );
SUN = new THREE.DirectionalLight( 0xffffff, 0.6 );
SCENE.add( SUN );
SCENE.add( new THREE.AmbientLight( 0xcccccc, 0.8 ) );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.minDistance = 1;
controls.maxDistance = 1000;
var geometry = new THREE.BufferGeometry();
var material = new THREE.MeshLambertMaterial( { color:0xff0000} );
vertices = new Float32Array([
0,0,0,
0,1,0,
1,0,0,
0,0,0,
0,0,1,
0,1,0,
0,0,0,
1,0,0,
0,0,1,
0,1,0,
0,0,1,
1,0,0,
]);
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
OBJ = new THREE.Mesh(geometry,material);
SCENE.add(OBJ);
camera.position.set(OBJ.position.x,10,OBJ.position.z-10);
camera.lookAt(OBJ.position);
controls.target.set(OBJ.position.x,1,OBJ.position.z);
camera.updateProjectionMatrix();
SUN.position.copy( camera.position );
SUN.target = OBJ;
document.body.appendChild( renderer.domElement );
renderer.render( SCENE, camera );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( SCENE, camera );
}
</script>
</body>
You create MeshLambertMaterial in 'material' variable. But when you create your Mesh you use some 'vertexColorMaterial' variable that is not described above. Maybe that is the problem in your code?

Three js renderer size issues. Trying to set a perfect size

I've been working on three js model , to embed the model to my website. Finally made it but there's only one problem.I couldn't get the renderer.setSize() to fit my div. In other words, I can see scroll bar which I don't want to see there. How do I setSize so that it perfectly fits my canvas ?
I saw one post regarding the same problem , he wanted to avoid scrolling as well. I tried to follow the answer as stated in the post but nothing's going on. Then I headed to three js documentation , followed what stated there.
.setSize ( width : Integer, height : Integer, updateStyle : Boolean ) : null
Still couldn't figure it out. Why even the code in documentation is not working ? BUT , i'm not sure if I found a trick , I was just playing around with the setSize values.
renderer.setSize( window.innerWidth * 0.99 ,window.innerHeight * 0.99);
as you can see there , I added * 0.99 , and there's no more scroll bar! Didn't mean to do it this way , but what's the correct code to adjust it ? Here's my code
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>THEE JS BOX APP</title>
<style>
body { margin: 0; width: 100%; height: 100% }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/OBJloader.js"></script>
<script>
// CREATING AN EMPTY SCENE
var scene = new THREE.Scene();
// CAMERA
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 9000 );
camera.position.z = 200;
// ORBIT CONTROL
var controls = new THREE.OrbitControls( camera );
// RENDERER
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff");
renderer.setSize( window.innerWidth * 0.99 ,window.innerHeight * 0.99);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// APPEND RENDERER TO DOM
document.body.appendChild( renderer.domElement );
// WINDOW RESIZE
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
// instantiate a loader
var loader = new THREE.OBJLoader();
// load a resource
loader.load(
// resource URL
'img/logovoivode1.obj',
// called when resource is loaded
function ( object ) {
scene.add( object );
},
// called when loading is in progresses
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
// ***************************** LIGHTING **********************************//
// White directional light at half intensity shining from the top.
//var directionalLight = new THREE.DirectionalLight( 0xffffff, 5 );
//scene.add( directionalLight );
var light = new THREE.AmbientLight( 0xffffff, 0.5); // soft white light
scene.add( light );
var pointlight = new THREE.PointLight( 0xffffff, 0.5, 1000);
light.position.set(10, 0, 25);
scene.add(pointlight);
//var DLight = new THREE.DirectionalLight( 0xffffff, 50);
//scene.add(DLight);
// var spotlight = new THREE.SpotLight( 0xffffff, 0.5, 1000, 0.3);
// ************************ END-OF-LIGHTING *****************************//
// CREATING A BOX
// var geometry = new THREE.BoxGeometry(1, 1, 1);
// var material = new THREE.MeshBasicMaterial({ color: 0xffffff, wireframe:true});
// var cube = new THREE.Mesh( geometry, material);
// ADD CUBE TO THE SCENE
// scene.add(cube);
// ANIMATION LOOP
function animate() {
requestAnimationFrame( animate );
//scene.rotation.x += 0.01;
//scene.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
Your issue is caused by "inner element whitespaces".
When an html parser parses your source code, it also parses the spaces/entets/tabs between your tags as text, and then makes it smaller till its just 1 space. This 1 space is the cause of your issue, but knowing what causes it is the first step to solving the problem.
Original problem, for reference:
body {
margin: 0;
width: 100%;
height: 100%;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/OrbitControls.js"></script>
<script>
// CREATING AN EMPTY SCENE
var scene = new THREE.Scene();
// CAMERA
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 9000 );
camera.position.z = 200;
// ORBIT CONTROL
var controls = new THREE.OrbitControls( camera );
// RENDERER
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff");
renderer.setSize( window.innerWidth ,window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// APPEND RENDERER TO DOM
document.body.appendChild( renderer.domElement );
// WINDOW RESIZE
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
scene.add( new THREE.Mesh( new THREE.CubeGeometry(100,130,70), new THREE.MeshBasicMaterial({ color: 0x444444 }) ) );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
</script>
Using font-size: 0
By setting the font-size to 0, you basically squash the space to PX width and height, making sure it doesn't contribute to your problem
body {
margin: 0;
width: 100%;
height: 100%;
font-size: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/OrbitControls.js"></script>
<script>
// CREATING AN EMPTY SCENE
var scene = new THREE.Scene();
// CAMERA
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 9000 );
camera.position.z = 200;
// ORBIT CONTROL
var controls = new THREE.OrbitControls( camera );
// RENDERER
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff");
renderer.setSize( window.innerWidth ,window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// APPEND RENDERER TO DOM
document.body.appendChild( renderer.domElement );
// WINDOW RESIZE
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
scene.add( new THREE.Mesh( new THREE.CubeGeometry(100,130,70), new THREE.MeshBasicMaterial({ color: 0x444444 }) ) );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
</script>
Using overflow: hidden
Just take our problems, and hide them for the next person trying to fix it properly.
body {
margin: 0;
width: 100%;
height: 100%;
}
html, body {
overflow: hidden;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/OrbitControls.js"></script>
<script>
// CREATING AN EMPTY SCENE
var scene = new THREE.Scene();
// CAMERA
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 9000 );
camera.position.z = 200;
// ORBIT CONTROL
var controls = new THREE.OrbitControls( camera );
// RENDERER
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff");
renderer.setSize( window.innerWidth ,window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// APPEND RENDERER TO DOM
document.body.appendChild( renderer.domElement );
// WINDOW RESIZE
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
scene.add( new THREE.Mesh( new THREE.CubeGeometry(100,130,70), new THREE.MeshBasicMaterial({ color: 0x444444 }) ) );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
</script>
Using display: flex
When you use the flex display mode, the browser ignores all inner white spaces in the current element
body {
margin: 0;
width: 100%;
height: 100%;
display: flex;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/OrbitControls.js"></script>
<script>
// CREATING AN EMPTY SCENE
var scene = new THREE.Scene();
// CAMERA
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 9000 );
camera.position.z = 200;
// ORBIT CONTROL
var controls = new THREE.OrbitControls( camera );
// RENDERER
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff");
renderer.setSize( window.innerWidth ,window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// APPEND RENDERER TO DOM
document.body.appendChild( renderer.domElement );
// WINDOW RESIZE
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
scene.add( new THREE.Mesh( new THREE.CubeGeometry(100,130,70), new THREE.MeshBasicMaterial({ color: 0x444444 }) ) );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
</script>
Setting the display of the canvas to block
If you set the display property of the canvas to block, then you don't have to worry about the inner element white spaces, as they don't have anny effect between block elements.
body {
margin: 0;
width: 100%;
height: 100%;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three#0.101.1/examples/js/controls/OrbitControls.js"></script>
<script>
// CREATING AN EMPTY SCENE
var scene = new THREE.Scene();
// CAMERA
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 9000 );
camera.position.z = 200;
// ORBIT CONTROL
var controls = new THREE.OrbitControls( camera );
// RENDERER
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff");
renderer.setSize( window.innerWidth ,window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// APPEND RENDERER TO DOM
document.body.appendChild( renderer.domElement );
// WINDOW RESIZE
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
scene.add( new THREE.Mesh( new THREE.CubeGeometry(100,130,70), new THREE.MeshBasicMaterial({ color: 0x444444 }) ) );
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
</script>

Three.js Collada model displayed black with no lights till a mouse movement

I've encountered one strange problem with displaying collada model in three.js
I suspect that something wrong with the logic of the script but I can't figure out.
The problem is that the Collada model is displayed black till a user moves a mouse (orbit controls). Only after this the model gets lighted.
So, initially, when the page loads, the model is black and this is confusing a user.
What's wrong with the code? Where could be the error?
The code of the script is the following:
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, controls, scene, renderer;
var pointLight;
init();
render();
function animate()
{
pointLight.position.copy( camera.position );
requestAnimationFrame(animate);
controls.update();
}
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( -40, 70, 70 );
controls = new THREE.OrbitControls( camera );
controls.damping = 0.2;
controls.addEventListener( 'change', render );
scene = new THREE.Scene();
// world
var mesh;
var loader = new THREE.ColladaLoader();
loader.load('./models/collada/test.dae', function (result) {
mesh = result.scene;
mesh.scale.set(0.3, 0.3, 0.3);
scene.add(mesh);
render();
});
// lights
var hemLight = new THREE.HemisphereLight(0x000000, 0x303030, 0.8);
scene.add(hemLight);
pointLight = new THREE.PointLight( 0xffffff, 1.1 );
pointLight.position.copy( camera.position );
scene.add( pointLight );
// renderer
renderer = new THREE.WebGLRenderer({antialias:true, alpha:true});
renderer.setClearColor(0xEEEEEE, 1);
renderer.shadowMapType = THREE.PCFSoftShadowMap;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
animate();
}
function onWindowResize()
{
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
render();
}
function render()
{
renderer.render( scene, camera );
}
</script>
You're not calling render() from your animate() function, so the scene is only rendered through the OrbitControls onChange event. Add render() at the end of animate() and it will work. You can also then remove the onChange callback, since you'll be rendering steadily.

Three.js - VRML Loader

I'm trying to use the Three.js with VRML (WRL) models. What I am wondering is that the model is loaded with variations of colors (colored). How can I load the model in solid color as the original file?
My example is: http://dev.logicarts.com.br/semapro/projeto-3d/teste-1.html
The code:
<div id="info">
three.js -
vrml format loader test -
<!--model from VRML 2.0 Tutorial,-->
</div>
<script src="js/three.min.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/VRMLLoader.js"></script>
<script src="js/Detector.js"></script>
<script src="js/stats.min.js"></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var container, stats;
var camera, controls, scene, renderer;
var cross;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10 );
camera.position.z = 6;
controls = new THREE.OrbitControls( camera );
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.noZoom = false;
controls.noPan = false;
scene = new THREE.Scene();
scene.add( camera );
// light
var dirLight = new THREE.DirectionalLight( 0xffffff );
dirLight.position.set( 200, 200, 1000 ).normalize();
camera.add( dirLight );
camera.add( dirLight.target );
var loader = new THREE.VRMLLoader();
loader.addEventListener( 'load', function ( event ) {
scene.add(event.content);
} );
loader.load( "3d/conjunto-carcaca.wrl" );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setSize( window.innerWidth, window.innerHeight );
container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
controls.handleResize();
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
stats.update();
}
</script>
If you add this code under the scene.add(event.content); statement, all the objects in your scene will turn red.
scene.traverse (function (object)
{
if (object instanceof THREE.Mesh) {
object.material.color.setHex( 0xff0000 );
}
});

Categories