three.js shadowCascade usage - three.js

I'm trying to use shadowCascade for directional lights. Using any code of the examples mentioned in https://github.com/mrdoob/three.js/issues/1888 results in a shader error + a periodical error Object [object Object] has no method 'decompose'.
Since it's a seldomly used and undocumented feature I have no clue where to even begin with debugging.
Even leaving all the code out and enabling shadowCascade in the console for the light while the scene is running results in the periodical error from above showing up.
Any help would be greatly appreciated!
Kind regards,
Doidel
PS: People always want to see some code. So here's some code.
var sunlight = new THREE.DirectionalLight();
sunlight.intensity = 0.5;
sunlight.position.set(100, 300, 100);
sunlight.castShadow = true;
sunlight.shadowBias = -0.0001;
sunlight.shadowMapWidth = sunlight.shadowMapHeight = 2048;
sunlight.shadowDarkness = 0.7;
var d = 250;
sunlight.shadowCameraLeft = -d;
sunlight.shadowCameraRight = d;
sunlight.shadowCameraTop = d;
sunlight.shadowCameraBottom = -d;
sunlight.shadowCameraNear = 200;
sunlight.shadowCameraFar = 800;
sunlight.shadowDarkness = 0.6;
sunlight.shadowBias = 0.000065;
sunlight.shadowCascade = true;
sunlight.shadowCascadeCount = 3;
sunlight.shadowCascadeNearZ = [ -1.000, 0.9, 0.975 ];
sunlight.shadowCascadeFarZ = [ 0.9, 0.975, 1.000 ];
sunlight.shadowCascadeWidth = [ 2048, 2048, 2048 ];
sunlight.shadowCascadeHeight = [ 2048, 2048, 2048 ];
sunlight.shadowCascadeBias = [ 0.00005, 0.000065, 0.000065 ];
sunlight.shadowCascadeOffset.set( 0, 0, -10 );
scene.add( sunlight );
sunlight.lookAt(new THREE.Vector3(0,0,0));

There was another discussion about the usage of shadowCascade with the conclusion to currently not use shadowCascade, due to not being maintained.

Related

Update position of shadow camera in render loop

I'm trying to set the position of my directional light shadow camera to be the same as my main perspective camera in the render loop:
sunlight = new THREE.DirectionalLight(0xffffff, 1);
sunlight.position.x = camera.position.x ;
sunlight.position.y = 300;
sunlight.position.z = camera.position.z ;from top
sunlight.castShadow = true;
sunlight.shadow.mapSize.width = 2048 ;
sunlight.shadow.mapSize.height = 2048 ;
sunlight.shadow.bias = -0.0027;
sunlight.shadow.camera.left = -75;
sunlight.shadow.camera.right = 75;
sunlight.shadow.camera.top = 75;
sunlight.shadow.camera.bottom = -75;
sunlight.shadow.camera.position = camera.position;
sunlight.shadow.camera.far = sunlight.position.distanceTo(scene.position) + 20;
sunlight.shadow.camera.near = sunlight.position.distanceTo(scene.position) - (camera.position.y * 2);
sunlight.shadow.camera.updateProjectionMatrix();
function render() {
renderer.render(scene, camera);
sunlight.shadow.camera.position = camera.position;
sunlight.shadow.camera.updateProjectionMatrix();
}
However the shadow camera does not move at all. Is it possible to update the position of a shadow camera during run-time?
The shadow.camera is more of an internal component to the sunlight.
The way to move the sunlight so that it follows the camera is more something like this:
sunlight.position.copy( camera.position );
sunlight.target.copy( camera.position );
sunlight.position.y += 20;
this ^ should make the sunlight stay above the camera, pointing down, at a distance of 20 units.
Also your shadow.camera.near / far setup looks a little weird.
I would just set those to something like
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 50.0;
..or something like that.

Three.js: PointLight change distance

I have made a scene with three.js in which I make use of a PointLight.
var distance = 10000;
var intensity = 10;
var decay = 0;
var hex = 0xFFFFFF;
var light1 = new THREE.PointLight(hex, intensity, distance, decay);
I want to use shadows, so I added
light1.shadow.camera.near = 200;
light1.shadow.camera.far = 10000;
light1.shadow.camera.fov = 90;
light1.shadow.bias = -0.00022;
light1.shadow.mapSize.width = 1024;
light1.shadow.mapSize.height = 1024;
Until here everything worked perfect. However, as soon as I include in the next line:
light1.castShadow = true;
Then the distance visibly changes from 10000 to 1000.
If I call the distance from light1 to the console, it is still 10000. Even though it is not like that in the canvas.
(I have changed it to a ~50-digit number with no change in distance)
Any suggestions on how to solve this?
You can try to create a shadow via THREE.Texture(), in this way the shadow will be an independent element and shouldn't influence the position of the PointLight.
var shadowTexture = new THREE.Texture(canvas);
shadowTexture.needsUpdate = true;
var shadowMaterial = new THREE.MeshBasicMaterial({map: shadowTexture, opacity: 0.5});
var shadowGeo = new THREE.PlaneBufferGeometry(100, 100, 100, 1);
// Locate the position of the shadows
mesh = new THREE.Mesh(shadowGeo, shadowMaterial);
mesh.position.y = 0;
mesh.rotation.x = - Math.PI / 2;
scene.add( mesh );
I am applying the shadow to a PlaneGeometry since I assume that the shadow is casted on the scene. In any case, give also a look at this example concerning shadows in a scene.

Three.js issue at edges of tiled texture using MeshFaceMaterial

I am trying to tile the texture from multiple images onto a plane geometry using MeshFaceMaterial. Every thing works fine, except for a blurry edge forming in between tiles.
.
var textureArray = [];
var tileColumns = 2;
var tileRows = 1;
textureArray[0] = THREE.ImageUtils.loadTexture('./test3.jpg');
textureArray[1] = THREE.ImageUtils.loadTexture('./test4.jpg');
var faceCountPerTileX = 2 * widthSegments/tileColumns;
var faceCountPerTileY = heightSegments/tileRows;
var faceCountX = 2 * widthSegments;
var faceCountY = heightSegments;
for(var tileIndexY = 0; tileIndexY < tileRows; tileIndexY++){
for(var tileIndexX = 0; tileIndexX < tileColumns; tileIndexX++){
var index = tileIndexY * tileColumns + tileIndexX;
textureArray[index].wrapS = THREE.RepeatWrapping;
textureArray[index].wrapT = THREE.RepeatWrapping;
textureArray[index].repeat.set(tileColumns,tileRows);
materialContainer[tileIndexY * tileColumns + tileIndexX] = new THREE.MeshBasicMaterial({
map: textureArray[tileIndexY * tileColumns + tileIndexX],
overdraw: true,
ambient: 0xffffff
});
for(var faceIndexY = tileIndexY * faceCountPerTileY; faceIndexY < (tileIndexY+1) * faceCountPerTileY; faceIndexY++){
for(var faceIndexX = tileIndexX * faceCountPerTileX; faceIndexX < (tileIndexX+1) * faceCountPerTileX; faceIndexX++){
g.faces[faceIndexY * faceCountX + faceIndexX].materialIndex = tileIndexY * tileColumns + tileIndexX;
}
}
}
}
var mat = new THREE.MeshFaceMaterial(materialContainer);
var obj = new THREE.Mesh(g, mat);
I have tried all known solutions, i have even tried writing a custom shader and using ShaderMaterial. But no luck, can some help me out to fix the issue?
By the looks of it, you set the texture mode of the invidual textures in your set to repeat.
This seems wrong, the individual textures do not repeat, they are displayed only once. Setting a texture to repeat causes the right side of the texture to "blend through" on the left (and vice versa), causing visible seams like the one on your screenshot.

Generating an block/voxel terrain efficiently without FPS drops?

I'm having a little trouble generating/displaying a terrain using Three.JS without major FPS drops. Here's the code I wrote to create each block and set the correct position:
var TO_METERS = 10;
var testOb = [];
var blockGeometry = new THREE.CubeGeometry(TO_METERS, TO_METERS, TO_METERS);
var blockMat = new THREE.MeshLambertMaterial({color: 0xFFFFFF, wrapAround: true, side: THREE.FrontSide, shading: THREE.FlatShading});
function loadChunk(startX, startY, startZ) {
var yVar = 0;
var zVar = 0;
var blockCo = 0;
var combinedGeometry = new THREE.CubeGeometry(0, 0, 0);
for (var x = 0; x <= 4999; x++) {
testOb[x] = new THREE.Mesh();
testOb[x].geometry = blockGeometry;
if (blockCo == 10) {
blockCo = 0;
if (zVar == 90) {
yVar += TO_METERS;
zVar = 0;
}
else {
zVar += TO_METERS;
}
}
testOb[x].position.x = (blockCo * TO_METERS) + startX;
testOb[x].position.y = (yVar - 500) + startY;
testOb[x].position.z = zVar + startZ;
testOb[x].castShadow = true;
blockCo++;
THREE.GeometryUtils.merge(combinedGeometry, testOb[x]);
}
var cMesh = new Physijs.BoxMesh(combinedGeometry, blockMat, 0);
scene.add(cMesh);
}
Basically it creates each block, sets the position and merges them together using THREE.GeometryUtils.merge to make up a "chunk" (a rectangle) MineCraft style.
I'm pretty sure the large number of individual blocks that make up each chunk is causing the low FPS. With only 10 chunks the FPS is fine. If I add any more the FPS drops drastically.
One thought I had was to use a WebWorker to do the processing, but of cause that isn't possible as I can't add the chunks or even use Three.JS within it. That also would only help the load time, not the FPS problem I'm having.
If anyone has any ideas how I would go about fixing this problem, I would really appreciate it. :) Maybe it would be possible to hide blocks which the camera can't see? Or I might just totally be doing it the wrong way. Thanks!

threejs modify envMap on mouseover

Im new in threejs, I want to learn some about this library... but, in my opinion, there is very little documentation.
Issue is:
I have a SphereGeometry and I want to give It some interactivity through mouse events, I'm using three.domevent.object3d.js for "mouseover" and "mouseout" events to make scale property bigger or smaller. But I can not to modify sphere material when mouseover is triggered because nothing happens. My code is:
sphere.on('mouseover', function(event){
event.target.scale.x *= 2;
event.target.scale.y *= 2;
event.target.scale.z *= 2;
event.target.material.envMap = textureCube;
event.target.material.combine = THREE.MixOperation;
event.target.material.reflectivity = 0.15;
}).on('mouseout', function(event){
event.target.scale.x *= 0.5;
event.target.scale.y *= 0.5;
event.target.scale.z *= 0.5;
event.target.material.envMap = null;
event.target.material.combine = THREE.MixOperation;
event.target.material.reflectivity = 0;
});
textureCube is a bunch of jpegs for skyboxMesh, its code is:
var r = "images/";
var urls = [ r + "px.jpg", r + "nx.jpg",
r + "py.jpg", r + "ny.jpg",
r + "pz.jpg", r + "nz.jpg" ];
textureCube = THREE.ImageUtils.loadTextureCube( urls );
Any help will be appreciated
Thanks
If you want to add or remove an environment map from a material, you will have to add
material.needsUpdate = true;
Have a look at the "How to update things" doc: https://threejs.org/docs/index.html#manual/en/introduction/How-to-update-things
three.domevent.object3d.js is not part of the library, so I can't comment on that.
three.js r.52

Resources