想使用java3d显示3d模型,就在网上搜索一番,发现有个作者写的已经实现了,如下:
实验后发现显示的模型没有纹理贴图。又以java3d显示纹理贴图搜索到一篇博客Java3D导入obj和3ds模型整理,使用后还是没有显示出纹理,以为是从网上下载的obj模型文件的问题,就安装了3dmax2019后自己手动把max模型导出成obj格式。
复制文件时偶然间把路径写成了"F:\\tmp\\obj\\taibainv\\aaa.obj"
而非"F:/tmp/obj/taibainv/aaa.obj"
,发现竟然成功显示模型贴图了!!又试了下"F:\\tmp\\obj\\taibainv/aaa.obj"
却不能正常显示。跟踪两种情况的代码执行,发现原因就在于com.sun.j3d.loaders.objectfile.ObjectFile的basePath属性,而该属性是由com.sun.j3d.loaders.objectfile.ObjectFile.setBasePathFromFilename赋值的,idea反编译该方法如下:
private void setBasePathFromFilename(String var1) {
if(var1.lastIndexOf(File.separator) == -1) {
this.setBasePath("." + File.separator);
} else {
this.setBasePath(var1.substring(0, var1.lastIndexOf(File.separator)));
}
}
原来是File.separator的问题。统一把路径中的/
换成File.separator
就好了。
尽管"F:/tmp/obj/taibainv/aaa.obj"
在windows系统下能访问到文件,但是在这里竟然出了坑。
好,问题解决!
附上文件(共两个java文件,一个模型文件):
- JavaModelObjLoaderSimpleWithKeyControl.java
- ObjFileReader.java
- 模型文件:https://gitee.com/valuetodays/ellen/tree/master/blog-attachment/eblog/20181208
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.*;
import javax.swing.*;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Enumeration;
/**
* 显示并控制单个模型
* LEFT/RIGHT 旋转模型
* HOME/END 缩放模型
*
*/
public class JavaModelObjLoaderSimpleWithKeyControl extends JFrame {
private static final long serialVersionUID = 207092618323821865L;
public class MyBehavior extends Behavior {
private TransformGroup transformGroup;
private Transform3D rotation = new Transform3D();
private double angleY = 0.0;
private double angleX = 0.0;
private double scale = 1.0;
public MyBehavior(TransformGroup transformGroup) {
this.transformGroup = transformGroup;
}
@Override
public void initialize() {
this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
}
@Override
public void processStimulus(Enumeration enumeration) {
AWTEvent[] event = null;
WakeupCriterion wakeupCriterion = (WakeupCriterion) enumeration.nextElement();
if (wakeupCriterion instanceof WakeupOnAWTEvent) {
event = ((WakeupOnAWTEvent) wakeupCriterion).getAWTEvent();
KeyEvent keyEvent = (KeyEvent) event[0];
if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT) {
angleY -= 0.1;
} else if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
angleY += 0.1;
} else if (keyEvent.getKeyCode() == KeyEvent.VK_HOME) {
scale = rotation.getScale()*0.9d;
} else if (keyEvent.getKeyCode() == KeyEvent.VK_END) {
scale = rotation.getScale()/0.9d;
}
rotation.rotY(angleY);
rotation.setScale(scale);
transformGroup.setTransform(rotation);
}
this.wakeupOn(new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
}
}
public BranchGroup createSceneGraph() {
// 创建场景图分支
BranchGroup group = new BranchGroup();
// 几何变换组节点
TransformGroup transGroup = new TransformGroup();
// 几何变换
Transform3D trans3d = new Transform3D();
// 缩放变换
trans3d.setScale(0.8);
//将几何变换节点对象添加到节点组
transGroup.setTransform(trans3d);
//将几何变化组添加到场景
group.addChild(transGroup);
// 球体作用范围边界对象
BoundingSphere bound = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
Color3f bgColor = new Color3f(0.05f, 0.05f, 0.2f);
Background bg = new Background(bgColor);
bg.setApplicationBounds(bound);
group.addChild(bg);
// 设置光源
Color3f lightColor = new Color3f(1.0f, 1.0f, 0.9f);
Vector3f lightDirection = new Vector3f(4.0f, -7.0f, -12.0f);
//设置定向光的颜色和影响范围
DirectionalLight light = new DirectionalLight(lightColor, lightDirection);
light.setInfluencingBounds(bound);
//将光源添加到场景
group.addChild(light);
//几何变换组节点 - 加载外部模型
TransformGroup objTrans = new TransformGroup();
objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
//加载Obj格式的模型文件 如下路径使用一个风格,要么全使用\\,要么使用/
// String resourcePath = "F:\\tmp\\obj\\taibainv\\aaa.obj"; // 显示纹理
String resourcePath = "F:/tmp/obj/taibainv/aaa.obj"; // 不显示纹理
objTrans.addChild(new ObjFileReader(resourcePath));
//将模型添加到变换组节点
transGroup.addChild(objTrans);
MyBehavior myBehavior = new MyBehavior(objTrans);
myBehavior.setSchedulingBounds(new BoundingSphere());
group.addChild(myBehavior);
group.compile();
return group;
}
public JavaModelObjLoaderSimpleWithKeyControl() {
// 创建3D场景绘制画布Canvas3D对象
Canvas3D canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
BranchGroup scene = createSceneGraph();
SimpleUniverse universe = new SimpleUniverse(canvas);
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(scene);
this.add(canvas);
this.setVisible(true);
this.setPreferredSize(new Dimension(300, 500));
this.setLocation(100, 50);
this.pack();
}
public static void main(String[] args) {
new JavaModelObjLoaderSimpleWithKeyControl();
}
}
import com.sun.j3d.loaders.Scene;
import com.sun.j3d.loaders.objectfile.ObjectFile;
import javax.media.j3d.BranchGroup;
public class ObjFileReader extends BranchGroup {
private double creaseAngle = 60.0;
/**
*
* 读取ObjModel文件
*
* @param filePath obj文件路径
*/
public ObjFileReader(String filePath) {
BranchGroup branchGroup = new BranchGroup();
int flags = ObjectFile.RESIZE;
ObjectFile objFile = new ObjectFile(flags, (float)(creaseAngle*Math.PI)/180);
Scene scenen = null;
try {
scenen = objFile.load(filePath);
} catch (Exception e) {
e.printStackTrace();
System.out.println("OBJ模型加载失败" + e.getMessage());
}
branchGroup.addChild(scenen.getSceneGroup());
this.addChild(branchGroup);
}
}