In a normal scenario, the shaow look like this
But after I modified the parameters ofdirectionalLight.shadow.camera
directionalLight.shadow.camera.left = -50
directionalLight.shadow.camera.right = 50
directionalLight.shadow.camera.top = -50
directionalLight.shadow.camera.bottom = 50
It became like this
How to resolve this problem?
https://jsfiddle.net/JesseLuo/z1m6uffu/12/
Shadows are simulated using a "camera" in the location of the light source, and that camera's frustum (or, its field of view) and resolution determine how precisely the shadow matches your object. You can't have perfectly detailed shadows covering large areas, so you need to tune the shadow camera to the part of the scene that's important. In this case, when you change the parameters to expand the camera's frustum, you've spread it over a larger area and lost precision.
To improve the result you can:
A. Increase the shadowMap's resolution. Higher values give better quality shadows at the cost of computation time. Values must be powers of 2.
light.shadow.mapSize.width = 1024;
light.shadow.mapSize.height = 1024;
B. Change the shadow type. PCFSoft may look better, but doesn't perform as well.
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
C. Reduce the dimensions of the shadow camera frustum to just the area you need to cover. Use a CameraHelper to see where the shadows are covering, like in this example.
scene.add( new THREE.CameraHelper( light.shadow.camera ) );
See THREE.LightShadow docs for more information.
Related
I have a complex object, i.e. a box, and I would like to cut it dynamically. This jsFiddle is a very simple example:jsFiddle
Very simple plane
var plane = new THREE.Mesh( geometry, material3 );
plane.rotation.x =1.3; // -Math.PI / 2;
gui.add(plane.rotation, "x", 0.1, Math.PI / 2).name("angle");
gui.add(plane.position, "y", -1, 1).name("h");
scene.add( plane );
I would like to remove from my object the upper part. Just like to cut off a piece from an apple using a knife.
The plane is the knife: In my example, you can play with 2 controls to move the plane up and down or change the angle.
Can you help me to hide the removed part from the object?
You've got two options:
You could use clipping as WestLangley mentioned above.
Clipping does not modify the vertex geometry, it's only visual.
Is non-destructive, so it's good for animating or making constant updates.
Clipping is mostly done with a few planes instead of complex geometry.
You could use a boolean operation with Constructive Solid Geometry.
Boolean does affect the vertex geometry, which can be exported.
Operation is "destructive", so you can't make updates once it's done.
Boolean can be performed with complex geometries, as long as they're "manifold".
Boolean operations require both geometries to be manifold geometries in order to work. This means both meshes have to be closed, without open faces. You cannot use infinitely thin planes, so the example in your JSFiddle wouldn't work. You would need to give each side a little bit of thickness, like using a box with a width of 0.0001 instead of a plane.
Plane has no lookAt method, so I can't just do lookAt(camera.position). Instead, it's defined with its normal, represented as a Vector3. How do I make this plane always face the camera?
Plane.setFromNormalAndCoplanarPoint can be used to accomplish this.
For a simple example, let's assume your camera is orbiting the origin. In this case, you can set up your plane to face the camera very easily:
// assume plane is a THREE.Plane
plane.setFromNormalAndCoplanarPoint( camera.position.clone().normalize(), scene.position )
This uses the camera's (normalized) position as the plane's normal, which works in this case.
If your camera is somewhere in free space, looking in an arbitrary direction, this is a little harder, but it's mostly visualization.
Remember, that a camera lives in its own "space," where it resides at the origin, and looks down the -Z axis. Now imagine where your plane would need to be created within that space. Let's just say that it could be placed at ( 10, 10, -10 ). We can again use some easy operations to compute the normal. The "hard" part is moving everything into world space, but three.js has convenience functions for that, too.
// in camera space...
let planePosition = new THREE.Vector3( 10, 10, -10 )
let normal = planePosition.clone().inverse().normalize()
// convert to world space...
camera.localToWorld( planePosition )
camera.localToWorld( normal )
normal.sub( camera.position ) // fix the normal based on the camera position
plane.setFromNormalAndCoplanarPoint( normal, planePosition )
One note about the code above, planePosition.clone().inverse().normalize() gets a copy of the plane position, inverts it across the origin, then normalizes it. This has the effect of creating a normal which will point at the camera because the camera sits at the origin in its own space. This is why you need to adjust the normal by the camera's position after converting everything to world coordinates.
I'm working on a three.js scene in which it would be hugely beneficial to be able to determine the subset of all faces (among all geometries) that are visible to the camera at a given time.
I understand one can determine whether a vertex is visible to the camera by doing something like:
camera.updateMatrix();
camera.updateMatrixWorld();
var frustum = new THREE.Frustum();
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse));
// The 3d point to check
var pos = new THREE.Vector3(x, y, z);
if (frustum.containsPoint(pos)) {
// Do something crazy...
}
My geometry has tens of thousands of 2d plane faces, all sitting on a larger plane, and I'd like to determine the set of of their faces that are visible to the camera fairly often (each time the camera zooms past a certain hyperplane, if possible).
I know one can do scene.children[childIndex].visible to see if a mesh is visible, but I have many faces on a mesh and want to determine which of the faces are visible. (All of my meshes are always rendered unless the user zooms wildly). I also know one can adapt this approach:
var frustum = new THREE.Frustum();
var cameraViewProjectionMatrix = new THREE.Matrix4();
// every time the camera or objects change position (or every frame)
camera.updateMatrixWorld(); // make sure the camera matrix is updated
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
cameraViewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
frustum.setFromMatrix( cameraViewProjectionMatrix );
console.log( frustum.intersectsBox( meshes[0].geometry.vertices[0] ) );
Is there a shortcut one can take to find the set of all faces visible to the camera at a given time? In my case, I could precompute the geometric mean of each planar face then use the code above to determine which of the faces is visible, but is there anything better than O(n) in this case?
I'd be very grateful for any ideas others can offer on this question!
Better than O(n)?
Given a sorted array of integers I believe one can determine the subset of those integers that line between an upper and lower bound in ~O(log(n)). Each face's geometric mean is a 3d point, so it seems possible to determine the set of points within the frustum with 3*O(log(n)), i.e. better than O(n) complexity.
Better than O(log(n))
An approximation better than O(log(n)) after some precomputing. Suppose we're dealing with only 1D (then we can generalize to 3D). Quantize the space of each axis then create a hash table with the following structure. For each unit in the quantized space, store the index position of the first point in the sorted array with that unit +- error value. Then given an upper and lower bound, round each to the nearest quantized unit and look up the values for those keys to identify the range of index positions within the span. This returns a list. Repeat for the other two dimensions and take the set intersection. [The frustum provides the upper and lower bounds for each dimension.]
Assume to have a scene with a street with many streetlights (more 20), you move an object close by them and you expect a shadow.
The lights, simply
var light = new THREE.PointLight(0xffffff, 0.5, 6.0);
Only the street has .receiveShadow = true and only the car has .castShadow = true (besides later the lights)
In three.js adding .castShadow = true to all of the lights causes following error
THREE.WebGLProgram: shader error: 0 gl.VALIDATE_STATUS false
gl.getProgramInfoLog Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (16).
Luckily in hour scene we only need a few (at max 4) of them to cast a shadow, as most of the lights are out of reach anyway.
I tried to use 2 approaches
Looping through all the lights and setting .castShadow = true or .castShadow = false dynamically.
Adding and removing the lights completely but setting them with no shadow or a shadow.
With both of them I got the same error.
What other approach would work?
Update
#neeh created a Fiddle for it here (to cause the error change var numLightRows = 8; to a higher number). Keep an eye on the error though, there will be another error with too many lights that isn't caused by the same problem
He also pointed out that we see here that a pointShadowMap is created even when not in use. This explains why there is no change with a "smarter" approach. This now is within the GLSL code.
So we are limited by the GPU, which in my case has 16 IMAGE_UNITS but that isn't the case for all GPUs (my CPU actually works fine with more). You can check on your system with renderer.capabilities.maxTextures. But as mentioned we really only need 4.
The problem remains.
The problem
Yes a new shadow map will be created for every light having castShadow = true (Actually, this is not the case, check this issue). A shadow map is a drawn on which a shadow is computed in order to be blended on a surface afterwards.
gl.getProgramInfoLog Fragment shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (16).
It means that your device can send no more than 16 textures per draw call. Typically, the car (street?) on which you'd like to put shadows is 1 draw call.
To draw a object that receives shadows, all the shadow maps should be blended together with the diffuse map. So this requires to use N+1 texture units for one single draw call. (N being the number of lights that can cast shadow.)
If you dig into Three.js shaders, you'd find this :
#ifdef USE_SHADOWMAP
#if NUM_DIR_LIGHTS > 0
// Reserving NUM_DIR_LIGHTS texture units
uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];
varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
#endif
...
#endif
Check this tool to see how much texture units your browser can handle (Fragment shader > Max Texture Image Units).
The solution ?
Dynamically creating and deleting lights is bad because it's memory-intensive (allocation of a shadow map...).
But, as gaitat said, you can enable shadows only for the nearest lights. Just do the following in your render loop :
Disable all shadows: light.castShadow = false;
Seek nearest lights
Enable shadow for N nearest lights: light.castShadow = true;
Improvement
This algorithm lonely is bad because it allocates one shadow map per light. In addition to be memory-consuming, the rendering would freeze for a bit every time you cross a new light that has no shadow map allocated...
Hence, the idea is to reuse the same shadows maps for the nearest lights. You can deal with shadow maps like this :
// create a new shadow map
var shadowMapCamera = new THREE.PerspectiveCamera(90, 1, 0.5, 500);
var shadow = new THREE.LightShadow(shadowMapCamera);
// use the shadow map on a light
light.shadow = shadow;
shadow.camera.position.copy(light.position);
light.castShadow = true;
You can get the maximum number of texture units with renderer.capabilities.maxTextures. So you can compute the number of shadow map to create based on it but remember to leave some for more regular maps like diffuseMap, normalMap...
Check out this fiddle for a full implementation (only 4 shadow maps are used).
I need to make light (sun) for casting shadows to all scene (DirectionalLight is the best, right?), but the quality is bad, so I'm trying to make the settings of the shadow: on/off, Low, Normal, High:
a = 512 ... 8192; b = 300 ... 8000
light.castShadow = checked; - no update (but if reload an objects it is work)
light.shadow.mapSize.width/height = a; - this works
light.shadow.camera.top/bottom/left/right = b; - no updating
Tried to see the changes, but nothing works:
light.shadow.camera.updateProjectionMatrix(); - shadows disappear at all
scene.updateMatrixWorld();
camera.updateProjectionMatrix();
camera.updateMatrixWorld();
camera.updateMatrix();
Is the any better way to do a sun?
And how to redraw the shadows?
Adding an example to better understand what I mean ->
Example
According to this link: https://github.com/mrdoob/three.js/wiki/Updates
Properties that can't be easily changed in runtime (once material is
rendered at least once):
numbers and types of uniforms
numbers and types of lights
presence or not of: texture, fog, vertex colors, skinning, morphing, shadow map, alpha test
Changes in these require building of new shader program. You'll need to set material.needsUpdate flag to true.
if you want to change shadow mapSize when runtime, you have to dispose()
light.shadow.map.dispose()
light.shadow.map = null
let s = 1024
light.shadow.mapSize = new THREE.Vector2(s, s)
https://threejs.org/docs/#manual/en/introduction/How-to-dispose-of-objects