Questions about spatial coordinates

spatial question about local coordinates and world coordinates.


If I change the code to


If I add the trailing to the model instead of the root node, the trailing geometry seems to be in world coordinates instead of local coordinates.

Then the trailing will not follow the blue box, how can I make the trailing follow the blue box in the case of local space?

Try setting the local translation to zero after adding the trailing to the model node.

I think this depends on your code, you should be adding the model node to the physics or get it moving in sync with the physics object.

1 Like

We are missing a part. Why do you want to add a “world space” thing like trails as a child of the model?

If you do that then everything becomes harder so there must be a reason you want to do that in the first place.

1 Like

I need to deal with other things in my life, so I’m a little late in replying, so sorry.
The code is written by @JhonKkk,Unfortunately I can’t ask him for specifics,He seems to be Closed cultivation,The last message left is that it will return in 2026。

So I can only ask this question in the community.

So you think this trailing should be added to the world space and not the local space?

 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
package mygame.ctrl;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import com.jme3.scene.Node;
import trailing.TrailingObject;

 * @author JhonKkk
public class TrailingCtrl extends AbstractControl {
    private Spatial mTrailingSpatial;

     * @return the trailingTagName
    public String getTrailingTagName() {
        return trailingTagName;

     * @param trailingTagName the trailingTagName to set
    public void setTrailingTagName(String trailingTagName) {
        this.trailingTagName = trailingTagName;
    private String trailingTagName = "trailingNode";

     * @return the enableTrailing
    public boolean isEnableTrailing() {
        return enableTrailing;

     * @param enableTrailing the enableTrailing to set
    public void setEnableTrailing(boolean enableTrailing) {
        this.enableTrailing = enableTrailing;

     * @return the length
    public float getLength() {
        return length;

     * @param length the length to set
    public void setLength(float length) {
        this.length = length;

     * @return the trailingMaterial
    public Material getTrailingMaterial() {
        return trailingMaterial;

     * @param trailingMaterial the trailingMaterial to set
    public void setTrailingMaterial(Material trailingMaterial) {
        this.trailingMaterial = trailingMaterial;
    //Any local variables should be encapsulated by getters/setters so they
    //appear in the SDK properties window and can be edited.
    //Right-click a local variable to encapsulate it with getters and setters.
    private TrailingObject mTrailingObject;
    private Material trailingMaterial;
    private boolean mIsFirst = true;
    private boolean enableTrailing = false;
    private float length = 5.0f;
    public TrailingCtrl(){
        mTrailingObject = new TrailingObject();

    protected void controlUpdate(float tpf) {
        //TODO: add code that controls Spatial,
        //e.g. spatial.rotate(tpf,tpf,tpf);
        if(trailingMaterial != null && mIsFirst){
            mIsFirst = false;
            if(mTrailingSpatial == null){
                mTrailingSpatial = ((Node)spatial).getChild(trailingTagName);
        if(trailingMaterial != null && enableTrailing){
//            System.out.println("localtion:" + spatial.getLocalTranslation());
            mTrailingObject.setTrailingVec(spatial.getLocalTranslation().add(spatial.getLocalRotation().getRotationColumn(1).mult(length)), spatial.getLocalTranslation());
           // mTrailingObject.setTrailingVec(new Vector3f(0, 10, 0), new Vector3f(0, 0, 0));
            mTrailingObject.sampling((long) (tpf * 1000L));
    protected void controlRender(RenderManager rm, ViewPort vp) {
        //Only needed for rendering-related operations,
        //not called when spatial is culled.
    public Control cloneForSpatial(Spatial spatial) {
        TrailingCtrl control = new TrailingCtrl();
        //TODO: copy parameters to new Control
        return control;
    public void read(JmeImporter im) throws IOException {;
        InputCapsule in = im.getCapsule(this);
        trailingMaterial = (Material) in.readSavable("trailingMaterial", null);
        setEnableTrailing(in.readBoolean("enableTrailing", false));
        length = in.readFloat("length", 5.0f);
        trailingTagName = in.readString("trailingTagName", null);
        //TODO: load properties of this Control, e.g.
        //this.value = in.readFloat("name", defaultValue);
    public void write(JmeExporter ex) throws IOException {
        OutputCapsule out = ex.getCapsule(this);
        out.write(trailingMaterial, "trailingMaterial", null);
        out.write(length, "length", 5.0f);
        out.write(isEnableTrailing(), "enableTrailing", false);
        out.write(trailingTagName, "trailingTagName", "trailingNode");
        if(mTrailingObject.mTrailingGeometry.getParent() != null){
        //TODO: save properties of this Control, e.g.
        //out.write(this.value, "name", defaultValue);


The original version of this code is in AbstractControl which means that AbstractControl can only get to the AbstractControl target space So how do I add TrailingCtrlAbstractControl to the world space?

I misunderstood your first post. I thought you were saying that it was working before and then you changed something and now it’s not working. In which case I wondered why you changed something.

If it was never working then it’s broken code and you will probably be better finding different code or learning how to write your own. Else there may still be 100 other things broken about it.

When it has never worked it may never work.

Your previous understanding was correct, the code was working, but it didn’t work the way I wanted it to, so I simply modified the code.

The code in this video is the original code, I have moved the model and you can see that the trailing is not in the right place.

This is @JhonKkk’s original approach,

My doubt is, if I need the trailing to follow the model correctly after the model moves what should I do? Add the trailing tail to the root Node so that it appears correctly in the screen? Or can I set the spatial transformation of the trailing model or something else? Can you give me some tips?

I have not looked at the code but the trail coordinates are probably in world space. This is the easiest to do since they won’t need to be recalculated every time the object moves again.

If the trail is in object space then every time the object moves ALL of the trail points will need to be reset to world->local coordinates.

And if the trail geometry data is no in world space then I don’t know. That’s how I would do it. Separate spatial, geometry in world space.

1 Like

Create a Node, add the trailing to it, and add the node to the physics space (a node is spatial, so don’t worry), then you can add everything you want to this Node including your player asset, I don’t understand why this doesn’t work with you.

The rootNode should be a static node (not moving).

1 Like