World Wind Java开发之十五——加载三维模型
目录
之前的一篇博客是关于加载粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能加载纹理的问题,一直没呢解决。那么WW如何加载常用的三维模型格式(3ds、obj、skp)呢,通过一番搜索,了解到WW可以加载collada的dae格式的三维模型,并且还可以加载kml\kmz文件,那么WW加载三维模型的方法就出来了:首先将其他格式三维模型转换为kmz或kml文件,再加载。这里我是从su的三维模型库中下载的skp文件,在su中可以直接转换为kmz文件,通过测试,这个方法是可行的。先来看下效果图:
1.效果图
第一幅是德国标志性建筑——柏林奥林匹克体育场,可以看到效果还是可以的,不过没有使用lod技术,一旦模型数量增多,会卡顿。
第二幅是也是德国地标性建筑——柏林电视塔。
第三幅是3D City DB上的德国柏林一些collada三维模型,需要的可以去下载做下测试
2.实现方法
开头已经明确了WW加载三维模型的路线,WW又提供了加载kml/kmz文件的demo(KMLViewer),所以要实现这个是很简单的了,只需根据自己的需要改动原demo,整合到自己的工程下即可,这里我改动原demo,编写了SmartScopeKMLViewer,方法参见之前的博客。所用到的数据,整理完上传到CSDN资源,需要的可以去下载。下载地址:http://download.csdn.net/detail/liushuo_whu/8512739
3.源代码
/*
Copyright (C) 2001, 2010 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwindx.examples.kml;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.awt.WorldWindowGLCanvas;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.ogc.kml.KMLAbstractFeature;
import gov.nasa.worldwind.ogc.kml.KMLRoot;
import gov.nasa.worldwind.ogc.kml.impl.KMLController;
import gov.nasa.worldwind.render.Offset;
import gov.nasa.worldwind.retrieve.RetrievalService;
import gov.nasa.worldwind.util.WWIO;
import gov.nasa.worldwind.util.WWUtil;
import gov.nasa.worldwind.util.layertree.KMLLayerTreeNode;
import gov.nasa.worldwind.util.layertree.KMLNetworkLinkTreeNode;
import gov.nasa.worldwind.util.layertree.LayerTree;
import gov.nasa.worldwindx.examples.util.BalloonController;
import gov.nasa.worldwindx.examples.util.HotSpotController;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.swing.SwingUtilities;
import javax.xml.stream.XMLStreamException;
/**
* 导入KML或KMZ文件,以图层形式查看,KML或KMZ文件的内容显示为一个要素树。在要素树上点击KML要素可以查看该要素
* ,在球上点击要素可以弹出要素的描述信息框
*/
public class SmartScopeKMLViewer
{
public static class KMLUtil
{
protected LayerTree layerTree; // 图层树
protected RenderableLayer hiddenLayer; // 渲染图层(图层树)
protected HotSpotController hotSpotController; // 热点controller
protected KMLApplicationController kmlAppController; // KMLcontroller
protected BalloonController balloonController; // BalloonController
protected WorldWindowGLCanvas wwd; // ww
public KMLUtil(WorldWindowGLCanvas worldWindowGLCanvas)
{
this.wwd = worldWindowGLCanvas;
// 初始化图层树
this.layerTree = new LayerTree(new Offset(20d, 160d, AVKey.PIXELS,
AVKey.INSET_PIXELS));
// this.layerTree.getModel().refresh(this.wwd.getModel().getLayers());
// 图层树渲染图层
this.hiddenLayer = new RenderableLayer();
this.hiddenLayer.addRenderable(this.layerTree);
this.wwd.getModel().getLayers().add(this.hiddenLayer);
// 注册图层选择和气球热点选择事件监听
this.hotSpotController = new HotSpotController(this.wwd);
// 注册kml事件监听
this.kmlAppController = new KMLApplicationController(this.wwd);
this.balloonController = new BalloonController(this.wwd)
{
@Override
protected void addDocumentLayer(KMLRoot document)
{
addKMLLayer(document);
}
};
// 关联kml管理器和balloon管理器
this.kmlAppController.setBalloonController(balloonController);
// Set up to receive SSLHandshakeExceptions that occur during
// resource retrieval.
WorldWind.getRetrievalService().setSSLExceptionListener(
new RetrievalService.SSLExceptionListener()
{
public void onException(Throwable e, String path)
{
System.out.println(path);
System.out.println(e);
}
});
}
/**
*
* @方法名称: addKMLLayer ;
* @方法描述: 添加KML图层: ;
* @参数 :@param kmlRoot
* @返回类型: void ;
* @创建人:bluce ;
* @创建时间:2015年3月17日 下午7:54:40;
* @throws
*/
protected void addKMLLayer(KMLRoot kmlRoot)
{
// Create a KMLController to adapt the KMLRoot to the World Wind
KMLController kmlController = new KMLController(kmlRoot);
// 添加kml图层
RenderableLayer layer = new RenderableLayer();
layer.setName((String) kmlRoot.getField(AVKey.DISPLAY_NAME));
layer.addRenderable(kmlController);
this.wwd.getModel().getLayers().add(layer);
// 添加kml图层树节点
KMLLayerTreeNode layerNode = new KMLLayerTreeNode(layer, kmlRoot);
this.layerTree.getModel().addLayer(layerNode);
this.layerTree.makeVisible(layerNode.getPath());
layerNode.expandOpenContainers(this.layerTree);
// Listens to refresh property change events from KML network link
// nodes. Upon receiving such an event this
// expands any tree paths that represent open KML containers. When a
// KML network link refreshes, its tree
// node replaces its children with new nodes created from the
// refreshed content, then sends a refresh
// property change event through the layer tree. By expanding open
// containers after a network link refresh,
// we ensure that the network link tree view appearance is
// consistent with the KML specification.
layerNode.addPropertyChangeListener(
AVKey.RETRIEVAL_STATE_SUCCESSFUL,
new PropertyChangeListener()
{
public void propertyChange(
final PropertyChangeEvent event)
{
if (event.getSource() instanceof KMLNetworkLinkTreeNode)
{
// Manipulate the tree on the EDT.
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
((KMLNetworkLinkTreeNode) event
.getSource())
.expandOpenContainers(layerTree);
wwd.redraw();
}
});
}
}
});
}
}
/**
*
* @项目名称:worldwind-1.5.0
* @类名称:WorkerThread
* @类描述:加载KML文件线程类
* @创建人:bluce
* @创建时间:2015年3月17日 下午7:58:38
* @修改备注:
* @版本:
*/
public static class WorkerThread extends Thread
{
/**
* 待加载kml文件,在构造函数中初始化
*/
protected Object kmlSource;
/**
* kmlapp
*/
protected KMLUtil KMLUtil;
public WorkerThread(Object kmlSource, KMLUtil KMLUtil)
{
this.kmlSource = kmlSource;
this.KMLUtil = KMLUtil;
}
/**
* Loads this worker thread's KML source into a new
* <code>{@link gov.nasa.worldwind.ogc.kml.KMLRoot}</code>, then adds
* the new <code>KMLRoot</code> to this worker thread's
* <code>AppFrame</code>. The <code>KMLRoot</code>'s
* <code>AVKey.DISPLAY_NAME</code> field contains a display name created
* from either the KML source or the KML root feature name.
* <p/>
* If loading the KML source fails, this prints the exception and its
* stack trace to the standard error stream, but otherwise does nothing.
*/
public void run()
{
try
{
KMLRoot kmlRoot = this.parse();
// 设置文档的显示名称
kmlRoot.setField(AVKey.DISPLAY_NAME,
formName(this.kmlSource, kmlRoot));
// 启动一个任务进程加载解析的kml文件
final KMLRoot finalKMLRoot = kmlRoot;
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
KMLUtil.addKMLLayer(finalKMLRoot);
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
*
* @方法名称: parse ;
* @方法描述: 解析KML文档 ;
* @参数 :@return 返回KMLRoot
* @参数 :@throws IOException:文档不可读
* @参数 :@throws XMLStreamException :文档解析出现错误
* @返回类型: KMLRoot ;
* @创建人:bluce ;
* @创建时间:2015年3月17日 下午8:02:59;
* @throws
*/
protected KMLRoot parse() throws IOException, XMLStreamException
{
// KMLRoot.createAndParse will attempt to parse the document using a
// namespace aware parser, but if that
// fails due to a parsing error it will try again using a namespace
// unaware parser. Note that this second
// step may require the document to be read from the network again
// if the kmlSource is a stream.
return KMLRoot.createAndParse(this.kmlSource);
}
}
protected static String formName(Object kmlSource, KMLRoot kmlRoot)
{
KMLAbstractFeature rootFeature = kmlRoot.getFeature();
if (rootFeature != null && !WWUtil.isEmpty(rootFeature.getName()))
return rootFeature.getName();
if (kmlSource instanceof File)
return ((File) kmlSource).getName();
if (kmlSource instanceof URL)
return ((URL) kmlSource).getPath();
if (kmlSource instanceof String
&& WWIO.makeURL((String) kmlSource) != null)
return WWIO.makeURL((String) kmlSource).getPath();
return "KML Layer";
}
}
转载自:https://blog.csdn.net/giser_whu/article/details/44418607