Ambient occlusion not showing in three.js - 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

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.

Three.js. MeshPhongMaterial has a uniform called diffuse. Why is it is not exposed nor can it be set?

In Three.js I am looking closely at the glsl source for MeshPhongMaterial. I notice the fragment shader relies on a uniform named diffuse. However there does not appear to be any way to set it. There is also an uniform named color that can be set and does indeed alter what looks like the diffuse color. Huh?
Is color copied to diffuse under the hood somehow? Can someone untangle this mystery for me.
If you look or search though the source you'll find it's set based on the color of the material
For example here
MeshPhongMaterial is not a subclass of ShaderMaterial even though they both extend Material.
Internally WebGLRenderer keeps track of / knows how to deal with two different things:
Any ShaderMaterial with any uniform. This means that you can make an exact copy of MeshPhongMaterial using ShaderMaterial and instead of myMaterial.color you'd have myMaterial.uniforms.color.
"Built-in" materials and their properties. For these, WebGLRenderer is aware of all the possible properties these materials expose. Gman has pointed out where in the code this happens (one of the places). For each material WebGLRenderer internally creates a ShaderMaterial but instead of handling it's uniforms like it would with any other such material, it manually keeps track and updates everything.
The built-in materials make little sense, since you can easily pipe foo.bar to foo.uniforms.bar using getters and setters leaving the renderer to only deal with shader materials.
If you really really want a uniform created for a built in material, you have to wait until the renderer creates them, and you can tap into this process with material.onBeforeCompile = shader=>{} (the shader object will contain the uniforms).

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.)

Can I set the ambient property of a MeshPhongMaterial to false in a three.js imported Blender model?

I'm doing a student project and I have a scene with an ambient light and a spotlight. I've imported a Blender model which has the line:
"colorAmbient" : [0.6400000190734865, 0.6400000190734865, 0.6400000190734865],
in the JSON file.
Is there any way to turn off this property in a MeshPhongMaterial so that it only reacts to the spotlight and not the ambient light.
I've tried removing the line and setting it to zero but this has had no effect. Can I turn this property off? Or should I remove the ambient light from a scene and use a different type such as Directional?
Thanks for any help.
In practice, the ambient reflectance of the material should usually match the material color, also known as the diffuse reflectance. Doing so will likely make your model look better.
For example, you can do this
material.ambient.copy( material.color );
or
material.ambient.set( 0xff0000 );
three.js r.67

lightMap / specularMap / shading with meshBasicMaterial

I'm currently working on something along the lines of a plugin for another program to add 3D capability to it, so I'm trying to put all the functionality i can from three.js into it, with the added goal of this being a good way to learn all the functionality of three.js firsthand.
I'm running into an issue now as i implement textures and materials that with mesh basic material, setting some things which the documentation on the main threejs.org site shows are features, doesn't actually do anything.
when i set a texture for either specularmap or lightmap nothing is actually showing up. Im pretty sure its not a mistake im making because setting the texture of the map works, but trying to set this same texture for the specularMap or lightMap is doing nothing. Does a regular texture work for these, or do i have to do something different?
I'd also like to know what the shading property does for mesh basic, because as far as i can see setting it to smoothshading/flatshading/noshading is doing nothing aswell.
MeshBasicMaterial does not respond to lights. Change your material to MeshLamberMaterial or MeshPhongMaterial, for example.
For MeshBasicMaterial and MeshLambertMaterial, the specularMap is used only to modulate the reflection when an environment map is used.
For any material, lightmaps require a second set of UVs. geometry.faceVertexUvs[ 0 ] contains the usual set of UVs; for a lightmap, you need to add geometry.faceVertexUvs[ 1 ], a second set of UVs.
For MeshBasicMaterial, the shading property only applies when an environment map is used. SmoothShading will yield smooth reflections; FlatShading will yield faceted reflections.
three.js r.66

Resources