[SOVLED]Need help with Importing old 3dmax ASE model

NEW
UPLOAD MY PROJECT ON GIT:AsePlugin
Developed with Eclipse 4.3 & JME SDK 3.0

Hi, I’m new to jme. These days I’m learning jme by re-develop an old C++ MMORPG.
Now I’m learning how to manage assets. The game, which I want to re-develop with jme, use 3dmax ASE models, so I write a AssetLoader (I called it AseLoader) to analysis ASE model files and import its model.

In most time the AseLoader works fine, while something wired happened after i import to Monster Model. They suppose to stand straight but … :chimpanzee_lobotized:

Your see the axis at left-buttom corner? I made a axis and a flag as objects of reference, the flag is all right but the axis was crooked… :sweat:

For someother model, the AseLoader works just fine.

It also works just fine for world model.(GUI made with @toneg0d gui lib)

My code for TestLoadMonster, I will paste the code of my AseLoader after this topic

    @Override
    public void simpleInitApp() {
        this.setPauseOnLostFocus(false);

        cam.setLocation(new Vector3f(100, 80, 100));
        cam.lookAt(Vector3f.ZERO, cam.getUp());
        this.flyCam.setMoveSpeed(100f);

        assetManager.registerLoader(AseLoader.class, "ase");

        if (new File("D:/Priston Tale/0_素材/Client").isDirectory()) {
            assetManager.registerLocator("D:/Priston Tale/0_素材/Client",
                    FileLocator.class);
        }
        if (new File("F:/1_DEVELOP/3_素材").isDirectory()) {
            assetManager.registerLocator("F:/1_DEVELOP/3_素材", FileLocator.class);
        }

        Spatial flag = assetManager.loadAsset(new AseKey("char/Flag/wow.ASE"));
        rootNode.attachChild(flag);

        Spatial anim = assetManager.loadAsset(new AseKey("data/model/animtest.ase"));
        anim.scale(0.1f);
        rootNode.attachChild(anim);

        Spatial rot = assetManager.loadAsset(new AseKey("data/model/rottest.ase"));
        rot.scale(0.1f);
        rot.move(0, 0, 30);
        rootNode.attachChild(rot);

        Spatial death_knight = assetManager.loadAsset(new AseKey("char/monster/death_knight/death_knight.ASE"));
        death_knight.move(0, 0, 300);
        rootNode.attachChild(death_knight);

        Spatial chaoscara = assetManager.loadAsset(new AseKey("char/monster/chaoscara/chaoscara.ASE"));
        chaoscara.move(0, 0, 150);
        rootNode.attachChild(chaoscara);
        
//        debugSke(death_knight);

        initAmbient();
        initKeys();
        initCrossHairs();

        viewPort.setBackgroundColor(ColorRGBA.LightGray);

        showNodeAxes(15);

    }

    private void initAmbient() {
        AmbientLight light = new AmbientLight();
        light.setColor(ColorRGBA.White);
        rootNode.addLight(light);
    }

    public void showNodeAxes(float axisLen) {
        Mesh mesh = new Grid(31, 31, 3.93701f);
        Geometry grid = new Geometry("Axis", mesh);
        Material gm = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        gm.setColor("Color", ColorRGBA.White);
        gm.getAdditionalRenderState().setWireframe(true);
        grid.setMaterial(gm);
        grid.center().move(0, -0.1f, 0);

        rootNode.attachChild(grid);

        //
        Vector3f v = new Vector3f(axisLen, 0, 0);
        Arrow a = new Arrow(v);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Red);
        Geometry geom = new Geometry(rootNode.getName() + "XAxis", a);
        geom.setMaterial(mat);
        rootNode.attachChild(geom);

        //
        v = new Vector3f(0, axisLen, 0);
        a = new Arrow(v);
        mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Green);
        geom = new Geometry(rootNode.getName() + "YAxis", a);
        geom.setMaterial(mat);
        rootNode.attachChild(geom);

        //
        v = new Vector3f(0, 0, axisLen);
        a = new Arrow(v);
        mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom = new Geometry(rootNode.getName() + "ZAxis", a);
        geom.setMaterial(mat);
        rootNode.attachChild(geom);
    }

Make sure you don’t change your static Vectors like Vector3f.ZERO etc. Do a comparison each frame e.g. if(!Vector3f.ZERO.equals(new Vector3f(0,0,0))){System.out println(“Zero changed!!”);} etc.

Here is the code of my AseLoader. I write it to parse ASE files and write a AseProcessor to generate JME3 Geometry. The animation part is under developing, it dosn’t work for now. Maybe i will need you help after i work out this probrom…

The AseLoader codeis to long. Here is a link to it:AseLoader
Sorry for use a Chinese websit, I will chage it to github later. :chimpanzee_neutral:

AseProcessor

/**
 * ASE资源处理器,用于将AseScene数据解析为JME3所能识别的数据结构。
 * 
 * @author yanmaoyuan
 * 
 */
public class AseProcessor implements CONSTANT {
    // 资源管理器
    private AssetManager manager = null;
    private AssetKey key = null;

    public AseProcessor(AssetInfo info) {
        this.manager = info.getManager();
        this.key = info.getKey();
    }

    // 模型节点
    private Node rootNode = null;
    private HashMap<String, Node> nodes = new HashMap<String, Node>();

    // 材质
    private Material missingMtl = null;// 材质丢失
    private Material alphaMtl = null;// 透明材质
    private Material wireframeMtl = null;// 白色线框

    public Node process(AseScene scene) {

        // 清空数据
        nodes.clear();

        rootNode = new Node("Ascii_Model_" + scene.name);
        // 组装模型
        compileModel(scene.getObjects());
        // 生成骨骼动画
        // compileSkeleton(scene);
        // 生成场景动画
        // compileAnimation(scene);
        return rootNode;
    }

    /*******************************
     * 
     * 生成JME3的Geometry和Node
     * 
     *******************************/

    /**
     * 生成可以被JME3识别的Geometry
     * 
     * @param objects
     * 
     * @return
     */
    protected void compileModel(List<GeomObject> objects) {
        cache.clear();

        for (GeomObject obj : objects) {

            // 生成网格数据
            if (!obj.hasMesh()) {
                // 没有网格数据,可能是一个HelpObject也可能是一个骨骼,总之什么都不干
            } else if (obj.isBone()) {
                // 如果是骨骼的话,那么在compileSkeleton中会生成骨骼动画
            } else if (!obj.hasMaterial() || !obj.hasTextureFace()) {
                Mesh mesh = compileSingleMesh(obj);

                Geometry geom = new Geometry(obj.name, mesh);
                geom.setModelBound(new BoundingBox());
                geom.updateModelBound();
                geom.setMaterial(getAlphaMaterial());// 随便给一个材质

                rootNode.attachChild(geom);
                geom = null;
            } else {
                switch (obj.mtl.clazz) {
                case "Standard": {// 标准材质
                    Mesh mesh = compileStandardMesh(obj);

                    Geometry geom = new Geometry(obj.name, mesh);
                    geom.setModelBound(new BoundingBox());
                    geom.updateModelBound();

                    Material material = makeMaterial(obj.mtl);
                    geom.setMaterial(material);

                    // 制作动画脚本
                    makeScript(geom, obj.mtl);
                    
                    rootNode.attachChild(geom);

                    material = null;
                    geom = null;
                    break;
                }
                case "Multi/Sub-Object": {// 多重子材质

                    /**
                     * 在有纹理贴图的情况下,将每个MESH_FACE的MTL_ID来把Face分组,
                     * 生成多个Geometry后再组装成一个Node。
                     */
                    constructMultiGeomNode(obj);

                    break;
                }
                case "Shell Material": {// 外壳材质
                    constructMultiGeomNode(obj);
                    break;
                }
                default:
                    System.out.println("Default" + obj.mtl.clazz);
                }
            }

        }

        cache.clear();
    }

    /**
     * 计算并生成网格数据
     * 
     * @param node
     * 
     * @param obj
     * @return
     */
    private void constructMultiGeomNode(GeomObject obj) {
        /*********************** 根据Material_REF把Face分组!! *******************/
        IntMap<List<Face>> faceMap = new IntMap<List<Face>>();
        for (int i = 0; i < obj.getFaceCount(); i++) {
            Face face = obj.faces.get(i);
            face.index = i;
            if (faceMap.get(face.mtlid) == null) {
                List<Face> groupByMtlid = new ArrayList<Face>();
                groupByMtlid.add(face);
                faceMap.put(face.mtlid, groupByMtlid);
            } else {
                List<Face> groupByMtlid = faceMap.get(face.mtlid);
                groupByMtlid.add(face);
            }
        }

        /********* 由于同一个Mesh中存在不同的贴图,因此我决定把它们拆分成多个不同的Geometry ************/
        for (Entry<List<Face>> entity : faceMap) {
            int mtl_id = entity.getKey();

            GeomObject subObj = obj.clone();
            subObj.faces = entity.getValue();
            subObj.name = obj.name + "_" + mtl_id;

            Mesh mesh = compileStandardMesh(subObj);
            Geometry geom = new Geometry(subObj.name, mesh);

            geom.setModelBound(new BoundingBox());
            geom.updateModelBound();

            // 设置材质
            if (obj.mtl.clazz.equals("Multi/Sub-Object")) {
                Material material = makeMaterial(obj.mtl.subMtls.get(mtl_id));
                geom.setMaterial(material);
                
                // 制作动画脚本
                makeScript(geom, obj.mtl.subMtls.get(mtl_id));
            } else {// 外壳材质
                Mtl diffuseMaps = obj.mtl.subMtls.get(0);// DiffuseMap
                Mtl lightMap = obj.mtl.subMtls.get(1);// LightMap;

                Material material = makeMaterial(diffuseMaps.subMtls.get(mtl_id)).clone();
                material.setTexture("LightMap", loadTexture(lightMap.diffuseMap.texName));
                geom.setMaterial(material);
                
                // 制作动画脚本
                makeScript(geom, diffuseMaps.subMtls.get(mtl_id));
            }
            rootNode.attachChild(geom);

            geom = null;
        }
    }

    /**
     * 生成子模型,计算每个网格的mesh
     * 
     * @param obj
     * @param mtl_id
     * @param faces
     * @return
     */
    private Mesh compileStandardMesh(final GeomObject obj) {
        // 计算Mesh
        Mesh mesh = new Mesh();
        int fCount = obj.faces.size();

        // 初始化网格数据,分配内存
        float v[] = new float[fCount * 3 * 3];
        int f[] = new int[fCount * 3];
        float tv[] = new float[fCount * 3 * 2];

        for (int i = 0; i < obj.faces.size(); i++) {
            Face face = obj.faces.get(i);

            // 顶点索引
            f[i * 3] = i * 3;
            f[i * 3 + 1] = i * 3 + 1;
            f[i * 3 + 2] = i * 3 + 2;

            // 计算顶点
            Vector3f v1 = obj.verts.get(face.v1);
            v[i * 3 * 3 + 0] = v1.x;
            v[i * 3 * 3 + 1] = v1.y;
            v[i * 3 * 3 + 2] = v1.z;
            Vector3f v2 = obj.verts.get(face.v2);
            v[i * 3 * 3 + 3] = v2.x;
            v[i * 3 * 3 + 4] = v2.y;
            v[i * 3 * 3 + 5] = v2.z;
            Vector3f v3 = obj.verts.get(face.v3);
            v[i * 3 * 3 + 6] = v3.x;
            v[i * 3 * 3 + 7] = v3.y;
            v[i * 3 * 3 + 8] = v3.z;

            // 计算纹理坐标
            Face uvFace = obj.uvFaces.get(face.index);
            Vector2f uv1 = obj.texCoords.get(uvFace.v1);
            Vector2f uv2 = obj.texCoords.get(uvFace.v2);
            Vector2f uv3 = obj.texCoords.get(uvFace.v3);
            tv[i * 6] = uv1.x;
            tv[i * 6 + 1] = uv1.y;
            tv[i * 6 + 2] = uv2.x;
            tv[i * 6 + 3] = uv2.y;
            tv[i * 6 + 4] = uv3.x;
            tv[i * 6 + 5] = uv3.y;
        }

        // 设置网格数据
        mesh.setBuffer(Type.Position, 3, v);
        mesh.setBuffer(Type.Index, 3, f);
        mesh.setBuffer(Type.TexCoord, 2, tv);

        mesh.setStatic();
        mesh.updateBound();
        mesh.updateCounts();

        return mesh;
    }

    /**
     * 生成网格数据
     * 
     * @param node
     * @param obj
     * @return
     */
    private Mesh compileSingleMesh(GeomObject obj) {
        Mesh mesh = new Mesh();

        float v[] = new float[obj.getVertexCount() * 3];
        for (int i = 0; i < obj.verts.size(); i++) {
            Vector3f vert = obj.verts.get(i);
            v[i * 3] = vert.x;
            v[i * 3 + 1] = vert.y;
            v[i * 3 + 2] = vert.z;
        }
        mesh.setBuffer(Type.Position, 3, v);

        int f[] = new int[obj.getFaceCount() * 3];
        for (int i = 0; i < obj.faces.size(); i++) {
            Face face = obj.faces.get(i);
            f[i * 3] = face.v1;
            f[i * 3 + 1] = face.v2;
            f[i * 3 + 2] = face.v3;
        }
        mesh.setBuffer(Type.Index, 3, f);

        mesh.setStatic();
        mesh.updateBound();
        mesh.updateCounts();

        return mesh;
    }

    /*******************************
     * 
     * 生成JME3的Material
     * 
     *******************************/
    HashMap<String, Material> cache = new HashMap<String, Material>();

    /**
     * 根据ASE材质数据,生成JME3能够识别的Material。
     * 
     * @param mtl
     * @return
     */
    private Material makeMaterial(Mtl mtl) {

        if (mtl == null) {
            return getMissingMaterial();
        }
        
        // wall:
        if ((mtl.ScriptState & sMATS_SCRIPT_NOTVIEW) != 0) {
            return getAlphaMaterial();
        }

        String key = String.format("%s_%s_%d", mtl.name, mtl.clazz, mtl.id);

        // 检查缓存中是否已有这个材质
        if (cache.get(key) != null) {
            return cache.get(key);
        }

        Material material = null;

        material = new Material(manager, "Common/MatDefs/Light/Lighting.j3md");

        material.setBoolean("UseMaterialColors", true);

        material.setColor("Ambient", ColorRGBA.White);
        material.setColor("Diffuse", ColorRGBA.White);
        material.setColor("Specular", ColorRGBA.White);
        material.setColor("GlowColor", ColorRGBA.Black);
        material.setFloat("Shininess", 25f);

        // 渲染方式
        RenderState rs = material.getAdditionalRenderState();

        rs.setAlphaTest(true);
        rs.setAlphaFallOff(0.01f);

        // 是否2面都显示?默认会切除背面。
        if (mtl.twoSide) {
            rs.setFaceCullMode(RenderState.FaceCullMode.Off);// twoside
        }

        if (mtl.diffuseMap != null) {
            Texture texture = loadTexture(mtl.diffuseMap.texName);
            switch (mtl.diffuseMap.BitmapFormState) {
            case CONSTANT.D3DTOP_ADD: {
                break;
            }
            }
            switch (mtl.diffuseMap.BitmapStageState) {
            case 0:
                break;
            }
            material.setTexture("DiffuseMap", texture);
        } else {
            rs.setFaceCullMode(FaceCullMode.FrontAndBack);// 没有贴图,不显示。
        }
        if (mtl.opacityMap != null) {
            Texture texture = loadTexture(mtl.opacityMap.texName);
            material.setTexture("AlphaMap", texture);
        }

        // TODO 没啥用
        int WindMeshBottom = 0;
        int MeshState = 0;
        if ((mtl.ScriptState & sMATS_SCRIPT_WIND) != 0) {
            WindMeshBottom = sMATS_SCRIPT_WINDZ1;
            MeshState = 0;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_WINDX1) != 0) {
            WindMeshBottom = sMATS_SCRIPT_WINDX1;
            MeshState = 0;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_WINDX2) != 0) {
            WindMeshBottom = sMATS_SCRIPT_WINDX2;
            MeshState = 0;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_WINDZ1) != 0) {
            WindMeshBottom = sMATS_SCRIPT_WINDZ1;
            MeshState = 0;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_WINDZ2) != 0) {
            WindMeshBottom = sMATS_SCRIPT_WINDZ2;
            MeshState = 0;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_WATER) != 0) {
            WindMeshBottom = sMATS_SCRIPT_WATER;
            MeshState = 0;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_NOTPASS) != 0) {
            MeshState = SMMAT_STAT_CHECK_FACE;
        } else {
            if ((mtl.ScriptState & sMATS_SCRIPT_PASS) != 0) {
                MeshState = 0;
            }
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_RENDLATTER) != 0) {
            MeshState |= sMATS_SCRIPT_RENDLATTER;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_CHECK_ICE) != 0) {
            MeshState |= sMATS_SCRIPT_CHECK_ICE;
        }
        if ((mtl.ScriptState & sMATS_SCRIPT_ORG_WATER) != 0) {
            MeshState = sMATS_SCRIPT_ORG_WATER;
        }

        // Blink Color
        if ((mtl.ScriptState & sMATS_SCRIPT_BLINK_COLOR) != 0
                && WindMeshBottom == 0) {
            int cnt = 0;
            for (cnt = 0; cnt < MAX_MAP_BLINK_COLOR_TIME; cnt++) {
                if (mtl.strScript.contains(szBlinkTimeScript[cnt]))
                    break;
            }

            if (cnt >= MAX_MAP_BLINK_COLOR_TIME)
                WindMeshBottom = dwBlinkTimeCode[0];
            else
                WindMeshBottom = dwBlinkTimeCode[cnt];
        }
        // 把材质放入缓存中
        cache.put(key, material);

        return material;
    }

    /**
     * 加载材质贴图
     * 
     * @param path
     * @return
     */
    private Texture loadTexture(String path) {
        Texture texture = null;
        try {
            texture = manager.loadTexture(path);
            texture.setWrap(WrapMode.Repeat);
        } catch (Exception ex) {
            texture = manager.loadTexture("Common/Textures/MissingTexture.png");
            texture.setWrap(WrapMode.Clamp);
        }
        return texture;
    }

    private void makeScript(Geometry geom, Mtl mtl) {
        // anim 动画!
        int AnimCount = 0;
        if(mtl == null) return;
        if (mtl.strScript != null) {
            if ((mtl.ScriptState & sMATS_SCRIPT_ANIM2) != 0)
                AnimCount = 2;
            if ((mtl.ScriptState & sMATS_SCRIPT_ANIM4) != 0)
                AnimCount = 4;
            if ((mtl.ScriptState & sMATS_SCRIPT_ANIM8) != 0)
                AnimCount = 8;
            if ((mtl.ScriptState & sMATS_SCRIPT_ANIM16) != 0)
                AnimCount = 16;
        }
        if (AnimCount != 0) {
            geom.addControl(new ScripteControl(mtl.strScript, 8));
        }
    }

    /**
     * 图片动画控制器
     * 
     * @author yanmaoyuan
     * 
     */
    class ScripteControl extends AbstractControl {
        // 图片数据
        private ArrayList<Texture> imgs = new ArrayList<Texture>();

        public ScripteControl(String script, int animCount) {
            if (animCount != 0) {
                int first = script.indexOf(":");
                int last = script.lastIndexOf(":");

                // 帧数
                int FrameSpeed = 0;
                if (last != first) {
                    String spd = script.substring(last + 1);
                    FrameSpeed = Integer.parseInt(spd);
                }

                // 图片参数
                String bmp = null;
                if (last != first)
                    bmp = script.substring(first + 1, last);
                else
                    bmp = script.substring(first + 1);
                for (int i = 0; i < animCount; i++) {
                    String tex = String.format(bmp, i);
                    String name = key.getFolder() + tex;
                    Texture texture = null;
                    try {
                        texture = manager.loadTexture(name);
                        texture.setWrap(WrapMode.Repeat);
                        imgs.add(texture);
                    } catch (Exception ex) {
                    }
                    
                }
            }
        }

        float second = 0;
        float internal = 1 / 5f;
        @Override
        protected void controlUpdate(float tpf) {
            second += tpf;
            if (second > internal) {
                second -= internal;
                changeImage();
            }
        }

        int n = 0;

        private void changeImage() {
            if (spatial instanceof Geometry) {
                n++;
                if (n >= imgs.size()) {
                    n = 0;
                }
                Geometry geom = (Geometry) spatial;
                geom.getMaterial().setTexture("DiffuseMap", imgs.get(n));
            }
        }

        @Override
        protected void controlRender(RenderManager rm, ViewPort vp) {
        }

        public ScripteControl clone() {
//            ScripteControl ctrl = new ScripteControl(script, animCount);
//            ctrl.spatial = spatial;
//            ctrl.imgs = imgs;
//            return ctrl;
            return this;
        }
    }

    /**
     * 显示材质Missing Material
     * 
     * @return
     */
    protected Material getMissingMaterial() {
        if (missingMtl == null) {
            missingMtl = new Material(manager,
                    "Common/MatDefs/Misc/Unshaded.j3md");
            missingMtl.setTexture("ColorMap",
                    loadTexture("Common/Textures/MissingMaterial.png"));
        }
        return missingMtl;
    }

    /**
     * 透明材质
     * 
     * @return
     */
    protected Material getAlphaMaterial() {
        if (alphaMtl == null) {
            alphaMtl = new Material(manager,
                    "Common/MatDefs/Misc/Unshaded.j3md");
            RenderState rs = alphaMtl.getAdditionalRenderState();
            rs.setFaceCullMode(RenderState.FaceCullMode.FrontAndBack);
        }
        return alphaMtl;
    }

    /**
     * 生成白色线框材质
     */
    protected Material getWireFrameMaterial() {
        if (wireframeMtl == null) {
            wireframeMtl = new Material(manager,
                    "Common/MatDefs/Misc/Unshaded.j3md");
            wireframeMtl.setColor("Color", ColorRGBA.White);
            RenderState rs = wireframeMtl.getAdditionalRenderState();
            rs.setWireframe(true);
        }
        return wireframeMtl;
    }

    /*******************************
     * 
     * 生成JME3的骨骼动画
     * 
     *******************************/

    /**
     * 生成JME3的骨骼动画
     * 
     * @param scene
     */
    protected void compileSkeleton(AseScene scene) {
        // 生成骨骼
        HashMap<String, Bone> boneMap = new HashMap<String, Bone>();
        List<Bone> boneList = new ArrayList<Bone>();
        for (GeomObject obj : scene.getObjects()) {
            if (!obj.isBone()) {
                System.out.println(obj.name);
                // 不是骨骼?
                continue;
            }
            // 创建骨骼!
            Bone bone = new Bone(obj.name);
            boneMap.put(obj.name, bone);
            boneList.add(bone);

            // 骨骼的继承关系
            if (obj.parent != null) {
                Bone parent = boneMap.get(obj.parent);
                parent.addChild(bone);
            }

            // 计算中心坐标
            bone.setBindTransforms(obj.pos, obj.rotation, obj.scale);

            bone = null;
        }
        Bone[] bones = boneList.toArray(new Bone[boneList.size()]);
        Skeleton ske = new Skeleton(bones);

        // 生成动画
        AnimControl ac = new AnimControl(ske);
        rootNode.addControl(ac);

    }
}

I didn’t chage it…I tried hard to avoid modify statics.

Vector3f.UNIT_X, Vector3f.UNIT_Z, Vector3f.UNIT_Y, Vector3f.UNIT_XYZ…

Thank you for your quickly reply, but none of these statics chaged.

if i don’t import monsters, it looks like fine but the FPS missed some part.


if i import deathknight model with out chaoscara it looks a little crooked.

if i import chaoscara model with out deathknight it looks very wired…

Then I guess your bone setup isn’t working properly.

The animation part is now under developing… I didn’t use it at all. And the other player model looks just fine.
I upload some more images, you can see it upon this topic.

public Node process(AseScene scene) {

    rootNode = new Node("Ascii_Model_" + scene.name);
    // build JME3 Geometry
    compileModel(scene.getObjects());
    // build bones - don't use
    // compileSkeleton(scene);
    // bake animation - don't use
    // compileAnimation(scene);
    return rootNode;
}

Here is the most strange part, if I don’t import any model, the FPS Bitmap also lost some part…

Toggle show fps button F5…

oh my! how can this happen??!! :chimpanzee_confused:

:frowning: Is there any one can help?
Maybe all sleeping…zzzzZZZZZ, but it’s 11:35 AM here in my country. :joy:

If everything is warped strangely then you’ve messed up one of the constants. You just have to figure out which one.

Or you’ve messed up your camera settings.

If only some things are warped then you are somehow sharing state between your spatials in a strange way. Strange because normally JME will not let you do this.

As to the FPS thing, it’s just acting like you toggled them off somehow.

It’s strange because you are the only one to have seen issues like that but we can’t really see enough of your code to drill into it in detail.

Thank you Paul, I write a new test app with your advices.

  1. Not everything is strangely, but many of the monster models were crooked. I upload pics of a “good” one and some “bad” ones.

  2. I print the cam settings in console, it looks just fine.

  3. For each Ase model, I create a Node with name"Ase_Model_***", and attach Geometry objects to it. some of them shared materils.

I’m now translate Chinese comments into English, then i will upload my ase plugin to github.

public class TestLoadMob extends SimpleApplication {

    public static void main(String[] args) {
        TestLoadMob app = new TestLoadMob();
        app.setPauseOnLostFocus(false);
        app.start();
    }

    @Override
    public void simpleInitApp() {
        System.out.println("Before");
        System.out.println("Loc:" + cam.getLocation() + " Rotation:" + cam.getRotation() + " Direction:" + cam.getDirection() + " Up:" + cam.getUp());
        System.out.println("ZERO:" + Vector3f.ZERO + " X:" + Vector3f.UNIT_X + " Y:" + Vector3f.UNIT_Y + " Z:" + Vector3f.UNIT_Z + " XYZ:" + Vector3f.UNIT_XYZ);
        
        assetManager.registerLoader(AseLoader.class, "ase");
        // This is my working folder.
        assetManager.registerLocator("D:/Priston Tale/0_素材/Client", FileLocator.class);
        
        AmbientLight light = new AmbientLight();
        light.setColor(ColorRGBA.White);
        rootNode.addLight(light);
        
        Spatial mob = assetManager.loadAsset(new AseKey("char/monster/death_knight/death_knight.ASE"));
        mob.scale(0.05f);
        rootNode.attachChild(mob);
        
        System.out.println("After");
        System.out.println("Loc:" + cam.getLocation() + " Rotation:" + cam.getRotation() + " Direction:" + cam.getDirection() + " Up:" + cam.getUp());
        System.out.println("ZERO:" + Vector3f.ZERO + " X:" + Vector3f.UNIT_X + " Y:" + Vector3f.UNIT_Y + " Z:" + Vector3f.UNIT_Z + " XYZ:" + Vector3f.UNIT_XYZ);
        
    }
    
    @Override
    public void simpleUpdate(float tpf) {
        super.simpleUpdate(tpf);
    }

}




Here it the link to github.JPsTale-AsePlugin

Thank you Normen. Thank you Paul.
I made another test case, thinking maybe i have found whats wrong. The Quaternion.IDENTITY has been chaged.

It’s the animation part. I defined a class KeyFrame, using some statics as init value. And in AseLoader I changed their value with set(…) method. That why some model was crooked while others are normal. The normal ones do not have animation data…so my code didn’t change the statics. :sweat:

package org.pstale.asset.animation;

import java.io.Serializable;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;

public class Keyframe implements Serializable {
    public Vector3f translation = Vector3f.ZERO;
    public Quaternion rotation = Quaternion.IDENTITY;
    public Vector3f scale = Vector3f.UNIT_XYZ;
}

Fixed KeyFrame, directly new Vector3f & Quaternion instead of using statics.

package org.pstale.asset.animation;

import java.io.Serializable;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;

public class Keyframe implements Serializable {

    public Vector3f translation = new Vector3f(0, 0, 0);
    public Quaternion rotation = new Quaternion(0, 0, 0, 1);
    public Vector3f scale = new Vector3f(1, 1, 1);

}

Probably:

…and then you must get the rotation later and modify it without cloning it. In general, NEVER set constants to mutable fields.

Yes, I have fixed it. Thank you.

Now DK looks much better. :kissing_heart: