Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scale part of an OBJ in ThreeJS

I have an .obj file that looks like this:

Handles

What I need to be-able to do is scale only a certain part of the handles - in this case the point at which the handles actual bend down from the top. So I'd want to be-able to make them longer in this case.

Does anyone have any direction or an example of how this can be accomplished? All of the examples I have seen are just on scaling the whole model and not just part of it.

I was thinking that I'd need to create a Spline based off of the vertices in the obj and then manipulate the Spline created but I was hoping there'd be any easier option as I don't know how to combine the model with the Spline

Thanks

EDIT I believe that the answer doesn't lie with Splines - it in fact lies with morphing the target attributes of the object. I'll post here when I get further on or, if anyone knows what I mean then please point me in the right direction.

EDIT 2 Following zero's suggestion I'm attempting to use SkinnedMeshes with bones. I'm at the point of trying to fill the skinIndices & skinWeights with Vector4 objects but Typescript is throwing an error:

Argument of type 'Vector4' is not assignable to parameter of type number

I know this is a Typescript problem rather than a ThreeJS problem but I created a jsfiddle that has the same code but the array for skinIndices in it is of type Vector4. The only reason I can think of that mine isn't is because I'm sending the BufferedGeometry of the .obj object through the THREE.fromBufferGeometry function:

let geometry = new THREE.Geometry().fromBufferGeometry(frontHandle.children[0].geometry);

EDIT 3

let geometry = new THREE.Geometry().fromBufferGeometry(frontHandle.children[0].geometry);

for ( let i = 0; i < geometry.vertices.length; i ++ ) {
  let vertex = geometry.vertices[ i ];
  let y = (vertex.y + sizing.halfHeight);

  let skinIndex = Math.floor( y / sizing.segmentHeight );
  let skinWeight = ( y % sizing.segmentHeight ) / sizing.segmentHeight;

  let vectorOne = new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0);
  let vectorTwo = new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0);

  // Here's where the compliant is
  geometry.skinIndices.push(vectorOne);
  geometry.skinWeights.push(vectorTwo);
}           

EDIT 4

I fixed the problem described above and now have this (the blue handle is the skinned mesh with numerous bones inside of it & the vertical blue & green line is the skeleton helper):

enter image description here

I've also added in the DATGUI helper which looks like this:

enter image description here

But I still can't seem to scale the mesh just right. The knotted parts of the handle in the screenshot should always stay the same size. I just need the handle part below them to extend when I scale them down and want the knotted parts to scale sideways when the bag gets bigger.

like image 208
Katana24 Avatar asked Oct 14 '17 19:10

Katana24


1 Answers

From what I understand, you are trying to deform your mesh. There are 2 principle ways to do mesh deformation:

  1. Morph Targets
  2. Skeletal Animation

Morph Targets

Morph targets allow you to define multiple transform "targets", or keyframes that you can blend your mesh between. This is usually used to animate a mesh. Morph targets are verbose. They are basically a duplication of your mesh, but with each vertex transformed to the way that you want the target to look. They allow for very fine-grained manipulation of vertices because you are able to dictate the exact transform of each vertex per keyframe. However, as stated above, they are verbose. You have to have each morph target available in some fashion so that you can blend the targets together.

If you have a 2000 vertex polygon and 3 morph targets, you'll have to keep the definition of 6000 vertices on hand.

Mesh Skin and Bones

Another way to control vertex transforms is to use bones. Bones allow you to add multiple transform influences to a vertex and, in a way, group vertices together so that you can transform the bone to get the mesh deformation that you want, rather than having to manually adjust individual vertices.

You are still going to define transform keyframes, but you are going to define them for the bones instead of the individual vertices. This has the benefit of conserving space and enabling transform reuse. Rather than having to define new transforms for every vertex in a mesh, you define a "skin" binding a mesh to a skeleton and the skeletal animation should act appropriately.


In your case, I am not sure which would be the more appropriate technique to apply. I think that a skin would help because you could set the weight of all of the vertices in the handle that you want to transform to the bone and then leave off the weightings of the knots and bag. Then you could apply whatever transforms you need to make.

three.js has support for Skinned Meshes. You can see the API and a demo here: Skinned Meshes.

like image 160
zero298 Avatar answered Sep 20 '22 12:09

zero298