This page has been translated automatically.
视频教程
界面
要领
高级
实用建议
基础
专业(SIM)
UnigineEditor
界面概述
资源工作流程
Version Control
设置和首选项
项目开发
调整节点参数
Setting Up Materials
设置属性
照明
Sandworm
使用编辑器工具执行特定任务
如何擴展編輯器功能
嵌入式节点类型
Nodes
Objects
Effects
Decals
光源
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
编程
基本原理
搭建开发环境
C++
C#
UnigineScript
统一的Unigine着色器语言 UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
材质和着色器
Rebuilding the Engine Tools
GUI
双精度坐标
应用程序接口
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
创建内容
内容优化
材质
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials

自定义导入插件

UNIGINE's Import System allows you to import models and scenes in various external formats (FBX, DAE, OBJ, etc.). Although the basic set of file formats supported by UNIGINE out-of-the-box includes the most commonly used ones, in some cases you may need to import models or scenes in some specific file format. Fortunately, the Import System can be extended to support any custom file format.UNIGINE的导入系统允许您以各种外部格式(FBX, DAE, OBJ等)导入模型和场景。尽管UNIGINE开箱即用支持的基本文件格式集包括最常用的文件格式,但在某些情况下,您可能需要以某些特定的文件格式导入模型或场景。幸运的是,可以扩展导入系统以支持任何自定义文件格式。

This example demonstrates how to:这个例子演示了如何:

  • Implement your own custom importer as a plugin.作为插件实现您自己的自定义导入器。
  • Create your own import pre-processor.创建您自己的导入预处理器。
  • Use your custom importer to bring a scene stored in a custom file format to UNIGINE.使用自定义导入器将场景以自定义文件格式存储到UNIGINE中。
注意
It is recommended that you've read the Import System article and familiarized with basic import functionality classes.建议您已经阅读了 Import System文章,并熟悉了基本的导入功能类

So, in this example, we are going to create a custom importer for a custom file format. Let it be an XML-based format in which we declare our scene as a hierarchy of nodes that have a transformation and can have a mesh, light, or camera attribute. Let our file format have a .myext extension. An example of a scene in our custom format containing all available elements is given below.因此,在本例中,我们将为自定义文件格式创建一个自定义导入器。让它成为一种基于xml的格式,在这种格式中,我们将场景声明为具有转换的节点层次结构,并且可以具有mesh、light或camera属性。让我们的文件格式有一个.myext扩展名。下面是一个包含所有可用元素的自定义格式的场景示例。

my_scene.myext

源代码 (XML)
<?xml version="1.0"?>
<scene name="my_custom_scene">
	<node name="root">
		<node name="Mesh1">
			<attribute type="mesh">
				<surfaces>
					<surface name="cube_surface1" offset="0" size="12"/>
					<surface name="cube_surface2" offset="12" size="12"/>
					<surface name="cube_surface3" offset="24" size="12"/>
				</surfaces>
				<vertices>
					<vertex>0.0 0.0 0.0</vertex>
					<vertex>0.0 1.0 0.0</vertex>
					<vertex>1.0 1.0 0.0</vertex>
					<vertex>1.0 0.0 0.0</vertex>
					<vertex>0.0 0.0 1.0</vertex>
					<vertex>0.0 1.0 1.0</vertex>
					<vertex>1.0 1.0 1.0</vertex>
					<vertex>1.0 0.0 1.0</vertex>
				</vertices>
				<indices num_indices="36">0 1 2 2 3 0 4 7 6 6 5 4 3 2 6 6 7 3 4 5 1 1 0 4 4 0 3 3 7 4 5 6 2 2 1 5</indices>
			</attribute>
			<transform>1 0 0 0.0 0 1 0 0.0 0 0 1 0.0 -0.5 -1 0.0 1.0</transform>
		</node>
		<node name="OmniLight1">
			<attribute type="light">
				<light_type>LIGHT_OMNI</light_type>
				<color>0.0 1.0 0.0 1.0</color>
				<intensity>0.5f</intensity>
			</attribute>
			<transform>1 0 0 0.0 0 1 0 0.0 0 0 1 0.0 5.0 5.0 5.0 1.0</transform>
		</node>
		<node name="OmniLight2">
			<attribute type="light">
				<light_type>LIGHT_OMNI</light_type>
				<color>0.0 0.0 1.0 1.0</color>
				<intensity>0.5f</intensity>
			</attribute>
			<transform>1 0 0 0.0 0 1 0 0.0 0 0 1 0.0 -5.0 5.0 5.0 1.0</transform>
		</node>
		<node name="ProjectedLight1">
			<attribute type="light">
				<light_type>LIGHT_PROJ</light_type>
				<color>1.0 0.0 0.0 1.0</color>
				<intensity>1.0f</intensity>
			</attribute>
			<transform>1 0 0 0.0 0 1 0 0.0 0 0 1 5.0 0 0 3.0 1.0</transform>
		</node>
		<node name="my_camera">
			<attribute type="camera">
				<camera_type>TYPE_PERSPECTIVE</camera_type>
				<near>0.001f</near>
				<far>10000.0f</far>
				<fov>60.0f</fov>
				<target>10.0 10.0 10.0</target>
			</attribute>
			<transform>1 0 0 0.0 0 1 0 0.0 0 0 1 0.0 0.0 -2.0 2.0 1.0</transform>
		</node>
	</node>
</scene>

For our importer, we're going to create and use a custom pre-processor to reset light colors to white when the corresponding flag is set. Thus, we're going to have the following import options and parameters:对于我们的导入器,我们将创建并使用自定义预处理器,以便在设置相应的标志时将浅色重置为白色。因此,我们将拥有以下导入选项和参数:

  • scale - scale factor to be used for imported scenescale - 用于导入场景的比例因子
  • vertex_cache - vertex cache optimization for meshesvertex_cache - 顶点缓存优化网格
  • make_lights_white - reset light colors flag for our pre-processormake_lights_white - 为我们的预处理器重置光的颜色标志

At the end of this example, we're going to have this model imported to UNIGINE's world and saved in UNIGINE's native file formats in the specified folder. But before we get started, a little bit of theory (as key points).在这个例子的最后,我们将把这个模型导入到UNIGINE的世界中,并以UNIGINE的本地文件格式保存在指定的文件夹中。但在我们开始之前,有一点理论(作为关键点)。

  • UNIGINE's API offers us a set of classes for implementing customized model import.UNIGINE的API为我们提供了一组来实现自定义的模型导入。
  • All meta information about your imported scene should be stored in an instance of the ImportScene class. Basically a scene may contain meshes (ImportMesh), lights (ImportLight), cameras (ImportCamera), and other elements (see the complete list here). You can specify which of these scene components are to be imported using the corresponding import flags (IMPORT_MESHES, IMPORT_LIGHTS, etc.)有关导入场景的所有元信息都应存储在 ImportScene 类的实例中。 基本上,场景可能包含网格体 (ImportMesh)、灯光 (ImportLight)、摄像机 (ImportCamera) 和其他元素(请参阅此处的完整列表)。 您可以使用相应的导入标志指定要导入哪些场景组件(IMPORT_MESHES, IMPORT_LIGHTS等)。
  • A custom importer should be inherited from the Importer class.自定义导入器应该从Importer类继承。
  • A custom import processor should be inherited from the ImportProcessor class.自定义导入处理器应该从ImportProcessor类继承。

Enough words! Let's get to business! The code below is supplemented with comments explaining the basic aspects of the process.足够的单词!我们开始谈正事吧!下面的代码补充了解释该过程基本方面的注释。

Making a Plugin
制作插件#

As you know, each importer should be implemented as a plugin. So, we're going to create a C++ plugin.如您所知,每个导入器都应该作为插件实现。我们将创建一个C++插件。

注意
To learn more about creating a C++ plugin, please, refer to this article.要了解有关创建 C++ 插件的更多信息,请参阅本文

First, we inherit our import plugin from the Plugin class. Then we specify a plugin name by overriding the get_name() method and also override the init() and shutdown() methods to perform initialization and cleanup. As a result, we will have the following header file:首先,我们从Plugin类继承了import插件。然后,我们通过覆盖get_name()方法来指定插件名称,还覆盖init()shutdown()方法来执行初始化和清理。因此,我们将得到以下头文件:

MyImportPlugin.h

源代码 (C++)
#pragma once
#include <UniginePlugin.h>
#include <UnigineVector.h>

struct MyImporterParameters;

class MyImportPlugin : public Unigine::Plugin
{
protected:
	// specifying our plugin's name
	const char *get_name() override;

	// overriding methods for initialization and cleanup on shutdown
	int init() override;
	int shutdown() override;

private:
	MyImporterParameters *importer_parameters{ nullptr };
	Unigine::Vector<void *> registered_importers;
	Unigine::Vector<void *> registered_processors;
};

As for plugin implementation, it's also simple. We include the header files for our importer and processor (MyImporter.h and MyImportProcessor.h) in addition to the plugin header file, implement plugin initialization and cleanup, and export the plugin.至于插件的实现,也很简单。除了插件头文件外,我们还包括了导入器和处理器的头文件(MyImporter.hMyImportProcessor.h),实现了插件初始化和清理,并导出了插件。

MyImportPlugin.cpp

源代码 (C++)
#include "MyImportPlugin.h"
#include "MyImporter.h" // our importer's header file
#include "MyImportProcessor.h" // our import processor's header file 

struct MyImporterParameters
{
	Unigine::String string_parameter;
};

namespace
{

	Unigine::Importer *importer_creator(void *args)
	{
		auto parameters = static_cast<MyImporterParameters *>(args);
		Unigine::Log::message("ImporterParameter: %s\n", parameters->string_parameter.get());
		return new MyImporter();
	}
	void importer_deletor(Unigine::Importer *importer, void *) { delete static_cast<MyImporter *>(importer); }

	Unigine::ImportProcessor *processor_creator(void *) { return new MyImportProcessor(); }
	void processor_deletor(Unigine::ImportProcessor *processor, void *) { delete processor; }

}

const char *MyImportPlugin::get_name()
{
	return "MyImportPlugin";
}

// plugin initialization
int MyImportPlugin::init()
{
	importer_parameters = new MyImporterParameters();
	importer_parameters->string_parameter = "MyStringParameter";

	// registering our custom importer and import processor
	for (const auto &ext : MyImporter::getExtensions())
	{
		registered_importers.append(Unigine::Import::registerImporter("MyVendorName", "MyImporter", ext, importer_creator, importer_deletor, importer_parameters));
	}

	if (!Unigine::Import::containsImportProcessor("MyImportProcessor"))
	{
		registered_processors.append(Unigine::Import::registerImportProcessor("MyImportProcessor", processor_creator, processor_deletor));
	}

	return 1;
}

// plugin cleanup on shutdown
int MyImportPlugin::shutdown()
{
	// removing our custom importer and import processor from the registry
	for (void *handle : registered_importers)
		Unigine::Import::unregisterImporter(handle);
	registered_importers.clear();

	for (void *handle : registered_processors)
		Unigine::Import::unregisterImportProcessor(handle);
	registered_processors.clear();

	delete importer_parameters;
	importer_parameters = nullptr;

	return 1;
}

extern "C"
{

	UNIGINE_EXPORT void *CreatePlugin()
	{
		return new MyImportPlugin();
	}

	UNIGINE_EXPORT void ReleasePlugin(void *plugin)
	{
		delete static_cast<MyImportPlugin *>(plugin);
	}

}

Implementing Import Functionality
实现导入功能#

First, we should define some intermediate data structures to which all parameters of the imported scene elements are to be extracted.首先,我们应该定义一些中间数据结构,将导入的场景元素的所有参数提取到这些数据结构中。

Auxiliary Data Structures辅助数据结构

源代码 (C++)
#pragma once
#include <UnigineMathLib.h>
#include <UnigineString.h>
#include <UnigineVector.h>

using namespace Unigine;

// camera metadata structure
struct MyCamera
{
	String type;
	float near_plane;
	float far_plane;
	float fov;
	Math::vec3 target;
};

// light metadata structure
struct MyLight
{
	String type;
	float intensity;
	Math::vec4 color;
};

// mesh metadata structure
struct MyMesh
{
	String type;
	Vector<String> surfaces;	
	Vector<Math::ivec3> polygons;
	Vector<Math::vec3> vertices;
	Vector<int> indices;
};

The general workflow will be as follows:一般的工作流程如下:

  1. Create an ImportScene instance within the override of the Importer::onImport() method:Importer::onImport()方法的覆盖中创建一个ImportScene实例:

    MyImporter.cpp

    源代码 (C++)
    bool MyImporter::onInit(const ImportScenePtr &scene, const char *filepath)
    {
    	// getting all necessary import parameters and making necessary preparations for scene import
    	scale = getParameterFloat("scale");
    
    	String filesystem_filepath = FileSystem::getAbsolutePath(filepath);
    	my_scene = Xml::create();
    	my_scene->load(filesystem_filepath);
    
    	Log::message("\n\nLAUNCHING IMPORTING PROCESS... \n");
    
    	// parse input file and fill metadata structures
    	return import_scene(scene);
    }
  2. Extract data from the input file, put it to the corresponding import structures (ImportMesh, ImportLight, etc.) and add them to the scene.从输入文件中提取数据,将其放入相应的导入结构(ImportMesh, ImportLight等)中,并将其添加到场景中。

    Our XML file parsing is implemented in the MyImporter::import_scene() and MyImporter::process_node() functions:XML文件解析是在MyImporter::import_scene()MyImporter::process_node()函数中实现的:

    MyImporter.cpp

    源代码 (C++)
    bool MyImporter::import_scene(const ImportScenePtr &import_scene)
    {
    	// performing necessary checks on file format
    	String n = my_scene->getName();
    	if (n != "scene")
    	{
    		Log::error("Scene loader: bad my_scene format\n");
    		return 0;
    	}
    
    	// checking scene name
    	String name = my_scene->getArg("name");
    	if (name.empty())
    	{
    		Log::error("Scene loader: scene name can't be empty\n");
    		return 0;
    	}
    	// parsing the input file and filling the ImportScene 
    	auto num_nodes = my_scene->getNumChildren();
    	Log::message("Importing [%s] scene num_nodes = %d\n", name.get(), num_nodes);
    	for (int i = 0; i < num_nodes; i++)
    	{
    		const XmlPtr child_xml = my_scene->getChild(i);
    		const String &child_name = child_xml->getName();
    
    		if (child_name == "node")
    		{
    			process_node(import_scene, nullptr, child_xml);
    		}
    		else
    		{
    			Log::error("Scene loader: unknown element \"%s\" in the \"%s\" scene\n",
    				child_name.get(), name.get());
    		}
    	}
    
    	return true;
    }

    MyImporter.cpp

    源代码 (C++)
    void MyImporter::process_node(const ImportScenePtr &import_scene, const ImportNodePtr &parent,
    XmlPtr scene_node)
    {
    	ImportNodePtr node = import_scene->addNode(parent);
    	node->setName(scene_node->getArg("name"));
    	if (scene_node->getChild("transform"))
    	{
    		Math::dmat4 transform = scene_node->getChild("transform")->getDMat4Data();
    		transform.m03 *= scale;
    		transform.m13 *= scale;
    		transform.m23 *= scale;
    		node->setTransform(transform);
    	}
    
    	// processing node attributes
    	XmlPtr attribute = scene_node->getChild("attribute");
    	if (attribute)
    	{
    		String attr_type = attribute->getArg("type");
    		if (attr_type == "light")
    		{
    			// creating and filling light metadata
    			MyLight *light = new MyLight();
    			lights.append(light);
    			light->type = attribute->getChildData("light_type");
    			light->color = attribute->getChild("color")->getVec4Data();
    			light->intensity = attribute->getChild("intensity")->getFloatData();
    
    			// processing light metadata and adding ImportLight to the scene
    			process_light(import_scene, node, light);
    
    			Log::message("Artribute light: named %s , type %s, color (%f, %f, %f, %f)\n",
    				node->getName(), light->type.get(),
    				light->color.x, light->color.y, light->color.z, light->color.w);
    		}
    		else if (attr_type == "camera")
    		{
    			// creating and filling camera metadata
    			MyCamera *camera = new MyCamera();
    			cameras.append(camera);
    
    			camera->type = attribute->getChildData("player_type");
    			camera->fov = attribute->getChild("fov")->getFloatData();
    			camera->near_plane = attribute->getChild("near")->getFloatData();
    			camera->far_plane = attribute->getChild("far")->getFloatData();
    			camera->target = attribute->getChild("target")->getVec3Data();
    
    			// processing camera metadata and adding ImportCamera to the scene
    			process_camera(import_scene, node, camera);
    			Log::message("Artribute camera: named %s , type %s, target (%f, %f, %f)\n",
    				node->getName(), camera->type.get(),
    				camera->target.x, camera->target.y, camera->target.z);
    		}
    		else if (attr_type == "mesh")
    		{
    			// creating and filling mesh metadata
    			MyMesh *mesh = new MyMesh();
    			meshes.append(mesh);
    
    			int num_surfaces = attribute->getChild("surfaces")->getNumChildren();
    			int num_vertices = attribute->getChild("vertices")->getNumChildren();
    
    			Log::message("Artribute mesh: named %s , %d surfaces, %d vertices\n",
    				node->getName(), num_surfaces, num_vertices);
    
    			// getting all surfaces
    			for (int i = 0; i < num_surfaces; ++i) {
    				XmlPtr xml_surf = attribute->getChild("surfaces")->getChild(i);
    				mesh->surfaces.append(xml_surf->getArg("name"));
    				// filling polygons data
    				mesh->polygons.append(
    					Math::ivec3(i, xml_surf->getIntArg("offset"), xml_surf->getIntArg("size")));
    				Log::message("\nSurface [%d] named: %s\n", i, mesh->surfaces[i].get());
    			}
    			// getting all vertices
    			for (int i = 0; i < num_vertices; ++i)
    			{
    				mesh->vertices.append(attribute->getChild("vertices")->getChild(i)->getVec3Data());
    
    				Log::message("Vertex [%d] coordinates:(%f, %f, %f)\n",
    					i, mesh->vertices[i].x, mesh->vertices[i].y, mesh->vertices[i].z);
    			}
    			// getting all indices
    			XmlPtr indices_xml = attribute->getChild("indices");
    			int num_indices = indices_xml->getIntArg("num_indices");
    
    			mesh->indices.resize(num_indices);
    			indices_xml->getIntArrayData(mesh->indices.get(), num_indices);
    
    			// processing mesh metadata and adding ImportMesh to the scene
    			process_mesh(import_scene, node, mesh);
    		}
    	}
    
    	// processing all node's children
    	int num_children = scene_node->getNumChildren();
    	for (int i = 0; i lt; num_children; ++i) {
    		XmlPtr child = scene_node->getChild(i);
    		const String &child_name = child->getName();
    		if (child_name == "node")
    			process_node(import_scene, node, child);
    	}
    }

    Scene components are added to the hierarchy in the corresponding MyImporter::process_*() methods. For example, for lights we'll have:场景组件在相应的MyImporter::process_*()方法中添加到层次结构中。例如,对于灯,我们有:

    MyImporter.cpp

    源代码 (C++)
    void MyImporter::process_light(const ImportScenePtr &import_scene, const ImportNodePtr &node, MyLight *my_light)
    {
    	Log::message("\n FUNCTION: process_light() reporting... \n");
    	// checking if the light import flag is set
    	if ((getFlags() & IMPORT_LIGHTS) == 0)
    		return;
    
    	// adding a light source to the scene and setting lignt source data
    	ImportLightPtr light = import_scene->addLight(node);
    	light->setData(my_light);
    }
  3. Use pre-processor(s) to prepare scene metadata when necessary (e.g. merge all static meshes into a single one, optimize vertex cache, etc.). In our example, we're going to strip off light color information if the corresponding option (make_lights_white) is set.必要时使用预处理器来准备场景元数据(例如,将所有静态网格合并为一个,优化顶点缓存等)。在我们的示例中,如果设置了相应的选项(make_lights_white),我们将剥离光的颜色信息。

    For a pre-processor, we should only override the ImportProcessor::onProcessScene() method.对于预处理器,我们应该只重写ImportProcessor::onProcessScene()方法。

    Custom Pre-Processor

    源代码 (C++)
    #pragma once
    #include <UnigineImport.h>
    
    // inheriting our custom pre-processor from the ImportProcessor;
    // as it is a pre-processor we should only override the onProcessScene() method
    class MyImportProcessor : public Unigine::ImportProcessor
    {
    protected:
    	bool onProcessScene(const Unigine::ImportScenePtr &scene) override;
    };

    Custom Pre-Processor

    源代码 (C++)
    #include "MyImportProcessor.h"
    #include "MyImporterData.h"
    
    using namespace Unigine;
    
    // custom scene preprocessor stripping out color information from all scene light sources
    bool MyImportProcessor::onProcessScene(const ImportScenePtr &scene)
    {
    	Log::message("\n MyImportProcessor reporting... \n");
    
    	// getting the number of lights in the scene
    	int num_lights = scene->getNumLights();
    
    	// checking if the scene contains lights and the make_lights_white flag is set
    	if (getImporter()->getParameterInt("make_lights_white"))
    	{
    		for (int i = 0; i < num_lights; i++)
    		{
    			// getting light data from the ImportLight sctructure
    			MyLight *light = static_cast<MyLight *>(scene->getLight(i)->getData());
    			// setting color to white
    			light->color = Math::vec4_one;
    		}
    	}
    
    	return true;
    }
  4. Process scene metadata corresponding to the type of the imported scene element and create UNIGINE objects (nodes, meshes, lights, cameras, etc.). This is performed in overrides of the Importer::onImport*() methods, i.e. for lights we'll have MyImporter::onImportlight() looking as follows:处理与导入场景元素类型相对应的场景元数据,并创建UNIGINE对象(节点、网格、灯光、相机等)。这是通过重写Importer::onImport*()方法来实现的,也就是说,对于灯光,我们将让MyImporter::onImportlight()看起来如下:

    MyImporter::onImportlight()

    源代码 (C++)
    LightPtr MyImporter::onImportLight(const ImportProcessorPtr &processor, const ImportLightPtr amp;import_light)
    {
    	Log::message("\n onImportLight reporting... \n");
    	// trying to generate a Unigine light source using the ImportLight data
    	LightPtr light = create_light(import_light);
    	if (!light)
    	{
    		Log::error("MyImporter::onImportLight: can't create light.\n");
    		return nullptr;
    	}
    
    	// process light - save light data to the resulting *.node file
    	processor->processLight(light, import_light);
    
    	return light;
    }

    UNIGINE objects creation is implemented in the MyImporter::create_*() methods. For our lights, we'll have create_light() as follows:UNIGINE对象的创建在MyImporter::create_*()方法中实现。对于我们的灯,create_light()如下所示:

    MyImporter::create_light()

    源代码 (C++)
    LightPtr create_light(const ImportLightPtr &import_light)
    {
    	using namespace Math;
    
    	MyLight *my_light = static_cast<MyLight *>(import_light->getData());
    
    	// getting light parameters from the ImportLight structure
    	String type = my_light->type;
    	vec4 color = vec4(my_light->color);
    	float intensity = my_light->intensity;
    
    	// checking light source type and creating a corresponding light source
    	if (type == "LIGHT_OMNI")
    	{
    		Log::message("\n FUNCTION: create_light() creating an OMNI light... \n");
    		LightOmniPtr light_omni = LightOmni::create(color, 100.0f);
    		light_omni->setIntensity(intensity);
    		light_omni->setShapeType(Light::SHAPE_RECTANGLE);
    		return light_omni;
    	}
    	else if (type == "LIGHT_PROJ")
    	{
    		Log::message("\n FUNCTION: create_light() creating a PROJ light... \n");
    		return LightProj::create(color, 100.0f, 60.0f);
    	}
    
    	Log::error("create_light: unknown light type.\n");
    	return nullptr;
    }
  5. Save generated UNIGINE objects to *.node and *.mesh files. This part is performed by the DefaultProcessor, so we do nothing here.将生成的UNIGINE对象保存到*.node*.mesh文件。这部分是由DefaultProcessor执行的,所以我们在这里什么也不做。

And there are a couple more things to consider for our importer - initialization and cleanup operations that are implemented in the constructor and destructor respectively. So, upon construction, we should set the default import parameters and add the necessary processors. While in the cleanup section, we should remove all added processors. In our case we have:对于导入器,还有一些事情需要考虑——分别在构造函数和析构函数中实现的初始化和清理操作。因此,在构造时,我们应该设置默认导入参数并添加必要的处理器。在清理部分,我们应该删除所有添加的处理器。在我们的例子中,我们有:

Initialization and Cleanup初始化和清除

源代码 (C++)
MyImporter::MyImporter()
{
	// setting up necessary import parameters
	setParameterInt("vertex_cache", 1);
	setParameterFloat("scale", 1.0f);

	// adding a custom pre-processor
	addPreProcessor("MyImportProcessor");
}

MyImporter::~MyImporter()
{
	// removing our custom pre-processor
	removePreProcessor("MyImportProcessor");

	// free memory
	for (MyLight *light : lights)
		delete light;
	for (MyCamera *camera : cameras)
		delete camera;
	for (MyMesh *mesh : meshes)
		delete mesh;
}
注意
These default values can be changed in your application when using the importer via the Importer::setParameter*() methods.当通过Importer::setParameter*()方法使用导入器时,可以在应用程序中更改这些默认值。

So, here is the resulting code for our importer (MyImporter)因此,这是我们的导入器(MyImporter)的结果代码

MyImporter.h

源代码 (C++)
#pragma once

#include <UnigineImport.h>
#include <UnigineMesh.h>
#include <UnigineHashMap.h>
#include <UnigineXml.h>

struct MyCamera;
struct MyLight;
struct MyMesh;

// declaring our custom importer
class MyImporter : public Unigine::Importer
{
	using ImportScenePtr = Unigine::ImportScenePtr;
	using ImportProcessorPtr = Unigine::ImportProcessorPtr;
	using ImportMeshPtr = Unigine::ImportMeshPtr;
	using ImportLightPtr = Unigine::ImportLightPtr;
	using ImportCameraPtr = Unigine::ImportCameraPtr;
	using ImportNodePtr = Unigine::ImportNodePtr;

public:
	MyImporter();
	~MyImporter() override;

	// here we define file extensions to be exported by our plugin, let it be a single .myext
	UNIGINE_INLINE static Unigine::Vector<Unigine::String> getExtensions() { return{ "myext" }; }

protected:
	// overriding methods that we're going to use to import required scene components
	bool onInit(const ImportScenePtr &scene, const char *filepath) override;
	bool onImport(const char *output_path) override;
	bool onImportMesh(const ImportProcessorPtr &processor, const Unigine::MeshPtr &mesh, const ImportMeshPtr &import_mesh) override;
	Unigine::LightPtr onImportLight(const ImportProcessorPtr &processor, const ImportLightPtr &import_light) override;
	Unigine::PlayerPtr onImportCamera(const ImportProcessorPtr &processor, const ImportCameraPtr &import_camera) override;
	Unigine::NodePtr onImportNode(const ImportProcessorPtr &processor, const ImportNodePtr &import_node) override;

private:

	// method creating a new import scene, performing file format checks and parsing the input file
	// to fill the hierarchy of metadata structures
	bool import_scene(const ImportScenePtr &import_scene);

	// the methods below check required flags, perform necessary data preparations and
	// add components to the hierarchy of scene metada structures (import_scene)
	void process_node(const ImportScenePtr &import_scene, const ImportNodePtr &parent, Unigine::XmlPtr scene_node);
	void process_mesh(const ImportScenePtr &import_scene, const ImportNodePtr &node, MyMesh *my_mesh);
	void process_light(const ImportScenePtr &import_scene, const ImportNodePtr &node, MyLight *my_light);
	void process_camera(const ImportScenePtr &import_scene, const ImportNodePtr &node, MyCamera *my_camera);

private:
	float scale{ 1.0f }; // scale factor for the imported scene
	Unigine::XmlPtr my_scene; // initial xml scene structure
	Unigine::Vector<MyLight *> lights;
	Unigine::Vector<MyCamera *> cameras;
	Unigine::Vector<MyMesh *> meshes;

};

MyImporter.cpp

源代码 (C++)
#include "MyImporter.h"
#include "MyImporterData.h"

#include <UnigineThread.h>
#include <UnigineFileSystem.h>
#include <UnigineMathLibGeometry.h>
#include <UnigineNodes.h>
#include <UnigineWorld.h>
#include <UnigineHashSet.h>
#include <UnigineMaterials.h>
#include <UnigineDir.h>
#include <UnigineSet.h>

using namespace Unigine;

// auxiliary functions creating UNIGINE objects
namespace
{

	bool create_mesh(const MeshPtr &mesh, const ImportMeshPtr &import_mesh, float scale);
	LightPtr create_light(const ImportLightPtr &import_light);
	PlayerPtr create_camera(const ImportCameraPtr &import_camera);

}

MyImporter::MyImporter()
{
	// setting up necessary import parameters
	setParameterInt("vertex_cache", 1);
	setParameterFloat("scale", 1.0f);

	// adding a custom pre-processor
	addPreProcessor("MyImportProcessor");
}

MyImporter::~MyImporter()
{
	// removing our custom pre-processor
	removePreProcessor("MyImportProcessor");

	// free memory
	for (MyLight *light : lights)
		delete light;
	for (MyCamera *camera : cameras)
		delete camera;
	for (MyMesh *mesh : meshes)
		delete mesh;
}

bool MyImporter::onInit(const ImportScenePtr &scene, const char *filepath)
{
	// getting all necessary import parameters and making necessary preparations for scene import
	scale = getParameterFloat("scale");

	String filesystem_filepath = FileSystem::getAbsolutePath(filepath);
	my_scene = Xml::create();
	my_scene->load(filesystem_filepath);

	Log::message("\n\nLAUNCHING IMPORTING PROCESS... \n");

	// parse input file and fill metadata structures
	return import_scene(scene);
}

bool MyImporter::onImport(const char *output_path)
{
	Log::message("\nOnImport() reporting... \n");

	ImportScenePtr scene = getScene();

	auto setup_processor = [this, output_path](ImportProcessorPtr proc) {
		proc->setOutputPath(output_path);
		proc->setImporter(getImporter());
	};

	// importing meshes
	if (ImportProcessorPtr proc = Import::createImportProcessor(getMeshesProcessor()))
	{
		setup_processor(proc);

		Unigine::MeshPtr mesh = Unigine::Mesh::create();

		int num_meshes = scene->getNumMeshes();
		for (int m = 0; m < num_meshes; ++m)
		{
			mesh->clear();
			importMesh(proc, mesh, scene->getMesh(m));
		}
	}

	// importing nodes
	if (ImportProcessorPtr proc = Import::createImportProcessor(getNodesProcessor()))
	{
		setup_processor(proc);

		int num_nodes = scene->getNumNodes();
		for (int n = 0; n < num_nodes; ++n)
		{
			ImportNodePtr node = scene->getNode(n);
			if (node->getParent() != nullptr)
				continue;

			NodePtr root_node = importNode(proc, node);
			setOutputFilepath(node->getFilepath());
			if (root_node)
				root_node.deleteForce();
		}
	}

	return true;
}

bool MyImporter::onImportMesh(const ImportProcessorPtr &processor, const MeshPtr &mesh, const ImportMeshPtr &import_mesh)
{
	Log::message("\n onImportMesh reporting... \n");

	// trying to generate a Unigine Mesh using the ImportMesh data
	if (!create_mesh(mesh, import_mesh, scale))
	{
		Log::error("MyImporter::onImportMesh: can't create mesh.\n");
		return false;
	}

	// checking vertex_cache parameter and optimizing cache if necessary
	if (getParameterInt("vertex_cache"))
		mesh->optimizeIndices(Unigine::Mesh::VERTEX_CACHE);

	// calling a default processor to save the mesh to a file
	return processor->processMesh(mesh, import_mesh);
}

PlayerPtr MyImporter::onImportCamera(const ImportProcessorPtr &processor, const ImportCameraPtr &import_camera)
{
	Log::message("\n onImportCamera reporting... \n");

	// trying to generate a Unigine player using the ImportCamera data
	PlayerPtr camera = create_camera(import_camera);
	if (!camera)
	{
		Log::error("MyImporter::onImportCamera: can't create camera.\n");
		return nullptr;
	}

	// process player
	processor->processCamera(camera, import_camera);
	return camera;
}

LightPtr MyImporter::onImportLight(const ImportProcessorPtr &processor, const ImportLightPtr &import_light)
{
	Log::message("\n onImportLight reporting... \n");
	// trying to generate a Unigine light source using the ImportLight data
	LightPtr light = create_light(import_light);
	if (!light)
	{
		Log::error("MyImporter::onImportLight: can't create light.\n");
		return nullptr;
	}

	// process light
	processor->processLight(light, import_light);
	return light;
}

NodePtr MyImporter::onImportNode(const ImportProcessorPtr &processor, const ImportNodePtr &import_node)
{
	Log::message("\n onImportNode reporting: importing %s node\n", import_node->getName());

	NodePtr node = convertNode(processor, import_node);
	processor->processNode(node, import_node);
	return node;
}

bool MyImporter::import_scene(const ImportScenePtr &import_scene)
{
	// performing necessary checks on file format
	String n = my_scene->getName();
	if (n != "scene")
	{
		Log::error("Scene loader: bad my_scene format\n");
		return 0;
	}

	// checking scene name
	String name = my_scene->getArg("name");
	if (name.empty())
	{
		Log::error("Scene loader: scene name can't be empty\n");
		return 0;
	}
	// parsing the input file and filling the ImportScene 
	auto num_nodes = my_scene->getNumChildren();
	Log::message("Importing [%s] scene num_nodes = %d\n", name.get(), num_nodes);
	for (int i = 0; i < num_nodes; i++)
	{
		const XmlPtr child_xml = my_scene->getChild(i);
		const String &child_name = child_xml->getName();

		if (child_name == "node")
		{
			process_node(import_scene, nullptr, child_xml);
		}
		else
		{
			Log::error("Scene loader: unknown element \"%s\" in the \"%s\" scene\n",
				child_name.get(), name.get());
		}
	}

	return true;
}

void MyImporter::process_node(const ImportScenePtr &import_scene, const ImportNodePtr &parent, XmlPtr scene_node)
{
	ImportNodePtr node = import_scene->addNode(parent);
	node->setName(scene_node->getArg("name"));
	if (scene_node->getChild("transform"))
	{
		Math::dmat4 transform = scene_node->getChild("transform")->getDMat4Data();
		transform.m03 *= scale;
		transform.m13 *= scale;
		transform.m23 *= scale;
		node->setTransform(transform);
	}

	// processing node attributes
	XmlPtr attribute = scene_node->getChild("attribute");
	if (attribute)
	{
		String attr_type = attribute->getArg("type");
		if (attr_type == "light")
		{
			// creating and filling light metadata
			MyLight *light = new MyLight();
			lights.append(light);
			light->type = attribute->getChildData("light_type");
			light->color = attribute->getChild("color")->getVec4Data();
			light->intensity = attribute->getChild("intensity")->getFloatData();

			// processing light metadata and adding ImportLight to the scene
			process_light(import_scene, node, light);

			Log::message("Artribute light: named %s , type %s, color (%f, %f, %f, %f)\n",
				node->getName(), light->type.get(),
				light->color.x, light->color.y, light->color.z, light->color.w);
		}
		else if (attr_type == "camera")
		{
			// creating and filling camera metadata
			MyCamera *camera = new MyCamera();
			cameras.append(camera);

			camera->type = attribute->getChildData("player_type");
			camera->fov = attribute->getChild("fov")->getFloatData();
			camera->near_plane = attribute->getChild("near")->getFloatData();
			camera->far_plane = attribute->getChild("far")->getFloatData();
			camera->target = attribute->getChild("target")->getVec3Data();

			// processing camera metadata and adding ImportCamera to the scene
			process_camera(import_scene, node, camera);
			Log::message("Artribute camera: named %s , type %s, target (%f, %f, %f)\n",
				node->getName(), camera->type.get(),
				camera->target.x, camera->target.y, camera->target.z);
		}
		else if (attr_type == "mesh")
		{
			// creating and filling mesh metadata
			MyMesh *mesh = new MyMesh();
			meshes.append(mesh);

			int num_surfaces = attribute->getChild("surfaces")->getNumChildren();
			int num_vertices = attribute->getChild("vertices")->getNumChildren();

			Log::message("Artribute mesh: named %s , %d surfaces, %d vertices\n",
				node->getName(), num_surfaces, num_vertices);

			// getting all surfaces
			for (int i = 0; i < num_surfaces; ++i) {
				XmlPtr xml_surf = attribute->getChild("surfaces")->getChild(i);
				mesh->surfaces.append(xml_surf->getArg("name"));
				// filling polygons data
				mesh->polygons.append(
					Math::ivec3(i, xml_surf->getIntArg("offset"), xml_surf->getIntArg("size")));
				Log::message("\nSurface [%d] named: %s\n", i, mesh->surfaces[i].get());
			}
			// getting all vertices
			for (int i = 0; i < num_vertices; ++i)
			{
				mesh->vertices.append(attribute->getChild("vertices")->getChild(i)->getVec3Data());

				Log::message("Vertex [%d] coordinates:(%f, %f, %f)\n",
					i, mesh->vertices[i].x, mesh->vertices[i].y, mesh->vertices[i].z);
			}
			// getting all indices
			XmlPtr indices_xml = attribute->getChild("indices");
			int num_indices = indices_xml->getIntArg("num_indices");

			mesh->indices.resize(num_indices);
			indices_xml->getIntArrayData(mesh->indices.get(), num_indices);

			// processing mesh metadata and adding ImportMesh to the scene
			process_mesh(import_scene, node, mesh);
		}
	}

	// processing all node's children
	int num_children = scene_node->getNumChildren();
	for (int i = 0; i < num_children; ++i) {
		XmlPtr child = scene_node->getChild(i);
		const String &child_name = child->getName();
		if (child_name == "node")
			process_node(import_scene, node, child);
	}
}

void MyImporter::process_mesh(const ImportScenePtr amp;import_scene, const ImportNodePtr &node, sMyMesh *my_mesh)
{
	Log::message("\n FUNCTION: process_mesh() reporting... \n");
	if ((getFlags() & IMPORT_MESHES) == 0)
		return;

	ImportMeshPtr mesh = import_scene->addMesh(node);
	mesh->setName(node->getName());

	ImportGeometryPtr geometry = mesh->addGeometry();
	geometry->setData(my_mesh);

	//adding surfaces to the mesh
	for (int i = 0; i < my_mesh->surfaces.size(); i++)
	{
		ImportSurfacePtr s = geometry->addSurface();
		s->setName(my_mesh->surfaces[i]);
		s->setTargetSurface(geometry->getNumSurfaces() - 1);
	}
}

void MyImporter::process_light(const ImportScenePtr &import_scene, const ImportNodePtr &node, MyLight *my_light)
{
	Log::message("\n FUNCTION: process_light() reporting... \n");
	// checking if the light import flag is set
	if ((getFlags() & IMPORT_LIGHTS) == 0)
		return;

	// adding a light source to the scene and setting lignt source data
	ImportLightPtr light = import_scene->addLight(node);
	light->setData(my_light);
}

void MyImporter::process_camera(const ImportScenePtr &import_scene, const ImportNodePtr &node, MyCamera *my_camera)
{
	Log::message("\n FUNCTION: process_camera() reporting... \n");
	// checking if the camera import flag is set
	if ((getFlags() & IMPORT_CAMERAS) == 0)
		return;

	// adding a camera to the scene and setting camera data
	ImportCameraPtr camera = import_scene->addCamera(node);
	camera->setData(my_camera);
}

namespace
{
	// auxiliary data structures to store mesh geometry information
	struct SurfaceData
	{
		int index;
		ImportSurfacePtr surface;
		Unigine::Vector<int> cindices;
		Unigine::Vector<int> tindices;
	};

	struct GeometryData
	{
		Unigine::Math::vec3 *vertices;
		Unigine::Math::dmat4 transform;
	};

	bool create_surfaces(const MeshPtr &mesh, const Unigine::Vector<SurfaceData> &surfaces, const GeometryData &geometry_data, float scale)
	{

		Log::message("\n FUNCTION: create_surfaces() reporting... \n");
		using namespace Unigine;
		using namespace Unigine::Math;

		const dmat4 &transform = geometry_data.transform;
		const Unigine::Math::vec3 *vertices = geometry_data.vertices;

		mat3 rotation = mat3(transform);
		// creating mesh surfaces using metadata
		for (const SurfaceData &surface : surfaces)
		{
			if (surface.cindices.empty())
				continue;

			int s = surface.surface->getTargetSurface();
			while (s >= mesh->getNumSurfaces())
				mesh->addSurface();

			mesh->setSurfaceName(s, surface.surface->getName());

			for (int index : surface.cindices) {
				mesh->addVertex(vec3(transform * vec3(vertices[index])), s);
				Log::message("\n FUNCTION: create_surfaces() reporting: adding vertex[%d] with coords (%f, %f, %f)... \n",
					index, vertices[index].x, vertices[index].y, vertices[index].z);
			}
			// applying scale
			mesh->setSurfaceTransform(Math::scale(vec3(scale)), s);
		}

		return true;
	}

	bool create_geometry(const Unigine::MeshPtr &mesh, const ImportGeometryPtr &geometry, float scale)
	{
		Log::message("\n FUNCTION: create_geometry() REPORTING... \n");
		using namespace Unigine;
		using namespace Unigine::Math;

		MyMesh *my_mesh = static_cast<MyMesh *>(geometry->getData());

		const dmat4 &transform = geometry->getTransform();

		GeometryData geometry_data;
		geometry_data.vertices = &my_mesh->vertices[0];
		geometry_data.transform = transform;

		Unigine::Vector<SurfaceData> surfaces_data;

		for (int n_surf = 0; n_surf < my_mesh->surfaces.size(); n_surf++)
		{
			// adding cindices and tindices and calling create surfaces
			SurfaceData &surface = surfaces_data.append();
			surface.index = n_surf;
			surface.surface = geometry->getSurface(n_surf);

			int offset = my_mesh->polygons[n_surf].y;
			int size = my_mesh->polygons[n_surf].z;
			for (int i = 0; i < size; i++)
			{
				surface.cindices.append(my_mesh->indices[offset + i]);
				surface.tindices.append(my_mesh->indices[offset + i]);
			}
		}

		create_surfaces(mesh, surfaces_data, geometry_data, scale);
		return true;
	}

	bool create_mesh(const Unigine::MeshPtr &mesh, const ImportMeshPtr &import_mesh, float scale)
	{
		Log::message("\n FUNCTION: create_mesh() reporting... \n");
		int num_geometries = import_mesh->getNumGeometries();
		for (int i = 0; i < num_geometries; ++i)
			create_geometry(mesh, import_mesh->getGeometry(i), scale);

		int num_surfaces = mesh->getNumSurfaces();

		// creating mesh indices
		mesh->createIndices();

		for (int s = 0; s < num_surfaces; ++s)
		{
			if (!mesh->getNumTangents(s, 0))
				mesh->createTangents(s, 0);

			for (int t = 1; t < mesh->getNumSurfaceTargets(s); ++t)
				mesh->createTangents(s, t);
		}

		// creating mesh bounds
		mesh->createBounds();

		return true;
	}

	LightPtr create_light(const ImportLightPtr &import_light)
	{
		using namespace Math;

		MyLight *my_light = static_cast<MyLight *>(import_light->getData());

		// getting light parameters from the ImportLight structure
		String type = my_light->type;
		vec4 color = vec4(my_light->color);
		float intensity = my_light->intensity;

		// checking light source type and creating a corresponding light source
		if (type == "LIGHT_OMNI")
		{
			Log::message("\n FUNCTION: create_light() creating an OMNI light... \n");
			LightOmniPtr light_omni = LightOmni::create(color, 100.0f);
			light_omni->setIntensity(intensity);
			light_omni->setShapeType(Light::SHAPE_RECTANGLE);
			return light_omni;
		}
		else if (type == "LIGHT_PROJ")
		{
			Log::message("\n FUNCTION: create_light() creating a PROJ light... \n");
			return LightProj::create(color, 100.0f, 60.0f);
		}

		Log::error("create_light: unknown light type.\n");
		return nullptr;
	}

	PlayerPtr create_camera(const ImportCameraPtr &import_camera)
	{
		Log::message("\n FUNCTION: create_camera() reporting... \n");

		MyCamera *my_camera = static_cast<MyCamera *>(import_camera->getData());

		// getting camera parameters from the ImportCamera structure
		float fov = my_camera->fov;
		float znear = my_camera->near_plane;
		float zfar = my_camera->far_plane;

		PlayerDummyPtr player_dummy = PlayerDummy::create();
		player_dummy->setZNear(znear);
		player_dummy->setZFar(zfar);
		//player_dummy->worldLookAt((Math::Vec3)my_camera->target, Math::vec3_up);

		// setting player projection
		if (my_camera->type == "TYPE_ORTHOGONAL")
			player_dummy->setProjection(Math::ortho(-1.0f, 1.0f, -1.0f, 1.0f, znear, zfar));

		if (my_camera->type == "TYPE_PERSPECTIVE")
			player_dummy->setFov(fov);

		return player_dummy;
	}

}

After we have implemented all the functionality, we compile the plugin library.实现所有功能后,我们编译插件库

Using a Plugin
使用插件#

Now that our library is ready, we should perform the following steps to use it in our project:现在我们的库已经准备好了,我们应该执行以下步骤来在项目中使用它:

  1. First, let us create a new project named MyProject that will use our library. Let it be a simple project using C++.首先,让我们创建一个名为MyProject的新项目,它将使用我们的库。让它成为一个使用C++的简单项目。
  2. Put the created plugin library module (a *.dll or *.so file) to the corresponding project's directory — bin/plugins/<vendor_name>/<plugin_name>. For more information about plugin naming and the paths to plugin folders, please refer to the Creating C++ Plugin article.将创建的插件库模块(*.dll*.so文件)放入相应的项目目录- bin/plugins/<vendor_name>/<plugin_name>。 有关插件命名和插件文件夹路径的更多信息,请参阅创建C++插件文章。

    注意
    Make sure your project's binary and plugin library have the same precision and version.确保项目的二进制和插件库具有相同的精度和版本
  3. Put the file in your custom format (my_scene.myext) to the data folder of the project.将文件以自定义格式(my_scene.myext)放入项目的data文件夹中。
  4. Provide plugin loading in one of the following ways:通过以下方式之一提供插件加载:

    • Pass the plugin as a command-line argument extern_plugin. Once passed, it is written into the configuration file.将插件作为命令行参数extern_plugin传递。一旦通过,它将被写入配置文件。

      命令行
      MyProject.exe -extern_plugin MyImportPlugin
    • Specify the plugin directly in the configuration file (data/configs/default.boot, extern_plugin string).在配置文件中直接指定插件(data/configs/default.boot, extern_plugin string)。
    • Add and use the plugin in the project's world logic via Engine::addPlugin() (or via Engine.addPlugin() for C# projects).通过Engine::addPlugin()(或c#项目的Engine.addPlugin())在项目的世界逻辑中添加和使用插件。
    • Add and use the plugin in the system logic:系统逻辑中添加并使用插件:

      • Add the plugin via Engine::addPlugin() and use it in the world logic. You cannot initialize the plugin in the system logic and call plugin functions from it at the same time.通过Engine::addPlugin()添加插件,并在世界逻辑中使用它。您不能在系统逻辑中初始化插件并同时从中调用插件函数。
      • Use the plugin in the system logic after initializing it via the command-line argument extern_plugin. 通过命令行参数 extern_plugin初始化插件后,在系统逻辑中使用该插件。
  5. Use the plugin in the project. We will add some lines of code to the init() method of the world logic (the AppWorldLogic.cpp file) to demonstrate the idea.在项目中使用插件。我们将向世界逻辑的init()方法(AppWorldLogic.cpp文件)添加一些代码行来演示这个想法。

    When it's necessary to set up import parameters:当需要设置导入参数时:

    源代码 (C++)
    #include "AppWorldLogic.h"
    #include <UnigineImport.h>
    #include <UnigineGame.h>
    
    using namespace Unigine;
    
    int AppWorldLogic::init()
    {
    	NodePtr node0 = importCustom();
    
    	if (PlayerPtr player = Game::getPlayer())
    	{
    		const Math::Vec3 position(5.8f, -1.5f, 3.0f);
    		player->setWorldTransform(
    			Math::inverse(Math::lookAt(position, Math::Vec3_zero, Math::vec3_up)));
    	}
    
    	return 1;
    }
    
    NodePtr AppWorldLogic::importCustom()
    {
    	// string to store the path to the resulting .node file with our imported scene
    	String filepath_node;
    
    	// getting an importer for our file extension from the list of importers registered in the Import System
    	ImporterPtr my_importer = Import::createImporterByFileName(DEFAULT_FILEPATH);
    	// if such importer was found setting up necessary import options
    	if (my_importer)
    	{
    		my_importer->setParameterInt("make_lights_white", 1);	// stripping off light color information
    		my_importer->setParameterFloat("scale", 0.8f);			// setting scale
    		my_importer->init(DEFAULT_FILEPATH, ~0);				// initializing the importer with default import flags IMPROT_LIGHTS, IMPORT_MESHES, IMPORT_CAMERAS, etc.
    
    																// importing our scene to the output folder
    		my_importer->import(DEFAULT_OUTPUT_PATH);
    
    		// getting a path to resulting *.node file with our imported scene
    		filepath_node = my_importer->getOutputFilepath();
    	}
    
    	if (filepath_node.empty())
    	{
    		Log::error("Scene import failure.\n");
    		return nullptr;
    	}
    
    	// reporting the result and adding a node reference to the world on success
    	Log::message("Successfully imported your scene, now you can use: %s\n",
    		filepath_node.get());
    	return NodeReference::create(filepath_node);
    }

    To import with default settings:使用默认设置导入:

    源代码 (C++)
    #include "AppWorldLogic.h"
    #include <UnigineImport.h>
    #include <UnigineGame.h>
    
    using namespace Unigine;
    
    int AppWorldLogic::init()
    {
    	NodePtr node1 = importDefault();
    
    	if (PlayerPtr player = Game::getPlayer())
    	{
    		const Math::Vec3 position(5.8f, -1.5f, 3.0f);
    		player->setWorldTransform(
    			Math::inverse(Math::lookAt(position, Math::Vec3_zero, Math::vec3_up)));
    	}
    
    	return 1;
    }
    
    NodePtr AppWorldLogic::importDefault()
    {
    	// string to store the path to the resulting .node file with our imported scene
    	String filepath_node;
    
    	// importing our scene with default settings to the output folder and getting a path to resulting *.node file
    	filepath_node = Import::doImport(DEFAULT_FILEPATH, DEFAULT_OUTPUT_PATH);
    
    	if (filepath_node.empty())
    	{
    		Log::error("Scene import failure.\n");
    		return nullptr;
    	}
    
    	// reporting the result and adding a node reference to the world on success
    	Log::message("Successfully imported your scene, now you can use: %s\n",
    		filepath_node.get());
    	return NodeReference::create(filepath_node);
    }

Now when we launch our project with the MyImportPlugin plugin loaded and the MyProject world opened, the scene is imported to the world, and the corresponding files are saved to the MyProject/data/output_folder/ folder.现在,当我们加载了MyImportPlugin插件并打开了MyProject世界启动项目时,场景被导入到世界中,相应的文件被保存到MyProject/data/output_folder/文件夹中。

最新更新: 2023-09-26
Build: ()