Changing anisotropy after render do not work - three.js

I have problem with updating THREE above version 137 - If I change anisotropy after an object was rendered, it breaks the material on the object.
For example, let's use from three.js examples webgl_loader_texture_tga.html. Now let's add into init():
scene.background = new THREE.Color()
window.setTimeout( () => {
mesh2.material.map.anisotropy = 16;
mesh2.material.map.needsUpdate = true;
}, 1000 );
After timeout runs, object changes into black and we get these warnings to the console:
[.WebGL-00005420002AC600] GL_INVALID_OPERATION: Level of detail outside of range.
[.WebGL-00005420002AC600] GL_INVALID_OPERATION: Texture format does not support mipmap generation.
EDIT:
Live example can be found here: https://codepen.io/kajbo/pen/mdpwybO
Please notice that if you change THREE version to 137 or below everything works as expected.

This is actually a bug in three.js. I have filed a PR at GitHub to solve this issue: https://github.com/mrdoob/three.js/pull/23808

Related

why three.js updates geometry only when new geometry is defined?

I have a question about updating geometry in three.js using dat.gui.
I expected I could update the geometry by updating the value tied into the geometry by object as below.
gui.add(parameter, 'width')
.min(1)
.max(10)
.step(0.1)
.name('cubeWidth')
.onChange((value) => {
mesh.geometry.dispose();
geometry.parameters.width = parameter.width
console.log(mesh)
})
However, it updates the geometry only when I redefine the geometry like below.
mesh.geometry = new THREE.BoxGeometry(parameter.width, 1, 1);
It's bit weird to me because even when I log the geometry data both shows the updated width value like below.
Why does only the first approach work while the other one not work?
geometry.parameters.width = parameter.width
This has no effect. Parameters are only processed when a geometry is created. The parameters property is in fact read-only.
The solution for your issue is indeed to recreate the geometry with the new set of parameters.

Three.js PMREMGenerator has incorrect texture filtering

I have a scene in Three (using AFrame) that requires environment mapping for lighting. Using a standard HDR cubemap, I get the following results:
This is correct as far as blurring based on roughness goes, since I have mipmaps being generated and the minFilter set to LinearMipmapLinearFilter. The issue with this approach is that ambient lighting isn't being applied - the light in the scene, a directional light, is the only thing providing any lighting information to the scene. Unfortunately, this results in entirely black shadows, no matter how bright the HDRI.
However, if I use the PMREMGenerator from Three in addition to the above, the ambient lighting issue is solved. Unfortunately, this is what happens as a result:
As shown here, the texture filtering is now out of whack. According to comments left in the PMREMGen script itself.
This class generates a Prefiltered, Mipmapped Radiance Environment Map (PMREM) from a cubeMap environment texture. This allows different levels of blur to be quickly accessed based on material roughness. It is packed into a special CubeUV format that allows us to perform custom interpolation so that we can support nonlinear formats such as RGBE. Unlike a traditional mipmap chain, it only goes down even more filtered 'mips' at the same LOD_MIN resolution, associated with higher roughness levels. In this way we maintain resolution to smoothly interpolate diffuse lighting while limiting sampling computation.
...which leads me to believe the output should be smoothed, like in my first example.
Here's my code for the first example:
const ctl = new HDRCubeTextureLoader();
ctl.setPath(hdrPath);
ctl.setDataType(THREE.UnsignedByteType);
const hdrUrl = [
`${src}/px.hdr`,
`${src}/nx.hdr`,
`${src}/py.hdr`,
`${src}/ny.hdr`,
`${src}/pz.hdr`,
`${src}/nz.hdr`
];
const hdrSky = ctl.load(hdrUrl, tex => this.skies[src] = hdrSky );
// Then later...
obj.material.envMap = this.skies[this.skySources[index]];
obj.material.needsUpdate = true;
Here's my code for the second example:
const ctl = new HDRCubeTextureLoader();
ctl.setPath(hdrPath);
ctl.setDataType(THREE.UnsignedByteType);
const hdrUrl = [
`${src}/px.hdr`,
`${src}/nx.hdr`,
`${src}/py.hdr`,
`${src}/ny.hdr`,
`${src}/pz.hdr`,
`${src}/nz.hdr`
];
const pmremGen = new PMREMGenerator(this.el.sceneEl.renderer);
pmremGen.compileCubemapShader();
const hdrSky = ctl.load(hdrUrl, tex => {
const hdrRenderTarget = pmremGen.fromCubemap(hdrSky);
this.skies[src] = hdrRenderTarget.texture;
});
// Then later...
obj.material.envMap = this.skies[this.skySources[index]];
obj.material.needsUpdate = true;
I seem to have hit a wall in regard to the filtering. Even when I explicitly change the filtering type and turn on mipmap generation inside of PMREMGenerator.js, the results appear to be the same. Here's an official example that uses the PMREMGenerator without any issue: https://threejs.org/examples/webgl_materials_envmaps_hdr.html
As a closing remark I will note that we're using Three.js r111 (and there are reasons we can't switch it out fully), so I brought in the current version of the PMREMGenerator from the latest version of Three as of this writing (r122 - later version needed as the r111 one is written completely differently). Thus, I wouldn't be surprised if this was all being caused by some conflict between versions.
EDIT: Just put the resulting envmap as a standard map on some planes, and much to my surprise none of the blurred LODS even show up. Here's what mine look like:
And here's what it should resemble (don't mind the torus knot):
EDIT: I've found a workaround for now (essentially, not using PMREMGenerator), but will leave this up in case a solution is discovered.
I believe the problem is with the argument you're using in fromCubemap(). Right now your code isn't using the tex cubetexture variable that's passed to the loaded callback. Try this:
const hdrSky = ctl.load(hdrUrl, tex => {
// use tex instead of hdrSky
const hdrRenderTarget = pmremGen.fromCubemap(tex);
this.skies[src] = hdrRenderTarget.texture;
});

Threejs: There is no texture bound to the unit 1

I am working on a glb viewer with threejs r116. In order to display metalness correctly, I add an environment map to the mesh.
Without the environment map, the model displays black, as expected. With the envMap it shows correctly but the console throws: RENDER WARNING: there is no texture bound to the unit 1.
model.traverse(n => {
if(n.isMesh){
if(n.material.metalness === 1){
n.material.envMap = cubeTexture
}
n.castShadow = true
n.receiveShadow = true
}
})
I tried setting a 1x1px white texture but couldn't figure out how to make that work.
This is how I create the cube texture:
let loader = new THREE.CubeTextureLoader()
let cubeTexture = loader.load([
'./images/envMap/posx.jpg', './images/envMap/negx.jpg',
'./images/envMap/posy.jpg', './images/envMap/negy.jpg',
'./images/envMap/posz.jpg', './images/envMap/negz.jpg'
])
You can safely ignore this warning. This happens because you are trying to use an environment map among other texture before it is actually loaded.
three.js allocates a texture unit as soon as a texture is applied to a material. However, the actual texture binding and upload can only be done after the texture has completely loaded. Firefox and Safari don't even log a warning in this case (at least on macOS).
If you want avoid the warning, start loading your glTF asset in the onLoad() callback of CubeTextureLoader.load().

glTF 2.0 animation not working

I'm trying to experiment a little with glTF 2.0 models with animation.
Unfortunately, when i try to update the THREE.animationMixer, I get a warning:
THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0.
Here's the setup:
The model:
I'm no 3D artist, so i've made a cube + torus in blender.
Also there are two actions in the Action Editor, moving the torus in two different ways.
You can download the .blend, and .glTF from here.
I think the export worked fine, since the model + animation are working in Don McCurdy's glTF viewer.
The Code:
I've tried using either Don McCurdy animation-mixer, or mixing Three.js into an a-frame component:
AFRAME.registerComponent("foo", {
init: function() {
var el = this.el;
setTimeout(()=>{
var model = el.getObject3D('mesh')
this.mixer = new THREE.AnimationMixer(model);
var clips = model.animations || (model.geometry || {}).animations ||
[];
console.log(this.mixer)
console.log(el)
console.log(clips[0])
const action = this.mixer.clipAction(clips[0], model);
action.setDuration(100).setLoop(THREE.LoopRepeat).play();
console.log(action)
}, 2000)
},
tick: function (t, dt) {
if (this.mixer && !isNaN(dt)) this.mixer.update(dt / 1000);
}
})
This code is basically a ripoff of Don's Loader. The only object that should be moving, the torus, dissapears, with the mentioned error, when I add the mixer.update part. Nothing logs as undefined, so the objects are created properly. Furthermore, the animation-mixer behavior is the same (i guess no surprise, since i just took part of it).
Any ideas what could be causing the problem ? I may be missing something, but i have no clue how to troubleshoot this.
Cubic bezier interpolation is broken in older versions of THREE (pre r87-r88 or so), which A-Frame 0.7.0 still uses. Switching to linear interpolation in Blender would work around this, or using the A-Frame master branch.
You also mention two actions in the Action Editor, which would be merged during export because multiple actions are still in progress for the Khronos glTF Blender exporter.
If that doesn't work, there is also another glTF Blender exporter to try: https://github.com/Kupoman/blendergltf/

EffectComposer second pass "overwrites" first pass

i want to render a texture on the background and the 3dscene in the foreground. i used the effectcomposer to do this.
how ever my first pass (the background) seems to be "overwritten" with the 2nd pass (the scene) the result only the scene gets drawn with a black background. it looks like the background of the second pass isnt drawn transparent or the transparancy is lost.
http://jsfiddle.net/mdwzx1f8/8/
var renderTex = new THREE.TexturePass(myTex);
var renderScene = new THREE.RenderPass(scene, camera);
composer.addPass(renderTex);
composer.addPass(renderScene);
var effectCopy = new THREE.ShaderPass(THREE.CopyShader);
effectCopy.renderToScreen = true;
composer.addPass(effectCopy);
i hope someone can take a quick look at it and point me in the right direction
thanks in advance
Updates:
07/07/2015
I tried clearing the zbuffer with renderer.clear(false, true, false);
Found a post on masking which i looked at but it wasnt added to
threejs as far as i can tell
https://github.com/mrdoob/three.js/issues/2448
08/07/2015
Found another interesting page https://github.com/mrdoob/three.js/issues/5979 not sure if this is related yet
Updated the fiddle if you comment line 53 you will see the 1st pass which should be visible if the scene background is drawn transparent
Bobafett in the threejs irc channel helped me out and he found my issue, it turns out that i called:
renderer.autoClear = false;
instead onrenderer.autoClearColor = false;
Here is the modified and working fiddle:
http://jsfiddle.net/mdwzx1f8/9/
I would like to thank all who have helped me in the search for the solution

Resources