A single plane with an alpha mask must cast shadows. It does but for the whole plane- not applying the alpha mask-.
Searching around I've found that adding a customDeptMaterial to the mesh should do it:
var customDepthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
alphaMap: alphaTex,
alphaTest: 0.5
} );
figures.customDepthMaterial = customDepthMaterial;
Not that I am very sure of what's going on exactly but I must be missing something because it keeps casting the whole plane
Please see the complete fiddle:
https://jsfiddle.net/truji7/gj7az9eo/34/
How can I cast the "alpha filtered" shadow?
PointLights are the only type of light that utilizes MeshDistanceMaterial instead of MeshDepthMaterial.
object.customDistanceMaterial = new THREE.MeshDistanceMaterial( {
alphaMap: alphaTex,
alphaTest: 0.5,
}
JSFiddle Example
Related
Attempting to use an alpha map to reveal reveal an underlying model according to the alpha maps. Currently the alpha map overrides the model texture and shows as all white.
I've tried loading the alpha map alone and applying it to a material which then gets attached to the object --> Shows the relevant alpha map as white, does not reveal the underlying model as expected
I've tried loading up the alpha map and also the texture into a MeshBasicMaterial --> Shows the full texture with none of it transparent
let material = new THREE.MeshBasicMaterial({
// map: iceTexture,
color: '0xffffff',
transparent : false,
side: THREE.DoubleSide,
alphaTest: 0.5,
alphaMap: this.alphaMaps[0]
});
The current result is that the alpha map shows as all white --> Current Output
This is the underlying texture I expect to be showing (just where the alpha map allows it to) --> Underlying Texture
NOTE: I am currently not using any shaders, the underlying model is a simple glb with the ice texture above applied
NOTE 2: In this answer It says to add in a second object behind the first object...that does not work, it just shows the object on top with no transparency applied
I think the line that's messing you up is transparent: false, when it should be transparent: true. I just tried the code below (click here for a live CodePen demo), and the transparency works as expected. I also don't think you need alphaTest: 0.5, since it seems you have an animation sequence that moves the gradient.
In the demo, I use this image as the alphaMap:
... and this image as the regular map:
The essence of the code is below:
// Load the textures
const texLoader = new THREE.TextureLoader();
var alphaTexture = texLoader.load("https://i.imgur.com/aH0jI5N.png");
var mapTexture = texLoader.load("https://i.imgur.com/qdWJkbc.jpg");
// Create geometry
var geometry = new THREE.PlaneBufferGeometry(10, 10, 10, 10);
// Create a basic material
var material = new THREE.MeshBasicMaterial({
map: mapTexture,
alphaMap: alphaTexture,
transparent: true
});
var plane = new THREE.Mesh( geometry, material );
I'm having an issue when rendering a white material in ThreeJS version 87.
Here are the steps to replicate:
A white PNG image that is loaded as texture
This texture is used to create a MeshBasicMaterial (passed as parameter map)
The MeshBasicMaterial is used along a plane Geometry to create a Mesh
The Mesh is added to an empty Scene and rendered on a WebGLRenderer with alpha: true and clearColor as white
The problem is that the rendered texture now has grey edges on parts that should be fully white.
This happens with any image with white edges. I've also tried many different configurations for the renderer and the material but to no avail.
I've made a very simple CodePen that replicates the behavior as simple as possible. Does anyone know how can this problem be solved?
CodePen:
https://codepen.io/ivan-i1/pen/pZxwZX
var renderer, width, height, scene, camera, dataUrl, threeTexture, geometry, material, mesh;
width = window.innerWidth;
height = window.innerHeight;
dataUrl = '//data url from image';
threeTexture = new THREE.ImageUtils.loadTexture(dataUrl);
material = new THREE.MeshBasicMaterial({
map: threeTexture,
transparent: true,
alphaTest: 0.1
});
material.needsUpdate = true;
geometry = new THREE.PlaneGeometry(5, 5);
mesh = new THREE.Mesh(geometry, material);
mesh.position.z = -5;
scene = new THREE.Scene();
scene.add(mesh);
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
renderer = new THREE.WebGLRenderer({
alpha: true
});
document.body.appendChild( renderer.domElement );
renderer.setSize(width, height);
renderer.setClearColor( 0xffffff, 1 );
//renderer.render(scene, camera);
function render() {
//Finally, draw to the screen
requestAnimationFrame(render);
renderer.render(scene, camera);
}
render();
Any help is truly appreciated.
ThreeJS/87
Edit:
I think I'm lacking more precision on my post.
This is the original full alpha image:
It might not show because its all white
And this is the same image with different transparencies on 4 quadrants:
This one too might not show because its all white
I got a helpful answer where I was told to make the alphaTest higher, but the problem is that doing that wipes out the transparent parts out of the images, and I need to conserve those parts.
Here is a copy of the codepen with the updated images and showing the same (but slight) grey edges:
codepen
Sorry for not being as precise the first time, any further help is even more appreciated.
Set alphaTest to 0.9.. or higher.. observe the improvement.
Your star texture has gray or black in the area outside the star, which is why you're seeing a gray halo. You can fix it by filling the image with white, (but not changing the alpha channel) in your image editing tool.
Also, you should upgrade to latest three.js (r95)
edit:
I'm not sure what your exact expectation is.. but there are many different settings that control alpha blending in THREE. There is renderer.premultipliedAlpha = true/false (defaults to true) and material.transparent = true/false; material.alphaTest is a threshold value to control at what level alpha is ignored completely. There are also the material.blending, .blendEquation .blendEquation, .blendEquationAlpha, blendDst and blendSrc. etc. etc. You probably need to read up on those.
https://threejs.org/docs/#api/materials/Material
For instance.. here is your texture with:
renderer.premultipliedAlpha = false;
notice the black border on one quadrant of your texture.
https://codepen.io/manthrax/pen/KBraNB
I am making a horror game and want to make a shadow move on a wall but I want it to appear as if it originated from no particular object. Is this possible and if so how do I implement this?
I have the feeling that dynamic textures will probably be the way to go but I am hoping there is some way using the three.js shadow map
You want a scene object to cast a shadow but be invisible.
First make sure your object will cast a proper shadow, then make the object invisible by adding:
object.material.colorWrite = false;
object.material.depthWrite = false;
The depthWrite setting is required if there are other objects in the scene. That property is not considered by the shadow mapping code.
Alternatively, you can try this, instead:
object.material.colorWrite = false;
object.material.transparent = true; // only needed if there are other transparent objects
object.renderOrder = Infinity;
three.js r.92
There's two ways to achieve this. One of them is by going "under the hood" of THREE.js and rendering the ShadowMap separately, with the object visibility = true, then setting visibility to false, then rendering the scene.
A much easier way is by assigning your object's opacity to something really low. Try 0.0001. It'll cast shadows, but be virtually invisible:
var ghostGeom = new THREE.BoxBufferGeometry(1, 1, 1);
var ghostMat = new THREE.MeshBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.0001
});
var ghostMesh = new THREE.Mesh(ghostGeom, ghostMat);
ghostMesh.castShadow = true;
Alternatively, you can use AdditiveBlending on the material, with the color set to pitch black. This will add 0 color to the final render, while still casting shadows:
var ghostMat = new THREE.MeshBasicMaterial({
color: 0x000000,
transparent: true,
blending: THREE.AdditiveBlending
});
I think what you need is a Projector which will cast a quad texture onto the ground or the wall.
I am trying to use THREE.Raycaster to show an html label when the user hover an object. It works fine if I use THREE.Mesh but with THREE.Sprite it looks like that there is a space that increases with the scale of the object.
The creation process is the same for both scenario, I only change the type based on USE_SPRITE variable.
if ( USE_SPRITE ) {
// using SpriteMaterial / Sprite
m = new THREE.SpriteMaterial( { color: 0xff0000 } );
o = new THREE.Sprite( m );
} else {
// using MeshBasicMaterial / Material
m = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
o = new THREE.Mesh(new THREE.PlaneGeometry( 1, 1, 1 ), m );
}
https://plnkr.co/edit/J0HHFMpDB5INYLSCTWHG?p=preview
I am not sure if it is a bug with THREE.Sprite or if I am doing something wrong.
Thanks in advance.
three.js r73
I would consider this a bug in three.js r.75.
Raycasting with meshes in three.js is exact. However, with sprites, it is an approximation.
Sprites always face the camera, can have different x-scale and y-scale applied (be non-square), and can be rotated (sprite.material.rotation = Math.random()).
In THREE.Sprite.prototype.raycast(), make this change:
var guessSizeSq = this.scale.x * this.scale.y / 4;
That should work much better for square sprites. The corners of the sprite will be missed, as the sprite is treated as a disk.
three.js r.75
When I used CanvasRenderer and SpriteMaterial, I was able to set a texture's rotation using the rotation attribute in the material. So, say for instance the texture is a cone, and I want to rotate it by 180 degrees:
material = new THREE.SpriteMaterial({
map : texture,
transparent : true,
rotation : Math.PI
});
But that doesn't seem to work with PointCloudMaterial in the WebGLRenderer. For example:
material = new THREE.PointCloudMaterial({
depthWrite : true,
alphaTest : 0.1,
map : texture,
transparent : true,
vertexColors : THREE.VertexColors,
rotation : Math.PI
});
So how can I go about rotating a texture with PointCloudMaterial and a PointCloud mesh? Note that in both instances, the texture is loaded as a base64 string, as follows:
var image = document.createElement('img');
var texture = new THREE.Texture(image);
image.src = /* The base64 string */
Thanks so much!
I ended up using the canvas to do this, following the pattern described at Three.js Rotate Texture. This pretty much worked like a charm.