Change the thickness of a NodePath

Lets say I have a ring shaped NodePath, and I want to change the distance from the center to the inner circle, or basically the thickness of the ring. How would I do that? I tried setting the x scale but it moves the item itself, I want to keep the position of the NodePath the same but just change the width.
Thanks

Just setting the X-scale should work for that axis–as long as the NodePath’s parent-node is located at the position (0, 0, 0).

However, even the parent isn’t so located, this can be done by scaling the NodePath relative to itself, I do believe.

You see, the various setters and getters for things like scale, position, HPR, etc. can in general be made to act relative to some other NodePath. This is done by passing that other NodePath in as an optional first parameter.

As a result, one can have a NodePath enact these methods relative to itself, thus–in this case–scaling it in place.


im trying to achieve this. I tried the thing you mentioned by passing in the nodepath but does not meet the requirement. is this possible to achieve using panda3d functions?

Ah, I feared that it might be so, I believe. With just the basic functions, I don’t see a way to do it, no.

There are a few ways that it might be done; offhand, two ideas that come to mind are a custom shader that offsets vertices and procedural generation (or alteration) of the geometry in question. And there’s likely more than one way to implement both!

By procedural generation are you referring to GeomNodes? Do you know how that would be used I’ve never used them yet.

No–all polygonal models include GeomNodes, as far as I’m aware. My understanding is that GeomNodes are simply the nodes used by the engine for the holding of geometry–whether that geometry is procedural or loaded from a model.

I believe that the manual has a section discussing procedural generation in Panda–you should find it here:
https://docs.panda3d.org/1.10/python/programming/internal-structures/procedural-generation/index

Otherwise, I think that I’ve seen some examples posted on the forum–you might find them in a search.

[edit] Come to think of it, I think that I recently saw some tools posted for the generation of simple shapes, such as your ring.

Ah, here:

Here is some code that should allow you to change the major and/or minor radius of a loaded torus (ring) model:

from panda3d.core import *
from direct.showbase.ShowBase import ShowBase


base = ShowBase()

dir_light = DirectionalLight("light")
light_np = base.camera.attach_new_node(dir_light)
light_np.set_hpr(20., -40., 0.)
base.render.set_light(light_np)

# load the model of a torus that lies in the XY-plane and is centered at (0., 0., 0.)
model = base.loader.load_model("torus.gltf")
model.reparent_to(base.render)
# initialize the radii with the values corresponding to the loaded model
old_radii = {
    "major": 10.,  # needs to be bigger than zero
    "minor": 3.    # needs to be strictly smaller than major radius
}

def set_radii(new_major_radius=None, new_minor_radius=None):

    geom = model.find("**/+GeomNode").node().modify_geom(0)
    v_data = geom.modify_vertex_data()
    pos_rewriter = GeomVertexRewriter(v_data, "vertex")
    major_radius = old_radii["major"]
    minor_radius = old_radii["minor"]

    if new_major_radius is not None:
        old_radii["major"] = new_major_radius

    if new_minor_radius is not None:
        old_radii["minor"] = new_minor_radius

    while not pos_rewriter.is_at_end():

        x, y, z = pos = Point3(pos_rewriter.get_data3())
        maj_rad_vec = Vec3(x, y, 0.).normalized()

        if new_minor_radius is not None:
            section_center = maj_rad_vec * major_radius
            min_rad_vec = pos - section_center
            pos = section_center + min_rad_vec * new_minor_radius / minor_radius

        if new_major_radius is not None:
            pos += maj_rad_vec * (new_major_radius - major_radius)

        pos_rewriter.set_data3(pos)


# change the major and/or minor radius of the torus model
set_radii(new_major_radius=8., new_minor_radius=6.)

base.disable_mouse()
base.camera.set_pos(0., -50., 60.)
base.camera.look_at(0., 0., 0.)

base.run()

This is the torus.gltf model that the code works with:

torus.gltf (107.1 KB)

It was created in Blender, with a major radius of 10 and a minor radius of 3. These initial values need to be known for the code to work correctly. The code also expects your torus to lie in the XY-plane and centered at the world origin, (0., 0., 0.) (this is the case by default in Blender when you add a torus to your scene).
Finally, make sure that the major radius is bigger than zero and that the minor radius is strictly smaller than the major radius.

The code allows you to change the radii multiple times, but beware that once you make the major radius zero or the minor one bigger than the major radius, subsequent calls to set_radii are likely to give wrong results.

2 Likes