Three.js emissive materials don't cast shadow - three.js

Conext
I'm using three.js, #react-three/drei and #react-three/fiber.
I'm loading a GLTF file that contains emissive materials using
const gltf = useLoader(GLTFLoader, '/model.glb')
When I inspect the loaded data like this:
for (const key of Object.keys(gltf.materials)) {
const v = gltf.materials[key] as MeshStandardMaterial & Material
if (!v.isMeshStandardMaterial) return
console.log(key, v, v.emissive, v.emissiveIntensity, v.emissiveMap)
}
I can see that certain materials have a color set and their emissiveIntensity is equal to 1.
Problem
Objects made of these emissive materials load and display correctly on the scene. They have the desired color. There is, however, one problem. I would like those emissive materials to behave like a directonalLight/pointLight - i.e. cast shadows and cause reflections. Right now, they only display as shiny blobs, but their light doesn't affect other objects.
Question
How do I make emissive materials cast shadows and create reflections? Do I need a shader or is there some hidden option that I'm not seeing?

Related

I can't get the aoMap showing in three.js using a glb/gltf asset

I’m having a hard time getting an aoMap working in three.js…
I have a glb asset with an aoMap on the red channel or something. When I bring it into to the babylon viewer, I can see the ao just fine, but it wont show up in the three.js viewer or my project. I think this has something to do with a second set of uvs, but I can't find a resource that involves doing that on top of using the gltf loader… I really don't know what to do here. Any response would be greatly appreciated!
Here is my code (I’m using a html-canvas as the texture)
And I get the model’s geometry and diffuse texture (all white) as desired, but the aomap isnt showing…
code
babylon viewer
three.js viewer
working application with shadows included in diffuse
not working, diffuse is just white, and aoMap is not showing
You're right about needing a second set of UVs. The reason behind this is that diffuse textures often repeat (think of a brick wall, or checkered t-shirt). AO shading, however, is more likely to be unique on each part of the geometry, so it's almost never repetitive. Since this often would need an alternative UV mapping method, the default is to use a second set of UVs.
You could do 2 things:
Re-export your GLTF asset with a duplicate set of UVs.
Duplicate existing UVs in Three.js by creating a new BufferAttribute in your geometry:
// Get existing `uv` data array
const uv1Array = mesh.geometry.getAttribute("uv").array;
// Use this array to create new attribute named `uv2`
mesh.geometry.setAttribute( 'uv2', new THREE.BufferAttribute( uv1Array, 2 ) );
.getAttribute and .setAttribute are methods of BufferGeometry, if you want to read more about them.

Ambient occlusion not showing in three.js

I'm using the MeshStandardMaterial in three.js and when I create and apply the material, all maps work fine except for the aoMap, which has no effect on the model. I suspect this is because I don't have a 2nd set of UVs (my UV unwrapping is done through Blender and I don't manually apply any UV at all in three.js), as the documentation says:
The red channel of this texture is used as the ambient occlusion map.
Default is null. The aoMap requires a second set of UVs, and
consequently will ignore the repeat and offset Texture properties.
I've tried using the below code to solve this:
var geometry = mesh.geometry;
geometry.addAttribute( 'uv2', new THREE.BufferAttribute( geometry.attributes.uv.array, 2 ) );
but had no luck. How do I copy my UV map to the uv2 property, or wherever it is needed to make ambient occlusion work?
An aoMap is an ambient occlusion map, and like its name says, it occludes ambient light. That is all it occludes.
There are currently three sources of ambient (or indirect) light in three.js: AmbientLight, HemiSphereLight, and LightMap.
So the aoMap occludes those three sources. It does not occlude direct light sources. Direct light sources include DirectionalLight, SpotLight, PointLight, and AreaLight.
three.js r.95
What kind of lighting are you using? I recreated your situation, and it works as expected. The things to look out for is that aoMap shows up with THREE.AmbientLight, but not with THREE.Spotlight. It also works if you use an envMap on your MeshStandardMaterial

Setting a texture in ThreeJS does nothing

I'm trying to set a texture to an already existing mesh like this:
const texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
(The source a HTML5 canvas and that part works ok.)
...
mesh.material[0].map = texture;
I can change the material color without any problems, but setting the texture doesn't change anything. I guess this is not how changing the texture should be done..? I'm using MeshPhongMaterial.
So, long story short: I want to be able dynamically change a texture of an mesh.
Edit:
I'm trying to set the texture to one of the materials of a Collada model that is loaded. By using dev tools I can see that the texture is there in the object, but it is just not visible. I can change the color of the same material without any problems. Sometimes I can see the texture appearing with wrong colors after a very long idle time (which is weird).

exporting a scene from blender to threejs: every object has just one single material

I have made a small scene in blender (6 objects, each using 1 to 4 materials).
When exporting this (using the materials, and the scene option) with the dev exporter and loading it via:
var loader = new THREE.ObjectLoader();
loader.load( 'assets/scene.json', function ( scene ) { ...
And then checking the scene, I can see it has 6 children (good) and that each of the five children only has one MeshLambertMaterial (instead of the material mix from blender) bad.
Any hints on what I am doing wrong?
Those are btw basic materials (just a color basically) no textures or anything.
The scene renders correctly (minus the material mix).
Here is a link to the 113kb scene file (zipped): http://jppresents.net/static/blender/exportBug/scene.zip
Looking at the file I think all materials are there - so the problem must be the way I load it?
Not a solution, but a work around:
Since the only difference between all my materials was just the color, I have now applied exactly one material with a multi colored texture per object.
Then I uv-mapped the faces of the object to the colors corresponding to the previously set material color.
This was easy using the hotkey "shift + G" which lets you select all faces with the same material. (Then just assign them to the texture material, move/scale those in the uv-view to the part of the texture that matches the old color.)

texture mapping different objects in three.js

We are studying on product designer project. Designer is ready.
I want to do 3d preview result with three.js.
How can we texture one side of phone case? or can we border texture mapping?
OBJLoader version:
http://www.shopilife.com/baskiburada/viewer/viewer_4.html
And some obj files cannot be textured. Error is "GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 2"
http://www.shopilife.com/baskiburada/viewer/viewer2.html
First, regarding re-texturing the back vs. front of the phone case. The approach here is to seperate the UV coordinates on the model itself. This way you have two sets of materials/textures/UVs. Then during runtime you load them both using a MeshFaceMaterial to load the two materials in an array like so:
materialArray.push(THREE.BasicMeshMaterial({color: 0xff0000})); //use whatever Material type you'd like of course
materialArray.push(THREE.BasicMeshMaterial({color: 0x0000ff}));
var multipleMaterial = new THREE.MeshFaceMaterial(materialArray);
phoneCaseMesh= new THREE.Mesh( geometry, multipleMaterial );
Then when you want to switch one out you would grab the mesh and change the mapping to the desired side something like:
phoneCaseMesh.material.materials[1].map = THREE.ImageUtils.loadTexture( 'newtexture.jpg' );
Second, regarding the Error on you second sample, WestLangley is correct the OBJ file has no UV coordinates to map to, so the index is out of bounds when you apply a texture. If you look at both OBJ files your iphone4.obj has vt entities while the untitled.obj is just v and f. Hope that helps

Resources