Curved / bent bar

Hello,

I would like to create a curved/bent bar, but I do not really find a good starting point. Would be great, if somebody could help me out. In this forum I found some hints about roads etc, but it does not really fit to my needs (or at least I do not see the connection or didn’t search for the correct things). I’m still nooby at JME, so sorry if there is an easy solution, that I haven’t found yet.

Given is a set of points p1, p2, p3 (and many more) and some height and width (and maybe an angle or radius).

The goal is to connect p1 and p2 (as well as p2 and p3) by a curved bar (kind of bent rectangular prism) with height and width from input parameters. Finally, it should look similar to this (only the red part):

image

Sounds somehow easy, doesn’t it? But I do not have a real approach. I assume, that I need to create a custom mesh (or even 6 to get a single bar for all 4 sides + start and end rectangle).

I already created some simple meshes, but it is still not the easiest topic for me. I suppose I also need some other parameters, to tell the mesh whether it is bent “left” or “right”?

Did anyone have a similar issue and/or can provide some lines of code, how the issue can be resolved? I spent many frustrating hours (more likely at least days) on this topic without a satisfying, proper solution.

Many thanks in advance

murcielago

And you actually need to do this at runtime in your game?

Versus 10 seconds of modeling in something like Blender?

The issue is, that the points are not fixed and differ in my scenarios. I assume, that Blender models are fixed in its shape?

Way 1. Custom Mesh (like you said)

  • require update geometry mesh and model bound

Way 2. Create it with modelling program like Blender.

  • use Morph shapes to modify verts (see my lipsync example)

Way 3. Use Geometry Shader / Compute shader / OpenCL

So. “Yes”

Edit: and for truly variable paths, you will need to implement a custom mesh. If you can get away with “sort of different” then a Blender model might still work.

Then. “Yes”. :slight_smile: I do have an XML file containing these points. And the XMLs might differ from case to case. So, I think, I need kind of dynamic creation during runtime.

yes, then seems like custom mesh is best way here. You seen wiki about it right?

Yes, I read the wiki and basically know how custom meshes can be created, including the UV-mapping etc. But the wiki describes some kind of “straight” mesh where you do know all the points on the (outer) lines, right?

PS: Referring to this: https://wiki.jmonkeyengine.org/docs/3.3/core/scene/custom_meshes.html

Maybe you find this helpful

1 Like

The Lemur way sounds cool, i think its worth to try.

But if you would want use “default way” below i can provide helpfull info:

Generally there are different ways of connecting points.

I think easy way would be “create each tris separatly”.

So lets assume you have “algorithm” to create “verticles”.
Starting from simple Cosine or other Interpolations that will calculate curve for you.

so you only need calculate points 4x times for each offset of them. (i hope you get what i mean)

When you will have point generation done, you only need create quads between each points stage.

Below Class can be helpfull for you, but you will anyway need provide own 4 Points for it.
(normals is just face direction, same when you enable Normals in Blender - blue lines)

public enum FaceEnum {
    Y(0, new Vector3i(0, 1, 0), new Vector3f[]{
        new Vector3f(0,1,0),
        new Vector3f(0,1,1),
        new Vector3f(1,1,0),
        new Vector3f(1,1,1)
    },new int[]{
        2,0,1, 1,3,2
    },new int[][]{
        new int[]{0,0},
        new int[]{0,1},
        new int[]{1,0},
        new int[]{1,1},
    }, 0), 
    YNEG(1, new Vector3i(0, -1, 0), new Vector3f[]{
        new Vector3f(0,0,0),
        new Vector3f(0,0,1),
        new Vector3f(1,0,0),
        new Vector3f(1,0,1)
    },new int[]{
        2,3,1,1,0,2
    },new int[][]{
        new int[]{0,0},
        new int[]{0,1},
        new int[]{1,0},
        new int[]{1,1},
    }, 0), 
    X(2, new Vector3i(1, 0, 0), new Vector3f[]{
        new Vector3f(1,0,0),
        new Vector3f(1,1,0),
        new Vector3f(1,0,1),
        new Vector3f(1,1,1)
    },new int[]{
        2,0,1, 1,3,2
    },new int[][]{
        new int[]{0,0},
        new int[]{0,1},
        new int[]{1,0},
        new int[]{1,1},
    }, 0), 
    XNEG(3, new Vector3i(-1, 0, 0), new Vector3f[]{
        new Vector3f(0,0,0),
        new Vector3f(0,1,0),
        new Vector3f(0,0,1),
        new Vector3f(0,1,1)
    },new int[]{
        2,3,1,1,0,2
    },new int[][]{
        new int[]{0,0},
        new int[]{0,1},
        new int[]{1,0},
        new int[]{1,1},
        
    }, 0), 
    Z(4, new Vector3i(0, 0, 1), new Vector3f[]{
        new Vector3f(0,0,1),
        new Vector3f(0,1,1),
        new Vector3f(1,0,1),
        new Vector3f(1,1,1)
    },new int[]{
        2,3,1,1,0,2
    },new int[][]{
        new int[]{0,0},
        new int[]{0,1},
        new int[]{1,0},
        new int[]{1,1},
    }, 0),
    ZNEG(5, new Vector3i(0, 0, -1), new Vector3f[]{
        new Vector3f(0,0,0),
        new Vector3f(0,1,0),
        new Vector3f(1,0,0),
        new Vector3f(1,1,0)
    },new int[]{
        2,0,1, 1,3,2
    },new int[][]{
        new int[]{0,0},
        new int[]{0,1},
        new int[]{1,0},
        new int[]{1,1},
        
    }, 0);
    private final int index;
    private final Vector3i offset;
    private final Vector3f[] baseVerts;
    private final int[] baseIndices;
    private final int[][] texturePosition;
    
    FaceEnum(int index, Vector3i offset,Vector3f[] baseVerts,int[] baseIndices, int[][] texturePosition, int textureType) {
        this.index = index;
        this.offset = offset;
        this.baseVerts = baseVerts;
        this.baseIndices = baseIndices;
        this.texturePosition = texturePosition;
    }

    public int getIndex() {
        return index;
    }
    
    public Vector3i getOffset() {
        return this.offset;
    }
    
    public Vector3f[] getBaseVerts(){
        return this.baseVerts;
    }

    public int[] getBaseIndexes() {
        return baseIndices;
    }
    
    public int[][] getTexturePositions(){
        return this.texturePosition;
    }
    
}

Then for each Face, you will be able to create buffer “user friendly way” that you will understand since you Operate over faces:

mesh = new Mesh();
        //The position buffer
        FloatBuffer pb = BufferUtils.createVector3Buffer(verts.size() * 3);
        //The normal buffer
        FloatBuffer nb = BufferUtils.createVector3Buffer(faceNormals.size() * 3 * 4);
        //The texCoord1 buffer
        FloatBuffer tb1 = BufferUtils.createVector2Buffer(textureCoords.size() * 2);
        //The index buffer
        IntBuffer ib = BufferUtils.createIntBuffer(indexes.size());
        for (Integer index : indexes) {
            ib.put(index);
        }
        for (Vector3f vert : verts) {
            pb.put(vert.x).put(vert.y).put(vert.z);
        }
        for (Vector3f faceNormal : faceNormals) {
            //faceNormal = new Vector3f(0, -1, 0);
            nb.put(faceNormal.x).put(faceNormal.y).put(faceNormal.z);
            nb.put(faceNormal.x).put(faceNormal.y).put(faceNormal.z);
            nb.put(faceNormal.x).put(faceNormal.y).put(faceNormal.z);
            nb.put(faceNormal.x).put(faceNormal.y).put(faceNormal.z);
        }
        for (Vector2f texCoords : textureCoords) {
            tb1.put(texCoords.x).put(texCoords.y);
        }
        if (!mesh.getBufferList().isEmpty()) {
            BufferUtils.destroyDirectBuffer(mesh.getBuffer(VertexBuffer.Type.Position).getData());
            BufferUtils.destroyDirectBuffer(mesh.getBuffer(VertexBuffer.Type.Normal).getData());
            BufferUtils.destroyDirectBuffer(mesh.getBuffer(VertexBuffer.Type.TexCoord).getData());
            BufferUtils.destroyDirectBuffer(mesh.getBuffer(VertexBuffer.Type.Index).getData());
        }
        mesh.setBuffer(VertexBuffer.Type.Position, 3, pb);
        mesh.setBuffer(VertexBuffer.Type.Normal, 3, nb);
        mesh.setBuffer(VertexBuffer.Type.TexCoord, 2, tb1);
        mesh.setBuffer(VertexBuffer.Type.Index, 1, ib);

Please note i could have too big buffers here, so verify me.

edit:

also dont forget use:

geometry.updateModelBound();

after update mesh

Thanks a lot. I haven’t worked with Lemur yet at all. Sounds like additional investigations and tests. But the video looks very similar to what I need (just without user input).

Also many thanks to you. I will also need to try this.

And just in case, the link to test in Lemur Gems topic looks like to be old one.

New links are:

I tried to implement / execute the DeformationDemo example to gain some experience, but I get an exception, after confirming the JME start screen:

Uncaught exception thrown in Thread[jME3 Main,5,main]
AbstractMethodError: Receiver class com.simsilica.lemur.event.KeyInterceptState does not define or inherit an implementation of the resolved method ‘abstract java.lang.String getId()’ of interface com.jme3.app.state.AppState.

I added lemur dependency to my maven / POM:

<dependency>
        <groupId>com.simsilica</groupId>
        <artifactId>lemur</artifactId>
        <version>1.10.1</version>
    </dependency>

No clue, what I’m doing wrong. Could you tell me, how I can simply test DeformationDemo? This kind of try and error is frustrating. Sorry to be a pain.

Can you try with latest version of Lemur? (v1.14.0)

1 Like

looks much better. Thanks a lot (again). I will check out, whether (and hopefully how) I can use it for my purposes.

1 Like