How to find vertex in mesh?

I have a character mesh and I want to find the local translation of the center vertex in the hand I was wondering if there are any prebuilt functions to handle this.





This is for a contest entry so time is of the essence.



Thank you.

Are you wanting to attach an item to that position, such as a sword?

Look at Bones in that case.



Otherwise, jme doesn’t know what a hand is or anything. For finding specific locations you use bones. For finding what you are targeting, such as with ray collision, the ray collision result will give you the vertex index, or at least the world location that the ray intersected.

@Sploreg said:
Are you wanting to attach an item to that position, such as a sword?
Look at Bones in that case.

Otherwise, jme doesn't know what a hand is or anything. For finding specific locations you use bones. For finding what you are targeting, such as with ray collision, the ray collision result will give you the vertex index, or at least the world location that the ray intersected.

Actuly I was hoping just to locate a vertex as if it was in a array of vector3 or somthing I wasn't planning to use bone animation. But if I must I will.

All vertices are in the vertex buffer of the mesh but getting the right mesh and vertex can prove to be difficult. Using bones is much more made for what you intend to do.

@normen said:
All vertices are in the vertex buffer of the mesh but getting the right mesh and vertex can prove to be difficult. Using bones is much more made for what you intend to do.


I intend to attach a particle emitter to selected vertex of a mesh and adding a control to handle the emitters properties and update the object to the correct location of the vert.

So you think the best solution for this is using bone locations?

No I’d say a special Influencer that gives you the location would be best there. If the particle is being put somewhere you should be able to trace that back.

@normen said:
No I'd say a special Influencer that gives you the location would be best there. If the particle is being put somewhere you should be able to trace that back.

I will try to make a control to attach to the emitter passing the vert index and the mesh that contains the vert. Does thia sound like the solution you are suggesting?

No: http://hub.jmonkeyengine.org/javadoc/com/jme3/effect/influencers/ParticleInfluencer.html

I am going for a effect like this so particle emitters attached to vert locations on the mesh and updating to the new locations when the mesh’s animation or location is changed.



but the Influencer will help for the concept of controlling the look of the links between emitters.



http://i188.photobucket.com/albums/z237/DamonLee666/Dungeons%20And%20Dragons/NightmareHorse.jpg

Hm, now there I’d go for bones again. Just attach ParticleEmitters to the bones in the specific locations.

Ok thank you for your time and patients :wink:

So I was going back through some of my old posts and I stumbled upon this one… LOL
Wow the problem I faced at this time wasn’t that hard but when you are starting out it’s tough so if anyone stumbles upon this I will leave a little example showing a way to find a vertex in a mesh.

public Vector3f findClosestVertex(Geometry geom, Vector3f point) {
        Vector3f tempVec = new Vector3f();
        Vector3f bestVec = new Vector3f();
        float bestDist = Float.MAX_VALUE;
        VertexBuffer buffer = geom.getMesh().getBuffer(VertexBuffer.Type.Position);
        for(int i = 0; i < buffer.getNumElements(); i++) {
            tempVec.setX((Float)buffer.getElementComponent(i, 0));
            tempVec.setY((Float)buffer.getElementComponent(i, 1));
            tempVec.setZ((Float)buffer.getElementComponent(i, 2));
            float tempDist = point.distance(tempVec);
            if(tempDist < bestDist) {
                bestVec.set(tempVec);
                bestDist = tempDist;
                vertId = "Vertex ID: " + i;
            }
        }
        return bestVec;
    }
2 Likes

Here is the full class I made it lets you click on Oto a box will be positioned on the vertex closest to the contact point. If you press the V key it switches Oto’s material to wire frame and Back so you can tell that the box is on a vertex and the id of the vertex is displayed in the lower left hand corner of the screen.

package com.skidrunner.test;

import com.jme3.app.SimpleApplication;
import com.jme3.collision.CollisionResults;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Ray;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;

public class TestVertexSelect extends SimpleApplication implements ActionListener {
    
    private boolean showWire = false;
    private String vertId = "";
    private Material otoMat;
    private Material wireMat;
    
    private Spatial oto;
    private Geometry marker;
    
    private CollisionResults results = new CollisionResults();
    private Ray ray = new Ray();
    
    @Override
    public void simpleInitApp() {
		// Hide StatView because it clutters the view.
        setDisplayStatView(false);
		
		// I want the camera to be static and show all of Oto
        flyCam.setEnabled(false);
        cam.setLocation(new Vector3f(0, 0, 15));
        
		// Create input mappings to trigger click event and toggle Oto's wire frame material
        inputManager.addMapping("SET_TARGET", new MouseButtonTrigger(
                MouseInput.BUTTON_LEFT));
        inputManager.addMapping("SET_WIRE", new KeyTrigger(KeyInput.KEY_V));
        inputManager.addListener(this, "SET_TARGET", "SET_WIRE");
        
		// Put Oto in the scene
        oto = assetManager.loadModel("Models/Oto/Oto.mesh.j3o");
        rootNode.attachChild(oto);
        
		// Load the materials I will be using
        otoMat = assetManager.loadMaterial("Materials/Oto.j3m");
        wireMat = assetManager.loadMaterial("Materials/WireFrame.j3m");
        
		// Create and attach the vertex marker
        Box b = new Box(0.125f, 0.125f, 0.125f);
        marker = new Geometry("Marker", b);
        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        mat.getAdditionalRenderState().setWireframe(true);
        marker.setMaterial(mat);
        rootNode.attachChild(marker);
        
		// Add a DirectionalLight because Oto's default material uses Lighting
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
        sun.setColor(ColorRGBA.White);
        rootNode.addLight(sun);
    }
    
    @Override
    public void simpleUpdate(float tpf) {
		// Display the current Vertex ID in the FPS Text
        fpsText.setText(vertId);
    }
    
    @Override
    public void simpleRender(RenderManager rm) { }
    
    @Override
    public void onAction(String name, boolean isPressed, float tpf) {
        if("SET_TARGET".equals(name) && isPressed) {
			// This is code copied directly from the Hello Picking Beginners Tutorial
            results.clear();
            Vector2f click2d = inputManager.getCursorPosition();
            Vector3f click3d = cam.getWorldCoordinates(
                    new Vector2f(click2d.x, click2d.y), 0f).clone();
            Vector3f dir = cam.getWorldCoordinates(
                    new Vector2f(click2d.x, click2d.y), 1f)
                    .subtractLocal(click3d).normalizeLocal();
            ray.setOrigin(click3d);
            ray.setDirection(dir);
            oto.collideWith(ray, results);
            if (results.size() > 0) {
				// I call a custom method that will return the closest vertex to the 3D click point
                Vector3f bestVec = findClosestVertex((Geometry)((Node)oto).getChild("Oto-geom-1"),
                        results.getClosestCollision().getContactPoint());
                marker.setLocalTranslation(bestVec);
            }
        } if("SET_WIRE".equals(name) && isPressed) {
			// Toggle wire frame material
            showWire = !showWire;
            if(showWire) {
                oto.setMaterial(wireMat);
            } else {
                oto.setMaterial(otoMat);
            }
        }
    }
    
	/**
	 * Find the closest Vertex in a mesh to a point in 3D space.
	 * @param geom
	 * @param point
	 * @return vertex
	 */
    public Vector3f findClosestVertex(Geometry geom, Vector3f point) {
		// Variables for finding the closest point
        Vector3f tempVec = new Vector3f();
        Vector3f bestVec = new Vector3f();
        float bestDist = Float.MAX_VALUE;
		
		// Get the geometry's vertex buffer
        VertexBuffer buffer = geom.getMesh().getBuffer(VertexBuffer.Type.Position);
		// Step through each element in the buffer
        for(int i = 0; i < buffer.getNumElements(); i++) {
			// Each element in the vertex buffer has 3 components x y and z
            tempVec.setX((Float)buffer.getElementComponent(i, 0));
            tempVec.setY((Float)buffer.getElementComponent(i, 1));
            tempVec.setZ((Float)buffer.getElementComponent(i, 2));
            float tempDist = point.distance(tempVec);
			// If its closer save it and move on
            if(tempDist < bestDist) {
                bestVec.set(tempVec);
                bestDist = tempDist;
                vertId = "Vertex ID: " + i;
            }
        }
        return bestVec;
    }
    
    public static void main(String[] args) {
        AppSettings settings = new AppSettings(true);
        settings.setTitle("Test Vertex Select");
        settings.setResolution(800, 450);
        settings.setFullscreen(false);
        settings.setFrameRate(60);
        
        TestVertexSelect app = new TestVertexSelect();
        app.setShowSettings(false);
        app.setSettings(settings);
        app.start();
    }
    
}
2 Likes