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. 
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);
}
}