How can I access different parts of an OBJ loaded with OBJMTLLoader? - javascript

I made a model of a building with 3DS Max where each room is a modified cube, I used OBJMTLLoader to load the OBJ file with his own MTL.
The problem is that I need to emphasize certain rooms according to the user requirements.
I use dat.gui to display a menu where the user can check/uncheck rooms to remark them (I think I will change the room size or marterial in order to emphasize it).
this is the code of my loader
var loader = new THREE.OBJMTLLoader();
loader.load( 'models/ed.obj', 'models/textures/ed.mtl',
//onLoad()
function ( object ){
contenido = object;
contenido.position.set(0,0,0);
contenido.position.y = -80;
contenido.name = 'edificio';
scene.add(contenido);
return contenido;
} //and other onLoad, and onError stuff
I can play with the whole model, I have a transparency function that adjust transparency to a dat.gui bar (the one called opciones.Opacidad)
contenido.traverse( function( object ) {
if( object.material ) {
object.material.opacity = opciones.Opacidad;
object.material.transparent = true;
}
And it works correctly, but the probblem come when I try to access internal cubes of the geometry to remark them in wireframe (for example) I use:
contenido.getObjectByName("RoomNameIn3DSMax").material.wireframe=true;
In order to find and show it in wireframe, because the OBJ file names every module with its 3DS Max name. But it does not work, It looks like the item is found because I don't get any error, but it does not appear in wireframe, also when I use another room names, sometimes the program show in wireframe lots of things that can include the requested one or not, another ones it finds "undefined" I think it has something to be with the Groups created by the OBJMTLLoader.
I've also tried
contenido.traverse( function ( child ) {
if ( child.name == "NameInOBJor3DSMax" ) {
child.material.wireframe = true;
}
})
But the result is the same.
So my question is, How can I access internal modules of my model loaded with OBJMTLLoader? As you can see I tried to use the "Object3D" methods to access the internal cubes of the whole model, am I doing it correctly? I can provide all the code and files if needed, you can see an approach of my problem here:
3DBuilding link
You can also see all code there ;)
Thank you for your attention, I hope someone can help me.
EDIT: When I do:
scene.getObjectByName("nameOfModule").material.color.set(0xff0000);
To remark it on red or just: .material.wireframe=true; it shows remarked a lot of things that are not realted. It does the same when I use scene.getObjectById(ObjectId, true); But it does not show the name of the object in the DOM Tree.
I am trying to use another exporting tools to see if the problem is just the OBJ Exporter. It is something really annoying.
Here are some screens of the problem.
What I try to remark:
as you can see, it's only a edited box
what is remarked:
If we go to the OBJ file we can see something like this:
#
# object SDHAE001
#
v 106.4733 84.7697 -94.9228
... (more vertices)
v 106.3747 76.8453 -96.3784
# 16 vertices
vn 0.0000 1.0000 -0.0000
...(more normals)
vn -0.9991 0.0046 0.0425
# 14 vertex normals
#and here the group of faces fot that object ( Using triangles )
g SDHAE001
usemtl wire_115115115
f 10663//5549 10664//5549 10665//5549
...(more triangle faces)
f 10676//5559 10663//5561 10678//5562
# 22 faces
As you can see, 3DS Max is creating Groups of polygons for my geometry, and as far as I know, OBJMTL ignores "g" groups, so when I try to remark something, it remarks A LOT of things... Trying with other exporters... Parsing manually the OBJ file would be so annoying...
EDITED AGAIN
I've been exploring the options, and OBJ is generated ok by 3DS MAX, BUT when I explore de DOM Tree, I can see the THREE.Mesh as an array where only some of the the pair indexes have the expected object with his own name, and odd indexes have some sort of geometry I can't control without any name assigned, and for some strange reason, there are some groups of "vertices" created in geometry instance with no sense, I upload some screens and the OBJ/MTL files to make my problem clearer:
Look at this, I will try to remark now a module called "Conserjeria". and this is the module located in the DOM Tree:
Bigger image
Here, on the first column we can see, first problem, my OBJ (all the geometry) file only has about 298 Objects, so why are there 1056 Mesh Objects? It is not very relevant because most of them are with empty names.
Second problem, on the second column you can see geometry property for "Conserjeria" room, I think here is where the problem is generated...
On the third column, I show you that strange "vertices" array for my "Conserjeria" object. I say strange, because it is composed by 6272 indexes... NOTHING in my OBJ file has 6272 vertices... You can see the OBJ here, and you can find Conserjeria if you want to see its structure (52v, 11vn, 80f). Might this be the reason why when I try to remark only certain objects it remarks a lot of them?
I've also tried with a simplified model of 3 boxes, 2 of them are correctly remarked, but the first one is not, have a look (use the checkboxes to remark them) I can't imagina why is this happening. (there are also 7 THREE.MESH index in the array when there are only 3 cubes in the scene...)
TestingCubes
Any help to remark only my rooms? I can share everything I have if needed(Code, OBJ, MTL, 3ds...)
Thank you to everyone who is trying to help me.

Looks like you got a problem with the mesh names.
When I execute the following script, it's working just fine:
scene.children[2].traverse(function(c) {
if(c.material && c.name.indexOf("INVESTIGACION_1_") >= 0) {
c.material.color.set(0xff0000)
}
})
That tints part of the model red, as expected.

Related

THREE.JS Multiple groups containing the same objects

I'm currently learning THREE.js and trying to make a playable rubik's cube.
I want to be able to rotate a face as a whole instead of moving every single cube one at a time, and I can do so by creating a THREE.Group and adding the cubes in it. The problem is that a single cube is contained in multiple faces, and I can't find a solution. If I create an object, add it to a first group, then add it to a second group, it is removed from the first group.
I'm pretty sure there is a workaround but can't find it as I'm really new to THREE.js and 3D programming (I only followed a basic course https://www.udemy.com/3d-programming-with-javascript-and-the-threejs-3d-library/).
There is my code but I don't think it will be very usefull anyway.
https://pastebin.com/Hq66UvBU
Thanks
Welcome to Stack Overflow. Please remember to edit your question to include your code, because when the pastebin link dies, your question loses important context.
The correct way to add an object to a THREE.Group is through the add function, like you do. But an object added to multiple groups will only ever be a child of the last group to which it was added. This is because add looks to see if the object already has a defined parent, and removes the object from that parent before setting the new parent (r97 code).
Example:
let obj = new THREE.Object3D()
let p1 = new THREE.Group()
let p2 = new THREE.Group()
p1.add(obj) // obj.parent == p1
p2.add(obj) // 1. three.js calls p1.remove(obj) 2. obj.parent == p2
Beyond this reason, and as #Mugen87 mentioned, your cubes need to not only be able to have multiple memberships, but also to be able to enter and leave face groups as their positions change. To me this says you will almost need to transform the cubes individually. You could use a THREE.Group to make it easier to conceptualize, but there would be extra overhead to actually implement it that way.
Maybe a late answer but try to work in another way and group the cubes that need to turn the moment the turn function is activated and then turn the group around, then empty the group.

How to apply transformation to selection in Illustrator by scripting

I managed to select every thing I want in Illustrator with a ExtendScript Toolkit javascript code: lots of things (text, path, symbols, ...) in several layers. Now I want to resize them the same way, then move them.
I know how to apply a transformation to one object by code, but I want to avoid looping on each element because it would be very very long and transformation would be applied from the anchor point of each element, so my drawings wouldn't be cohesive.
So, I am looking for a way to do like in Illustrator UI: right click > transform > scale. Is there any UI command like this I could access from code (javascript)?
There are at least three ways to do this:
Record AI Actions that perform required transformations, and then play these Actions (by DoScript) from your script
Group selected objects and apply required transformations to the group as #Dane proposed. You need to backup the Layer object property to allow objects to be restored in original layers, as shown in VBA example below:
For i = Index_Lo To Index_Hi
Call Layers_Backup.Add(Item:=SelectedItems(i).Layer, Key:=Format(i))
Call SelectedItems(i).Move(Temp_Group, AiElementPlacement.aiPlaceAtEnd)
Next i
Call Temp_Group.Resize(scaleX:=120, scaleY:=120, changeLineWidths:=120)
For i = Index_Lo To Index_Hi
Call SelectedItems(i).Move(Layers_Backup(Format(i)), AiElementPlacement.aiPlaceAtEnd)
Next i
Call Windows API functions (like PostMessage (..., WM_COMMAND, ..., ...), SendDlgItemMessage, FindWindowEx etc) to show, fill and execute required AI transformations dialog boxes
IMHO, item #1 is the easiest to implement while item#2 is the most reliable
So I dont know if you can get away with not looping in some form or other. that said, if you dont mind putting your selection in to a group, it might be faster to loop through your selection adding to a group which might be faster than looping and through the selection and scale and moving each element. With the group object you can then do groupObject.scale() and .translate().
Here is a snippet i took from a script of mine.
#target "illustrator"
var aiApp = app.activeDocument;
var aSelection = aiApp.selection;
var aGroup = app.activeDocument.groupItems.add();
for (i=0; i < aSelection.length; i++){
aSelection[i].move( aGroup, ElementPlacement.INSIDE);
aSelection[i].move( aGroup, ElementPlacement.PLACEATEND);
}
//moves up 700 points and scales by 200
aGroup.translate(0,700)
aGroup.resize(200, 200, true , true, true, true, 200)

Fabric js : No group member update while moving

My first question here, after years of finding solutions in other's topics !
First, sorry if my english is not perfect !
I'm using Fabric js in my application and I have to implement a button to group texts or images.
However, I noticed that, when I move the group on the canvas, the group coords are updated but not the group's objects'.
On the canvas, objects are moving well with their group, but in the console, it seems that they always have the same 'top' and 'left' values.
Is it a normal groups behaviour, in which case, I really don't understand, or there is something I am missing ?
It can be noted that I added objects in the group with the addWithUpdate(obj) method.
I really hope someone can help me !
Yes this is normal.
However you can find the position without destroying and rebuilding the group in this way:
given a group that is a fabric.Group and a childObject that is a subclass of fabric.Object you can:
1) create a point with childObject top and left
var point = new fabric.Point(childObject.left, childObject.top);
2) get the group transformMatrix:
var transform = group.calcTransformMatrix();
3) transform the point with this matrix:
var actualCoordinates = fabric.util.transformPoint(point, transform);
and you should be set.

paper.js: getting raw pixel data for two layers/groups?

I am trying to get the raw pixel data from two "items" in paper.js. One is already a Raster object so that's not too bad. The problem is that I have another Group object containing a bunch of triangles and I want to capture the Raster data for that layer and then be able to compare it.
I have the following (highlighted lines) code:
https://gist.github.com/mtahmed/2b27c4c6aee42d3ac3fb#file-paper_update-js
It seems to always return 0 or some other odd unexpected number. Any hints/ideas?
Thanks! :)
It looks like you are always setting child_gene.visible = false, but never set it back to visible = true before you rasterize the layer in computeFitness(). I'm not sure that there's a need for juggling layers in each frame - it should work just as well without it.
Here's a simplified example that uses a square with a gradient as the target raster.

how to use traverse in three.js to modify wireframe

I have several objects, when it was selected the check box would change the wireframe property to true or false ( run time) .
function toggleWireFrame(obj){
var f = function(obj2)
{
if(obj2.hasOwnProperty("material")){
obj2.material.wireframe=!obj2.material.wireframe;
}
}
obj.traverse(f);
}
1) Your code should work, if you call toggleWireFrame on each of the meshes, one by one.
toggleWireFrame(meshA);
toggleWireFrame(meshB);
This would make sense if each of these meshes are made up of several meshes and you need to toggle all the sub-meshes too. You might get mesh hierarchies like that a lot if you import models from an OBJ file, for example.
2) Or did you want to call toggleWireFrame only once and have all your meshes' wireframe toggled?
If that's the case, you will have to call
toggleWireFrame(scene);
or even
toggleWireFrame(myObject3D);
where myObject3D is an Object3D instance which is the parent of all the meshes that you want to toggle wireframe status.
traverse() works by iterating through all children and grandchildren of the starting object. You need to make sure that all the objects that you want to toggle to wireframe is parented under this starting object, as shown in the examples above.
3) Another option is to use an array to store each material as they are created, and then iterate through this array to change the wireframe attribute when the user toggles the check box.
This is what I use on my projects, it just inverses the boolean since it will be true or false.
function wireframeToggle(i) {
bool = i.material.wireframe;
i.material.wireframe = !bool;
}
Working example (x for wireframe)

Categories

Resources