how to use traverse in three.js to modify wireframe - javascript

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)

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)

Three.js - object.visible = true, not showing up right away

I'm hiding and unhiding parts of my Three.js scene using the .visible property on my objects.
By default certain objects (rooms) have the .visible property to false. When the camera is within a certain mesh (the room bounding box) the .visible property is set to true and the room shows up.
But there seems to be a delay (seconds or less) after setting the .visible property to true and the room actually being rendered. This delay is shortened after entering the rooms more than once.
What is the cause of this delay? Is there a way to know when or if the room is ready for rendering? It doesn't seem like update events are being fired after setting the .visible property to true, so listening for those won't help.
I appreciate any help,
Greets!
EDIT
Because I couldn't use ColladaLoader2.js I decided to simply traverse the models loaded with the ColladaLoader.js and replace all geometry properties with a BufferGeometry copy made from the existing Geometry object. After that I found out that setting the .dynamic property of an existing Geometry object to false seems to have the same effect.
dae.traverse(function (obj) {
if (obj.hasOwnProperty('geometry')) {
obj.dynamic = false;
//obj.geometry = new THREE.BufferGeometry().fromGeometry(obj.geometry);
}
});
Now when I set the object's .visible property to true the engine freezes for a little while, instead of the earlier mentioned delay before the object becomes visible. For now I'll have to decide where I want to little freeze to occur, because I don't think all objects can be visible at the same time for performance reasons.
It would be nice to have more control and information about if an object and it's geometry is loaded and ready to be viewed, or if it needs to be reloaded into memory. Now it's unclear if a BufferGeometry will show up immediately when .visible is set to true or a short freeze will occur.
Geometry needs to be converted to BufferGeometry prior to rendering. This conversion will not occur if mesh.visible is false. The conversion can take some time if your geometries are complex, or if there are a lot of geometries to convert.
A work-around is to create your meshes using BufferGeometry.
var bufferGeometry = new THREE.BufferGeometry().fromGeometry( geometry );
var mesh = new THREE.Mesh( bufferGeometry, material );
three.js r.73
In my code I see the same thing when objects are first switched to visible, but subsequent switches between visible true/false do not seem to cause another delay.
Hence one workround would be to set the visible flag on every object and render everything when WebGLRenderer is not shown on the browser (e.g. when it is behind a level loading screen) then set the objects visible flags appropriately to how you want them prior to showing the screen... Now there should be no delay as you toggle them visible.

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

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.

Three.js hiding objects of loaded model

I have model (exported from Blender) which contains two meshes. One mesh is rigged and animated character, second mesh - hair model. I need to select one of the meshes and hide it or change it's texture.
I load model like this:
jsonLoader.load('./models/character.js', function(geometry, materials) {
for(var i = 0; i < geometry.animations.length; i++){
THREE.AnimationHandler.add( geometry.animations[i] );
}
var character = new THREE.SkinnedMesh( geometry );
});
Now both meshes works like one solid mesh.
You can make an object invisible by setting its visible property to false.
character.visible = false;
You need to convert this two meshes in two different objects to make them selectable (see this nice post to learn how to select an object).
Once the object is selected you can change its property to make it visible or hide it.

Categories

Resources