When I merge geometries, then I export in STL, here is the result of mesh I can finally get:
As you can see, the join is not well aligned.
If I export same objects from my 3D software, this is what I get and how it would look like:
Here it is exported as 1 object.
In Threejs, scene is imported from glb.
My code for merged:
function mergeGeometries(clone) {
let geoms=[]
let meshes=[]
clone.updateMatrixWorld(true,true)
clone.traverseVisible(e=>e.isMesh && meshes.push(e) && (geoms.push(( e.geometry.index ) ? e.geometry.toNonIndexed() : e.geometry().clone())))
geoms.forEach((g,i)=>g.applyMatrix4(meshes[i].matrixWorld));
let gg = BufferGeometryUtils.mergeBufferGeometries(geoms,true)
gg.applyMatrix4(clone.matrix.clone().invert());
gg.userData.materials = meshes.map(m=>m.material)
gg.scale(10,10,10)
var mergeMesh = new THREE.Mesh(gg, new THREE. MeshLambertMaterial ({color: 0xff0000}));
return mergeMesh
}
Is there another way or did I miss something to export a combination of objects as one object in STL or OBJ ?
Related
I have a square shape .obj model and 2 textures. How do I apply one texture on it's top face and another on rest of faces?
There are a ton of ways to do what you're asking all with varying complexity depending on your needs. It looks like you want to apply two materials to your object and not two textures.
It looks this way because it seems you want the textures to be interchangeable so there's no way you're going to combine the images and keep resolution and OBJ & THREE.Material only support one set of uv attributes so you can't use a single material and multiple textures. So multiple materials it is...
Multiple materials
If you have two materials (2 THREE.Materials which correlate to 2 WebGL programs) then each face needs to know what material it's assigned to.
While the THREE.js multi material API has been in flux for quite a while and there are differences between THREE.Geometry and THREE.BufferGeometry, fortunately for you THREE.OBJLoader supports material groups out of the box. To get this into THREE.js, you want to apply multiple materials in your 3D editor to your object and then export the OBJ to get everything. Doing it by hand is a little harder and requires calling addGroup as shown in the docs/the link above.
In THREE.js you simply pass in all the materials as an array to your object demonstrated in this answer. I also updated your fiddle to do the same thing. Relevant code shown below
var loadingManager = new THREE.LoadingManager();
var ObjLoader = new THREE.OBJLoader(loadingManager);
var textureLoader = new THREE.TextureLoader(loadingManager);
//Material 1 with first texture
var material = new THREE.MeshLambertMaterial({map: textureLoader.load('https://dl.dropboxusercontent.com/s/nvnacip8fhlrvm4/BoxUV.png?dl=0')});
//Material 2 with second texture
var material2 = new THREE.MeshLambertMaterial({map:
textureLoader.load('https://i.imgur.com/311w7oZ.png')});
ObjLoader.load(
'https://dl.dropboxusercontent.com/s/hiazgei0rxeirr4/cabinet30.obj?dl=0',
function ( object ) {
var geo = object.children[0].geometry;
var mats = [material, material2];
//These are just some random groups to demonstrate multi material, you need to set these up so they actually work for your object, either in code or in your 3D editor
geo.addGroup(0,geo.getAttribute("position").count/2,0);
geo.addGroup(geo.getAttribute("position").count/2,
geo.getAttribute("position").count/2,1);
//Mesh with multiple materials for material parameter
obj = new THREE.Mesh(geo, mats);
obj.position.y = 3;
});
A non-buffergeometry, Geometry.merge(), takes a matrix to apply to the geometry when merging:
.merge ( geometry, matrix, materialIndexOffset )
However, BufferGeometry.merge() does not take a matrix:
.merge ( bufferGeometry, offset )
I have confirmed that merging two BufferGeomtries together does not preserve transforms of the objects being merged.
Here's the kicker: I would like to do this without converting to a Geometry at any step. I would like to do it all in BufferGeometry land.
Is this possible?
We have been doing sich merging of (mostly single objects) to maintain the transformations for JSON Object exporting.
To bake the transformations we do run a small function
getFixedMesh = function(geometry) {
var fixedmesh = null;
switch (geometry.constructor.name) {
case 'BufferGeometry':
var srcmesh = new THREE.Mesh(geometry);
srcmesh.updateMatrix();
return THREE.BufferGeometryUtils.mergeBufferGeometries([srcmesh.geometry]);
default:
var srcmesh = new THREE.Mesh(geometry);
srcmesh.updateMatrix();
fixedmesh = new THREE.Geometry();
fixedmesh.merge(srcmesh.geometry, srcmesh.matrix);
return fixedmesh;
}
}
This works for many arrangements, but still does some errors on LineSegments (and others?)
BufferGeometry has .applyMatrix ( matrix ) method that you can use to 'bake' object transform into vertex data before merging it.
I am using bullet/ammo.js with three.js. I have a 3d mesh and I want to use the exact shape for collision detection with a soft body. Is there a way I can create a 3d rigid body (in bullet) from a mesh (in three.js)?
Here is an example:
http://kidzinski.com/miamisura/lazy3d/ (please wait a second for the 3d model to download). I have a cloth falling on a 3d body and I need to simulate collision of this cloth with the body.
I am new to these frameworks sorry if I fundamentally misunderstood something.
It looks like you can do some work to turn an arbitrary Three.js mesh into a Bullet concave mesh. This is supported by Physi.js, which is a plug and play solution to link Three.js directly to ammo.js. I personally wouldn't recommend using the project (Physi.js) but you can look at the source code to see how they implement concave meshes.
First they loop over the geometry to create a custom list of "triangle" data objects on these lines of physi.js
for ( i = 0; i < geometry.faces.length; i++ ) {
face = geometry.faces[i];
if ( face instanceof THREE.Face3) {
triangles.push([
...
Then these triangles are passed off to Ammo.js to make a new Ammo.btBvhTriangleMeshShape on these lines:
for ( i = 0; i < description.triangles.length; i++ ) {
...
triangle_mesh.addTriangle( _vec3_1, _vec3_2, _vec3_3, true );
}
...
shape = new Ammo.btBvhTriangleMeshShape( triangle_mesh, true, true );
This should be a good starting point for building your own Ammo.js custom mesh.
There are lots of threads around the web, that Physijs Concave mesh does not work with collission. It seems, that btBvhTriangleMeshShape is not intended to work with collission in ammo.js, as I found out searching for that topic in bullet related forums.
What worked for me, is btConvexHullShape:
var triangle, triangle_mesh = new Ammo.btTriangleMesh;
var btConvexHullShape = new Ammo.btConvexHullShape();
var _vec3_1 = new Ammo.btVector3(0,0,0);
var _vec3_2 = new Ammo.btVector3(0,0,0);
var _vec3_3 = new Ammo.btVector3(0,0,0);
for ( i = 0; i < triangles.length; i++ ) {
triangle = triangles[i];
_vec3_1.setX(triangle[0].x);
_vec3_1.setY(triangle[0].y);
_vec3_1.setZ(triangle[0].z);
btConvexHullShape.addPoint(_vec3_1,true);
_vec3_2.setX(triangle[1].x);
_vec3_2.setY(triangle[1].y);
_vec3_2.setZ(triangle[1].z);
btConvexHullShape.addPoint(_vec3_2,true);
_vec3_3.setX(triangle[2].x);
_vec3_3.setY(triangle[2].y);
_vec3_3.setZ(triangle[2].z);
btConvexHullShape.addPoint(_vec3_3,true);
triangle_mesh.addTriangle(
_vec3_1,
_vec3_2,
_vec3_3,
true
);
}
return btConvexHullShape;
In the process of learning physic based 3d with threejs, I also want to mention the following best practice: when using complex models, create a low poly model that you can push to that converter function instead of the original model, or you will encounter a stack overflow.
i use objloader to load a obj file and add it into scene,
var loader = new THREE.OBJLoader();
loader.load( 'testcude.obj', function ( object ) {
object.traverse( function ( child ) {
if( child instanceof THREE.Mesh ) {
child.material = woodmap;
}
});
object.name="stairs";
scene.add( object );
});
and i found that inside obj file, there is formatted like this:
#
# object Box002
#
v -14.0000 17.9249 9.0000
v -14.0000 17.9249 -9.0000
...
...
...
f 10/8/12 9/5/12 13/6/12 16/7/12
# 6 polygons
my question is, is that possible to pick the 'Box002' and set a rotation.x?
i try getObjectByName but no work..
i exported this obj file from 3dsmax, or any other file format possible to do this?
r66.
thank you, cheer~~
If you want to apply different operations to different parts of your model you need to save your model as separate objects from within 3dsmax. Wavefront .obj models are not named as you might think. What you are seeing is just a comment in the file and it is ignored when the file is parsed.
I am loading several models into scene using the same geometry like so (pseudo code):
var geoCache = [];
function parseJSONGeometry(json_geo){
// this code is the three.js model parser from the jsonloader
return geometry;
}
function loadCachedGeo(data){
if( !geoCache[data.id] ){
geoCache[json.id] = parseJSONGeometry(data);
}
return geoCache[json.id];
}
function loadObjects(json){
var mats = [];
combined = new THREE.Geometry();
for(i=0<i<json.geometries.length;i++){
data = json.geometries[i];
geo = loadCachedGeo(data.id);
mats.push(new THREE.MeshBasicMaterial(map:THREE.imageUtils.loadTexture(data.src)));
mesh = new THREE.Mesh(geo);
mesh.position.set(data.x,data.y,data.z);
combined = THREE.GeometryUtils.mergeGeometry(combined,mesh);
}
mesh = new THREE.Mesh(combined,new THREE.MeshFaceMaterial(mats));
scene.add(mesh);
}
I also cache the textures, however I omitted that for the sake of simplicity.
When I call:
renderer.info.render.faces
renderer.info.memory.textures
renderer.info.memory.programs
renderer.info.memory.geometries;
renderer.info.render.calls
I notice when one object is on the screen the poly count is say 1000, textures: 1, calls: 1, shaders: 1 and geometries: 1. When two objects are on the screen 2000 faces are reported, 1 texture, 1 shader, 2 calls, and 2 geometries.
I thought that reusing geometry in this fashion only loads the geometry once into the gpu. Am I missing something, can someone PLEASE explain this behavior?
Three.js r59
You need to inspect
renderer.info.memory.geometries
There is also
renderer.info.memory.textures
renderer.info.memory.programs
three.js r.59