How to get a shadow using SpriteMaterial and a DirectionalLight - javascript

My code :
Directional light :
light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-50, 50, 300);
light.castShadow = true;
light.shadowDarkness = 0.4;
light.shadowMapWidth = 1024;
light.shadowMapHeight = 1024;
scene.add(light);
Sprite :
var spriteMaterial = new THREE.SpriteMaterial({map: texture});
var info = new THREE.Sprite( spriteMaterial );
info.castShadow = true;
info.scale.set(infoScale, infoScale, infoScale);
info.name = continent.label;
info.userData.continent = continent;
info.userData.id = continent.id;
info.userData.type = 'info';
hubInfos.push(info);
Here is the result my aircraft has a shadow but not the sprite

Sprites in three.js do not cast shadows.
One work-around is to use PlaneGeometry like so:
scene.add( plane );
plane.lookAt( camera );
Note: LookAt() will not work correctly if the plane is a child of a rotating object; it must be a child of the scene.
three.js r.74

Related

Three.js render not showing a simple cube when I want to show simple mesh

I want to show a simple plane and a simple cube but the plane hides the cube, the cube is located between the camera and the plane, but the plane "hides" the cube.
This is my scene without plane:
and here it is with the plane added:
I am pretty sure they are in a location where the cube should to be showed.
Here is my code:
var scene = new THREE.Scene(),
camera = new THREE.PerspectiveCamera(45,Window.innerWidth,window.innerHeight,0.1,1000),
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
var axes = new THREE.AxisHelper(20);
scene.add(axes);
var cubeGeometry = new THREE.CubeGeometry(4,4,4);
var cubeMaterial = new THREE.MeshBasicMaterial({color:0x777777});
var cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
//cube.castShadow = true;
cube.position.x = 0;
cube.position.y = 10;
cube.position.z = 5;
scene.add(cube);
var planeGeometry = new THREE.PlaneGeometry(60,20);
var planeMaterial = new THREE.MeshBasicMaterial({color: 0x55cc88});
var plane = new THREE.Mesh(planeGeometry,planeMaterial);
plane.rotation.x = -0.5*Math.PI;
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
//scene.add(plane);
//plane.receiveShadow = true;
camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;
camera.lookAt(scene.position);
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40,60,-10);
scene.add(spotLight);
//renderer.setClearColor(0xEEEEEE,1);
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.render(scene,camera);
$("#WebGl-salida").append(renderer.domElement);
Pay attention to names of objects and order and correctness of parameters in methods:
camera = new THREE.PerspectiveCamera(45,Window.innerWidth,window.innerHeight,0.1,1000)
should be like:
camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,0.1,1000)
jsfiddle example
Many thanks! Both for the answer and for the suggestion to edit the question to make it more understandable (my English has to improve) Now it is working perfectly.

How to make plane geometry lookAt camera using threejs

I have added sphere and plane geometry to scene when I rotate the camera the plane geometry should look at the
camera, I have used camera.lookAt( plane.position ); this did not work then i tried to use
plane.quaternion.copy( camera.quaternion ); only 1 plane geometry looked at the camera can someone please help
me how to solve this problem. I have also added the image and code below.
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var metrics = context.measureText( cardinal.name );
var textWidth = metrics.width;
context.fontSize = '100pt Calibri';
context.fillStyle = 'red';
context.fillText(cardinal.name, 0, 50);
var texture = new THREE.Texture(canvas) ;
texture.needsUpdate = true;
//var spriteAlignment = new THREE.Vector2(0,0) ;
var material = new THREE.MeshBasicMaterial( {color: 0xffffff, side: THREE.DoubleSide ,map : texture} );
var geometry = new THREE.PlaneGeometry( 0.5, 0.3);
plane = new THREE.Mesh( geometry, material );
plane.position.set(X_value,0,Z_value);
//camera.lookAt(X_value,0,Z_value);
//plane.lookAt(camera.position);
scene.add(plane);
}
function animate(spritearray) {
//sprite.update();
//spritearray.update();
for(var j=0; j<spritearray.length; j++){
var labelupdate = spritearray[j];
labelupdate.update();
}
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
camera.lookAt( plane.position );
}

Shadow is abnormally-shaped for MeshLambertMaterial in Three.js r76?

Using r70, the shadow shows as expected - r70 example (Shadow it correct shape)
Using r76 however, the shadow is abnormally shaped - r76 example (Shadow is abnormally shaped)
You can see that the shadows on the MeshLambertMaterial on the ground plane are not as expected.
Why is the shadows becoming abnormally shaped?
What needs to be changed to get it working in r76?
Here is the code I am using (same in both example):
var light;
light = new THREE.SpotLight(0xdfebff, 1);
light.position.set(300, 400, 50);
light.castShadow = true;
light.shadowCameraVisible = true;
scene.add(light);
var groundMaterial = new THREE.MeshLambertMaterial({
color: 0xFF0000,
});
plane = new THREE.Mesh(new THREE.PlaneGeometry(500, 500), groundMaterial);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
plane.castShadow = false;
scene.add(plane);
var boxgeometry = new THREE.CubeGeometry(100, 100, 100);
var boxmaterial = new THREE.MeshLambertMaterial({
color: 0x0aeedf
});
var cube = new THREE.Mesh(boxgeometry, boxmaterial);
cube.castShadow = true;
cube.position.x = 0;
cube.position.y = 100;
cube.position.z = 0;
scene.add(cube);
webglRenderer = new THREE.WebGLRenderer({ alpha: true });
webglRenderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
webglRenderer.domElement.style.position = "relative";
webglRenderer.shadowMapEnabled = true;
webglRenderer.shadowMapSoft = true;
The first thing to do is to add a shadow camera helper so you can see what is going on:
light.shadowCameraHelper = new THREE.CameraHelper( light.shadow.camera );
scene.add( light.shadowCameraHelper );
It is clear that the shadow camera frustum is clipping the shadow.
Starting in three.js r.76, the shadow camera frustum is automatically set so it more closely matches the spotLight field-of-view.
If you would like to override that, you can specify a custom shadow frustum like so:
// custom shadow frustum
light.shadow = new THREE.LightShadow( new THREE.PerspectiveCamera( 30, 1, 200, 700 ) );
updated fiddle: http://jsfiddle.net/ef4r5s76/5/
three.js r.76/r.77

Getting the coordinates on the scene (three js)

I'm really struggling with this and have gone through several discussions that are not really related to my problem. If anybody can help, I would greatly appreciate.
I'm writing a html document using the three.js library. There is a scene called scaledScene as below (scaledMap and scaledScene are already defined):
scaledMap = new THREE.Mesh(
new THREE.PlaneGeometry( 1600, 1200 ),
new THREE.MeshBasicMaterial( {
map: new THREE.ImageUtils.loadTexture( 'texture/test1.png' ),
//wireframe: true,
side: THREE.DoubleSide
} )
);
scaledScene.add( scaledMap );
The scene is created by a high solution picture that's zoomed in to the highest level. Zooming is not allowed but only panning.
controls.noZoom = true;
controls.noPan = false;
I would like to get the absolute coordinates on the scene when panning. For example, if I pan to the top left corner, I'd like to get the information that the cursor or the view is located at top left corner. Is this possible? If so, how do I do it?
You want a picking ray.
A ray can be sent from the center of the viewport to the map in 3d space. this will tell you the pixel of the map that's currently at the center of the viewport.
I have created a fiddle.
The code is as follows. It disables rotation of the camera so that only panning is available. The pixel of the image that is at the center of the view port is listed below the viewport. Remember that threejs uses cartesian space. So an image that is 150px / 150px will report pixels from -75 to 75. So if both of your x is negative and your y is positive, then you know you're viewing the top left portion of the image.
The fiddle: http://jsfiddle.net/v1g64zkb/
var width = 400;
var height = 300;
var aspect = width/height;
var near = 1;
var far = 1000;
var angle = 45;
var createRenderer = function(){
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width,height);
return renderer;
}
var camera;
var createCamera = function(){
camera = new THREE.PerspectiveCamera(
angle, aspect, near, far);
camera.position.set( 0, 0, 100 );
camera.lookAt(new THREE.Vector3( 0, 0, 0 ));
return camera;
}
var createScene = function(){
var scene = new THREE.Scene();
return scene;
}
var createControls = function(camera){
var controls = new
THREE.OrbitControls(camera);
controls.rotateSpeed = 0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = true;
controls.noPan = false;
return controls;
}
var createLight = function(){
var light = new THREE.PointLight(0xFFFFFF);
light.position.x=0;
light.position.y=0;
light.position.z=100;
return light;
}
var scene = createScene();
var camera = createCamera();
var controls = createControls(camera);
var light = createLight();
var renderer = createRenderer();
scene.add(light);
scaledMap = new THREE.Mesh(
new THREE.PlaneGeometry( 150, 150 ),
new THREE.MeshBasicMaterial( {
map: new THREE.ImageUtils.loadTexture( '../img/logo.png' ),
color:0xFFFFFF,
side: THREE.DoubleSide
} )
);
scene.add( scaledMap );
var raycaster = new THREE.Raycaster();
var cameraPosition = new THREE.Vector2();
cameraPosition.x = 0;
cameraPosition.y = 0;
console.log(cameraPosition)
var render = function(){
renderer.render(scene,camera);
raycaster.setFromCamera( cameraPosition, camera );
var intersects = raycaster.intersectObjects( scene.children );
if(intersects[0] != undefined){
$("#output").html(intersects[0].point.x.toFixed(2)+" "+intersects[0].point.y.toFixed(2));
}
renderer.render( scene, camera );
}
controls.addEventListener('change',render);
var animate = function(){
requestAnimationFrame(animate);
render();
controls.update();
}
animate();
$("#container").append(renderer.domElement);
//edit: I would not run a picking ray inside a render call. This is just a simplified example. Use the controls change event or whatever to fire the picking ray.

How to render pixelated textures with three js?

I modified a minecraft-ish demo so you can jump around and place blocks. But the texture of the blocks I construct is smoothed and not pixelated for some reason.
The source I think is relevant:
var textureDirt = THREE.ImageUtils.loadTexture( 'img/dirt.png' );
textureGrass.magFilter = THREE.NearestFilter;
textureGrass.minFilter = THREE.LinearMipMapLinearFilter;
var material = new THREE.MeshLambertMaterial( { map: textureDirt, ambient: 0xbbbbbb, vertexColors: THREE.VertexColors } );
var geometry = new THREE.CubeGeometry(1,1,1);
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = point[0];
mesh.position.y = point[1];
mesh.position.z = point[2];
// for physics
mesh.blockType = type;
world[point] = mesh;
scene.add(mesh);
Live demo:
http://ubershmekel.github.com/mine3js/
The rest of the source:
https://github.com/ubershmekel/mine3js/blob/master/js/main.js
After reviewing the question, I found the bug. I didn't apply the filters to the dirt material
textureGrass.magFilter = THREE.NearestFilter;
textureGrass.minFilter = THREE.LinearMipMapLinearFilter;
Should have been
textureDirt.magFilter = THREE.NearestFilter;
textureDirt.minFilter = THREE.LinearMipMapLinearFilter;

Categories