Weird behaviour of shadows in THREE.js - javascript

I am trying to render a set of photos, positioned in 3-dimensional space, which cast shadows on one another. I am starting with two rectangles, and here is my code
function loadScene() {
var WIDTH = 1200,
HEIGHT = 500,
VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1,
FAR = 10000,
world = document.getElementById('world'),
renderer = new THREE.WebGLRenderer(),
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR),
scene = new THREE.Scene(),
texture = THREE.ImageUtils.loadTexture('image.jpg', {}, function() {
renderer.render(scene, camera);
}),
material = new THREE.MeshLambertMaterial({map: texture}),
solidMaterial = new THREE.MeshPhongMaterial({color: 0xCC0000}),
rectangle = new THREE.PlaneGeometry(200, 120),
mesh = new THREE.Mesh(rectangle, material),
mesh1 = new THREE.Mesh(rectangle, material),
spotLight = new THREE.SpotLight(0xFFFFFF, 1.3);
camera.position.set(0, 0, 200);
mesh.translateX(140);
mesh.translateZ(-70);
mesh.receiveShadow = true;
mesh1.castShadow = true;
spotLight.position.x = -100;
spotLight.position.y = 230;
spotLight.position.z = 230;
spotLight.castShadow = true;
scene.add(spotLight);
scene.add(mesh);
scene.add(mesh1);
renderer.setSize(WIDTH, HEIGHT);
renderer.shadowMapEnabled = true;
renderer.render(scene, camera);
world.appendChild(renderer.domElement);
}
Here solidMaterial is a solid red, and material is a textured material. What I get is the following:
If I use material for both the meshes, the rectangles appear as expected, but without shadows. Same if I use solidMaterial for both.
If I use material for mesh (the one farther away) and solidMaterial for mesh1, I see a red rectangle which casts shadow on a textured one. This is the only case that works as I would expect.
If I use solidMaterial for mesh (the one farther away) and material for mesh1, I see a red rectangle with the shadow on it, but the textured rectangle in front is not drawn at all.
What is the correct use of shadows?

It turns out the shadow does not appear when the two rectangles have the same material. I wonder whether this a bug in THREE.js.
On the other hand, if I use two different material, the shadow appears as expected, even if they have the same texture.

Related

Three.js displacementMap does not affect lighting, only vertices

I'm using Three.js to apply a displacement map to a simple plane. The displacement applies successfully, but the lighting is wrong, as if all the normals remain unchanged. The result is a surface with the right shape that's lit as if it were flat.
displacement map:
result:
How can I fix this to properly change the lighting?
Here is the relevant bit of code:
// shortened from actual code - please excuse any small typos
var renderer = new THREE.WebGLRenderer();
renderer.setSize(500, 250);
var scene = new THREE.Scene();
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(100, 100, 100);
var ambient = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(light);
scene.add(ambient);
var camera = new THREE.PerspectiveCamera(60, 2, 1, 20000);
var geometry = new THREE.PlaneBufferGeometry(100, 100, 1000, 1000);
geometry.rotateX(-Math.PI / 2);
var material = new THREE.MeshPhongMaterial();
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('circlemap.png');
material.displacementScale = 20;
material.displacementMap = texture;
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// ... later
renderer.render(scene, camera)
edit: when I set flatShading: true in the material, the normals are updated correctly, but look bad (because of the flat shading):
You're going to have to pass a normalMap along with your displacementMap.
See this demo, when normalScale = 0 it's the equivalent of having no normalMap, and you can see that the reflections don't follow the displacement, only the default topography. However, when normalMap is 1, then the reflections do respect the displacement.
You need to generate a normalMap.

THREE.ShaderMaterial opacity not working

I am switching to ShaderMaterial from MeshBasicMaterial in order to provide filters on my mesh textures. ShaderMaterial inherits from Material and hence opacity parameter is present. But changing this parameter doesn't change opacity of object. I am using THREE.HueSaturationShader which does not set alpha value.
I have added a very simple fiddle to showcase the situation
http://jsfiddle.net/thenectorgod/89aahytL/1/.
// BufferGeometry Tester
var hostDiv, scene, renderer, camera;
var WIDTH = 500;//window.innerWidth,
HEIGHT = 500;//window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
function init() {
hostDiv = document.createElement('div');
document.body.appendChild(hostDiv);
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor( 0x888888, 1 );
hostDiv.appendChild(renderer.domElement);
camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 50;
camera.lookAt(scene.position);
var geometry = new THREE.PlaneBufferGeometry(20,20);
var material = new THREE.ShaderMaterial({
transparent: true,
depthTest: false
});
material.opacity = 0;
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
scene.add(camera);
animate();
}
function render() {
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
}
init();
Though I set the opacity to 0 the object is still visible.
How can I use both opacity and Shaders without adding extra opacity parameter in all of them.
Your shader material has no shader. By default it renders something like MeshBasicMaterial but with a hardcoded GLSL color of red, and no transparency / opacity.
If you want a ShaderMaterial, you actually need to write GLSL shaders for it.

Wrapping images around sphere

I've read many blogs/questions about this and didn't find the right answer. I'm creating an earth in three.js. But every time I'm mapping my texture and bump map it doesn't show. Also there aren't any console errors. It still shows my light on the sphere so the sphere is still there. But the textures won't show. :(
var scene,
camera,
light,
renderer,
earthObject;
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight;
var angle = 45,
aspect = WIDTH / HEIGHT,
near = 0.1,
far = 3000;
//Environment
var container = document.getElementById('container');
camera = new THREE.PerspectiveCamera(angle, aspect, near, far);
camera.position.set(0, 0, 0);
scene = new THREE.Scene();
//light
scene.add(new THREE.AmbientLight(0x333333));
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5,3,5);
scene.add(light);
var earthGeo = new THREE.SphereGeometry (30, 40, 400),
earthMat = new THREE.MeshPhongMaterial();
// diffuse map
earthMat.map = THREE.ImageUtils.loadTexture('http://i317248.iris.fhict.nl/LSTE/globe/Images/globe.jpg');
// bump map
earthMat.bumpMap = THREE.ImageUtils.loadTexture('http://i317248.iris.fhict.nl/LSTE/globe/Images/bump.jpg');
earthMat.bumpScale = 8;
var earthMesh = new THREE.Mesh(earthGeo, earthMat);
earthMesh.position.set(-100, 0, 0);
earthMesh.rotation.y=5;
scene.add(earthMesh);
camera.lookAt( earthMesh.position );
//Renderer code.
var renderer = new THREE.WebGLRenderer({antialiasing : true});
renderer.setSize(WIDTH, HEIGHT);
renderer.domElement.style.position = 'relative';
container.appendChild(renderer.domElement);
renderer.autoClear = false;
renderer.shadowMapEnabled = true;
function render () {
renderer.render(scene, camera);
}
render();
Two problems in your code:
you're not waiting for the images to load before rendering the scene
you're having Cross-domain Policy problems (https://en.wikipedia.org/wiki/Same-origin_policy) so the images are actually never loaded

Clara.io exported object not visible in Three.JS canvas - Only black square

I am using Three.JS and imported an object which was exported as a JSON from clara.io. My problem is that the object is not visible in the canvas and all I get is a black square with the same size I set in the variable (400 and 300 pixels).
Here's my code:
var WIDTH = 400,
HEIGHT = 300;
// set some camera attributes
var VIEW_ANGLE = 45,
ASPECT = WIDTH / HEIGHT,
NEAR = 1,
FAR = 100000;
var $container = $('#wrapper');
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
var camera =
new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0xcccccc, 0.002);
camera.position.z = 300;
scene.add(camera);
camera.z = 100;
renderer.setSize(WIDTH, HEIGHT);
$container.append(renderer.domElement);
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
var loader = new THREE.ObjectLoader();
loader.load("js/suzanne-blender.json", function (obj) {
scene.add(obj)
});
renderer.render(scene, camera);
What I expect to see is the model with the material as I exported it from clari.io. Thanks.
Here's a link to the object JSON file
I just tried the JSON by loading it into the ThreeJS editor here: http://threejs.org/editor/ (just drag and drop it.) I then added a single light and dragged the light to not be exactly at the center. I could see the Suzanne model fine in the editor. This means that the issue must be in the code you are using to visualize the model. Maybe you just need to add a point light that is off to one side to light the object properly?
Best regards,
Ben Houston

Plain Terrain in ThreeJS

I am trying to draw a plane terrain in using ThreeJS but it doesn't work.
Here is my plane creation code:
var plane = new THREE.Mesh(new THREE.PlaneGeometry(300, 300), new THREE.MeshBasicMaterial({
color: 0x0000ff
}));
plane.overdraw = true;
this.scene.add(plane);
Pretty straight-forward. Actually I just copied it from some site.
This is how I initialize scene and camera:
this.camera =
new THREE.PerspectiveCamera(
45, // view angle
width / height, // aspect
0.1, // near
10000); // far
this.scene = new THREE.Scene();
// add the camera to the scene
this.scene.add(this.camera);
// the camera starts at 0,0,0
// so pull it back
this.camera.position.z = 800;
this.camera.position.y = -100;
I also have a sphere of radius 20 in the center. It shows up just fine.
What am I missing?
The camera is looking at the "back face" of the plane.
A plane have two sides, but only one is visible.
Two solutions:
1) Move the camera to look at the "front face" of the plane:
this.camera.position.y = 100;
2) Or, activate the doubleSided flag:
plane.doubleSided = true;

Categories