I want to apply a script(from javascript) only in ONE DIV(not at all the page). Is it possible? (I think it's a resize problem if we modify the height of the div it partly works but the width doesn't affect by change(I talk about the div))
Here's my script:
var camera2, scene2;
function init2() {
var container, stats;
container = document.createElement( 'div' );
document.body.appendChild( container );
camera2 = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
camera2.position.z = 250;
scene2 = new THREE.Scene();
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
scene2.add( ambientLight );
var pointLight = new THREE.PointLight( 0xffffff, 0.8 );
camera2.add( pointLight );
scene2.add( camera2 );
var loader = new THREE.OBJLoader();
var mtlLoader = new THREE.MTLLoader();
mtlLoader.load( "3d_models/OBJ/ano/ano.mtl", function( materials ) {
materials.preload();
console.log(materials);
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.load("3d_models/OBJ/ano/ano.obj", function ( object ) {
console.log(object.children[0])
scene2.add( object );
onRenderFcts.push(function(){
object.rotation.y += 0.03;
})
});
},
function ( xhr ) {
console.log( 'OBJ ' + ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log(error);
});
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
}
And is it possible to change the background, it's actually a black background I just want a transparent background.
EDIT: Here is the screenshot: the golden rign is my 3d object and the green square is my div
image
EDIT2: To clarify the problem, I have a page and on the page there is a div just want to apply the three.js function only on this div. So at the end, i could see my golden ring only in the div
I obtained a "correct" result by grope. Here's the code I modify:
container = document.createElement( 'div' );
var att = document.createAttribute("class");
att.value = "test";
container.setAttributeNode(att);
document.body.appendChild( container );
then here's the test and canvas class in css:
.test{
width:100px;
height:100px;
position: fixed;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
}
canvas{
width:500px;
height:500px;
margin-top: -275px;
margin-left: -630px;
}
But now there is another problem. If a I try to call the script on a more complex code it doesn't work ! The console doesn't notice error. Here's the picture describing the situation: img
So the golden ring should be on the marker(the logo on the left) and in the black zone there is normally the golden ring rotate normally. Also the blackzone can be fixed with the tips in the com of my first post.
Related
I'm starting on three.js and I'm already stuck on a trivial case : display an image on a sprite. I can only get a black plane following the lines written in the documentation:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>TEST Sprite</title>
<style>
body { margin: 0; background-color:#000; }
canvas { width: 100%; height: 100%; }
#glRender {
position:absolute;
top: 50px;
left: 200px;
min-width: 200px;
width: 50%;
min-height: 200px;
z-index: 1;
height: 50%;
border: 10px solid #38272C;
}
</style>
</head>
<body>
<div id="glRender"></div>
<script src="http://threejs.org/build/three.js"></script>
<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 / 2, window.innerHeight / 2 );
container = document.getElementById( 'glRender' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
// A simple cube
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 );
// completely black...
var photoTexLoad = new THREE.TextureLoader().load( 'http://s2.favim.com/610/150817/plage-summer-Favim.com-3137863.jpg' );
var matPhoto = new THREE.SpriteMaterial( { map: photoTexLoad, color: 0xffffff } );
var sprite = new THREE.Sprite( matPhoto );
sprite.scale.set( 2, 2, 2 );
sprite.position.set( 1, 0, 0.5 );
scene.add( sprite );
camera.position.z = 5;
function render() {
requestAnimationFrame( render );
cube.rotation.x += 0.01;
cube.rotation.y += 0.1;
renderer.render( scene, camera );
}
render();
</script>
</body>
</html>
I get the spinning green cube intersecting with a black plane.
What did I miss to have the image displayed on the plane?
.TextureLoader().load() is asynchronous. Trying to apply it immediately after invoking it leads to a black plane in your code most likely because the texture has not finished loading.
You can solve this by:
Passing a callback to .load as a 2nd parameter. (It is called once the texture has finished loading):
var matPhoto,
sprite,
texloader = new THREE.TextureLoader();
texloader.load('http://s2.favim.com/610/150817/plage-summer-Favim.com-3137863.jpg',
function(tex) {
matPhoto = new THREE.SpriteMaterial( { map: tex, color: 0xffffff } );
sprite = new THREE.Sprite( matPhoto );
//...etc...
}
);
OR
set an event listener:
var texloader = new THREE.TextureLoader();
texloader.load('http://s2.favim.com/610/150817/plage-summer-Favim.com-3137863.jpg');
textureLoader.addEventListener('load', function(event){
// event.content holds the texture---------------v
matPhoto = new THREE.SpriteMaterial( { map: event.content, color: 0xffffff } ); = event.content;
});
I just found out I got the "CORS" issue highlighted in question three.js: texture goes all black
The code is working fine but I cannot try to load an image from external website or directly on my computer, only files on my localhost.
For testing, I now use a specific instance of google chrome using a desktop shortcut launching the browser as : "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --args --user-data-dir="C:/Chrome dev session" --disable-web-security
I'm very new to Three.JS and 3D web dev in general what I'm trying to do is mimic this action: https://www.youtube.com/watch?v=HWSTxPc8npk&feature=youtu.be&t=7s Essentially this is a set of 3D planes and upon click the whole stack reacts and gives space around the one that's clicked.
For now, my base case is 3 planes and figuring first out if I can click the the middle one, how do I get the others to jump back smoothly as if they were pushed rather than instant appear and disappear as they do now on the click of a button.
The long term goal is to have a separate button for every plane so that on click, the selected plane will have padding around it and the rest of the planes in stack move accordingly.
I've looked into Tween.js, and CSS3D but pretty overwhelmed as a newbie. Any tutorials or tips would be greatly appreciated!
// Our Javascript will go here.
window.addEventListener( 'resize', onWindowResize, false );
function onWindowResize(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
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 geometry = new THREE.PlaneGeometry( 3, 3, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var plane = new THREE.Mesh( geometry, material );
plane.rotation.y = -.7;
var material2 = new THREE.MeshBasicMaterial( { color: 0x0000ff } );
var material3 = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var plane2 = new THREE.Mesh(geometry, material2 );
plane2.rotation.y = -.7;
plane2.position.x = 1;
var plane3 = new THREE.Mesh(geometry, material3);
plane3.rotation.y = -.7;
plane3.position.x = -1;
scene.add( plane, plane2, plane3 );
camera.position.z = 5;
function render() {
requestAnimationFrame( render );
// cube.rotation.x += 0.1;
// cube.rotation.y += 0.1;
renderer.render( scene, camera );
}
render();
function clickFirst() {
TWEEN.removeAll();
var tween = new TWEEN.Tween(plane3.position).to({x: -2}, 1000).start();
tween.easing(TWEEN.Easing.Elastic.InOut);
render();
}
</script>
<button onclick="clickFirst();" style="background-color: white; z-index: 9999;">Click me</button>
First, you need to locate the 2 planes.
Second, you need to make the planes clickable:
https://threejs.org/examples/#webgl_interactive_cubes
https://github.com/josdirksen/learning-threejs/blob/master/chapter-09/02-selecting-objects.html
Third, you should use Tween.js for the transition.
after picking the right plane, make a tween for the other planes with a tween, all to move on the same Axis:
example:
createjs.Tween.get(plane3.position.z).to(
plane3.position.z + 100
, 1000, createjs.Ease.cubicOut)
If you will add some code here after starting to implement i would be able to help more.
I have a model i'm exporting from blender 2.76b into json and then loading with three.js 71. Blender the model looks fine. In webGL the model is completely black. I'm think it has something to do with the textures but i'm not sure. The model is a fairly complex model made from maya and exported as an fbx. I've tested with simpler models and different textures and not had any problems but there's something wrong with this one.
Any suggestions would be appreciated greatly.
Link to the json: http://we.tl/GnQiOfAhOD
Here's the code.
<!DOCTYPE html>
<html lang="en">
<head>
<title>MultiLoader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
color: #000;
margin: 0px;
overflow: hidden;
}
#info {
text-align: center;
padding: 10px;
z-index: 10;
width: 100%;
position: absolute;
}
a {
text-decoration: underline;
cursor: pointer;
}
#stats { position: absolute; top:0; left: 0 }
#stats #fps { background: transparent !important }
#stats #fps #fpsText { color: #aaa !important }
#stats #fps #fpsGraph { display: none }
</style>
</head>
<body>
<div id="info">MultiLoader Testing</div>
<script src="build/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/ColladaLoader.js"></script>
<script src="js/OBJLoader.js"></script>
<script>
WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 1,
FAR = 10000;
var container, stats;
var camera, scene, renderer;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
// SCENE
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0xffffff, 500, 10000 );
// CAMERA
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
camera.position.set(60, 40, 120);
camera.lookAt(scene.position);
scene.add(camera);
//LIGHTS
var front = new THREE.DirectionalLight( 0xffffff, 5.4 );
front.position.set( 0, 140, 1500 );
front.position.multiplyScalar( 1.1 );
//front.color.setHSL( 0.6, 0.075, 1 );
scene.add( front );
var ambient = new THREE.AmbientLight(0xffffff);
scene.add( ambient );
var back = new THREE.DirectionalLight( 0xffffff, 0.5 );
back.position.set( 0, -140, -1500);
scene.add( back );
//Avatar Tests
var loader = new THREE.JSONLoader();
loader.load('models/Maya/modelExport.json', function ( geometry, materials ) {
material = new THREE.MeshFaceMaterial( materials );
avatar = new THREE.Mesh( geometry, material );
}
);
loader.onLoadComplete=function(){
avatar.scale.set(30, 30, 30);
var position = new THREE.Vector3(0,-20,0);
avatar.position.add(position);
scene.add( avatar );
}
// RENDERER
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( scene.fog.color );
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMapEnabled = true;
container.appendChild( renderer.domElement );
// Orbit Controls
controls = new THREE.OrbitControls( camera, renderer.domElement );
//controls.addEventListener( 'change', render ); // add this only if there is no animation loop (requestAnimationFrame)
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.enableZoom = true;
//
stats = new Stats();
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 );
}
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
</script>
</body>
</html>
There are several issues with the code and model.
For the model: The entry mapLight should have been named mapDiffuse. I know you are exporting the model so you need to find how to make this happen.
For the code:
Your ambient light is very strong. It washes out everything. Try a value of 0x222222 or remove it from the scene totally.
Your camera does not need to be added to the scene.
Remove renderer.setClearColor( fog_color ) just to see if you get the correct meshes and materials first. Then you can go the scene effects.
Your texture size is way big. It is not supported in webgl. Try a size of 1024 and then move up is you need to.
Finally your loader.onLoadComplete() is never called (and will never be). Move that part of the code in your loader.load() callback function.
After all this you will see your girl.
I've created a simple WebGL 3D Panorama application using a SphereGeometry, PerspectiveCamera and a CanvasTexture. Now, I'm looking to bring the scene to life by adding "HotSpots" over certain parts of the SphereGeometry. The problem I'm having is understanding how to update the various DOMElements so that their position is reflective of the updated Camera position.
Basically, as the Camera rotates the various DOMElements would move in and out of view relative to the direction the camera is spinning. I tried positioning a <div> absolute to the <canvas> and translating the X and Y position using the returned PerspectiveCamera camera.rotation but it didn't really work; here's my JS & CSS implentation:
CSS
#TestHotSpot {
/* not sure if using margins is the best method to position hotspot */
margin-top: 50px;
margin-left: 50px;
width: 50px;
height: 50px;
background: red;
position: absolute;
}
JavaScript
/**
CONFIG is my stored object variable; it contains the PerspectiveCamera instance
code is being called inside of my RequestAnimationFrame
**/
config.camera.updateProjectionMatrix();
config.controls.update(delta);
document.getElementById("TestHotSpot").style.transform = "translate("+ config.camera.rotation.x +"px, "+ config.camera.rotation.y +"px)";
Here is also a live example of the desired effect.
What would be the best solution to fix this problem? What I noticed when I ran this that the DOMElements would only slightly move; I also noticed that they wouldn't really take in account where along the SphereGeometry they were placed (for example, being positioned "behind" the Camera; really complex!
I'm happy to use any plugins for the THREE.js engine as well as follow any tutorials. Thank you so much for replying in advance!
Try to set a planemesh/mesh to the desired point.
Copy the position of the css elements (domElements created with three.js cssObject [if you already know]) along with planemesh/mesh 's position.
And you will be done !!
Okay, chiming in on my own question! I had a few problems but I've figured out how to get CSS3d mixing in with THREE.js WebGL scenes.
So the first thing I had to do was update my THREE.js Library; I was running 71 from an earlier download but I needed to update it to the library Mr.Doob was using in this example. I also updated my CSS3d library to the file included in that same example.
I then used this method (the same specified in the link) to create a demo scene.
var camera, scene, renderer;
var scene2, renderer2;
var controls;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 200, 200, 200 );
controls = new THREE.TrackballControls( camera );
scene = new THREE.Scene();
scene2 = new THREE.Scene();
var material = new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true, wireframeLinewidth: 1, side: THREE.DoubleSide } );
//
for ( var i = 0; i < 10; i ++ ) {
var element = document.createElement( 'div' );
element.style.width = '100px';
element.style.height = '100px';
element.style.opacity = 0.5;
element.style.background = new THREE.Color( Math.random() * 0xffffff ).getStyle();
var object = new THREE.CSS3DObject( element );
object.position.x = Math.random() * 200 - 100;
object.position.y = Math.random() * 200 - 100;
object.position.z = Math.random() * 200 - 100;
object.rotation.x = Math.random();
object.rotation.y = Math.random();
object.rotation.z = Math.random();
object.scale.x = Math.random() + 0.5;
object.scale.y = Math.random() + 0.5;
scene2.add( object );
var geometry = new THREE.PlaneGeometry( 100, 100 );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.copy( object.position );
mesh.rotation.copy( object.rotation );
mesh.scale.copy( object.scale );
scene.add( mesh );
}
//
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
renderer2 = new THREE.CSS3DRenderer();
renderer2.setSize( window.innerWidth, window.innerHeight );
renderer2.domElement.style.position = 'absolute';
renderer2.domElement.style.top = 0;
document.body.appendChild( renderer2.domElement );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
renderer.render( scene, camera );
renderer2.render( scene2, camera );
}
After I had that working, I re-purposed the CSS3d scene, CSS3d object and the CSS3d renderer to be included in my scene.
Good luck to anyone else and hopefully this helps!
I have a 'choose file' button I want to use for loading a client side file instead of loading from the server path in loader.load() on line 86. I'm guessing I need to use File API but haven't figured out how after looking at this solution.
Existing web page that loads file from server path in line 86:
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color:#fea47c;
}
div {
position:relative;
left:200px;
top:0px;
background-color: #eeeeee;
border:1px solid black;
width:550px;
height:550px;
}
canvas {
width:550px;
height:550px;
}
input#file
{
position:relative;left:425px;
}
</style>
</head>
<body>
<input type="file" name="file" id="file"></input><br><br>
<script src="https://raw.github.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/loaders/STLLoader.js"></script>
<script src="https://raw.github.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
<script>
var container, camera, scene, renderer, controls;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
var width = container.clientWidth;
var height = container.clientHeight;
camera = new THREE.PerspectiveCamera(
35, // field of view in degrees?
width / height, // canvas based aspect ratio; use when canvas is smaller than page
.1 , // distance to nearest side of rendered space
10000 // distance to farthest side of rendered space
);
camera.position.set( 0, 0, 10);
scene = new THREE.Scene();
controls = new THREE.TrackballControls( camera , container);
controls.addEventListener( 'change', render );
// object
var loader = new THREE.STLLoader();
loader.addEventListener( 'load', function ( event ) {
var geometry = event.content;
var material = new THREE.MeshLambertMaterial( { ambient: 0xff5533, color: 0xff5533 } );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
} );
loader.load( 'path to .stl file on server usually goes here' );
// lights
scene.add( new THREE.AmbientLight( 0x222222 ) );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
directionalLight.position = camera.position;
scene.add( directionalLight );
// renderer
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( width , height );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function addLight( x, y, z, color, intensity ) {
var directionalLight = new THREE.DirectionalLight( color, intensity );
directionalLight.position.set( x, y, z )
scene.add( directionalLight );
}
function onWindowResize() {
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize( width, height );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render();
}
function render() {
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
</script>
</body>
</html>
Is the script on a server? In general web browsers are made to not permit file:// references except when the page itself is a file:// reference (and even then you might need to set some security/debug flags, varying according to the browser). So if you are running a webgl script in a page that's accessed via http:// you may be out of luck unless you piggyback through a file service like dropbox.