Added player character and step in/out of dialogue in scene 101
This commit is contained in:
+193
@@ -0,0 +1,193 @@
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEngine.ProBuilder.Stl
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes the file format of an STL file.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public enum FileType
|
||||
{
|
||||
/// <summary>Use the [ASCII](https://en.wikipedia.org/wiki/ASCII) file format.</summary>
|
||||
Ascii,
|
||||
/// <summary>Use the [Binary](https://en.wikipedia.org/wiki/Binary_file) file format.</summary>
|
||||
Binary
|
||||
};
|
||||
|
||||
/**
|
||||
* Export STL files from Unity mesh assets.
|
||||
*/
|
||||
static class pb_Stl
|
||||
{
|
||||
/**
|
||||
* Write a mesh file to STL.
|
||||
*/
|
||||
public static bool WriteFile(string path, Mesh mesh, FileType type = FileType.Ascii, bool convertToRightHandedCoordinates = true)
|
||||
{
|
||||
return WriteFile(path, new Mesh[] { mesh }, type, convertToRightHandedCoordinates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a collection of mesh assets to an STL file.
|
||||
* No transformations are performed on meshes in this method.
|
||||
* Eg, if you want to export a set of a meshes in a transform
|
||||
* hierarchy the meshes should be transformed prior to this call.
|
||||
*
|
||||
* string path - Where to write the file.
|
||||
* IList<Mesh> meshes - The mesh assets to write.
|
||||
* FileType type - How to format the file (in ASCII or binary).
|
||||
*/
|
||||
public static bool WriteFile(string path, IList<Mesh> meshes, FileType type = FileType.Ascii, bool convertToRightHandedCoordinates = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case FileType.Binary:
|
||||
{
|
||||
// http://paulbourke.net/dataformats/stl/
|
||||
// http://www.fabbers.com/tech/STL_Format
|
||||
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create), new ASCIIEncoding()))
|
||||
{
|
||||
// 80 byte header
|
||||
writer.Write(new byte[80]);
|
||||
|
||||
uint totalTriangleCount = (uint) (meshes.Sum(x => x.triangles.Length) / 3);
|
||||
|
||||
// unsigned long facet count (4 bytes)
|
||||
writer.Write( totalTriangleCount );
|
||||
|
||||
foreach(Mesh mesh in meshes)
|
||||
{
|
||||
Vector3[] v = convertToRightHandedCoordinates ? Left2Right(mesh.vertices) : mesh.vertices;
|
||||
Vector3[] n = convertToRightHandedCoordinates ? Left2Right(mesh.normals) : mesh.normals;
|
||||
int[] t = mesh.triangles;
|
||||
int triangleCount = t.Length;
|
||||
if(convertToRightHandedCoordinates)
|
||||
System.Array.Reverse(t);
|
||||
|
||||
for(int i = 0; i < triangleCount; i += 3)
|
||||
{
|
||||
int a = t[i], b = t[i+1], c = t[i+2];
|
||||
|
||||
Vector3 avg = AvgNrm(n[a], n[b], n[c]);
|
||||
|
||||
writer.Write(avg.x);
|
||||
writer.Write(avg.y);
|
||||
writer.Write(avg.z);
|
||||
|
||||
writer.Write(v[a].x);
|
||||
writer.Write(v[a].y);
|
||||
writer.Write(v[a].z);
|
||||
|
||||
writer.Write(v[b].x);
|
||||
writer.Write(v[b].y);
|
||||
writer.Write(v[b].z);
|
||||
|
||||
writer.Write(v[c].x);
|
||||
writer.Write(v[c].y);
|
||||
writer.Write(v[c].z);
|
||||
|
||||
// specification says attribute byte count should be set to 0.
|
||||
writer.Write( (ushort)0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
string model = WriteString(meshes);
|
||||
File.WriteAllText(path, model);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogError(e.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a Unity mesh to an ASCII STL string.
|
||||
*/
|
||||
public static string WriteString(Mesh mesh, bool convertToRightHandedCoordinates = true)
|
||||
{
|
||||
return WriteString(new Mesh[] { mesh }, convertToRightHandedCoordinates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a set of meshes to an ASCII string in STL format.
|
||||
*/
|
||||
public static string WriteString(IList<Mesh> meshes, bool convertToRightHandedCoordinates = true)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
string name = meshes.Count == 1 ? meshes[0].name : "Composite Mesh";
|
||||
|
||||
sb.AppendLine(string.Format("solid {0}", name));
|
||||
|
||||
foreach(Mesh mesh in meshes)
|
||||
{
|
||||
Vector3[] v = convertToRightHandedCoordinates ? Left2Right(mesh.vertices) : mesh.vertices;
|
||||
Vector3[] n = convertToRightHandedCoordinates ? Left2Right(mesh.normals) : mesh.normals;
|
||||
int[] t = mesh.triangles;
|
||||
if(convertToRightHandedCoordinates) System.Array.Reverse(t);
|
||||
int triLen = t.Length;
|
||||
|
||||
for(int i = 0; i < triLen; i+=3)
|
||||
{
|
||||
int a = t[i];
|
||||
int b = t[i+1];
|
||||
int c = t[i+2];
|
||||
|
||||
Vector3 nrm = AvgNrm(n[a], n[b], n[c]);
|
||||
|
||||
sb.AppendLine(string.Format("facet normal {0} {1} {2}", nrm.x, nrm.y, nrm.z));
|
||||
|
||||
sb.AppendLine("outer loop");
|
||||
|
||||
sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[a].x, v[a].y, v[a].z));
|
||||
sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[b].x, v[b].y, v[b].z));
|
||||
sb.AppendLine(string.Format("\tvertex {0} {1} {2}", v[c].x, v[c].y, v[c].z));
|
||||
|
||||
sb.AppendLine("endloop");
|
||||
|
||||
sb.AppendLine("endfacet");
|
||||
}
|
||||
}
|
||||
|
||||
sb.AppendLine(string.Format("endsolid {0}", name));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static Vector3[] Left2Right(Vector3[] v)
|
||||
{
|
||||
Vector3[] r = new Vector3[v.Length];
|
||||
|
||||
for (int i = 0; i < v.Length; i++)
|
||||
r[i] = new Vector3(v[i].z, -v[i].x, v[i].y);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Average of 3 vectors.
|
||||
*/
|
||||
private static Vector3 AvgNrm(Vector3 a, Vector3 b, Vector3 c)
|
||||
{
|
||||
return new Vector3(
|
||||
(a.x + b.x + c.x) / 3f,
|
||||
(a.y + b.y + c.y) / 3f,
|
||||
(a.z + b.z + c.z) / 3f );
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 396694d6dbd4734419cea5be4a942c9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.ProBuilder.Stl
|
||||
{
|
||||
/**
|
||||
* Provides menu items for writing STL files from a scene selection.
|
||||
*/
|
||||
static class pb_Stl_Exporter
|
||||
{
|
||||
/**
|
||||
* Export a hierarchy of GameObjects to path with file type.
|
||||
*/
|
||||
public static bool Export(string path, GameObject[] gameObjects, FileType type)
|
||||
{
|
||||
Mesh[] meshes = CreateWorldSpaceMeshesWithTransforms(gameObjects.Select(x => x.transform).ToArray());
|
||||
bool success = false;
|
||||
|
||||
if(meshes != null && meshes.Length > 0)
|
||||
{
|
||||
if(!string.IsNullOrEmpty(path))
|
||||
success = pb_Stl.WriteFile(path, meshes, type);
|
||||
}
|
||||
|
||||
for(int i = 0; meshes != null && i < meshes.Length; i++)
|
||||
Object.DestroyImmediate(meshes[i]);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a list of mesh values with their relative transformations intact.
|
||||
*/
|
||||
private static Mesh[] CreateWorldSpaceMeshesWithTransforms(IList<Transform> transforms)
|
||||
{
|
||||
if(transforms == null || transforms.Count < 1)
|
||||
return null;
|
||||
|
||||
// move root node to center of selection
|
||||
Vector3 p = Vector3.zero;
|
||||
|
||||
for(int i = 0; i < transforms.Count; i++)
|
||||
p += transforms[i].position;
|
||||
Vector3 mesh_center = p / (float) transforms.Count;
|
||||
|
||||
GameObject root = new GameObject();
|
||||
root.name = "ROOT";
|
||||
root.transform.position = mesh_center;
|
||||
|
||||
// copy all transforms to new root gameobject
|
||||
foreach(Transform t in transforms)
|
||||
{
|
||||
GameObject go = (GameObject) GameObject.Instantiate(t.gameObject);
|
||||
go.transform.SetParent(t.parent, false);
|
||||
go.transform.SetParent(root.transform, true);
|
||||
}
|
||||
|
||||
// move root to 0,0,0 so mesh transformations are relative to origin
|
||||
root.transform.position = Vector3.zero;
|
||||
|
||||
// create new meshes by iterating the root node and transforming vertex & normal
|
||||
// values (ignoring all other mesh attributes since STL doesn't care about them)
|
||||
List<MeshFilter> mfs = root.GetComponentsInChildren<MeshFilter>().Where(x => x.sharedMesh != null).ToList();
|
||||
int meshCount = mfs.Count;
|
||||
Mesh[] meshes = new Mesh[meshCount];
|
||||
|
||||
for(int i = 0; i < meshCount; i++)
|
||||
{
|
||||
Transform t = mfs[i].transform;
|
||||
|
||||
Vector3[] v = mfs[i].sharedMesh.vertices;
|
||||
Vector3[] n = mfs[i].sharedMesh.normals;
|
||||
|
||||
for(int it = 0; it < v.Length; it++)
|
||||
{
|
||||
v[it] = t.TransformPoint(v[it]);
|
||||
n[it] = t.TransformDirection(n[it]);
|
||||
}
|
||||
|
||||
Mesh m = new Mesh();
|
||||
|
||||
m.name = mfs[i].name;
|
||||
m.vertices = v;
|
||||
m.normals = n;
|
||||
m.triangles = mfs[i].sharedMesh.triangles;
|
||||
|
||||
meshes[i] = m;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
GameObject.DestroyImmediate(root);
|
||||
|
||||
return meshes;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cfc7aced6c45c0499ba73f07e633bac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Vendored
+294
@@ -0,0 +1,294 @@
|
||||
#pragma warning disable 0219
|
||||
|
||||
using UnityEngine;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace UnityEngine.ProBuilder.Stl
|
||||
{
|
||||
/**
|
||||
* Import methods for STL files.
|
||||
*/
|
||||
static class pb_Stl_Importer
|
||||
{
|
||||
const int MAX_FACETS_PER_MESH = 65535 / 3;
|
||||
|
||||
class Facet
|
||||
{
|
||||
public Vector3 normal;
|
||||
public Vector3 a, b, c;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("{0:F2}: {1:F2}, {2:F2}, {3:F2}", normal, a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import an STL file at path.
|
||||
*/
|
||||
public static Mesh[] Import(string path)
|
||||
{
|
||||
if( IsBinary(path) )
|
||||
{
|
||||
try
|
||||
{
|
||||
return ImportBinary(path);
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning(string.Format("Failed importing mesh at path {0}.\n{1}", path, e.ToString()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ImportAscii(path);
|
||||
}
|
||||
}
|
||||
|
||||
private static Mesh[] ImportBinary(string path)
|
||||
{
|
||||
Facet[] facets;
|
||||
|
||||
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(fs, new ASCIIEncoding()))
|
||||
{
|
||||
// read header
|
||||
byte[] header = br.ReadBytes(80);
|
||||
uint facetCount = br.ReadUInt32();
|
||||
facets = new Facet[facetCount];
|
||||
|
||||
for(uint i = 0; i < facetCount; i++)
|
||||
facets[i] = br.GetFacet();
|
||||
}
|
||||
}
|
||||
|
||||
return CreateMeshWithFacets(facets);
|
||||
}
|
||||
|
||||
private static Facet GetFacet(this BinaryReader binaryReader)
|
||||
{
|
||||
Facet facet = new Facet();
|
||||
facet.normal = binaryReader.GetVector3();
|
||||
|
||||
// maintain counter-clockwise orientation of vertices:
|
||||
facet.a = binaryReader.GetVector3();
|
||||
facet.c = binaryReader.GetVector3();
|
||||
facet.b = binaryReader.GetVector3();
|
||||
binaryReader.ReadUInt16(); // padding
|
||||
|
||||
return facet;
|
||||
}
|
||||
private static Vector3 GetVector3(this BinaryReader binaryReader)
|
||||
{
|
||||
Vector3 vector3 = new Vector3();
|
||||
for (int i = 0; i < 3; i++)
|
||||
vector3[i] = binaryReader.ReadSingle();
|
||||
return vector3.UnityCoordTrafo();
|
||||
}
|
||||
|
||||
private static Vector3 UnityCoordTrafo(this Vector3 vector3)
|
||||
{
|
||||
return new Vector3(-vector3.y, vector3.z, vector3.x);
|
||||
}
|
||||
|
||||
const int SOLID = 1;
|
||||
const int FACET = 2;
|
||||
const int OUTER = 3;
|
||||
const int VERTEX = 4;
|
||||
const int ENDLOOP = 5;
|
||||
const int ENDFACET = 6;
|
||||
const int ENDSOLID = 7;
|
||||
const int EMPTY = 0;
|
||||
|
||||
private static int ReadState(string line)
|
||||
{
|
||||
if(line.StartsWith("solid"))
|
||||
return SOLID;
|
||||
else if(line.StartsWith("facet"))
|
||||
return FACET;
|
||||
else if(line.StartsWith("outer"))
|
||||
return OUTER;
|
||||
else if(line.StartsWith("vertex"))
|
||||
return VERTEX;
|
||||
else if(line.StartsWith("endloop"))
|
||||
return ENDLOOP;
|
||||
else if(line.StartsWith("endfacet"))
|
||||
return ENDFACET;
|
||||
else if(line.StartsWith("endsolid"))
|
||||
return ENDSOLID;
|
||||
else
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
private static Mesh[] ImportAscii(string path)
|
||||
{
|
||||
List<Facet> facets = new List<Facet>();
|
||||
|
||||
using(StreamReader sr = new StreamReader(path))
|
||||
{
|
||||
string line;
|
||||
int state = EMPTY, vertex = 0;
|
||||
Facet f = null;
|
||||
bool exit = false;
|
||||
|
||||
while(sr.Peek() > 0 && !exit)
|
||||
{
|
||||
line = sr.ReadLine().Trim();
|
||||
int previousState = state;
|
||||
state = ReadState(line);
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case SOLID:
|
||||
continue;
|
||||
|
||||
case FACET:
|
||||
f = new Facet();
|
||||
f.normal = StringToVec3(line.Replace("facet normal ", ""));
|
||||
break;
|
||||
|
||||
case OUTER:
|
||||
vertex = 0;
|
||||
break;
|
||||
|
||||
case VERTEX:
|
||||
// maintain counter-clockwise orientation of vertices:
|
||||
if (vertex == 0) f.a = StringToVec3(line.Replace("vertex ", ""));
|
||||
else if(vertex == 2) f.c = StringToVec3(line.Replace("vertex ", ""));
|
||||
else if (vertex == 1) f.b = StringToVec3(line.Replace("vertex ", ""));
|
||||
vertex++;
|
||||
break;
|
||||
|
||||
case ENDLOOP:
|
||||
break;
|
||||
|
||||
case ENDFACET:
|
||||
facets.Add(f);
|
||||
break;
|
||||
|
||||
case ENDSOLID:
|
||||
exit = true;
|
||||
break;
|
||||
|
||||
case EMPTY:
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CreateMeshWithFacets(facets);
|
||||
}
|
||||
|
||||
private static Vector3 StringToVec3(string str)
|
||||
{
|
||||
string[] split = str.Trim().Split(null);
|
||||
Vector3 v = new Vector3();
|
||||
|
||||
float.TryParse(split[0], out v.x);
|
||||
float.TryParse(split[1], out v.y);
|
||||
float.TryParse(split[2], out v.z);
|
||||
|
||||
return v.UnityCoordTrafo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the first 80 bytes of a file and if they are all 0x0 it's likely
|
||||
* that this file is binary.
|
||||
*/
|
||||
private static bool IsBinary(string path)
|
||||
{
|
||||
// http://stackoverflow.com/questions/968935/compare-binary-files-in-c-sharp
|
||||
FileInfo file = new FileInfo(path);
|
||||
|
||||
if(file.Length < 130)
|
||||
return false;
|
||||
|
||||
var isBinary = false;
|
||||
|
||||
using(FileStream f0 = file.OpenRead())
|
||||
{
|
||||
using(BufferedStream bs0 = new BufferedStream(f0))
|
||||
{
|
||||
for(long i = 0; i < 80; i++)
|
||||
{
|
||||
var readByte = bs0.ReadByte();
|
||||
if (readByte == 0x0)
|
||||
{
|
||||
isBinary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isBinary)
|
||||
{
|
||||
using (FileStream f0 = file.OpenRead())
|
||||
{
|
||||
using (BufferedStream bs0 = new BufferedStream(f0))
|
||||
{
|
||||
var byteArray = new byte[6];
|
||||
|
||||
for (var i = 0; i < 6; i++)
|
||||
{
|
||||
byteArray[i] = (byte)bs0.ReadByte();
|
||||
}
|
||||
|
||||
var text = Encoding.UTF8.GetString(byteArray);
|
||||
isBinary = text != "solid ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isBinary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo test with > USHORT_MAX vertex count meshes
|
||||
*/
|
||||
private static Mesh[] CreateMeshWithFacets(IList<Facet> facets)
|
||||
{
|
||||
int fl = facets.Count, f = 0, mvc = MAX_FACETS_PER_MESH * 3;
|
||||
Mesh[] meshes = new Mesh[fl / MAX_FACETS_PER_MESH + 1];
|
||||
|
||||
for(int i = 0; i < meshes.Length; i++)
|
||||
{
|
||||
int len = System.Math.Min(mvc, (fl - f) * 3);
|
||||
Vector3[] v = new Vector3[len];
|
||||
Vector3[] n = new Vector3[len];
|
||||
int[] t = new int[len];
|
||||
|
||||
for(int it = 0; it < len; it += 3)
|
||||
{
|
||||
v[it ] = facets[f].a;
|
||||
v[it+1] = facets[f].b;
|
||||
v[it+2] = facets[f].c;
|
||||
|
||||
n[it ] = facets[f].normal;
|
||||
n[it+1] = facets[f].normal;
|
||||
n[it+2] = facets[f].normal;
|
||||
|
||||
t[it ] = it;
|
||||
t[it+1] = it+1;
|
||||
t[it+2] = it+2;
|
||||
|
||||
f++;
|
||||
}
|
||||
|
||||
meshes[i] = new Mesh();
|
||||
meshes[i].vertices = v;
|
||||
meshes[i].normals = n;
|
||||
meshes[i].triangles = t;
|
||||
}
|
||||
|
||||
return meshes;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7dc1dc9c919fa434c915ad64201952dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user