I am trying to set up image background for my scene with globe in three.js, but unfortunately, when I did it the main object of my scene also became black (the same colour with background.
I used method:
renderer = new THREE.WebGLRenderer({ antialias: false, alpha:true });
Which makes default background transparent. And then I added image-background in CSS part.
My whole script for the scene looks like this:
var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
//closer
camera.position.z = 500;
scene = new THREE.Scene();
group = new THREE.Group();
scene.add( group );
// earth
var loader = new THREE.TextureLoader();
loader.load( 'textures/mapnew1.jpg', function ( texture ) {
var geometry = new THREE.SphereGeometry( 180, 32, 32 );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
group.add( mesh );
} );
// shadow
var canvas = document.createElement( 'canvas' );
canvas.width = 128;
canvas.height = 128;
var context = canvas.getContext( '2d' );
var gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
);
gradient.addColorStop( 0.1, '#000000' );
gradient.addColorStop( 1, '#000000' );
context.fillStyle = gradient;
context.fillRect( 0, 0, canvas.width, canvas.height );
var texture = new THREE.CanvasTexture( canvas );
var geometry = new THREE.PlaneBufferGeometry( 300, 300, 3, 3 );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = - 200;
mesh.rotation.x = - Math.PI / 2;
group.add( mesh );
renderer = new THREE.CanvasRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer = new THREE.WebGLRenderer({ antialias: false, alpha:true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor(0x000000, 0);
container.appendChild( renderer.domElement );
stats = new Stats();
container.appendChild( stats.dom );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.08;
camera.position.y += ( - mouseY - camera.position.y ) * 0.08;
camera.lookAt( scene.position );
group.rotation.y -= 0.003;
renderer.render( scene, camera );
}
</script>
This is my CSS:
body {
color: #ffffff;
font-family:'Futura';
font-size:20px;
text-align: center;
background-image: url(textures/starfield.png);
background-color: black;
margin: 0px;
overflow: hidden;
}
Do you have any ideas how to fix it and make globe visible?
Thank you very much!
Regarding the background image, you are setting the alpha value for WebGLRenderer, which is correct. You didn't post your CSS, but ensure you're setting the background image on your container, not on the canvas.
Also, comment out this line:
renderer.setClearColor(0x000000, 0);
You don't need to set a clear color, since you are clearing to transparency, not a color. That should resolve the background image issue.
Regarding the all-black model, you need a light in your scene. Try adding this to your init method:
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
This will add a light source at the location of your camera (and will follow the camera as it moves).
Edit to add snippet:
var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0,
mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
//closer
camera.position.z = 500;
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
scene = new THREE.Scene();
group = new THREE.Group();
scene.add(group);
// earth
var loader = new THREE.TextureLoader();
loader.crossOrigin = '';
loader.load('https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Equirectangular_projection_SW.jpg/640px-Equirectangular_projection_SW.jpg', function(texture) {
var geometry = new THREE.SphereGeometry(180, 32, 32);
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var mesh = new THREE.Mesh(geometry, material);
group.add(mesh);
});
// shadow
var canvas = document.createElement('canvas');
canvas.width = 128;
canvas.height = 128;
var context = canvas.getContext('2d');
var gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
);
gradient.addColorStop(0.1, '#000000');
gradient.addColorStop(1, '#000000');
context.fillStyle = gradient;
context.fillRect(0, 0, canvas.width, canvas.height);
var texture = new THREE.CanvasTexture(canvas);
var geometry = new THREE.PlaneBufferGeometry(300, 300, 3, 3);
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var mesh = new THREE.Mesh(geometry, material);
mesh.position.y = -200;
mesh.rotation.x = -Math.PI / 2;
group.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: false,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
//renderer.setClearColor(0x000000, 0);
container.appendChild(renderer.domElement);
stats = new Stats();
container.appendChild(stats.dom);
document.addEventListener('mousemove', onDocumentMouseMove, false);
//
window.addEventListener('resize', onWindowResize, false);
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function onDocumentMouseMove(event) {
mouseX = (event.clientX - windowHalfX);
mouseY = (event.clientY - windowHalfY);
}
//
function animate() {
requestAnimationFrame(animate);
render();
stats.update();
}
function render() {
camera.position.x += (mouseX - camera.position.x) * 0.08;
camera.position.y += (-mouseY - camera.position.y) * 0.08;
camera.lookAt(scene.position);
group.rotation.y -= 0.003;
renderer.render(scene, camera);
}
body {
color: #ffffff;
font-family: 'Futura';
font-size: 20px;
text-align: center;
background-image: url(https://upload.wikimedia.org/wikipedia/commons/6/62/Starsinthesky.jpg);
background-color: black;
margin: 0px;
overflow: hidden;
}
<script src="https://threejs.org/build/three.js"></script>
<script src="https://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<div id="container"></div>
three.js r86
Since a while, there is:
var texture = new THREE.TextureLoader().load( "textures/bg.jpg" );
scene.background = texture;
I'm using three.js v 0.87
There are two ways to do it
1) Load a image using TextureLoader and set it as background. This will result into static background which may not look very realistic.
var texture = new THREE.TextureLoader().load(
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
);
scene.background = texture;
2) Use skybox to load images for top, left, right bottom, front back sides. Then set them inside a cube or sphere geometry
var urls = [
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg",
"https://images.pexels.com/photos/110854/pexels-photo-110854.jpeg"
];
var materialArray = [];
for (var i = 0; i < 6; i++)
materialArray.push(
new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(urls[i]),
side: THREE.BackSide
})
);
var skyGeometry = new THREE.SphereGeometry(400, 32, 32);
var skyMaterial = new THREE.MeshFaceMaterial(materialArray);
var skybox = new THREE.Mesh(skyGeometry, skyMaterial);
scene.add(skybox);
This will give a sphere with images as texture on backside. Just replace THREE.SphereGeometry with THREE.CubeGeometry and you can emulate envMap.
The previous solutions didn't work for me,
they miss the using of callback so at least from v.0.124 of the library,
this is how you can set the background image for the scene:
var texture_bg = new THREE.TextureLoader().load("img/bg.jpg", () => {
scene.background = texture_bg;
});
Related
I'm trying to create an ocean for my Three.js application. I took the example from this site:
https://codepen.io/RemiRuc/pen/gJMwOe?fbclid=IwAR2caTQL-AOPE2Gv6x4rzSWBrOmAh2j-raqesOO0XbYQAuSG37imbMszSis
var params = {
res : 32,
speed : 8,
amp : 2,
wireframe : true,
backgroundColor : 0x9c81e3,
planeColor : 0x4a4a4a
}
var scene = new THREE.Scene();
scene.background = new THREE.Color(params.backgroundColor)
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 )
let canvas = document.getElementById("webgl")
var renderer = new THREE.WebGLRenderer({canvas:canvas, antialias: true})
renderer.setSize( window.innerWidth, window.innerHeight )
var simplex = new SimplexNoise()
var light = new THREE.AmbientLight( 0xcccccc ); // soft white light
scene.add( light );
var pointLight = new THREE.PointLight( 0xeeeeee, 1, 100 );
pointLight.position.set( 0, 20, -20 );
scene.add( pointLight );
let geometry, material, plane
createPlane()
camera.position.z = 5;
camera.position.y = 3;
camera.lookAt(new THREE.Vector3( 0, 3, 0 ))
var animate = function () {
requestAnimationFrame( animate );
for (var i = 0; i < geometry.vertices.length; i++) {
var z = (i + Date.now() * params.speed/100000)
geometry.vertices[i].z = simplex.noise4D(z,z,z,z) * params.amp
plane.geometry.verticesNeedUpdate = true;
}
scene.background = new THREE.Color(params.backgroundColor)
material.color = new THREE.Color(params.planeColor)
material.wireframe = params.wireframe
camera.rotation.y += 0.001
renderer.render( scene, camera );
};
animate();
function createPlane(){
geometry = new THREE.PlaneGeometry( 200, 200, params.res,params.res );
material = new THREE.MeshLambertMaterial( {color: params.planeColor, side: THREE.DoubleSide, wireframe: params.wireframe} );
plane = new THREE.Mesh( geometry, material );
scene.add( plane );
plane.rotation.x = Math.PI/2
}
/***RESIZE***/
window.addEventListener('resize', ()=>{
document.querySelector('canvas').style.width = window.innerWidth + "px"
document.querySelector('canvas').style.height = window.innerHeight + "px"
renderer.setSize( window.innerWidth, window.innerHeight )
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
})
var gui = new dat.GUI()
var controller = gui.add(params, "res", 0, 100).name("Plane resolution")
gui.add(params, "speed", 0, 500).name("Wave speed")
gui.add(params, "amp", 0, 20).name("Wave amplitude")
gui.add(params, "wireframe", 0, 20).name("Wireframe")
gui.addColor(params, "backgroundColor").name("Background color")
gui.addColor(params, "planeColor").name("Plane color")
controller.onChange(()=>{
scene.remove(plane)
createPlane()
})
Issue is, I'm using PlaneBufferGeometry instead of PlaneGeometry, and it seems there are some differences
My code in render after creating the waterPlane
for (var i = 0; i < waterGeometry.attributes.position.count; i++) {
var z = (i + Date.now() * params.speed/100000);
waterGeometry.attributes.position[i] = simplex.noise4D(z,z,z,z) * params.amp;
}
waterGeometry.attributes.position.needsUpdate = true;
waterPlaneMesh.attributes.position.needsUpdate = true;
I'm not getting any errors, but no matter what I do, all I get is a flat wireframe plane geometry that doesn't move or anything. I think issue is in the updating of the plane?
This is an example of how you can displace vertices of a buffer geometry, using that SimplexNoise library:
body {
margin: 0;
background-color: #000;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three#0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three#0.136.0/examples/jsm/controls/OrbitControls";
import { createNoise3D } from "https://cdn.skypack.dev/simplex-noise";
let simplex = createNoise3D();
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 2000);
camera.position.set(0, 0.5, 1).setLength(12);
let renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", onWindowResize);
//scene.add(new THREE.GridHelper())
let controls = new OrbitControls(camera, renderer.domElement);
let light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));
let v3 = new THREE.Vector3();
let v2 = new THREE.Vector2();
let g = new THREE.PlaneGeometry(200, 200, 100, 100);
g.rotateX(-Math.PI *0.5);
let m = new THREE.MeshLambertMaterial({color: "aqua", wireframe: false});
let o = new THREE.Mesh(g, m);
scene.add(o);
let clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
let t = clock.getElapsedTime();
for(let i = 0; i < g.attributes.position.count; i++){
v2.fromBufferAttribute(g.attributes.uv, i).addScalar(t * 0.01).multiplyScalar(20);
let h = simplex(v2.x, v2.y, t * 0.1);
g.attributes.position.setY(i, h);
}
g.computeVertexNormals();
g.attributes.position.needsUpdate = true;
});
function onWindowResize() {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
}
</script>
I've dug around everywhere looking for a solution to this. It seems that on OrbitControls and TrackballControlls the camera wont stay horizontal! As you move around with TrackballControlls the scene starts to roll. OrbitControlls dragging from left to right only rolls the scene. I'd like to be able to use the TrackballControls but keep the camera level with the horizon when moving around the center of the scene. Is this possible?
My code:
// SETUP GLOBAL VARIABLES
var camera, controls, scene, renderer;
// PLANET PHYSICAL LOCATIONS
var sun, mercPL, venPL, earthPL, marsPL, jupPL, satPL, urPL, nepPL;
// TIME, AND SCALARS
var now, scalar, planetScalar;
init();
animate();
function init() {
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 100000 );
camera.position.z = 200;
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.8;
controls.enableZoom = true;
// ADD THE SUN PHYSICAL LOCATION
var geometry = new THREE.SphereGeometry(5, 30, 30, 0, Math.PI * 2, 0, Math.PI * 2);
var material = new THREE.MeshBasicMaterial({color: "Yellow"});
sun = new THREE.Mesh(geometry, material);
scene.add(sun);
var segmentCount = 32,
radius = 80,
geometry = new THREE.Geometry(),
material = new THREE.LineBasicMaterial({ color: 0xFFFFFF });
for (var i = 0; i <= segmentCount; i++) {
var theta = (i / segmentCount) * Math.PI * 2;
geometry.vertices.push(
new THREE.Vector3(
Math.cos(theta) * radius,
Math.sin(theta) * radius,
0));
}
scene.add(new THREE.Line(geometry, material));
var segmentCount2 = 32,
radius2 = 120,
geometry2 = new THREE.Geometry(),
material2 = new THREE.LineBasicMaterial({ color: 0xFFFFFF });
for (var i = 0; i <= segmentCount2; i++) {
var theta = (i / segmentCount2) * Math.PI * 2;
geometry2.vertices.push(
new THREE.Vector3(
Math.cos(theta) * radius2,
Math.sin(theta) * radius2,
0));
}
scene.add(new THREE.Line(geometry2, material2));
//
window.addEventListener( 'resize', onWindowResize, false );
//
render();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
controls.update();
render(); // MUST BE HERE FOR ANIMATION
}
function render() {
renderer.render( scene, camera );
}
Thanks!
Perhaps this can help you ( all the options are commented in the orbit library)
Level Horizon:
controls.minPolarAngle = Math.PI / 2;
controls.maxPolarAngle = Math.PI / 2;
Focus of Orbit:
controls.target = (cube.position);
Result: (Note: My mouse controls are inverted (Orbit Right / Pan Left) )
Three.js Lock Orbit Controls
Edit: After reviewing your comments code, I think this is what you want:
Three.js Orbit Controls pt 2.
The gist is that :
a) you need to provide the camera with an up vector:
camera.up.set( 0, 0, 1 );
And
b) Target the sun with the camera:
camera.lookAt(sun.position);
You can still play with the damping, and lock the angles ( there are also vertical constraints if you need them) and speed up down the yaw, but I hope this gets you closer.
I am trying to create an online 3D manipulation tool. I have got my THREE.js view set up with a rotating cube and a grid. When I run the code it works 100% fine, but if I resize the view it does not adjust the THREE.js screen with it. (It shrinks the length or width of the scene depending on how the browser view changes.) causing to view to look distorted.
$(function(){
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, .1, 500);
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xdddddd);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
var axis = new THREE.AxisHelper(10);
scene.add(axis);
var color = new THREE.Color("rgb(255,0,0)");
var color2 = new THREE.Color(0xd3d3d3);
var grid = new THREE.GridHelper(50, 15, color, color2);
scene.add(grid);
var cubeGeometry = new THREE.BoxGeometry(5, 5, 5);
var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff3300});
var cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
/*var planeGeometry = new THREE.PlaneGeometry(30, 30, 30);
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff});
var plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -.5*Math.PI;
plane.position.y = -.1
plane.recieveShadow = true;
scene.add(plane);*/
cube.position.x = 2.5;
cube.position.y = 4;
cube.position.z = 2.5;
cube.castShadow = true;
scene.add(cube);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.castShadow = true;
spotLight.position.set(15, 30, 50);
scene.add(spotLight);
camera.position.x = 40;
camera.position.y = 40;
camera.position.z = 40;
camera.lookAt(scene.position);
var guiControls = new function(){
this.rotationX = 0.01;
this.rotationY = 0.01;
this.rotationZ = 0.01;
}
var datGUI = new dat.GUI();
datGUI.add(guiControls, 'rotationX', 0, 1);
datGUI.add(guiControls, 'rotationY', 0, 1);
datGUI.add(guiControls, 'rotationZ', 0, 1);
render();
function render() {
//Me trying to reset the camera view every render
camera.fov = 45
camera.aspect = window.innerWidth / window.innerHeight
camera.near = .1
camera.far = 500
scene.add(camera);
cube.rotation.x += .1;
renderer.setSize(window.innerWidth, window.innerHeight);
requestAnimationFrame(render);
renderer.render(scene, camera);
}
$("#world").append(renderer.domElement);
renderer.render(scene, camera);
});
Add an event listener in your code to handle the resize:
window.addEventListener( 'resize', onWindowResize, false );
And then:
function onWindowResize() {
w = window.innerWidth;
h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize( w, h );
}
Or, since you are using jQuery, you can add this instead:
$( window ).resize(function() {
w = window.innerWidth;
h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize( w, h );
});
Click here to see a working codePen.
I am just started to learn three.js and tried to run example on codepen. Example is not able to run or show the globe
http://codepen.io/anon/pen/NxYXgb
Not sure where i did wrong
var container, stats;
var camera, scene, renderer;
var group;
var mouseX = 0, mouseY = 0;
var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 2000 );
camera.position.z = 500;
scene = new THREE.Scene();
group = new THREE.Group();
scene.add( group );
// earth
var loader = new THREE.TextureLoader();
loader.load( 'textures/land_ocean_ice_cloud_2048.jpg', function ( texture ) {
var geometry = new THREE.SphereGeometry( 200, 20, 20 );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
group.add( mesh );
} );
// shadow
var canvas = document.createElement( 'canvas' );
canvas.width = 128;
canvas.height = 128;
var context = canvas.getContext( '2d' );
var gradient = context.createRadialGradient(
canvas.width / 2,
canvas.height / 2,
0,
canvas.width / 2,
canvas.height / 2,
canvas.width / 2
);
gradient.addColorStop( 0.1, 'rgba(210,210,210,1)' );
gradient.addColorStop( 1, 'rgba(255,255,255,1)' );
context.fillStyle = gradient;
context.fillRect( 0, 0, canvas.width, canvas.height );
var texture = new THREE.CanvasTexture( canvas );
var geometry = new THREE.PlaneBufferGeometry( 300, 300, 3, 3 );
var material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
var mesh = new THREE.Mesh( geometry, material );
mesh.position.y = - 250;
mesh.rotation.x = - Math.PI / 2;
group.add( mesh );
renderer = new THREE.CanvasRenderer();
renderer.setClearColor( 0xffffff );
renderer.setPixelRatio( window.devicePixelRatio );
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 );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
mouseX = ( event.clientX - windowHalfX );
mouseY = ( event.clientY - windowHalfY );
}
//
function animate() {
requestAnimationFrame( animate );
render();
stats.update();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * 0.05;
camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
camera.lookAt( scene.position );
group.rotation.y -= 0.005;
renderer.render( scene, camera );
}
I am Trying to create an interactive Sphere with JavaScript for an assignment for HCI, the problem is that I am a novice to JavaScript and Three.js.
what I am after is to make it so when the sphere is clicked on that it displays the statistics of a specific subject. I have created the sphere and made it into an object but I am having trouble with the interaction of the sphere. I don't care if a div or a alert opens when the sphere is clicked on but I just need it to work as a dummy version
below is an example in JavaScript and THREE.js:
var sphere = new Object({}); //declared sphere as an object first.
var angularSpeed = 0.2;
var lastTime = 0;
function animate (){
//update
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
var angleChange = angularSpeed * timeDiff * 0.1 * Math.PI / 1000;
sphere.rotation.y -= angleChange;
sphere2.rotation.sphere -=angleChange;
lastTime = time;
// render
renderer.render(scene, camera);
requestAnimationFrame(function(){ //request new frame
animate();
});
}
// renderer
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 500;
// scene
var scene = new THREE.Scene();
//material
var material = new THREE.MeshLambertMaterial({
map:THREE.ImageUtils.loadTexture('images/earth2.jpg')});
//sphere geometry
sphere = new THREE.Mesh(new THREE.SphereGeometry( 100, 50, 50 ), material);
sphere.overdraw = true;
sphere.rotation.x = Math.PI * 0.1;
sphere.position.x= 0; // moves position horizontally (abscissa) + = right and - = left
sphere.position.y= 0; // moves position virtually (ordinate) + = right and - = left
sphere.position.z= 0; // moves position z (applicate) + = forwards and - = backwards
scene.add(sphere);
//animate
animate();
var sphere = new Object:({event});
function statistics(){
alert('You clicked on the div!') // displays the statistics before the rendering
};
sphere.onMouseDown=statistics(event);
.onMouseDown is only available for HTML element. You can't use this function for THREE.js objects, but Raycaster is exactly what you want!
jsfiddle
var container, stats;
var camera, scene, projector, raycaster, renderer, selected, sphere;
var mouse = new THREE.Vector2(), INTERSECTED;
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
scene = new THREE.Scene();
var light = new THREE.DirectionalLight( 0xffffff, 2 );
light.position.set( 1, 1, 1 ).normalize();
scene.add( light );
var light = new THREE.DirectionalLight( 0xffffff );
light.position.set( -1, -1, -1 ).normalize();
scene.add( light );
sphere = new THREE.Mesh(new THREE.SphereGeometry( 20, 50, 50 ), new THREE.MeshNormalMaterial());
sphere.overdraw = true;
scene.add(sphere);
projector = new THREE.Projector();
raycaster = new THREE.Raycaster();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 0xf0f0f0 );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.sortObjects = false;
container.appendChild(renderer.domElement);
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
renderer.domElement.addEventListener( 'mousedown', onCanvasMouseDown, false);
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.lookAt(new THREE.Vector3(0,0,0));
camera.position = new THREE.Vector3(0,100,100);
// find intersections
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
raycaster.set( camera.position, vector.sub( camera.position ).normalize() );
selected = raycaster.intersectObjects( scene.children );
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function onDocumentMouseMove( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
}
//detect mouse click on the sphere
function onCanvasMouseDown( event ){
if(selected[0].object==sphere){
statistics();
}
}
function statistics(){
alert('You clicked on the div!') // displays the statistics before the rendering
};