Three.js Folding Effect Image - javascript

I am trying to create folding effect like folding a paper in half.
I am using Three.js Library to help me manipulate the image.
I have created 2 face paper using 2 PlaneGeometry and loaded on them texture with ImageUtils.loadTexture.
I am curious if there is a way to split the image in half and then rotate one half on his edge so you create the folding effect.
I guess this can be done since the create plane function THREE.PlaneGeometry(width, height, widthSegments, heightSegments); has widthSegments and heightSegments parameters.
<html>
<head>
<title>My first Three.js app</title>
<style>
body {
background-color: #ffffff;
margin: 0px;
overflow: hidden;
}
container {
background-color: #ffffff;
}
</style>
</head>
<body>
<div id="container" ></div>
<script src="three.min.js"></script>
<script src="OrbitControls.js"></script>
<script src="stats.min.js"></script>
<script>
var renderer, scene, camera, card;
var container, stats;
init();
animate();
function init() {
container = document.getElementById('container');
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xffffff, 1.0);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.domElement);
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 300;
controls = new THREE.OrbitControls(camera, container);
camera.lookAt(scene.position);
// geometry
var geometry1 = new THREE.PlaneGeometry(90, 110, 3, 1);
var geometry2 = new THREE.PlaneGeometry(90, 110, 3, 1);
geometry2.applyMatrix(new THREE.Matrix4().makeRotationY(Math.PI));
// textures
var textureFront = new THREE.ImageUtils.loadTexture('Flyer2pag1.png'); // Flyer has image sorce in project folder
var textureBack = new THREE.ImageUtils.loadTexture('Flyer2pag2.png');
// material
var material1 = new THREE.MeshBasicMaterial({ color: 0xffffff, map: textureFront });
var material2 = new THREE.MeshBasicMaterial({ color: 0xffffff, map: textureBack });
// card
card = new THREE.Object3D();
scene.add(card);
// mesh
var mesh1 = new THREE.Mesh(geometry1, material1);
card.add(mesh1);
var mesh2 = new THREE.Mesh(geometry2, material2);
card.add(mesh2);
}
function animate() {
requestAnimationFrame(animate);
//card.rotation.y += 0.01;
stats.update();
renderer.render(scene, camera);
}
</script>
</body>
</html>

Related

rotate sphere in three.js so that mapped image of globe matches GeoJSON that is also shown in three.js

I have created a globe in three.js and am using an image mapped to the sphere.
On top of this, I'm using the ThreeGeoJSON library to render geojson data.
However the geographies don't match up.
I need to rotate the globe with the mapped image so that they align, but I can't figure out how to do so. I tried setting a quaternion variable and rotating based on that, but can't get it working. Any help or pointers would be very much appreciated.
Here you can see a working version of what I've done so far:
http://bl.ocks.org/jhubley/8450d7b0df0a4a9fd8ce52d1775515d5
All of the code, images, data here:
https://gist.github.com/jhubley/8450d7b0df0a4a9fd8ce52d1775515d5
I've also pasted the index.html below.
<html>
<head>
<title>ThreeGeoJSON</title>
<script src="threeGeoJSON.js"></script>
<!-- Three.js library, movement controls, and jquery for the geojson-->
<script src="three.min.js"></script>
<script src="TrackballControls.js"></script>
<script src="jquery-1.10.2.min.js"></script>
</head>
<body>
<script type="text/JavaScript">
var width = window.innerWidth,
height = window.innerHeight;
// Earth params
var radius = 9.99,
segments = 32,
rotation = 0 ;
//New scene and camera
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(55, width / height, 0.01, 1000);
camera.position.z = 1;
camera.position.x = -.2;
camera.position.y = .5;
//New Renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
//Add lighting
scene.add(new THREE.AmbientLight(0x333333));
var light = new THREE.DirectionalLight(0xe4eef9, .7);
light.position.set(12,12,8);
scene.add(light);
var quaternion = new THREE.Quaternion();
quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 );
var sphere = createSphere(radius, segments);
//sphere.rotation.y = rotation;
sphere.rotation = new THREE.Euler().setFromQuaternion( quaternion );
scene.add(sphere)
//Create a sphere to make visualization easier.
var geometry = new THREE.SphereGeometry(10, 32, 32);
var material = new THREE.MeshPhongMaterial({
//wireframe: true,
//transparent: true
});
function createSphere(radius, segments) {
return new THREE.Mesh(
new THREE.SphereGeometry(radius, segments, segments),
new THREE.MeshPhongMaterial({
map: THREE.ImageUtils.loadTexture('relief.jpg'),
bumpMap: THREE.ImageUtils.loadTexture('elev_bump_4k.jpg'),
bumpScale: 0.005,
specularMap: THREE.ImageUtils.loadTexture('wateretopo.png'),
specular: new THREE.Color('grey')
})
);
}
var clouds = createClouds(radius, segments);
clouds.rotation.y = rotation;
scene.add(clouds)
function createClouds(radius, segments) {
return new THREE.Mesh(
new THREE.SphereGeometry(radius + .003, segments, segments),
new THREE.MeshPhongMaterial({
map: THREE.ImageUtils.loadTexture('n_amer_clouds.png'),
transparent: true
})
);
}
//Draw the GeoJSON
var test_json = $.getJSON("countries_states.geojson", function(data) {
drawThreeGeo(data, 10, 'sphere', {
color: 'red'
})
});
//Draw the GeoJSON loggerhead data
var test_json = $.getJSON("loggerhead-distro-cec-any.json", function(data) {
drawThreeGeo(data, 10, 'sphere', {
color: 'blue'
})
});
//Set the camera position
camera.position.z = 30;
//Enable controls
var controls = new THREE.TrackballControls(camera);
//Render the image
function render() {
controls.update();
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
</script>
</body>
</html>
Instead of ancient r66, I used r81 (just replaced three.min.js). I modified your createSphere() function a bit, and seems it's working.
function createSphere(radius, segments) {
var sphGeom = new THREE.SphereGeometry(radius, segments, segments);
sphGeom.rotateY(THREE.Math.degToRad(-90));
return new THREE.Mesh(
sphGeom,
new THREE.MeshPhongMaterial({
map: new THREE.TextureLoader().load('relief.jpg'),
bumpMap: new THREE.TextureLoader().load('elev_bump_4k.jpg'),
bumpScale: 0.005,
specularMap: new THREE.TextureLoader().load('wateretopo.png'),
specular: new THREE.Color('grey')
})
);
}
The only thing I did was to rotate the sphere's geometry around Y-axis at -90 degrees. The result is here

onchange in dropdown triggers function but no change in three.js output

I am trying to make the page display either a green or a brown floor using three.js depending on the selection from a drop down list. However, I see that the floor images do not change although control does go to the function.
JS fiddle here (I could not upload images though)
The code is below.
<!DOCTYPE html>
<html>
<head>
<title>Floor change</title>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<script>
// global variables
var renderer;
var scene;
var camera;
var container;
//controls
var controls;
//html elements
var colorselection = "green";
function init() {
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
SCREEN_WIDTH-=200;
// SCREEN_HEIGHT -= 100;
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
camera = new THREE.PerspectiveCamera(45, SCREEN_WIDTH / SCREEN_HEIGHT, 0.1, 1000);
// create a render, sets the background color and the size
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
// position and point the camera to the center of the scene
camera.position.x = 0;
camera.position.y = 30;
camera.position.z = 40;
camera.lookAt(scene.position);
// add the output of the renderer to the html element
document.body.appendChild(renderer.domElement);
// attach div element to variable to contain the renderer
container = document.getElementById( 'ThreeJS' );
// attach renderer to the container div
container.appendChild( renderer.domElement );
}
function floor()
{
///////////
// FLOOR //
///////////
if(colorselection == "green")
var floorTexture = new THREE.ImageUtils.loadTexture( 'green.jpg' );
else if(colorselection == "brown")/*go with 2 for now*/
var floorTexture = new THREE.ImageUtils.loadTexture( 'brown.png' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 20, 20 );
// DoubleSide: render texture on both sides of mesh
var floorMaterial = new THREE.MeshBasicMaterial( { map: floorTexture, side: THREE.DoubleSide } );
var floorGeometry = new THREE.PlaneGeometry(110, 110, 1, 1);
var floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.position.y = -0.5;
floor.rotation.x = Math.PI / 2;
scene.add(floor);
animate();
}
//scheduler loop
function animate() {
renderer.render(scene,camera)
requestAnimationFrame(animate)
}
function myfunction()
{
colorselection = document.getElementById("mydropdownlist").value;
console.log("clicked on '"+ colorselection + "'")
floor();
}
// calls the init function when the window is done loading.
window.onload = init;
</script>
<body>
<script src="js/Three.js"></script>
<div id="ThreeJS" style="z-index: 1; position: absolute; left:0px; top:0px"></div>
<select id="mydropdownlist" onchange="myfunction()">
<option value="green">green</option>
<option value="brown">brown</option>
</select>
</body>
<style>
#mydropdownlist
{
position:absolute;
left:1200px;
top:20px
}
</style>
</html>
I have uploaded the images brown.png and green.jpg used above.
I copied your code to a local .html file, put it in the example directory for 3js, stuck the pictures there, and then updated the path to three.js to the default one
src="../build/Three.js"
and ran it in chrome. It worked, the floor colors changed when i used the drop-down. It also works in firefox.
I do see a problem however. You add the new floor mesh each time to the scene, but do not remove the old one. I expect to see a scene.remove(floor) before you make a new one so you dont get a bunch piled up in the scene. I also noticed that you have a function called floor and a variable called floor which can cause confusion.
Also, if you are using chrome, you need to use --disable-web-security as a command-line switch if you want to see the textures when the files are on your local drive instead of a web-server.
<!DOCTYPE html>
<html>
<head>
<title>Floor change</title>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<script>
// global variables
var renderer;
var scene;
var camera;
var container;
var floormesh=null;
//controls
var controls;
//html elements
var colorselection = "green";
function init() {
var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
SCREEN_WIDTH-=200;
// SCREEN_HEIGHT -= 100;
// create a scene, that will hold all our elements such as objects, cameras and lights.
scene = new THREE.Scene();
// create a camera, which defines where we're looking at.
camera = new THREE.PerspectiveCamera(45, SCREEN_WIDTH / SCREEN_HEIGHT, 0.1, 1000);
// create a render, sets the background color and the size
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000, 1.0);
renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
// position and point the camera to the center of the scene
camera.position.x = 0;
camera.position.y = 30;
camera.position.z = 40;
camera.lookAt(scene.position);
// add the output of the renderer to the html element
document.body.appendChild(renderer.domElement);
// attach div element to variable to contain the renderer
container = document.getElementById( 'ThreeJS' );
// attach renderer to the container div
container.appendChild( renderer.domElement );
}
function floor()
{
///////////
// FLOOR //
///////////
if(colorselection == "green")
var floorTexture = new THREE.ImageUtils.loadTexture( 'green.jpg' );
else if(colorselection == "brown")/*go with 2 for now*/
var floorTexture = new THREE.ImageUtils.loadTexture( 'brown.png' );
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set( 20, 20 );
// DoubleSide: render texture on both sides of mesh
var floorMaterial = new THREE.MeshBasicMaterial( { map: floorTexture, side: THREE.DoubleSide } );
var floorGeometry = new THREE.PlaneGeometry(110, 110, 1, 1);
if(floormesh)
scene.remove(floormesh);
floormesh = new THREE.Mesh(floorGeometry, floorMaterial);
floormesh.position.y = -0.5;
floormesh.rotation.x = Math.PI / 2;
scene.add(floormesh);
animate();
}
//scheduler loop
function animate() {
renderer.render(scene,camera)
requestAnimationFrame(animate)
}
function myfunction()
{
colorselection = document.getElementById("mydropdownlist").value;
console.log("clicked on '"+ colorselection + "'")
floor();
}
// calls the init function when the window is done loading.
window.onload = init;
</script>
<body>
<script src="../build/Three.js"></script>
<div id="ThreeJS" style="z-index: 1; position: absolute; left:0px; top:0px"></div>
<select id="mydropdownlist" onchange="myfunction()">
<option value="green">green</option>
<option value="brown">brown</option>
</select>
</body>
<style>
#mydropdownlist
{
position:absolute;
left:1200px;
top:20px
}
</style>
</html>

Three.js: Cannot change value in dat.GUI

i have an instance of dat.GUI. I added a "comboBox" to that instance to make a selection of possible values. When i run my app, the dat.GUI appears with the comboBox but there is a problem: I cannot change it's default value (my gui is frozen), here is my code:
<html>
<head>
<title>Stack Overflow</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<div id="container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="js/three.min.js"></script>
<script src="js/optimer_regular.typeface.js"></script>
<script src="js/TrackballControls.js"></script>
<script src="js/stats.min.js"></script>
<script src="js/threex.dynamictexture.js"></script>
<script src="js/dat.gui.min.js"></script>
<script>
//Basic Three components
var scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000 );
//position camera
camera.position.z = 700;
//Set camera controls
var 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 ];
//Set the renderer
var renderer = new THREE.WebGLRenderer( { antialias: false } );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
//Set the lights
var light;
scene.add( new THREE.AmbientLight( 0x404040 ) );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 1, 1 );
scene.add( light );
//GUI
initGUI();
//Let's add a cube
var geometry = new THREE.BoxGeometry( 50, 50, 50 );
var material = new THREE.MeshBasicMaterial( { color: 0x5484d3 } );
var cube = new THREE.Mesh( geometry, material );
cube.position.set(0,20,50)
scene.add( cube );
function initGUI(){ //HERE IS THE MEAT, I THINK
var LevelView = function() {
this.level = 'Operacion';
// Define render logic ...
};
var gui = new dat.GUI();
var text = new LevelView();
gui.add(text, 'level', [ 'Operacion', 'Procesos', 'Participantes', 'Fuentes de Datos', 'Logica de software', 'Telecomunicaciones', 'Infraestructura'] ).onChange(function(value){
this.level = value;
});
}
function animate() {
requestAnimationFrame( animate );
render();
}
//Render scene
function render() {
controls.update();
renderer.render( scene, camera );
}
animate();
</script>
</body>
</html>
¿What i am doing wrong? I need to be able to change values with my GUI.
Solution: If you use a mouse-controlled camera with three.js, you have to comment the following line in the MouseListener of the mouseDown action:
event.preventDefault();
Place div containing dat.gui element bellow Three.js div
<div id="ThreeJS" style="position: absolute; left:0px; top:0px"></div>
and then dat.gui
<div id="gui"></div>

TextGeometry not displaying, Could anyone tell me why?

I have the following Three.js code:
<html>
<head>
<title>My first Three.js app</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="js/three.min.js"></script>
<script src="js/optimer_regular.typeface.js"></script>
<script>
//Basic Three components
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 );
//Let´s add a 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 );
camera.position.z = 5;
//Let´s add a text
var material2 = new THREE.MeshPhongMaterial({
color: 0x00ff00
});
var textGeom = new THREE.TextGeometry( 'Sitescope', {
font: 'optimer',
weight: 'normal'
});
var textMesh = new THREE.Mesh( textGeom, material2 );
scene.add( textMesh );
//Render scene
function render() {
requestAnimationFrame( render );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
render();
</script>
</body>
When i run my code, My cube renders well but my text does not appear anywhere.
The only output that i get in the javascript console is:
THREE.WebGLRenderer 69.
Could anyone tell me why my text does not appear? (I am a beginner in Three.js) Thanks!
When using a THREE.MeshPhongMaterial() you need a light in the scene. Otherwise the model will come out black. If your scene background is also black you will never know if the model was drawn or not. Take a look at this fiddle. I am using THREE.MeshNormalMaterial(). Replace it with PhongMaterial to see what I am talking about. You can see the text is being drawn with black color just because it is over the green cube.

How to change the background by buttons on three.js?

I am new in three.js and using the following code I want to know how to change the background by clicking a button. So I think there is something different than using "switch" and "break". Here is something with .loadTexture am I right?
<html lang="en">
<head>
<title>gyroscopic</title>
<meta charset="utf-8">
<meta name="viewport" content="user-scalable=no, initial-scale=1">
<style>
body {
margin: 0px;
background-color: #000000;
overflow: hidden;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="three.min.js"></script>
<script src="DeviceOrientationControls.js"></script>
<script>
(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(80, window.innerWidth / window.innerHeight, 1, 1100);
controls = new THREE.DeviceOrientationControls( camera );
scene = new THREE.Scene();
var geometry = new THREE.SphereGeometry( 500, 316, 18 );
geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) );
var material = new THREE.MeshBasicMaterial( {
map: THREE.ImageUtils.loadTexture( 'pic.jpg' )
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var geometry = new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
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);
})();
</script>
</body>
</html>
You should be able to change the texture using .loadTexture on a button click listener.
So you would probably add something like this to your HTML:
<button id="change-background">Change Background</button>
Then in Javascript:
var backgroundButton = document.getElementById('change-background');
backgroundButton.addEventListener('click', function(){
material.map = THREE.ImageUtils.loadTexture('//new image path//');
});
You'll obviously need to replace the //new image path// with whatever URL you have for the new image.
The only question would be whether this updates the material on the mesh as well. I'm sure it does, but have no way of testing it at present.

Categories

Resources