THREE.WebGLProgram Shader Error because of defined v1 constant - three.js

I am using Three.js and I am loading an HDR as an environment map for the scene. Upon loading, I receive this error:
The line in questions is this:
I am assuming that the defined v1 causes an issue in this line because it is not undefined.
I am loading the HDR map like this:
return new Promise((resolve, reject) => {
new RGBELoader()
.setDataType(THREE.HalfFloatType)
.load(
path, // <-- hdr file
(texture) => {
// I tried fromEquirectangular and fromCubemap
// const envMap = this.pmremGenerator.fromEquirectangular(texture).texture;
const envMap = this.pmremGenerator.fromCubemap(texture).texture;
texture.needsUpdate = true;
resolve({ envMap });
},
undefined,
reject
);
});
Does anyone know what is causing this issue in THREE?

const envMap = this.pmremGenerator.fromCubemap(texture).texture;
I doubt this method call is correct. RGBELoader can not load textures in the cube map format. You probably want to use fromEquirectangular(). Before using this method, you need this line in your onLoad() callback:
texture.mapping = THREE.EquirectangularReflectionMapping;
Besides, please check if the usage of PMREMGenerator is actually necessary in your app. In latest releases, three.js internally uses PMREMGenerator to prepare environment maps for the usage with PBR materials.

Related

Collider made of geometry does not match mesh data(position, scale, ..etc)

I wanted to load the spatial model using the gltfloader, and then create a collision with geometry data.
By the way, I’m trying to get help with a different result than I expected.
problem image
here is sample image
You can see that the collider is larger than the visible Mesh data.
Most of the spatial data has the above situation.
The example code used is as follows. (tsx on react)
function Space(props) {
const url = props.data?.spaceFileName ? `https://space-test.vrin.co.kr/files/${props.data.spaceFileName}` : null;
const model = useGLTF(url);
const clone = model.scene;
const getCollide = (child) => {
console.log(child);
const geometry = new Geometry().fromBufferGeometry(child.geometry);
const vertices = geometry.vertices.map((v) => new THREE.Vector3().copy(v));
const faces = geometry.faces.map((f) => [f.a, f.b, f.c]);
const normals = geometry.faces.map((f) => new THREE.Vector3().copy(f.normal));
return <Object key={child.uuid} clone={clone} args={[vertices, faces, normals]} model={model} />
};
const traverseObject = (child) => child.children.map((c) => {
if (c.type === 'Object3D' || c.type === 'Group') {
return traverseObject(c);
} if (c.type === 'Mesh') {
return getCollide(c);
}
});
const objects = traverseObject(model.scene)
return <group dispose={null}>{objects}</group>;
}
Some spatial data generate collisions properly, but some spatial data do not generate collisions properly.
make sample image
here is sample what i made on blender
As a result of watching the Blender program, it is expected that it does not seem to be able to properly load the Geometry layer at the top.
blender2
If you look at the collation in the image above, there is a group called Sketchfeb at the top.
If i erase that group layer,
blender2
It can be seen that it is very similar to the shape of the collision body shown in the first picture.
I don’t know if I wrote the recursive function incorrectly or if there is an internal problem with the module.
Does anyone know the solution?
I don’t know if I wrote the recursive function incorrectly or if there is an internal problem with the module.
Does anyone know the solution?

The function "getRenderProxy" to get a ThreeJS Mesh from an object's fragId in Forge Viewer doesn't work correctly

I'm trying to get a threeJS Mesh from Autodek Forge objects using the function
'viewer.impl.getRenderProxy(viewer.model, fragId)'.
The problem that I encounter is if I put this function in a loop routine to get Meshs of multiple objects, I get just a random Mesh.
To find out the problem's origin, I used a similar function that is :
'viewer.impl.getFragmentProxy(viewer.model, fragId)'
and it worked just fine.
Her is the routine code that I use and the result :
for(let i = 0, len = nodNamee.length; i < (len); i = i+3){
var instanceTree = viewer.model.getData().instanceTree;
var fragIds = [];
instanceTree.enumNodeFragments(nodNamee[i+1], function(fragId){
fragIds.push(fragId);
});
fragIds.forEach(function(fragId) {
var renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId);
fragtoMesh.push(renderProxy);
//var fragmentproxy = viewer.impl.getFragmentProxy(viewer.model, fragId);
//fragtoProxy.push(fragmentproxy);
});
}
Result :
Arry of fragtoMesh
This is because the getFragmentProxy method always returns the same instance of THREE.Mesh, just with different properties. Basically, the method works like this under the hood:
let cachedMesh = new THREE.Mesh();
// ...
getRenderProxy(model, fragId) {
// Find the geometry, material, and other properties of the fragment
cachedMesh.geometry = fragGeometry;
cachedMesh.material = fragMaterial;
// ...
return cachedMesh;
}
// ...
Note that this is a performance optimization because if the getFragmentProxy (which is only meant for internal use) function returned a new instance every time it's called by other parts of Forge Viewer, it would cause a huge memory churn.
So in your case, if you really need to store all the THREE.Mesh instances in an array, you'll need to clone them or copy their individual properties into separate THREE.Mesh objects.

Multiple GLTF loading and Merging on server side

We are trying to merge multiple GLTFs on server side and export the merged gltf as final result on server.
Things we have trued that worked and that didn't:
We have used three js GLTFLoader parse method to load multiple gltf files, merge the parent and children of the loaded objects and export the final model using GLTFExporter.
We have used jsdom to resolve the issues related to window, document etc.
Above mentioned points work for gltfs without textures
While Loading GLTF with textures the response gets stuck.
a) We tried hosting the files on server and use the GLTFLoader load method with "localhost:******" as loader path.
b) Internally TextureLoader invoked ImageLoader where the onLoad event was not getting triggered at all . May be jsdom was not invoking this.
c) To solve this we changed ImageLoader to have canvas image :
const { Image } = require("canvas");
const image = new Image();
image.onload = onImageLoad;
image.onerror = onImageError;
d) The load method got resolved after above change.
e) Next step - Exporting the GLTF - We got stuck due to ImageData not found error. We added ImageData from canvas and the GLTF was exported.
f) The exported GLTF is not viewable die to corrupted data in images
"images": [
{
"mimeType": "image/png",
"uri": "data:,"
}
],
If someone loaded and merged GLTfs with texture images purely server side, Please Help!
As three.js is primarily a 3D rendering library for the web, and relies on various web image and WebGL APIs, I'm not sure using THREE.GLTFLoader is the most efficient way to merge glTF files on a Node.js server. I'd suggest this, instead:
import { Document, NodeIO } from '#gltf-transform/core';
import { KHRONOS_EXTENSIONS } from '#gltf-transform/extensions';
const io = new NodeIO().registerExtensions(KHRONOS_EXTENSIONS);
const document = new Document();
const root = document.getRoot();
// Merge all files.
for (const path of filePaths) {
document.merge(io.read(path));
}
// (Optional) Consolidate buffers.
const buffer = root.listBuffers()[0];
root.listAccessors().forEach((a) => a.setBuffer(buffer));
root.listBuffers().forEach((b, index) => index > 0 ? b.dispose() : null);
io.write('./output.glb', document);
It's worth noting that this process will result in a glTF file containing multiple separate scenes. If you want to combine them into a single scene, arranged in some way, you'd need to use the scene API to do that. If the files are not on disk, there are other NodeIO APIs for processing binary or JSON files in memory.

Why is this Threejs cloned Group loaded via GLTFLoader misbehaving?

So I am trying to clone the soldier model from the Three.js examples, because I want more than one later:
https://threejs.org/examples/webgl_animation_skinning_blending.html
I changed line 93 to read:
const loader = new GLTFLoader();
loader.load( 'https://threejs.org/examples/models/gltf/Soldier.glb', function ( gltf ) {
model = gltf.scene.clone();
scene.add( model );
model.traverse( function ( object ) {
if ( object.isMesh ) object.castShadow = true;
} );
But now the soldier is huge.
Why is this happening and is there a fix for it?
Here is a jsfiddle showing the problem:
https://jsfiddle.net/paranoidray/jLpzk374/22/
If you check out the jsfiddle and change line 93 and remove the clone() call.
Everything works again...
Any help would be very much appreciated.
Please clone gltf.scene like so:
model = SkeletonUtils.clone( gltf.scene );
Cloning of skinned meshes is not yet supported in the core. However, you can use SkeletonUtils.clone() to perform this task.
https://jsfiddle.net/yesxrq7g/

Make a instance of the Object returned by the THEE.js OBJMTLLoader

I'm deply sory about ask this question again here. I know that the members os Stack Overflow are not for my exclusive
use but a realy need to find a solution to this problem.
Let me explain better because last time I was not that clear about what I wanted.
Iam using the THREE.JS to develop a RPG like game. What I have in mind is a game just like IronBane MMO but without
the web server function for now (just use for the single player).
I'm relative new to THREE.js and, in some point, I start to work in a library to handle the object loadings im
my level. Because I use the 3DStudio Max to make de models, I decide to use the OBJMTLLoader library provided.
I've nailed the function to load de static objects and its something like this.
function loadObject(obj,mtl,pos){ // Adiciona objeto sem vinculá-lo a uma variável
var loader = new THREE.OBJMTLLoader();
loader.load( obj, mtl, function ( object ) {
object.position.set(pos[0],pos[1],pos[2]);
scene.add( object );
});
}
The problem comes when I need to intance this object. I tried many things for example:
function addObject(obj,mtl){ // Declara e adiciona um objeto no mapa
var conteudo;
var loader = new THREE.OBJMTLLoader();
loader.load( obj,mtl, function( object ){
conteudo = object;
});
setTimeout(function(){
scene.add( conteudo );
},1000);
The conteudo variable came undefined of course. I understand then that I need to wait the object to load first. It
takes about 2 render cicles. For this I use then the setTimeout function. With the scene.add( conteudo ) the object
was sucessfuly added to the scene. I try then to use a
return conteudo;
and, when I call...
var objeto = new addObject('object path','material path')
I get a instance of addObject and not Object3D as I expected. I try also to declare a array outside de function and
push it from inside the addObject like this:
function addObject(obj,mtl,objectArray)
var loader = new THREE.OBJMTLLoader();
loader.load( obj,mtl, function( object ){
conteudo = object;
});
setTimeout(function(){
scene.add( conteudo );
objectArray.push( conteudo );
},1000);
In this second one when I console.log the array I get:
Array[1]
0 : THREE.Object3D
length : 1
but when I try to use Array[0] or console.log(Array.length) I get undefined and 0 respectivly.
I would realy appreciate if someone could help-me solve this one. That would be awesome. Thanks you!
consider waiting with adding the objects.
function init(next){
var loader = new THREE.OBJMTLLoader();
loader.load( obj, mtl, function ( object ) {
object.position.set(pos[0],pos[1],pos[2]);
conteudo = object;
next();
});
}
function next(){
scene.add( conteudo );
objectArray.push( conteudo );
console.log(objectArray)
... work from here, here you are sure that the model is loaded ...
}
init(next);
This waits until the object is loaded and then it will execute next.

Resources