Three.js LOD object not rendering any models - three.js

so I'm experimenting with the LOD object in Three.js however I'm having trouble getting it to work. The code that i am using (excluding some standard setup code like creating a scene etc.) is shown here:
let treeHighDetail = new THREE.Object3D();
let treeLowDetail = new THREE.Object3D();
const gltfLoader = new GLTFLoader();
gltfLoader.load('./resources/low_poly_tree.glb', (gltf) => {
console.log(gltf)
treeLowDetail.add(gltf.scene);
treeLowDetail.traverse(c => {
c.castShadow = true;
})
})
gltfLoader.load('./resources/tree.glb', (gltf) => {
console.log(gltf)
treeHighDetail.add(gltf.scene);
treeHighDetail.traverse(c => {
c.castShadow = true;
})
})
const lod = new THREE.LOD();
let treeMesh = treeHighDetail.clone();
lod.addLevel(treeMesh, 5);
treeMesh = treeLowDetail.clone();
lod.addLevel(treeMesh, 20);
scene.add(lod);
I have two tree models, one low poly and one relatively high. I am attempting to have the high poly tree be displayed when i am close to the object, and the low poly tree render when i am further away from it. Running this code doesn't produce any errors in the console, however none of the models are rendered into the scene at any distance. Any ideas on what the issue could be would be greatly appreciated.

You are accessing the glTF asset before they have been loaded. The above load() method calls are asynchronously so you have to wait for their completion.
There are different ways to achieve this. You could create an instance of THREE.LoadingManager, use it as an argument for GLTFLoader's constructor call and then use its onLoad() callback for creating the LODs.
Or you rewrite your code to use the async/await pattern which is probably the more elegant solution. It would look like so:
const gltfLoader = new GLTFLoader();
const [ gltfLowDetail, gltfHighDetail ] = await Promise.all( [
gltfLoader.loadAsync( './resources/low_poly_tree.glb' ),
gltfLoader.loadAsync( './resources/tree.glb' ),
] );
const treeLowDetail = new THREE.Object3D();
const treeHighDetail = new THREE.Object3D();
treeLowDetail.add(gltfLowDetail.scene);
treeLowDetail.traverse(c => {
c.castShadow = true;
})
treeHighDetail.add(gltfHighDetail.scene);
treeHighDetail.traverse(c => {
c.castShadow = true;
})
const lod = new THREE.LOD();
let treeMesh = treeHighDetail.clone();
lod.addLevel(treeMesh, 5);
treeMesh = treeLowDetail.clone();
lod.addLevel(treeMesh, 20);
scene.add(lod);
You have to ensure the function/method holding this code is async as well.

Related

I’m trying to point to some part of the object, the whole object is pointed

I’m trying to point to some part of the object, the whole object is pointed, I don’t know what the problem is, I tried many options, I decided to ask for help
GIf
Code
function hoverPieces() {
// Material
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
if (INTERSECTED != intersects[0].object) {
if (INTERSECTED)
INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
INTERSECTED = intersects[0].object;
INTERSECTED.currentHex = INTERSECTED.material.emissive.getHex();
INTERSECTED.material.emissive.setHex(0xff0000);
}
} else {
if (INTERSECTED)
INTERSECTED.material.emissive.setHex(INTERSECTED.currentHex);
INTERSECTED = null;
}
}
Gist Link
https://gist.github.com/artur33s/b26e005283e1f605bab228483ee2e198
If needed Object (.glb):
https://wetransfer.com/downloads/54c0ef08f2fe2a4525388458ee175df220220223203644/3799a1
You can traverse, or loop through all the objects in the scene of the gltf:
gltf.scene.traverse((object) => {
if (object.material !== undefined) { //If there is no material on the object
object.material = object.material.clone(); //clone the material
}
});
That's all!

Updating three.js texture throughthe dat.gui dropdown

I have loaded different textures using textureLoader and I am trying to update them using dat.gui controls.
Why is the code below not working?
gui.add(mesh.position, "y", -1, 1, 0.1);
gui.add(mesh.material, "map", { alpha: alphaTexture, color: colorTexture, normal: normalTexture })
.onChange(() => {
mesh.material.needsUpdate = true;
console.log("updated");
});
It gives this error:
"Uncaught TypeError: m is undefined" [error][1]
After some tweaking, I found that the values of object(or array) in the third argument only supports string types, so passing a object as a value would not work.
This is the closest workaround that I could think of..
/* GUI options */
const guiOptions = {
mesh_material_map: "color",
};
/* Textures */
const textureLoader = new THREE.TextureLoader(loadingManager);
const colorTexture = textureLoader.load("/textures/door/color.jpg");
const alphaTexture = textureLoader.load("/textures/door/alpha.jpg");
const normalTexture = textureLoader.load("/textures/door/normal.jpg");
const guiTextureHash = {
color: colorTexture,
alpha: alphaTexture,
normal: normalTexture,
};
/* Add to gui */
gui.add(guiOptions, "mesh_material_map", Object.keys(guiTextureHash)).onChange((value) => {
mesh.material.map = guiTextureHash[value];
mesh.needsUpdate = true;
console.log("updated", value);
});
I found your topic looking for a texture picker. It's probably a little away from your starting point but could help some other. I finally made a simple texture picker with a dropdown selection key with dat.gui. The goal is to be able to change on the fly my matcap texture, going through an array of loaded texture.
const gui = new dat.GUI()
const textureLoader = new THREE.TextureLoader()
const myMatCap = [
textureLoader.load('./textures/matcaps/1.png'),
textureLoader.load('./textures/matcaps/2.png'),
textureLoader.load('./textures/matcaps/3.png')
]
const parameters = {
color: 0xff0000,
matCapTexture: 0
}
const updateAllMaterials = () => {
scene.traverse( (child)=>{
if(child instanceof THREE.Mesh && child.material instanceof THREE.MeshMatcapMaterial) {
child.material.matcap = myMatCap[ parameters.matCapTexture]
child.material.needsUpdate = true
}
})
}
gui.add(parameters, 'matCapTexture', {
terracotta: 0,
grey: 1,
chrome: 2,
}).onFinishChange(()=>{
updateAllMaterials()
})
let mesh = new THREE.Mesh(
geometry,
new THREE.MeshMatcapMaterial({
side: THREE.DoubleSide,
matcap: myMatCap[ parameters.matCapTexture ]
})
);
scene.add(mesh)

How to add lightmap to three js?

I baked some lightmap from on blender 2.8(Bake type - combined, Influence - "Direct", "Indirect", "Diffuse").
After that, I tried to add lightmap to part of my model.
function initColor(parent, type, mtl) {
parent.traverse(o => {
if (o.isMesh) {
if (o.name.includes(type)) {
o.material = mtl;
}
}
});
}
var lightmapTexture = new THREE.ImageUtils.loadTexture( "images/FrontLightmap.png" );
var front_material = new THREE.MeshBasicMaterial({lightMap: lightmapTexture });
const INITIAL_MAP = [
{childID: "Front", mtl: front_material}
];
for (let object of INITIAL_MAP) {
initColor(theModel, object.childID, object.mtl);
}
But the result - black material(front part).
Is there is possible to separately usage of lightmap and different material colors at the same time?

A-Frame: Geometry Caching / Registering new Geometry from GLTF

I'm hoping to get some help using geometry instancing with A-Frame. I was trying to figure out the bottleneck for my web app and after implementing pooling for physics objects being created in the scene, saw that the number of draw calls was increasing with each new object -- I had thought that by utilizing the asset management system in A-Frame my models were automatically cached, but I think I was mistaken.
I was wondering, if I register the geometry of the model using AFRAME.registerGeometry, would I be able to utilize geometry instancing? I saw that creating from a pool of object using the A-Frame geometry primitives did not increase the geometry count of the scene on a per-entity basis. I took a shot at loading my GLTF and registering the geometry from the mesh, but I'm getting an error from a-node that I don't understand:
<script>
AFRAME.registerGeometry('ramshorn', {
schema: {
depth: {default: 1, min: 0},
height: {default: 1, min: 0},
width: {default: 1, min: 0},
},
init: function(data) {
var model = null;
var geometry = null;
var manager = new THREE.LoadingManager();
manager.onLoad = function () {
console.log(geometry);
this.geometry = geometry;
console.log(this.geometry);
}
var gltfLoader = new THREE.GLTFLoader(manager);
gltfLoader.setCrossOrigin('anonymous');
const src = "./assets/ramsHorn/Ram's Horn 2.gltf";
gltfLoader.load(src, function ( gltf ) {
console.log("Gltf: " + gltf);
model = gltf.scene;
console.log("Model: " + model)
model.children.forEach((child) => {
console.log(child);
});
gltf.scene.traverse(function (o) {
if (o.isMesh) {
geometry = o.geometry;
//console.log(geometry);
//tried assigning "this.geometry" here
}
});
}, undefined, function ( error ) {
console.error(error);
});
//tried assigning "this.geometry" here
}
});
</script>
Error:
core:a-node:error Failure loading node: TypeError: "t is undefined"
aframe-master.min.js:19:658
Any help with this would be appreciated! Thanks
The code at 19:658 in aframe-master.min.js is trying to run something with a variable t but it has not been declared.
By using aframe-master.js it would be possible to get a more meaningful error.

A-Frame Scene Using OffscreenCanvas

I am seeking advice on implementing an A-Frame scene using OffscreenCanvas. I am using https://github.com/spite/ccapture.js to record my VR scene and the result is very janky and slow when FPS is above 30.
The video and the code samples within the Google link below provide examples of modifying Three.js to leverage OffscreenCanvas. Thus, I believe it is possible to modify A-Frame to include an OffscreenCanvas option.
https://developers.google.com/web/updates/2018/08/offscreen-canvas
https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
I have experimented with modifying the A-Frame a-scene setupRenderer function to use an OffscreenCanvas within the rendererConfig, but I am running into getContext issues.
I am not sure what the best approach is to offload rendering (and getting blob/bitmap image) to a Web Worker.
I want to take advantage of rendering in the Worker without conflicting with the built in requestAnimationFrame functionality of A-Frame.
Any advice is greatly appreciated. Thank you.
https://github.com/aframevr/aframe/blob/master/src/core/scene/a-scene.js#L561
setupRenderer: {
value: function () {
var self = this;
var renderer;
var rendererAttr;
var rendererAttrString;
var rendererConfig;
const offscreenCanvas = this.canvas.transferControlToOffscreen();
const worker = new Worker('./canvasworker.js');
worker.postMessage({ msg: 'init', canvas: offscreenCanvas }, [offscreenCanvas]);
rendererConfig = {
alpha: true,
antialias: !isMobile,
canvas: offscreenCanvas,
logarithmicDepthBuffer: false
};
this.maxCanvasSize = {height: 1920, width: 1920};
if (this.hasAttribute('renderer')) {
rendererAttrString = this.getAttribute('renderer');
rendererAttr = utils.styleParser.parse(rendererAttrString);
if (rendererAttr.precision) {
rendererConfig.precision = rendererAttr.precision + 'p';
}
if (rendererAttr.antialias && rendererAttr.antialias !== 'auto') {
rendererConfig.antialias = rendererAttr.antialias === 'true';
}
if (rendererAttr.logarithmicDepthBuffer && rendererAttr.logarithmicDepthBuffer !== 'auto') {
rendererConfig.logarithmicDepthBuffer = rendererAttr.logarithmicDepthBuffer === 'true';
}
this.maxCanvasSize = {
width: rendererAttr.maxCanvasWidth
? parseInt(rendererAttr.maxCanvasWidth)
: this.maxCanvasSize.width,
height: rendererAttr.maxCanvasHeight
? parseInt(rendererAttr.maxCanvasHeight)
: this.maxCanvasSize.height
};
}
renderer = this.renderer = new THREE.WebGLRenderer(rendererConfig);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.sortObjects = false;
if (this.camera) { renderer.vr.setPoseTarget(this.camera.el.object3D); }
this.addEventListener('camera-set-active', function () {
renderer.vr.setPoseTarget(self.camera.el.object3D);
});
loadingScreen.setup(this, getCanvasSize);
},
writable: window.debug
},
I would like to take advantage of OffscreenCanvas and rendering on a Web Worker to maintain a consistent 60 fps.

Resources