Shadow aliasing with ShaderMaterial on three.js - three.js

Here a picture of my problem, like you can see my shadows aren't smooth on my ShaderMaterial wich is a copy of PhongMaterial.
For the moment I have try all of these solution find on internet but nothing seems to work :
groundGeometry.computeFaceNormals();
groundGeometry.computeVertexNormals();
groundGeometry.verticesNeedUpdate = true;
renderer.shadowMapType = THREE.PCFShadowMap; //And all options possible
renderer.shadowMapCullFace = THREE.CullFaceBack; //And the other one
renderer = new THREE.WebGLRenderer({ antialias : true });
I also play with the different parameters of my SpotLight (also try with Directional light:
shadowMapWidth
shadowMapHeight
shadowCameraLeft
shadowCameraRight
shadowCameraBottom
shadowCameraTop
shadowCameraNear
shadowCameraFar
shadowBias
To be honest I don't know what to do now :/
So any help would be very appreciate !

Probably it is causes by self-shadowing. Try to set a small value of shadowBias like 0.05 or -0.05.
If your scene permits, reduce as much as possible the shadowmap frustum, changing the value of shadowCamera options to fit exactly the objects that you want.
If the angle between the light and normal at some point of the object is nearly 90 degrees, you can try to scale the bias depending of slope. There is an approach called slope scaled bias that consist in scale the bias depending of the angle between light vector and normal vector. The formula is:
float slope_bias = bias * tan(acos(dot(normal,-lightDirection)));
I hope it helps a little bit.

Related

Change facing direction of CSS3DObject

I have a 3D scene with a bunch of CSS object that I want to rotate so that they are all pointing towards a point in the space.
My CSS objects are simple rectangles that are a lot wider than they are high:
var element = document.createElement('div');
element.innerHTML = "test";
element.style.width = "75px";
element.style.height = "10px";
var object = new THREE.CSS3DObject(element);
object.position.x = x;
object.position.y = y;
object.position.z = z;
Per default, the created objects are defined as if they are "facing" the z-axis. This means that if I use the lookAt() function, the objects will rotate so that the "test" text face the point.
My problem is that I would rather rotate so that the "right edge" of the div is pointing towards the desired point. I've tried fiddling with the up-vector, but I feel like that wont work because I still want the up-vector to point up. I also tried rotating the object Math.PI/2 along the y axis first, but lookAt() seems to ignore any prior set rotation.
It seems like I need to redefine the objects local z-vector instead, so that it runs along with the global x-vector. That way the objects "looking at"-direction would be to the right in the scene, and then lookAt() would orient it properly.
Sorry for probably mangling terminology, newbie 3D programmer here.
Object.lookAt( point ) will orient the object so that the object's internal positive z-axis points in the direction of the desired point.
If you want the object's internal positive x-axis to point in the direction of the desired point, you can use this pattern:
object.lookAt( point );
object.rotateY( - Math.PI / 2 );
three.js r.84

Outline object (normal scale + stencil mask) three.js

For some time, I've been trying to figure out how to do an object selection outline in my game. (So the player can see the object over everything else, on mouse-over)
This is how the result should look:
The solution I would like to use goes like this:
Layer 1: Draw model in regular shading.
Layer 2: Draw a copy in red color, scaled along normals using vertex shader.
Mask: Draw a black/white flat color of the model to use it as a stencil mask for the second layer, to hide insides and show layer 1.
And here comes the problem. I can't really find any good learning materials about masks. Can I subtract the insides from the outline shape? What am I doing wrong?
I can't figure out how to stack my render passes to make the mask work. :(
Here's a jsfiddle demo
renderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, renderTargetParameters)
composer = new THREE.EffectComposer(renderer, renderTarget)
// composer = new THREE.EffectComposer(renderer)
normal = new THREE.RenderPass(scene, camera)
outline = new THREE.RenderPass(outScene, camera)
mask = new THREE.MaskPass(maskScene, camera)
// mask.inverse = true
clearMask = new THREE.ClearMaskPass
copyPass = new THREE.ShaderPass(THREE.CopyShader)
copyPass.renderToScreen = true
composer.addPass(normal)
composer.addPass(outline)
composer.addPass(mask)
composer.addPass(clearMask)
composer.addPass(copyPass)
Also I have no idea whether to use render target or renderer for the source of the composer. :( Should I have the first pass in the composer at all? Why do I need the copy pass? So many questions, I know. But there are just not enough resources to learn from, I've been googling for days.
Thanks for any advice!
Here's a js fiddle with working solution. You're welcome. :)
http://jsfiddle.net/Eskel/g593q/6/
Update with only two render passes (credit to WestLangley):
http://jsfiddle.net/Eskel/g593q/9/
The pieces missing were these:
composer.renderTarget1.stencilBuffer = true
composer.renderTarget2.stencilBuffer = true
outline.clear = false
Now I think I've found a bit simpler solution, from the THREEx library. It pre-scales the mesh so you dont need a realtime shader for it.
http://jeromeetienne.github.io/threex.geometricglow/examples/geometricglowmesh.html

Get exact Intersection-Point of a Ray and a Sprite

I want to get the exact intersection point of a ray and a sprite. But when I do this:
var ray = new THREE.Raycaster( camera.position, vector.sub(camera.position ).normalize());
var sprite = new THREE.Sprite(spriteMaterial);
var intersect = ray.intersectObject(sprite);
then intersect.point is just the position of the sprite, instead of the exact point that I need.
I need this so I can check if the part of the texture that has been clicked is visible or not. (Alpha value)
Is there a way to get the exact intersection, or is there a better way to achieve my goal?
This is not currently supported. See Raycaster.js if you want to try to hack your own solution. Sprites can be rotated (turned on their side), so the solution is not trivial.
A reasonable work-around is to create a Mesh from a PlaneGeometry and set
mesh.quaternion = camera.quaternion.
three.js r.64

Three.js lightMap causes an error WebGLRenderingContext: GL ERROR :GL_INVALID_OPERATION

I'm loading a jpeg file for light map
var texture = new THREE.ImageUtils.loadTexture("textures/metal.jpg");
Then I apply the texture to THREE.MeshPhongMaterial
var frontMaterial = new THREE.MeshPhongMaterial( {
color: 0xfade7e,
specular: 0xffffff,
ambient: 0xaa0000,
lightMap:texture
} )
Full error message is WebGLRenderingContext: GL ERROR :GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2
Is here something wrong? An error occures in all browsers. Three.js r.56
As explained by #alteredq in this thread, a LightMap requires a second set of UVs.
The point of lightmaps is that they can live independently of other textures, thus giving other textures chance to be much higher detail. Lightmaps use their own set of UV coordinates (usually auto-generated by some light baking solution, as opposed to artist-created primary UV set).
Using lightmaps with the same UVs as everything else doesn't make much sense, as then you could achieve basically the same result for less texture cost simply by baking light map together with color map (this is e.g. what Rage uses, it looks fantastic but needs boatload of textures).
Also lightmaps should be multiplicative, not additive. Big use case for lightmaps are pre-baked shadows and ambient occlusion, so you need to be able to darken things.
So the answer to your question is that geometry.faceVertexUvs[0] contains the usual set of UVs; you need to add to your geometry geometry.faceVertexUvs[1].
three.js r.56
This error become because the Three.js buffers are outdated. When your add some textures (map,bumpMap ...) to a Mesh, you must recompose the buffers and update UVs like this :
ob is THREE.Mesh, mt is a Material, tex is a texture.
tex.needsUpdate = true;
mt.map = tex;
ob.material = mt;
ob.geometry.buffersNeedUpdate = true;
ob.geometry.uvsNeedUpdate = true;
mt.needsUpdate = true;
That's all folks !
Hope it's help.
Regards.
Sayris

Three.js custom objLoader geometry lighting

I have this object I'm loading with THREE.objLoader and then create a mesh with it like so:
mesh = new THREE.SceneUtils.createMultiMaterialObject(
geometry,
[
new THREE.MeshBasicMaterial({color: 0xFEC1EA}),
new THREE.MeshBasicMaterial({
color: 0x999999,
wireframe: true,
transparent: true,
opacity: 0.85
})
]
);
In my scene I then add a DirectionalLight, it works and I can see my object, however it's like the DirectionalLight was an ambient one. No face is getting darker or lighter as it should be.
The object is filled with the color, but no lighting is applied to it.
If someone can help me with that it would be much appreciated :)
What could I be missing ?
Jsfiddle here: http://jsfiddle.net/5hcDs/
Ok folks, thanks to Maƫl Nison and mr doob I was able to understand the few things I was missing, being the total 3d noob that I am... I believe people starting to get into the 3d may find useful a little recap:
Basic 3d concepts
A 3d Face is made of some points (Vertex), and a vector called a normal, indicating the direction of the face (which side is the front and which one is the backside).
Not having normals can be really bad, because lighting is applied on the frontside only by default. Hence the black model when trying to apply a LambertMaterial or PhongMaterial.
An OBJ file is a way to describe 3D information. Want more info on this? Read this wikipedia article (en). Also, the french page provides a cube example which can be useful for testing.
Three.js tips and tricks
When normals are not present, the lighting can't be applied, hence the black model render. Three.js can actually compute vertex and face normals with geometry.computeVertexNormals() and/or geometry.computeFaceNormals() depending on what's missing
When you do so, there's a chance Three.js' normal calculation will be wrong and your normals will be flipped, to fix this you can simply loop through your geometry's faces array like so:
/* Compute normals */
geometry.computeFaceNormals();
geometry.computeVertexNormals();
/* Next 3 lines seems not to be mandatory */
mesh.geometry.dynamic = true
mesh.geometry.__dirtyVertices = true;
mesh.geometry.__dirtyNormals = true;
mesh.flipSided = true;
mesh.doubleSided = true;
/* Flip normals*/
for(var i = 0; i<mesh.geometry.faces.length; i++) {
mesh.geometry.faces[i].normal.x = -1*mesh.geometry.faces[i].normal.x;
mesh.geometry.faces[i].normal.y = -1*mesh.geometry.faces[i].normal.y;
mesh.geometry.faces[i].normal.z = -1*mesh.geometry.faces[i].normal.z;
}
You have to use a MeshPhongMaterial. MeshBasicMaterial does not take light in account when computing fragment color.
However, when using a MeshPhongMaterial, your mesh becomes black. I've never used the OBJ loader, but are you sure your model normales are right ?
Btw : you probably want to use a PointLight instead. And its position should probably be set to the camera position (light.position = camera.position should do the trick, as it will allow the light to be moved when the camera position will be edited by the Controls).

Resources