i asked yesterday about how to draw 3D objects in the browser, be able to manipulate them with the mouse and be sure that it works in every browser. Now i am using three.js and im quite happy because it actually works.
I was able to understand the basic tutorial, draw my first scene and rotate the first cube etc.
Now i want to be able to rotate the complete scene with the mouse, googled and found this link. Works fine in the example and i tried to copy the example. Current code looks like this:
<html>
<head>
<title>My first Three.js app</title>
<style>canvas { width: 100%; height: 100% }</style>
</head>
<body>
<script src="three.min.js"></script>
<script src="TrackballControls.js"></script>
<script type="text/javascript">
// Variables
var scene, camera, controls, renderer;
var geometry, material, cube;
init();
animate();
render();
function init() {
// Scene, camera
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 500, window.innerWidth / window.innerHeight, 0.1, 1000 );
// Mouse controls
controls = new THREE.TrackballControls(camera);
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
controls.keys = [ 65, 83, 68 ];
controls.addEventListener('change',test,false);
// Renderer
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// Basic cube to show
geometry = new THREE.CubeGeometry(10,10,10);
material = new THREE.MeshBasicMaterial({color:0x00ff00});
cube = new THREE.Mesh(geometry);
scene.add(cube);
camera.position.z = 10;
}
function test() {
alert("hi");
render();
}
function animate() {
requestAnimationFrame(render);
controls.update();
}
function render() {
renderer.render(scene, camera);
//cube.rotation.x += 0.1;
//cube.rotation.y += 0.1;
}
</script>
</body>
But it doesn't work. The testoutput "hi" only appears once. It should appear quite often when using the mouse. What i tried to accomplish is that controls.addEventListener('change',test,false); looks if anything with the mouse changes (position, keydown etc.) and then calls a new renderframe. In the example (Example) it somehow does what i want it to do.
What am i doing wrong here? I just want to be able to rotate the camera with mousedragging. And yes i am totally new to this. Just read about it for 2 hours now.
Thanks in advance.
Related
I am a novice to Javascript and ThreeJS. I have a 3D rotating cube that appears on top of a static background, but one frustrating property is that the cube typically appears first and then the background image appears. How do I ensure the background is rendered first? Specifically, I always want the background image to appear before the cube.
My code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
function resize() {
var aspect = window.innerWidth / window.innerHeight;
let texAspect = bgWidth / bgHeight;
let relAspect = aspect / texAspect;
bgTexture.repeat = new THREE.Vector2( Math.max(relAspect, 1), Math.max(1/relAspect,1) );
bgTexture.offset = new THREE.Vector2( -Math.max(relAspect-1, 0)/2, -Math.max(1/relAspect-1, 0)/2 );
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = aspect;
camera.updateProjectionMatrix();
}
const scene = new THREE.Scene();
// Arguments:
// 1) Field of Value (degrees)
// 2) Aspect ratio
// 3) Near clipping plane
// 4) Far clipping plane
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer();
// Need to set size of renderer. For performance, may want to reduce size.
// Can also reduce resolution by passing false as third arg to .setSize
renderer.setSize( window.innerWidth, window.innerHeight );
// Add the rendered to the HTML
document.body.appendChild( renderer.domElement );
// A BoxGeometry is an object that contains all points (vertices) and fill (faces)
// of the cube
const geometry = new THREE.BoxGeometry();
// Determines surface color (maybe texture?)
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
// Mesh takes a geometry and applies the material to it
const cube = new THREE.Mesh( geometry, material );
// Add background image
const loader = new THREE.TextureLoader();
bgTexture = loader.load('https://images.pexels.com/photos/1205301/pexels-photo-1205301.jpeg' ,
function(texture) {
// Resize image to fit in window
// Code from https://stackoverflow.com/a/48126806/4570472
var img = texture.image;
var bgWidth = img.width;
var bgHeight = img.height;
resize();
});
scene.background = bgTexture;
// By default, whatever we add to the scene will be at coordinates (0, 0, 0)
scene.add( cube );
camera.position.z = 5;
// This somehow creates a loop that causes the rendered to draw the scene
// every time the screen is refreshed (typically 60fps)
function animate() {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
This is happening because the texture is taking longer to load than it takes for Three.js to set up the rest of the scene. You already have a handler for the onLoad callback of TextureLoader.load(), so we can use that to adjust the behavior.
Before scene.add( cube );, add a new line:
cube.visible = false;
Now the cube will still be added to the scene, but it won't be visible. Now after the resize() call at the end of function(texture), add
cube.visible = true;
While testing the problem and solution locally, I ran into a few other, less significant issues with your code. You can see all of the changes I had to make to get it running properly at this Gist.
I try to do a 3D animation with Three.js controls. During the execution of my code in Firefox, a have this error :
EDIT
SyntaxError: import declarations may only appear at top level of a module
And here is my code, simplified :
<!DOCTYPE html>
<head>
<title>Three.js Test</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100%;};
</style>
</head>
<body>
<script src="js/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script type="module">
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);
//keep the scene in center of the page
window.addEventListener('resize', function() {
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width,height);
//prevent distortion
camera.aspect = width / height;
camera.updateProjectionMatrix();
});
controls = new THREE.OrbitControls(camera, renderer.domElement);
// create the shape
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0xFF0080 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
function animate()
{
requestAnimationFrame( animate );
/*cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
cube.rotation.z += 0.01;*/
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
I don't understand where the error came from and I don't know how to fix it.
I now run my code on a wamp server.
Thanks for your help !
import * as THREE from './jsthree.module.js';
It seems there is a typo. It should be ./js/three.module.js.
In any event, ensure to run your code on a local web server in order to avoid any security issues. More information about this topic in the following guide:
https://threejs.org/docs/index.html#manual/en/introduction/How-to-run-things-locally
I am trying to just copy the example three.js page into my own small website with a canvas where the 3d animation should be added to. But it just shows nothing even though it shows no errors.
I tried figuring it out by myself but nothing seems to work :(
i have my canvas element in one div on the page:
var canvas = document.getElementById("background");
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.canvas = canvas;
renderer.setSize(canvas.innerWidth, canvas.innerHeight);
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;
var animate = function() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
#background {
height: 100%;
width: 100%;
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.min.js"></script>
<canvas id='background'></canvas>
Can you please take a look and show me what i did wrong?
Unless there is a reason for trying to create your own canvas, you can just let three.js produce its own with the following code:
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
With this it creates a new element sets the height and width to match the window and then adds it to the html.
To alter the style further you should use
renderer.domElement.style.attribute = "";
and then you just replace attribute with whatever you are trying to modify.
For more examples you can visit this link:
https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Using_dynamic_styling_information
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
I got this code from webgl I have used it same as they mentioned in their tutorial but i cannot get result on my browser screen only i can see is just black background nothing else. i have used three.js library to create 3d model of cube.
<pre>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
canvas { width: 100%; height: 100% }
</style>
<title>Pryamid</title>
</head>
<body>
<script>
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 cubegeometry = new THREE.CubeGeometry(1,1,1);
var cubematerial = new THREE.MeshBasicMaterial({wireframe: true, color: 0x000000});
var cube = new THREE.Mesh(cubegeometry, cubematerial);
scene.add(cube);
camera.position.z = 5;
var render = function () {
requestAnimationFrame(render);
cube.rotation.y += 0.01;
cube.rotation.x += 0.01;
cube.rotation.z += 0.01;
renderer.render(scene, camera);
};
// Calling the render function
window.onload = function() {
render();
};
</script>
</body>
</html>
Is this your full code? I think it would be helpful if you posted the full HTML context of what you're trying to achieve.
However, what I see at first blink, is that you either don't add the rendering target to your HTML page, or you don't use the canvas you have in your HTML to render to.
The easiest way to get your cube displayed, is by adding the rendering canvas to your page's DOM, with:
document.body.appendChild( renderer.domElement );