Three.js - Insert separate js file in HTML - javascript

I am working with three.js right now and have a 3D cube rendered in HTML. The HTML code looks like this:
<div id="render" class="center-block">
<script>
var camera;
var scene;
var renderer;
var mesh;
var geometry;
var material1;
var material2;
var material3;
var material4;
var material5;
var material6;
var materials;
var meshFaceMaterial;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 20, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set( 0, 0, 0 );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 ).normalize();
scene.add(light);
geometry = new THREE.CubeGeometry( 10, 10, 10);
material1 = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('http://vignette1.wikia.nocookie.net/scifiminibuilders/images/8/88/Your_Picture_Here.png/revision/latest?cb=20130507015051') } );
material2 = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('http://vignette1.wikia.nocookie.net/scifiminibuilders/images/8/88/Your_Picture_Here.png/revision/latest?cb=20130507015051') } );
material3 = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('http://vignette1.wikia.nocookie.net/scifiminibuilders/images/8/88/Your_Picture_Here.png/revision/latest?cb=20130507015051') } );
material4 = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('http://vignette1.wikia.nocookie.net/scifiminibuilders/images/8/88/Your_Picture_Here.png/revision/latest?cb=20130507015051') } );
material5 = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('http://vignette1.wikia.nocookie.net/scifiminibuilders/images/8/88/Your_Picture_Here.png/revision/latest?cb=20130507015051') } );
material6 = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture('http://vignette1.wikia.nocookie.net/scifiminibuilders/images/8/88/Your_Picture_Here.png/revision/latest?cb=20130507015051') } );
materials = [material1, material2, material3, material4, material5, material6];
meshFaceMaterial = new THREE.MeshFaceMaterial( materials );
mesh = new THREE.Mesh(geometry, meshFaceMaterial );
mesh.position.z = -50;
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById('render').appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
function animate() {
mesh.rotation.x += .016;
mesh.rotation.y += .015;
mesh.rotation.y += .014;
render();
requestAnimationFrame( animate );
}
function render() {
renderer.render( scene, camera );
}
</script>
</div>
There is quite too much script. I want to make a separate .js file from that, but don't know how do accomplish it with three.js. Any suggestions?
EDIT:
As I understand, the script works like a canvas tag, without entering the tag in HTML. This probably disturbs by making a separate .js file...

You just need to add a reference to the other .js file. You've already got a reference on your page for THREE.js, I assume. So you can just copy that and reference that second file.
<script src="THREE.js"></script>
<script src="other_script.js"></script>
And put all your extra code into other_script.js (or whatever filename you use).

You most likely need to wrap your functions in a document ready tag like this:
$(function(){
init();
animate();
})
That way the external js file has been loaded for sure before you try using the functions inside of it... Basically it has to be available in the DOM when your functions fire.

Related

Having problems to set a glTF object to a different layer in Three.js

I´m trying to make use of layers in Three.js.
I have this script with a sphere, a triangle and a glTF object (car).
I made a second layer enable: camera.layers.enable(1);
Set the sphere, the triangle and the glTF object to the layer 1:
car.layers.set( 1 );
sphere.layers.set( 1 );
triangle.layers.set( 1 );
But when i set the camera to the layer 1 ( camera.layers.set(1); ), the glTF object does not display, but other elements do. So, it seens like i can´t set the glTF object to a different layer then default layer.
Here is the code. What could be wrong?
Thanks for the attention!
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, 0.1, 3000);
camera.position.set( 0, 0.1, 1 );
camera.layers.enable(1);
camera.layers.set(1);
var renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setClearColor("#f5e5e5");
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// LIGHT ------------------------------------------------------------------------------>
var dLight = new THREE.DirectionalLight( 0x0000ff, 6.5 );
dLight.position.set(1500, -700, 500);
dLight.castShadow = true;
dLight.layers.set(1);
scene.add( dLight);
// Load a glTF resource -------------------------------------------------------->
var loader = new THREE.GLTFLoader();
var car;
loader.load('car.gltf', function ( gltf ) {
car = gltf.scene.children[0];
car.scale.set(0.5, 0.5, 0.5);
car.position.z = 0;
car.position.y = -0.095;
car.layers.set(1);
scene.add( gltf.scene );
render();
});
// SPHERE --------------------------------------------------------------->
var material = new THREE.MeshLambertMaterial();
var geometry = new THREE.SphereGeometry(0.05, 20, 20);
var sphere = new THREE.Mesh(geometry, material);
sphere.position.x = 0.25;
scene.add(sphere);
sphere.layers.set( 1 );
// TRIANGLE ------------------------------------------------------------->
var geometre = new THREE.Geometry();
geometre.vertices.push(new THREE.Vector3(-0.25, -0.1, 0));
geometre.vertices.push(new THREE.Vector3(0, 0.30, 0));
geometre.vertices.push(new THREE.Vector3(0.25, -0.1, 0));
geometre.vertices.push(new THREE.Vector3(-0.25, -0.1, 0));
var triangle= new THREE.Line(geometre, new THREE.LineBasicMaterial({ color: 0x000000, linewidth: 12 }));
triangle.layers.set( 1 );
scene.add(triangle);
// POST-PROCESSING ------------------------------------------------------->
var composer = new THREE.EffectComposer(renderer);
var renderPass = new THREE.RenderPass(scene, camera);
composer.addPass(renderPass);
var pass1 = new THREE.GlitchPass(0);
composer.addPass(pass1);
// RENDER -------------------------------------------------------------->
requestAnimationFrame(render);
function render(){
sphere.rotation.y += -0.02;
car.rotation.y += 0.01;
composer.render();
requestAnimationFrame(render);
};
</script>
You have to set layers recursively for the entire hierarchy of objects like so:
gltf.scene.traverse( function( object ) {
object.layers.set( 1 );
} );
By default, a layer configuration does not automatically apply to its descendant nodes in the scene graph.
three.js r116

change a picture dynamically 360

<div style="margin-bottom: 200px">
sdsadasdas
</div>
<div id="container"></div>
<div id="info"> </div>
I have an image using three.js which I need to change dynamically by others when I click on a button
<!-- <script src="three.min.js"></script> -->
<script>
var camera, scene, renderer;
var texture_placeholder,
isUserInteracting = false,
onMouseDownMouseX = 0, onMouseDownMouseY = 0,
lon = 0, onMouseDownLon = 0,
lat = 0, onMouseDownLat = 0,
phi = 0, theta = 0;
var imagen='HabitacionPrincipal'
init(imagen);
function cambio(){
//What would I need to place here to be able to make the change dynamically?
}
function init(imagen) {
var container, mesh;
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
camera.target = new THREE.Vector3( 0, 0, 0 );
scene = new THREE.Scene();
var geometry = new THREE.SphereGeometry( 500, 60, 40 );
geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) );
console.log(imagen)
var material = new THREE.MeshBasicMaterial( {
map: THREE.ImageUtils.loadTexture( imagen+'.jpg' )
} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
animate();
}
</script>
I need to change the image by a previously selected one
I tried this post but not sucessc
Threejs Change image at runtime
You need to make the variable globally accessible, instead of limiting its scope to the init() function.
Think of it as a Venn diagram, you have to place material outside init() and cambio() so that it's available to both. You can do this by declaring it on line 1:
var camera, scene, renderer, material;
Then, you can initialize material inside init() without using var:
function init(imagen) {
// ...
material = new THREE.MeshBasicMaterial( {
map: THREE.ImageUtils.loadTexture( imagen+'.jpg' )
} );
// ...
}
Once you're ready to call cambio(), the material will be globally available, so you can access it and change its map:
function cambio(){
material.map = THREE.ImageUtils.loadTexture( 'secondImage.jpg' );
}

Three js in a class

I tried to set all the necessary functionality into one class in order to create a simple three.js scene with a cube. I don't get any errors, but the scene stays black when I open it in the browser.
Here is my code:
class SceneInit {
constructor(fov = 45,camera,scene,controls,renderer)
{
this.camera = camera;
this.scene = scene;
this.controls = controls;
this.renderer = renderer;
this.fov = fov;
}
initScene() {
this.camera = new THREE.PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 1, 1000);
this.camera.position.z = 15;
this.controls = new THREE.TrackballControls( this.camera );
//this.controls.addEventListener('change', this.renderScene);
this.scene = new THREE.Scene();
//specify a canvas which is already created in the HTML file and tagged by an id //aliasing enabled
this.renderer = new THREE.WebGLRenderer({canvas: document.getElementById('myThreeJsCanvas') , antialias: true});
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this.renderer.domElement);
//ambient light which is for the whole scene
let ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
ambientLight.castShadow = false;
this.scene.add(ambientLight);
//spot light which is illuminating the chart directly
let spotLight = new THREE.SpotLight(0xffffff, 0.55);
spotLight.castShadow = true;
spotLight.position.set(0,40,10);
this.scene.add(spotLight);
//if window resizes
window.addEventListener('resize', this.onWindowResize, false);
}
animate(){
requestAnimationFrame( this.animate.bind(this) );
this.render();
this.controls.update();
}
render(){
this.renderer.render( this.scene, this.camera );
}
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize( window.innerWidth, window.innerHeight );
}
}
And then I try to instantiate a new object and add an object to the scene. When I try to print the children of the scene, it returns me the right objects, but as I mentioned before the scene stays black. Only the renderer window is getting drawed in the browser.
let test = new SceneInit(45);
test.initScene();
test.animate();
let geometry = new THREE.BoxBufferGeometry( 200, 200, 200 );
let material = new THREE.MeshBasicMaterial();
let mesh = new THREE.Mesh( geometry, material );
test.scene.add(mesh);
console.log(test.scene.children); //returns 3 objects (ambientLight, spotLight, mesh)
I got the answer.
The problem in the code was that the BoxGeometry was too big and the camera was inside the box. With the clipping set to 1 it wouldn't even render it.
So the solution is to set a smaller BoxGeometry. or to move the camera away!

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?

Repeating a bump map

I'm trying to apply a bump map to a plane to create a vaguely felt-like surface using Three.js r55.
Here's my code:
var mapHeight = THREE.ImageUtils.loadTexture("images/felt.png");
mapHeight.repeat.set(2, 2);
mapHeight.wrapS = mapHeight.wrapT = THREE.RepeatWrapping;
mapHeight.format = THREE.RGBFormat;
var groundMaterial = new THREE.MeshPhongMaterial({
ambient: 0x008800, color: 0x008800, specular: 0x888888,
shininess: 25, bumpMap: mapHeight, bumpScale: 10, metal: false
} );
scene.add(new THREE.Mesh(new THREE.PlaneGeometry(0.3, 0.3), groundMaterial));
Notice how I set the texture to repeat twice along x/y axes. However what I'm seeing only applies the texture in one quadrant:
I would expect this with clamp/repeat wrapping (or whatever it's called) but I've requested RepeatWrapping here.
How can I have the bump map correctly repeat an arbitrary number of times on the plane.
EDIT - Full Code
I set about making a simple reproduction case. This is pretty minimal and reproduces the image below (from a slightly different camera angle.) The output has the identical problem.
<!DOCTYPE html>
<html>
<head>
<script src="scripts/libs/three.min.js" type="text/javascript"></script>
</head>
<body>
<div id="scene-container"></div>
<script>
init();
function init() {
var camera, scene, renderer;
scene = new THREE.Scene();
scene.add( new THREE.AmbientLight( 0x555555 ) );
var light = new THREE.DirectionalLight( 0x555555 );
light.position.set( 0, 0, 10 );
scene.add( light );
var bumpMapTexture = THREE.ImageUtils.loadTexture( "images/felt.png", undefined, function () {
requestAnimationFrame( function () {
// render once texture has loaded
renderer.render( scene, camera );
} );
} );
bumpMapTexture.repeat.set( 2, 2 );
bumpMapTexture.wrapS = bumpMapTexture.wrapT = THREE.RepeatWrapping;
var groundMaterial = new THREE.MeshPhongMaterial( {
ambient: 0x00AA00,
color: 0x00AA00,
bumpMap: bumpMapTexture
} );
scene.add( new THREE.Mesh( new THREE.PlaneGeometry( 3, 3 ), groundMaterial ) );
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.01, 100000 );
camera.position.set( 0, 0, 3 );
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );// renderer.render(scene, camera);
document.getElementById( 'scene-container' ).appendChild( renderer.domElement );
}
</script>
</body>
</html>
This links to Three.js r55 (minified).
Any help appreciated.
If you want a texture to repeat, it's size in pixels in each dimension must be a power of two ( e.g., 512 x 256 ).
If you have a diffuse map and a bumpMap, they must have the same offset/repeat settings. See for example this answer.
three.js r.55

Categories

Resources