I need to make a ball with a texture on it. I'm very new at WebGL and Three.js. The problem is that I see a White Sphere but not the texture on it. As a new user I am not able to submit a picture.
The code part is this:
function init() {
canvas = document.getElementById( 'canvas' );
camera = new THREE.PerspectiveCamera( 90, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
scene = new THREE.Scene();
camera.lookAt (scene.position);
var llum = new THREE.DirectionalLight();
llum.intensity=50;
llum.position.x=camera.position.x;
llum.position.y=camera.position.y;
llum.position.z=camera.position.z;
llum.lookAt(scene.position);
scene.add(llum);
var texture = THREE.ImageUtils.loadTexture('ull.jpg');
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial( texture );
var quality = 16, step = 1024 / quality;
var geom = new THREE.SphereGeometry(500,100,100);
mesh = new THREE.Mesh( geom, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer({ antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
canvas.innerHTML = "";
//Afegim al canvas el que hem de renderitzar
canvas.appendChild( renderer.domElement );
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
window.addEventListener( 'resize', onWindowResize, false );
}
Thanks in advance.
It should be like this:
var material = new THREE.MeshBasicMaterial( { map: texture } );
Since this is the first page that shows up in Google search results I will post what was solution in my case. I draw texture on square but the square was actually rotated backward so camera saw back of the square without texture, after fixing rotation everything worked fine.
var geometry = new THREE.PlaneGeometry(FLOOR_SIZE, FLOOR_SIZE, 10, 10);
var loader = new THREE.TextureLoader();
loader.load('images/floor.jpg', function ( texture ) {
var material = new THREE.MeshBasicMaterial({
map: texture,
overdraw: 0.5
});
var floor = new THREE.Mesh( geometry, material );
// ROTATION THAT MADE SQUARE INVISIBLE WAS Math.PI/2
floor.rotation.x = -Math.PI/2;
floor.position.y = -0.1;
scene.add(floor);
});
Related
I'm working on an app that should allow users to manipulate 3D objects in the scene and observe how their changes affect the ground shadow:
In this scene, the yellow cylinder casts a shadow on a white plane with the middle of the cylinder contained in the green cube. What I would like to happen is for the cube to remove the middle of the shadow, like so:
Obviosly, my first thought was to subtract the green cube volume from the yellow cylinder volume and after a bit of googling I found CSG.js. Unfortunately, CSG.js is too slow for the actual model that I'm going to use, which will going to have at least 15k vertices.
I started digging into the Three.js source and reading about shadow maps to understand how shadows are produced, but my shader-fu is not strong enough yet to fully grasp how I can tweak shadow rendering.
How can I achieve this "shadow subtraction" effect?
var camera, scene, renderer;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.z = 500;
camera.position.y = 100;
camera.lookAt(scene.position);
var ambient = new THREE.AmbientLight(0x909090);
scene.add(ambient);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.0 );
directionalLight.position.set( -300, 300, 0 );
directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 10;
directionalLight.shadow.camera.far = 2000;
directionalLight.shadow.camera.right = 350;
directionalLight.shadow.camera.left = -350;
directionalLight.shadow.camera.top = 350;
directionalLight.shadow.camera.bottom = -350;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
scene.add( directionalLight );
//var lightHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
//scene.add(lightHelper);
var geometry = new THREE.CylinderGeometry( 50, 50, 400, 32 );
var material = new THREE.MeshPhongMaterial( {color: 0xffff00} );
var cylinder = new THREE.Mesh( geometry, material );
cylinder.castShadow = true;
scene.add( cylinder );
var geometry = new THREE.BoxGeometry( 110, 110, 110 );
var material = new THREE.MeshPhongMaterial( {color: 0x00ff00} );
var cube = new THREE.Mesh( geometry, material );
cube.castShadow = true;
scene.add( cube );
var geometry = new THREE.PlaneGeometry( 3000, 3000, 32 );
var material = new THREE.MeshPhongMaterial( {color: 0xffffff, side: THREE.DoubleSide} );
var plane = new THREE.Mesh( geometry, material );
plane.lookAt(new THREE.Vector3(0, 1, 0));
plane.position.y = -200;
plane.receiveShadow = true;
scene.add( plane );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.BasicShadowMap;
document.body.appendChild( renderer.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 );
renderer.render( scene, camera );
}
jsFiddle
Update:
What about a more complicated scene? Is it possible for the shadow from the red cylinder to be unaffected (you can see it being cut in half with cube.customDepthMaterial = new THREE.MeshBasicMaterial({ depthTest: false}))?
Updated jsFiddle
You can subtract an object's shadow from the rest of scene by setting the object's .customDepthMaterial property like so:
var cube = new THREE.Mesh( geometry, material );
cube.castShadow = true;
cube.receiveShadow = false;
// The secret sauce
cube.customDepthMaterial =
new THREE.MeshBasicMaterial({ depthTest: false});
scene.add( cube );
jsFiddle
No shader-fu required.
Why This Works
When the shadow map is rendered, each object's depth material ( .customDepthMaterial or the default ) is used to render the scene from the light's perspective. The depth material's resulting render represents the object's depth from the camera packed as RGBA. Since THREE.MeshBasicMaterial defaults to { color: 0xffffff, opacity: 1 }, it will return the maximum depth which makes the object further than the shadow camera's far.
I disabled depthTest because in your desired result screenshot you clipped the area where the cube's given the cylinder wasn't there. Disabling depthTest means that parts of the cube which are blocked by the cylinder will still cut out the shadow, giving you your desired result.
Documentation
There unfortunately is no documentation on .customDepthMaterial yet but I did find an official example where it is used.
Updated Answer:
To allow an object's shadow to always show:
You can use the same trick as above just setting the material's color and opacity to 0
Make sure it's added to the scene after the 'subtractive shadow' object. This way the additive shadow will win out even though they both have depthTest disabled.
updated jsFiddle
If you have anything more complicated, it will be up to you to figure out a way to manage the order of the shadow rendering.
Tested in r77
This is my first question in StackOverflow, but I've been browsing it for some years now, so I kindly ask you to bear with me. :)
I've been experimenting with Three.js to create a 3D world, and everything looked fine until I needed to control the camera. Since I'm using this lib to avoid having to do matricial calculations myself I found and added TrackballControls to my code aswell. It worked fine but then my camera could pass through the 3D shapes, and also below terrain. Unfortunately, although the movement is exactly what I needed, it didn't serve the purpose of allowing camera to respect collision.
My scene is simply the ground (thin BoxGeometry) and a cube (normal-sized BoxGeometry), and a rotating sphere that shares directionalLight position for a "sun light" effect. Some people here suggested adding Physijs to the code and simulate() physics within the scene, and adding a BoxMesh to the camera to make the physics apply to it aswell, but it simply didn't work (scene turned blank).
My working code so far (without Physijs) is:
window.onload = function() {
var renderer, scene, camera, ground, box, sphere, ambient_light, sun_light, controls;
var angle = 0;
var clock = new THREE.Clock();
init();
render();
function init(){
// Create renderer and add it to the page
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xffffff );
renderer.shadowMapEnabled = true;
document.body.appendChild( renderer.domElement );
// Create a scene to hold our awesome 3D world
scene = new THREE.Scene();
/*** 3D WORLD ***/
// Objects
ground = new THREE.Mesh(
new THREE.BoxGeometry(50, 1, 50),
new THREE.MeshLambertMaterial({ color: 0x33CC33 }),
0 // mass
);
ground.receiveShadow = true;
scene.add( ground );
box = new THREE.Mesh(
new THREE.BoxGeometry( 10, 10, 10 ),
new THREE.MeshLambertMaterial({ color: 0xDD3344 })
);
box.position.y = 5;
box.castShadow = true;
scene.add( box );
sphere = new THREE.Mesh(
new THREE.SphereGeometry( 3, 32, 32 ),
new THREE.MeshBasicMaterial({ color: 0xFFBB00 })
);
sphere.position.set( 1, 15.5, 5 );
scene.add( sphere );
// Light
ambient_light = new THREE.AmbientLight( 0x333333 );
ambient_light.mass = 0;
scene.add( ambient_light );
sun_light = new THREE.DirectionalLight( 0xBBBBBB );
sun_light.position.set( 1, 15.5, 5 );
sun_light.castShadow = true;
sun_light.shadowCameraNear = 1;
sun_light.shadowCameraFar = 100;
sun_light.shadowCameraLeft = -50;
sun_light.shadowCameraRight = 50;
sun_light.shadowCameraTop = -50;
sun_light.shadowCameraBottom = 50;
sun_light.shadowBias = -.01;
scene.add( sun_light );
// Create a camera
camera = new THREE.PerspectiveCamera(
45, // FOV
window.innerWidth / window.innerHeight, // Aspect Ratio
1, // Near plane
1000 // Far plane
);
camera.position.set( 30, 30, 30 ); // Position camera
camera.lookAt( box.position ); // Look at the scene origin
scene.add(camera);
// After swapping THREE.Mesh to Physijs.BoxMesh, this is where I'd attach a BoxMesh to the camera
window.addEventListener( 'resize', onWindowResize, false );
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 4.0;
controls.panSpeed = 0.3;
controls.staticMoving = true; // No sliding after-effects
}
function render() {
// use requestAnimationFrame to create a render loop
angle += .007;
var oscillateZ = Math.sin(angle * (Math.PI*4));
var oscillateX = -Math.cos(angle * (Math.PI*4));
//console.log(oscillateZ);
sphere.position.setZ( sphere.position.z + oscillateZ );
sphere.position.setX( sphere.position.x + oscillateX );
sun_light.position.setZ( sun_light.position.z + oscillateZ );
sun_light.position.setX( sun_light.position.x + oscillateX );
requestAnimationFrame( render );
controls.update();
renderer.render( scene, camera );
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
};
Can you guys enlighten me? Thank you for your time!
#Edit
Physijs attempt
I am attempting to have my skybox not be affected by the camera.far parameter. I would like to cull all other scene objects with this just not the skybox.
When I set skyBox.frustumCulled = false; it makes no difference. skyBox being the mesh of course.
Is this done by adding another render pass? If so I would need 2 different cameras one with a really high far value to allow viewing of the skybox right? How can this be done efficiently?
For clarity here is the snippet from my terrain object code used for drawing the skybox:
shader = THREE.ShaderLib["cube"];
shader.uniforms["tCube"].value = this.cubetexture;
mat = new THREE.ShaderMaterial({
uniforms: shader.uniforms,
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
depthWrite: false,
side: THREE.BackSide
});
geo = new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(1024, 1024, 1024));
mesh = new THREE.Mesh(geo, mat);
mesh.rotation.y += 90;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 50;
mesh.frustumCulled = false;
mesh.matrixAutoUpdate = false;
mesh.rotationAutoUpdate = false;
mesh.updateMatrix();
this.skybox = mesh;
scene.add(this.skybox);
You're adding a skybox in the 'main' scene. A better way to accomplish a skydome would be to create a new scene. this will be the 'background' to your 'main' scene. There's also a discussion about skydomes v.s. skyboxes, simply put, a box saves polys, a dome looks better. in this example i'll be using a dome/sphere.
var renderer = new THREE.WebGLRenderer( {alpha: true, antialias: true} );
var mainScene = new THREE.Scene();
var mainCamera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
var skydome = {
scene: new THREE.Scene(),
camera: new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 20000 );
};
skydome.material = new THREE.MeshBasicMaterial({color: 0x0F0F0F}) //the material for the skydome, for sake of lazyness i took a MeshBasicMaterial.
skydome.mesh = new THREE.Mesh(new THREE.SphereGeometry(100, 20, 20), skydome.material);
skydome.scene.add(skydome.mesh);
now, during the render function you adjust only the rotation of the skydome camera, not the position.
var render = function(){
requestAnimationFrame( render );
skydome.camera.quaternion = mainCamera.quaternion;
renderer.render(skydome.scene, skydome.camera); //first render the skydome
renderer.render(mainScene, mainCamera);//then render the rest over the skydome
};
renderer.autoclear = false; //otherwise only the main scene will be rendered.
I'm trying add subdivisions to a sphere like this:
http://stemkoski.github.com/Three.js/Subdivision-Cube.html
Here's my code: http://jsfiddle.net/mdrorum/HvFLw/
<script src="http://mrdoob.github.com/three.js/build/three.js"></script>
<script type="text/javascript">
var camera, scene, renderer;
var geometry, material, mesh;
var smooth, subdiv, modifier;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.z = 1000;
scene = new THREE.Scene();
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
geometry = new THREE.SphereGeometry( 200 );
material = new THREE.MeshBasicMaterial( { color: 0x00ff00, wireframe: true } );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
var smooth = mesh.clone();
var subdiv = 3;
var modifier = new THREE.SubdivisionModifier( subdiv );
//modifier.modify( smooth );
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
renderer.render( scene, camera );
}
</script>
This works fine, but uncomment: //modifier.modify( smooth );
Nothing happens. :(
How I can add subdivisions?
Here you can find a good tutorial with a working demo. Citing the author:
// First we want to clone our original geometry.
// Just in case we want to get the low poly version back.
var smooth = THREE.GeometryUtils.clone( geometry );
// Next, we need to merge vertices to clean up any unwanted vertex.
smooth.mergeVertices();
// Create a new instance of the modifier and pass the number of divisions.
var divisions = 3;
var modifier = new THREE.SubdivisionModifier(divisions);
// Apply the modifier to our cloned geometry.
modifier.modify( smooth );
// Finally, add our new detailed geometry to a mesh object and add it to our scene.
var mesh = new THREE.Mesh( smooth, new THREE.MeshPhongMaterial( { color: 0x222222 } ) );
scene.add( mesh );
You are trying to modify a mesh. You need to modify a geometry.
modifier.modify( geometry );
We've tried the next code:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.0001, 999);
camera.position.set( 0, 0, 3 );
scene.add( camera );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000, wireframe: true } );
var image = $('#tmp')[0]
var texture = new THREE.Texture(image);
texture.needsUpdate = true;
var img_material = new THREE.MeshBasicMaterial({color: 0x000000, map: texture });
var plane_geometry = new THREE.PlaneGeometry(2, 2);
var imageMesh = new THREE.Mesh(plane_geometry, img_material);
imageMesh.doubleSided = true;
scene.add(imageMesh);
renderer = new THREE.CanvasRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
$('#container').append( renderer.domElement );
renderer.render(scene, camera);
but when we switched to:
renderer = new THREE.SVGRenderer();
it stop rendering texture over image geometry. Can anybody say why so?
THREE.SVGRenderer doesn't support textures.