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

You may also like...