0
\$\begingroup\$

I am looking for an algorithm that allows me to scale a 3D model with certain fixed edges. For example scaling up a window should have the frame remain a fixed width while the length of the frame pieces increases or a kitchen sink should have the tap remain at a fixed size while the rest increases.

frames

Note that in the example it's a 2D model while in reality it's a 3D model, scaling can also happen along certain axis (so only scaling over the Z-axis, rather than over all axis at the same time).

Performance is of minor concern(it's a small part of the loading sequence to which I can allocate an extra thread) so a c#/pseudocode solution is acceptable, it doesn't have to be implementable as a shader.

So far I was thinking about some kind of energy formulation/graph based system but I cannot get that to work with possible with death ends in the model. I looked for scientific papers on the issue but couldn't find the right paper (I vaguely remember there being one I learned about in university).

edit: it should also be able to handle situations like this: complex geometry where the parts that shouldn't scale are intermixed with the geometry of the object, this could also (in you don't want all of this to focus on architecture) be something like the eyes of an animal.

Lastly there is also the possibility of some edges being fixed and others (in the same face) not being fixed, I was hoping to solve this like so: enter image description here

\$\endgroup\$
10
  • \$\begingroup\$ I hope this explain the problem well enough, I couldn't find the answer in google scholar as I don't know the exact keywords, so I hope that this is clear, if it isn't please feel free to leave a comment so I can add information. \$\endgroup\$
    – Thijser
    Apr 16 '20 at 7:55
  • \$\begingroup\$ Have you looked at adapting the 9-Slice scaling technique commonly applied in 2D UI systems? It covers exactly this case, and a 3D analog could be done in a reasonably lightweight shader. There's also a "stretchables" technique used in Obduction, explained in this GDC talk \$\endgroup\$
    – DMGregory
    Apr 16 '20 at 8:39
  • \$\begingroup\$ @DMGregory From my understanding 9 slice limits the number of possible slices by a fair amount, furthermore it's possible that there is something on the other end of the model that should be scaled up (from the part that shouldn't scale). Sadly the link to the GDC talk is broken (at least for me) \$\endgroup\$
    – Thijser
    Apr 16 '20 at 8:47
  • \$\begingroup\$ @DMGregory I got the GDC working, it looks like that heavily focusses on textures, whereas I'm only interested in the geometry (shaders and textures are someone else's problem in a later step of the processes and will be done procedurally). \$\endgroup\$
    – Thijser
    Apr 16 '20 at 9:03
  • \$\begingroup\$ 9 slice limits to 9 slices, but that doesn't preclude you from making a 27 slice or whatever you need. You describe only scaling along the z axis though: for that you'd often need only 3 slices: one for the constant-size near end, one for the constant-size far end, and one for the stretched middle. Can you diagram the problem case you're considering so we can understand where this might not cover your needs? \$\endgroup\$
    – DMGregory
    Apr 16 '20 at 9:29
1
\$\begingroup\$

Here's a rough sketch of an approach you can use:

Add an extra texture coordinate to each vertex of your mesh. This will serve as an index, identifying which scaling behaviour that vertex should use.

  • 0 : default scaling behaviour
  • 1 : rigid part #1
  • 2 : rigid part #2
  • ... etc.

When you prepare to draw the mesh, compute a separate transformation matrix for each of these scaling behaviours. The 0th/default behaviour is just your normal model-to-world matrix. You can compute the others as...

float3 offset = (modelToWorld * rigidPartRootPoint).xyz;
float4x4 rigidPartMatrix = Translate(offset) * Rotate(objectRotation) * Scale(1, 1, 1);

Here "root point" is the place where this rigid part is "attached" to the underlying stretchable object. This point will track with the stretching applied to the rest of the object, while the rest of the points in the rigid part will maintain their exact offset relative to the root.

Upload each of these matrices to your shader as an array of uniform variables. (Optionally, you can pre-multiply each one with your view projection matrix to save an extra matrix multiply in the shader)

Finally, in your vertex shader, use your extra texture coordinate to select which matrix to use when transforming the vertex.

This will require your model's topology to be set up such that each vertex follow wholly one scaling behaviour or the other. If you need a blend, then you're getting into bone weight territory: each vertex will need multiple model matrix indices and an interpolation weight between them.

\$\endgroup\$
1
  • \$\begingroup\$ This looks like a good start, I think I'm going to work out the pseudocode for this (in detail) tomorrow. \$\endgroup\$
    – Thijser
    Apr 16 '20 at 13:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.