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),所以要实现这个是非常easy的了。仅仅需依据自己的须要修改原demo。整合到自己的project下就可以,这里我修改原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"; } }