Files
beyond/Assets/SatorImaging/TerrainToolkit/Editor/TerrainFbxExporter.cs
2024-11-20 15:21:28 +01:00

604 lines
17 KiB
C#

namespace SatorImaging.TerrainToolkit
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text;
using System.IO;
using System;
public static class TerrainFbxExporter
{
private const string MenuItemName = "Export Terrain as FBX...";
static Terrain terrain;
static float progress = 0f;
//[MenuItem("File/Export Terrain...", priority = 9999)]
//[MenuItem("Edit/" + MenuItemName, priority = 9999)]
//[MenuItem("Assets/" + MenuItemName, priority = 9999)]
[MenuItem("GameObject/" + MenuItemName, priority = 39)]
[MenuItem("Component/" + MenuItemName, priority = 9999)]
public static void Export()
{
progress = 0f;
var sel = Selection.activeGameObject;
if (!sel)
{
EditorUtility.DisplayDialog(typeof(TerrainFbxExporter).Namespace, "No Terrain selected.", "OK");
return;
}
terrain = sel.GetComponent<Terrain>();
if (!terrain)
{
EditorUtility.DisplayDialog(typeof(TerrainFbxExporter).Namespace, "Selected object is NOT Terrain.", "OK");
return;
}
float scale_factor = 1f;
var mesh_name = "UnityTerrain_" + sel.gameObject.name;
var mat_name = "UnityTerrain_Material";
// export path
var fbx_path = EditorUtility.SaveFilePanel(typeof(TerrainFbxExporter).Namespace, null, mesh_name, "fbx");
if (string.IsNullOrEmpty(fbx_path))
{
return;
}
using (var sw = new StreamWriter(fbx_path))
{
var sb = new StringBuilder();
// HEADER //////////////////////////////////////////////////
sb.Append(@"; FBX 6.1.0 project file
; Copyright (C) 1997-2010 Autodesk Inc. and/or its licensors.
; All rights reserved.
; ----------------------------------------------------
FBXHeaderExtension: {
FBXHeaderVersion: 1003
FBXVersion: 6100
CurrentCameraResolution: {
CameraName: ""Producer Perspective""
CameraResolutionMode: ""Fixed Resolution""
CameraResolutionW: 960
CameraResolutionH: 540
}
CreationTimeStamp: {
Version: 1000
Year: " + DateTime.Now.Year + @"
Month: " + DateTime.Now.Month + @"
Day: " + DateTime.Now.Day + @"
Hour: " + DateTime.Now.Hour + @"
Minute: " + DateTime.Now.Minute + @"
Second: " + DateTime.Now.Second + @"
Millisecond: " + DateTime.Now.Millisecond + @"
}
Creator: """ + typeof(TerrainFbxExporter).FullName + @"""
}
; Document Description
;------------------------------------------------------------------
Document: {
Name: """ + mesh_name + @"""
}
; Document References
;------------------------------------------------------------------
References: {
}
; Object definitions
;------------------------------------------------------------------
Definitions: {
Version: 100
Count: 4
ObjectType: ""Model"" {
Count: 1
}
ObjectType: ""Material"" {
Count: 1
}
ObjectType: ""SceneInfo"" {
Count: 1
}
ObjectType: ""GlobalSettings"" {
Count: 1
}
}
; Object properties
;------------------------------------------------------------------
Objects: {
Model: ""Model::" + mesh_name + @""", ""Mesh"" {
Version: 232
Properties60: {
Property: ""GeometricTranslation"", ""Vector3D"", """",0,0,0
Property: ""GeometricRotation"", ""Vector3D"", """",0,0,0
Property: ""GeometricScaling"", ""Vector3D"", """",1,1,1
Property: ""Show"", ""bool"", """",1
Property: ""NegativePercentShapeSupport"", ""bool"", """",1
Property: ""DefaultAttributeIndex"", ""int"", """",0
Property: ""Lcl Translation"", ""Lcl Translation"", ""A""," + ((double)-terrain.transform.position.x) + "," + ((double)terrain.transform.position.y) + "," + ((double)terrain.transform.position.z) + @"
Property: ""Lcl Rotation"", ""Lcl Rotation"", ""A"",0,0,0
Property: ""Lcl Scaling"", ""Lcl Scaling"", ""A"",1,1,1
Property: ""Visibility"", ""Visibility"", ""A"",1
Property: ""currentUVSet"", ""KString"", ""U"", ""map1""
Property: ""Color"", ""ColorRGB"", ""N"",0.8,0.8,0.8
Property: ""BBoxMin"", ""Vector3D"", ""N"",0,0,0
Property: ""BBoxMax"", ""Vector3D"", ""N"",0,0,0
Property: ""Primary Visibility"", ""bool"", ""N"",1
Property: ""Casts Shadows"", ""bool"", ""N"",1
Property: ""Receive Shadows"", ""bool"", ""N"",1
}
MultiLayer: 0
MultiTake: 0
Shading: T
Culling: ""CullingOff""
");
sw.Write(sb.ToString());
sb.Length = 0; // clear
ShowProgressBar("Exporting Vertices");
// VERTEX LOOP //////////////////////////////////////////////////
sb.Append(" Vertices: ");
// write once
//Debug.LogFormat("TerrainData.Size: {0}", terrain.terrainData.size);
//Debug.LogFormat("TerrainData.Heightmap Width x Height: {0} x {1}", terrain.terrainData.heightmapWidth, terrain.terrainData.heightmapHeight);
//Debug.LogFormat("TerrainData.Heightmap Resolution: {0}", terrain.terrainData.heightmapResolution);
float scale_x = scale_factor * (terrain.terrainData.size.x / (terrain.terrainData.heightmapResolution - 1));
//float scale_x = scale_factor * terrain.terrainData.size.x;
//scale_x *= terrain.terrainData.size.x;
//float scale_y = terrain.terrainData.heightmapHeight;
float scale_y = scale_factor * terrain.terrainData.size.y;
scale_y = scale_factor;
float scale_z = scale_factor * (terrain.terrainData.size.z / (terrain.terrainData.heightmapResolution - 1));
//float scale_z = scale_factor * terrain.terrainData.size.z;
//scale_z *= terrain.terrainData.size.z;
float pos_y = 0;
for (var z = 0; z < terrain.terrainData.heightmapResolution; z++)
{
for (var x = 0; x < terrain.terrainData.heightmapResolution; x++)
{
pos_y = terrain.terrainData.GetHeight(x, z);
sb.Append(Convert.ToString((double)(-x * scale_x)).Replace(',', '.') + ',');
sb.Append(Convert.ToString((double)(pos_y * scale_y)).Replace(',', '.') + ',');
sb.Append(Convert.ToString((double)(z * scale_z)).Replace(',', '.') + ',');
}
}
sw.WriteLine(sb.ToString());
sb.Length = 0; // clear
ShowProgressBar("Exporting Polygons");
// POLYGON LOOP //////////////////////////////////////////////////
sb.Append(" PolygonVertexIndex: ");
int num_polygons = (terrain.terrainData.heightmapResolution - 1) * (terrain.terrainData.heightmapResolution);
int index_offset = terrain.terrainData.heightmapResolution;
int skip_index = terrain.terrainData.heightmapResolution;
for (var i = 0; i < num_polygons; i++)
{
if (0 == (i + 1) % terrain.terrainData.heightmapResolution)
{
continue;
}
// v0, v1, v2, v3 will be... 0,1,2,-4
sb.Append(i + "," + (i + 1) + "," + (index_offset + i + 1) + ",-" + (index_offset + i + 1) + ",");
}
sw.WriteLine(sb.ToString());
sb.Length = 0; // clear
ShowProgressBar("Exporting Edges");
// EDGE LOOP //////////////////////////////////////////////////
//sw.WriteLine(" Edges: ");
//sw.WriteLine ("");
sw.WriteLine(" GeometryVersion: 124");
ShowProgressBar("Exporting Normals");
// NORMALS ///////////////////////////////////////////////////
sb.Append(@"
LayerElementNormal: 0 {
Version: 101
Name: """"
MappingInformationType: ""ByVertice""
ReferenceInformationType: ""Direct""
Normals: ");
float local_pos_x = 1f / (terrain.terrainData.heightmapResolution - 1);
float local_pos_z = 1f / (terrain.terrainData.heightmapResolution - 1);
var norm = new Vector3();
for (var z = 0; z < terrain.terrainData.heightmapResolution; z++)
{
for (var x = 0; x < terrain.terrainData.heightmapResolution; x++)
{
//norm = terrain.terrainData.GetInterpolatedNormal((x % (terrain.terrainData.heightmapWidth - 1)) * local_pos_x, z * local_pos_z);
norm = terrain.terrainData.GetInterpolatedNormal(x * local_pos_x, z * local_pos_z);
sb.Append(-norm.x + "," + norm.y + "," + norm.z + ",");
}
}
sb.Append(@"
}");
sw.WriteLine(sb.ToString());
sb.Length = 0; // clear
ShowProgressBar("Exporting UVs");
// UV ////////////////////////////////////////////////////////
sb.Append(@"
LayerElementUV: 0 {
Version: 101
Name: ""map1""
MappingInformationType: ""ByPolygonVertex""
ReferenceInformationType: ""IndexToDirect""
UV: ");
local_pos_x = 1f / (terrain.terrainData.heightmapResolution - 1);
local_pos_z = 1f / (terrain.terrainData.heightmapResolution - 1);
for (var z = 0; z < terrain.terrainData.heightmapResolution; z++)
{
for (var x = 0; x < terrain.terrainData.heightmapResolution; x++)
{
sb.Append((x * local_pos_x) + "," + (z * local_pos_z) + ",");
}
}
sb.AppendLine("");
// UV INDEX ////////////////////////////////////////////////////////
// tired...
sb.Append(@"
UVIndex: ");
for (var i = 0; i < num_polygons; i++)
{
if (0 == (i + 1) % terrain.terrainData.heightmapResolution)
{
continue;
}
// v0, v1, v2, v3 will be... 0,1,2,-4
sb.Append(i + "," + (i + 1) + "," + (i + 1 + index_offset) + "," + (i + 0 + index_offset) + ",");
}
sb.Append(@"
}");
sw.WriteLine(sb.ToString());
sb.Length = 0; // clear
ShowProgressBar("Building FBX Scene");
sb.Append(@"
LayerElementMaterial: 0 {
Version: 101
Name: """"
MappingInformationType: ""AllSame""
ReferenceInformationType: ""IndexToDirect""
Materials: 0
}
Layer: 0 {
Version: 100
LayerElement: {
Type: ""LayerElementNormal""
TypedIndex: 0
}
LayerElement: {
Type: ""LayerElementMaterial""
TypedIndex: 0
}
LayerElement: {
Type: ""LayerElementColor""
TypedIndex: 0
}
LayerElement: {
Type: ""LayerElementUV""
TypedIndex: 0
}
}
NodeAttributeName: ""Geometry::" + mesh_name + @"_ncl1_1""
}");
sb.Append(@"
SceneInfo: ""SceneInfo::GlobalInfo"", ""UserData"" {
Type: ""UserData""
Version: 100
MetaData: {
Version: 100
Title: """"
Subject: """"
Author: """"
Keywords: """"
Revision: """"
Comment: """"
}
Properties60: {
}
}
Material: ""Material::" + mat_name + @""", """" {
Version: 102
ShadingModel: ""lambert""
MultiLayer: 0
Properties60: {
Property: ""ShadingModel"", ""KString"", """", ""Lambert""
Property: ""MultiLayer"", ""bool"", """",0
Property: ""EmissiveColor"", ""Color"", ""A"",0,0,0
Property: ""EmissiveFactor"", ""Number"", ""A"",1
Property: ""AmbientColor"", ""Color"", ""A"",0,0,0
Property: ""AmbientFactor"", ""Number"", ""A"",1
Property: ""DiffuseColor"", ""Color"", ""A"",0.5,0.5,0.5
Property: ""DiffuseFactor"", ""Number"", ""A"",0.8
Property: ""Bump"", ""Vector3D"", """",0,0,0
Property: ""NormalMap"", ""Vector3D"", """",0,0,0
Property: ""BumpFactor"", ""double"", """",1
Property: ""TransparentColor"", ""Color"", ""A"",0,0,0
Property: ""TransparencyFactor"", ""Number"", ""A"",1
Property: ""DisplacementColor"", ""ColorRGB"", """",0,0,0
Property: ""DisplacementFactor"", ""double"", """",1
Property: ""VectorDisplacementColor"", ""ColorRGB"", """",0,0,0
Property: ""VectorDisplacementFactor"", ""double"", """",1
Property: ""Emissive"", ""Vector3D"", """",0,0,0
Property: ""Ambient"", ""Vector3D"", """",0,0,0
Property: ""Diffuse"", ""Vector3D"", """",0.4,0.4,0.4
Property: ""Opacity"", ""double"", """",1
}
}
GlobalSettings: {
Version: 1000
Properties60: {
Property: ""UpAxis"", ""int"", """",1
Property: ""UpAxisSign"", ""int"", """",1
Property: ""FrontAxis"", ""int"", """",2
Property: ""FrontAxisSign"", ""int"", """",1
Property: ""CoordAxis"", ""int"", """",0
Property: ""CoordAxisSign"", ""int"", """",1
Property: ""OriginalUpAxis"", ""int"", """",1
Property: ""OriginalUpAxisSign"", ""int"", """",1
Property: ""UnitScaleFactor"", ""double"", """",100
Property: ""OriginalUnitScaleFactor"", ""double"", """",1
Property: ""AmbientColor"", ""ColorRGB"", """",0,0,0
Property: ""DefaultCamera"", ""KString"", """", ""Producer Perspective""
Property: ""TimeMode"", ""enum"", """",11
Property: ""TimeProtocol"", ""enum"", """",2
Property: ""SnapOnFrameMode"", ""enum"", """",0
Property: ""TimeSpanStart"", ""KTime"", """",1924423250
Property: ""TimeSpanStop"", ""KTime"", """",384884650000
Property: ""CustomFrameRate"", ""double"", """",-1
}
}
}
");
// CONNECTION //////////////////////////////////////////////////
sb.Append(@"
; Object connections
;------------------------------------------------------------------
Connections: {
Connect: ""OO"", ""Model::" + mesh_name + @""", ""Model::Scene""
Connect: ""OO"", ""Material::" + mat_name + @""", ""Model::" + mesh_name + @"""
}
;Takes and animation section
;----------------------------------------------------
Takes: {
Current: ""Take 001""
Take: ""Take 001"" {
FileName: ""Take_001.tak""
LocalTime: 1924423250,230930790000
ReferenceTime: 1924423250,230930790000
;Models animation
;----------------------------------------------------
;Generic nodes animation
;----------------------------------------------------
;Textures animation
;----------------------------------------------------
;Materials animation
;----------------------------------------------------
;Constraints animation
;----------------------------------------------------
}
}
;Version 5 settings
;------------------------------------------------------------------
Version5: {
AmbientRenderSettings: {
Version: 101
AmbientLightColor: 0,0,0,1
}
FogOptions: {
FlogEnable: 0
FogMode: 0
FogDensity: 0.002
FogStart: 0.3
FogEnd: 1000
FogColor: 1,1,1,1
}
Settings: {
FrameRate: ""24""
TimeFormat: 1
SnapOnFrames: 0
ReferenceTimeIndex: -1
TimeLineStartTime: 1924423250
TimeLineStopTime: 384884650000
}
RendererSetting: {
DefaultCamera: ""Producer Perspective""
DefaultViewingMode: 0
}
}");
sw.WriteLine(sb.ToString());
sb.Length = 0; // clear
EditorUtility.ClearProgressBar();
sw.Close();
sw.Dispose();
Debug.Log(".fbx Exported successfully.");
AssetDatabase.Refresh();
}
}
static void ShowProgressBar(string info)
{
progress += 1f / (6f);
EditorUtility.DisplayProgressBar(typeof(TerrainFbxExporter).Namespace, info, progress);
}
}
}