Added player character and step in/out of dialogue in scene 101

This commit is contained in:
2026-08-15 15:22:47 +02:00
parent a42f25d5fa
commit 38ba2b0eff
2019 changed files with 181227 additions and 265 deletions
@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("Unity.ProBuilder")]
[assembly:InternalsVisibleTo("Unity.ProBuilder.Editor")]
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 90c015bd1316c423b9aad70704f602ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,134 @@
// Original CSG.JS library by Evan Wallace (http://madebyevan.com), under the MIT license.
// GitHub: https://github.com/evanw/csg.js/
//
// C++ port by Tomasz Dabrowski (http://28byteslater.com), under the MIT license.
// GitHub: https://github.com/dabroz/csgjs-cpp/
//
// C# port by Karl Henkel (parabox.co), under MIT license.
//
// Constructive Solid Geometry (CSG) is a modeling technique that uses Boolean
// operations like union and intersection to combine 3D solids. This library
// implements CSG operations on meshes elegantly and concisely using BSP trees,
// and is meant to serve as an easily understandable implementation of the
// algorithm. All edge cases involving overlapping coplanar polygons in both
// solids are correctly handled.
using UnityEngine;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.ProBuilder.Editor.Tests")]
namespace UnityEngine.ProBuilder.Csg
{
/// <summary>
/// Base class for CSG operations. Contains GameObject level methods for Subtraction, Intersection, and Union
/// operations. The GameObjects passed to these functions will not be modified.
/// </summary>
static class CSG
{
public enum BooleanOp
{
Intersection,
Union,
Subtraction
}
const float k_DefaultEpsilon = 0.00001f;
static float s_Epsilon = k_DefaultEpsilon;
/// <summary>
/// Tolerance used by <see cref="Plane.SplitPolygon"/> determine whether planes are coincident.
/// </summary>
public static float epsilon
{
get => s_Epsilon;
set => s_Epsilon = value;
}
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void ResetStaticsOnLoad()
{
s_Epsilon = k_DefaultEpsilon;
}
#endif
/// <summary>
/// Performs a boolean operation on two GameObjects.
/// </summary>
/// <returns>A new mesh.</returns>
public static Model Perform(BooleanOp op, GameObject lhs, GameObject rhs)
{
switch (op)
{
case BooleanOp.Intersection:
return Intersect(lhs, rhs);
case BooleanOp.Union:
return Union(lhs, rhs);
case BooleanOp.Subtraction:
return Subtract(lhs, rhs);
default:
return null;
}
}
/// <summary>
/// Returns a new mesh by merging @lhs with @rhs.
/// </summary>
/// <param name="lhs">The base mesh of the boolean operation.</param>
/// <param name="rhs">The input mesh of the boolean operation.</param>
/// <returns>A new mesh if the operation succeeds, or null if an error occurs.</returns>
public static Model Union(GameObject lhs, GameObject rhs)
{
Model csg_model_a = new Model(lhs);
Model csg_model_b = new Model(rhs);
Node a = new Node(csg_model_a.ToPolygons());
Node b = new Node(csg_model_b.ToPolygons());
List<Polygon> polygons = Node.Union(a, b).AllPolygons();
return new Model(polygons);
}
/// <summary>
/// Returns a new mesh by subtracting @lhs with @rhs.
/// </summary>
/// <param name="lhs">The base mesh of the boolean operation.</param>
/// <param name="rhs">The input mesh of the boolean operation.</param>
/// <returns>A new mesh if the operation succeeds, or null if an error occurs.</returns>
public static Model Subtract(GameObject lhs, GameObject rhs)
{
Model csg_model_a = new Model(lhs);
Model csg_model_b = new Model(rhs);
Node a = new Node(csg_model_a.ToPolygons());
Node b = new Node(csg_model_b.ToPolygons());
List<Polygon> polygons = Node.Subtract(a, b).AllPolygons();
return new Model(polygons);
}
/// <summary>
/// Returns a new mesh by intersecting @lhs with @rhs.
/// </summary>
/// <param name="lhs">The base mesh of the boolean operation.</param>
/// <param name="rhs">The input mesh of the boolean operation.</param>
/// <returns>A new mesh if the operation succeeds, or null if an error occurs.</returns>
public static Model Intersect(GameObject lhs, GameObject rhs)
{
Model csg_model_a = new Model(lhs);
Model csg_model_b = new Model(rhs);
Node a = new Node(csg_model_a.ToPolygons());
Node b = new Node(csg_model_b.ToPolygons());
List<Polygon> polygons = Node.Intersect(a, b).AllPolygons();
return new Model(polygons);
}
}
}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 136c7ff4a0ec419280b8df0d260180d0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 291cedf2747a43b19e37963cf9100589
folderAsset: yes
DefaultImporter:
userData:
@@ -0,0 +1,139 @@
using System;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace UnityEngine.ProBuilder.Csg
{
/// <summary>
/// Representation of a mesh in CSG terms. Contains methods for translating to and from UnityEngine.Mesh.
/// </summary>
sealed class Model
{
List<Vertex> m_Vertices;
List<Material> m_Materials;
List<List<int>> m_Indices;
public List<Material> materials
{
get { return m_Materials; }
set { m_Materials = value; }
}
public List<Vertex> vertices
{
get { return m_Vertices; }
set { m_Vertices = value; }
}
public List<List<int>> indices
{
get { return m_Indices; }
set { m_Indices = value; }
}
public Mesh mesh
{
get { return (Mesh)this; }
}
public Model(GameObject gameObject) :
this(gameObject.GetComponent<MeshFilter>()?.sharedMesh,
gameObject.GetComponent<MeshRenderer>()?.sharedMaterials,
gameObject.GetComponent<Transform>())
{
}
/// <summary>
/// Initialize a Model from a UnityEngine.Mesh and transform.
/// </summary>
public Model(Mesh mesh, Material[] materials, Transform transform)
{
if(mesh == null)
throw new ArgumentNullException("mesh");
if(transform == null)
throw new ArgumentNullException("transform");
m_Vertices = VertexUtility.GetVertices(mesh).Select(x => transform.TransformVertex(x)).ToList();
m_Materials = new List<Material>(materials);
m_Indices = new List<List<int>>();
for (int i = 0, c = mesh.subMeshCount; i < c; i++)
{
if (mesh.GetTopology(i) != MeshTopology.Triangles)
continue;
var indices = new List<int>();
mesh.GetIndices(indices, i);
m_Indices.Add(indices);
}
}
internal Model(List<Polygon> polygons)
{
m_Vertices = new List<Vertex>();
Dictionary<Material, List<int>> submeshes = new Dictionary<Material, List<int>>();
int p = 0;
for (int i = 0; i < polygons.Count; i++)
{
Polygon poly = polygons[i];
List<int> indices;
if (!submeshes.TryGetValue(poly.material, out indices))
submeshes.Add(poly.material, indices = new List<int>());
for (int j = 2; j < poly.vertices.Count; j++)
{
m_Vertices.Add(poly.vertices[0]);
indices.Add(p++);
m_Vertices.Add(poly.vertices[j - 1]);
indices.Add(p++);
m_Vertices.Add(poly.vertices[j]);
indices.Add(p++);
}
}
m_Materials = submeshes.Keys.ToList();
m_Indices = submeshes.Values.ToList();
}
internal List<Polygon> ToPolygons()
{
List<Polygon> list = new List<Polygon>();
for (int s = 0, c = m_Indices.Count; s < c; s++)
{
var indices = m_Indices[s];
for (int i = 0, ic = indices.Count; i < indices.Count; i += 3)
{
List<Vertex> triangle = new List<Vertex>()
{
m_Vertices[indices[i + 0]],
m_Vertices[indices[i + 1]],
m_Vertices[indices[i + 2]]
};
list.Add(new Polygon(triangle, m_Materials[s]));
}
}
return list;
}
public static explicit operator Mesh(Model model)
{
var mesh = new Mesh();
VertexUtility.SetMesh(mesh, model.m_Vertices);
mesh.subMeshCount = model.m_Indices.Count;
for (int i = 0, c = mesh.subMeshCount; i < c; i++)
mesh.SetIndices(model.m_Indices[i], MeshTopology.Triangles, i);
return mesh;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 14789abc21c8f4551995149f67010e23
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,256 @@
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace UnityEngine.ProBuilder.Csg
{
sealed class Node
{
public List<Polygon> polygons;
public Node front;
public Node back;
public Plane plane;
public Node()
{
front = null;
back = null;
}
public Node(List<Polygon> list)
{
Build(list);
}
public Node(List<Polygon> list, Plane plane, Node front, Node back)
{
this.polygons = list;
this.plane = plane;
this.front = front;
this.back = back;
}
public Node Clone()
{
Node clone = new Node(this.polygons, this.plane, this.front, this.back);
return clone;
}
// Remove all polygons in this BSP tree that are inside the other BSP tree
// `bsp`.
public void ClipTo(Node other)
{
this.polygons = other.ClipPolygons(this.polygons);
if (this.front != null)
{
this.front.ClipTo(other);
}
if (this.back != null)
{
this.back.ClipTo(other);
}
}
// Convert solid space to empty space and empty space to solid space.
public void Invert()
{
for (int i = 0; i < this.polygons.Count; i++)
this.polygons[i].Flip();
this.plane.Flip();
if (this.front != null)
{
this.front.Invert();
}
if (this.back != null)
{
this.back.Invert();
}
Node tmp = this.front;
this.front = this.back;
this.back = tmp;
}
// Build a BSP tree out of `polygons`. When called on an existing tree, the
// new polygons are filtered down to the bottom of the tree and become new
// nodes there. Each set of polygons is partitioned using the first polygon
// (no heuristic is used to pick a good split).
public void Build(List<Polygon> list)
{
if (list.Count < 1)
return;
bool newNode = plane == null || !plane.Valid();
if (newNode)
{
plane = new Plane();
plane.normal = list[0].plane.normal;
plane.w = list[0].plane.w;
}
if (polygons == null)
polygons = new List<Polygon>();
var listFront = new List<Polygon>();
var listBack = new List<Polygon>();
for (int i = 0; i < list.Count; i++)
plane.SplitPolygon(list[i], polygons, polygons, listFront, listBack);
if (listFront.Count > 0)
{
// SplitPolygon can fail to correctly identify coplanar planes when the epsilon value is too low. When
// this happens, the front or back list will be filled and built into a new node recursively. This
// check catches that case and sorts the front/back lists into the coplanar polygons collection.
if (newNode && list.SequenceEqual(listFront))
polygons.AddRange(listFront);
else
(front ?? (front = new Node())).Build(listFront);
}
if (listBack.Count > 0)
{
if (newNode && list.SequenceEqual(listBack))
polygons.AddRange(listBack);
else
(back ?? (back = new Node())).Build(listBack);
}
}
// Recursively remove all polygons in `polygons` that are inside this BSP tree.
public List<Polygon> ClipPolygons(List<Polygon> list)
{
if (!this.plane.Valid())
{
return list;
}
List<Polygon> list_front = new List<Polygon>();
List<Polygon> list_back = new List<Polygon>();
for (int i = 0; i < list.Count; i++)
{
this.plane.SplitPolygon(list[i], list_front, list_back, list_front, list_back);
}
if (this.front != null)
{
list_front = this.front.ClipPolygons(list_front);
}
if (this.back != null)
{
list_back = this.back.ClipPolygons(list_back);
}
else
{
list_back.Clear();
}
// Position [First, Last]
// list_front.insert(list_front.end(), list_back.begin(), list_back.end());
list_front.AddRange(list_back);
return list_front;
}
// Return a list of all polygons in this BSP tree.
public List<Polygon> AllPolygons()
{
List<Polygon> list = this.polygons;
List<Polygon> list_front = new List<Polygon>(), list_back = new List<Polygon>();
if (this.front != null)
{
list_front = this.front.AllPolygons();
}
if (this.back != null)
{
list_back = this.back.AllPolygons();
}
list.AddRange(list_front);
list.AddRange(list_back);
return list;
}
#region STATIC OPERATIONS
// Return a new CSG solid representing space in either this solid or in the
// solid `csg`. Neither this solid nor the solid `csg` are modified.
public static Node Union(Node a1, Node b1)
{
Node a = a1.Clone();
Node b = b1.Clone();
a.ClipTo(b);
b.ClipTo(a);
b.Invert();
b.ClipTo(a);
b.Invert();
a.Build(b.AllPolygons());
Node ret = new Node(a.AllPolygons());
return ret;
}
// Return a new CSG solid representing space in this solid but not in the
// solid `csg`. Neither this solid nor the solid `csg` are modified.
public static Node Subtract(Node a1, Node b1)
{
Node a = a1.Clone();
Node b = b1.Clone();
a.Invert();
a.ClipTo(b);
b.ClipTo(a);
b.Invert();
b.ClipTo(a);
b.Invert();
a.Build(b.AllPolygons());
a.Invert();
Node ret = new Node(a.AllPolygons());
return ret;
}
// Return a new CSG solid representing space both this solid and in the
// solid `csg`. Neither this solid nor the solid `csg` are modified.
public static Node Intersect(Node a1, Node b1)
{
Node a = a1.Clone();
Node b = b1.Clone();
a.Invert();
b.ClipTo(a);
b.Invert();
a.ClipTo(b);
b.ClipTo(a);
a.Build(b.AllPolygons());
a.Invert();
Node ret = new Node(a.AllPolygons());
return ret;
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b6fe112f5d10423ab960f97d7b6e699
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,156 @@
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace UnityEngine.ProBuilder.Csg
{
/// <summary>
/// Represents a plane in 3d space.
/// <remarks>Does not include position.</remarks>
/// </summary>
sealed class Plane
{
public Vector3 normal;
public float w;
[System.Flags]
enum EPolygonType
{
Coplanar = 0,
Front = 1,
Back = 2,
Spanning = 3 /// 3 is Front | Back - not a separate entry
};
public Plane()
{
normal = Vector3.zero;
w = 0f;
}
public Plane(Vector3 a, Vector3 b, Vector3 c)
{
normal = Vector3.Cross(b - a, c - a);//.normalized;
w = Vector3.Dot(normal, a);
}
public override string ToString() => $"{normal} {w}";
public bool Valid()
{
return normal.magnitude > 0f;
}
public void Flip()
{
normal *= -1f;
w *= -1f;
}
// Split `polygon` by this plane if needed, then put the polygon or polygon
// fragments in the appropriate lists. Coplanar polygons go into either
// `coplanarFront` or `coplanarBack` depending on their orientation with
// respect to this plane. Polygons in front or in back of this plane go into
// either `front` or `back`.
public void SplitPolygon(Polygon polygon, List<Polygon> coplanarFront, List<Polygon> coplanarBack, List<Polygon> front, List<Polygon> back)
{
// Classify each point as well as the entire polygon into one of the above
// four classes.
EPolygonType polygonType = 0;
List<EPolygonType> types = new List<EPolygonType>();
for (int i = 0; i < polygon.vertices.Count; i++)
{
float t = Vector3.Dot(this.normal, polygon.vertices[i].position) - this.w;
EPolygonType type = (t < -CSG.epsilon) ? EPolygonType.Back : ((t > CSG.epsilon) ? EPolygonType.Front : EPolygonType.Coplanar);
polygonType |= type;
types.Add(type);
}
// Put the polygon in the correct list, splitting it when necessary.
switch (polygonType)
{
case EPolygonType.Coplanar:
{
if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
coplanarFront.Add(polygon);
else
coplanarBack.Add(polygon);
}
break;
case EPolygonType.Front:
{
front.Add(polygon);
}
break;
case EPolygonType.Back:
{
back.Add(polygon);
}
break;
case EPolygonType.Spanning:
{
List<Vertex> f = new List<Vertex>();
List<Vertex> b = new List<Vertex>();
for (int i = 0; i < polygon.vertices.Count; i++)
{
int j = (i + 1) % polygon.vertices.Count;
EPolygonType ti = types[i], tj = types[j];
Vertex vi = polygon.vertices[i], vj = polygon.vertices[j];
if (ti != EPolygonType.Back)
{
f.Add(vi);
}
if (ti != EPolygonType.Front)
{
b.Add(vi);
}
if ((ti | tj) == EPolygonType.Spanning)
{
float t = (this.w - Vector3.Dot(this.normal, vi.position)) / Vector3.Dot(this.normal, vj.position - vi.position);
Vertex v = VertexUtility.Mix(vi, vj, t);
f.Add(v);
b.Add(v);
}
}
if (f.Count >= 3)
{
if (f.SequenceEqual(polygon.vertices))
front.Add(polygon);
else
{
var p = new Polygon(f, polygon.material);
if (p.plane.Valid())
front.Add(p);
}
}
if (b.Count >= 3)
{
if (b.SequenceEqual(polygon.vertices))
back.Add(polygon);
else
{
var p = new Polygon(b, polygon.material);
if (p.plane.Valid())
back.Add(p);
}
}
}
break;
} // End switch(polygonType)
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2665d2fb2b90b4916bfb3868cda99ea3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,37 @@
using UnityEngine;
using System.Collections.Generic;
namespace UnityEngine.ProBuilder.Csg
{
/// <summary>
/// Represents a polygon face with an arbitrary number of vertices.
/// </summary>
sealed class Polygon
{
public List<Vertex> vertices;
public Plane plane;
public Material material;
public Polygon(List<Vertex> list, Material mat)
{
vertices = list;
plane = new Plane(list[0].position, list[1].position, list[2].position);
material = mat;
}
public void Flip()
{
vertices.Reverse();
for (int i = 0; i < vertices.Count; i++)
vertices[i].Flip();
plane.Flip();
}
public override string ToString()
{
return $"[{vertices.Count}] {plane.normal}";
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 52ebe52d390074084bebc0878e3f74b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,193 @@
using System;
using UnityEngine;
namespace UnityEngine.ProBuilder.Csg
{
/// <summary>
/// Holds information about a single vertex, and provides methods for averaging between many.
/// <remarks>All values are optional. Where not present a default value will be substituted if necessary.</remarks>
/// </summary>
struct Vertex
{
Vector3 m_Position;
Color m_Color;
Vector3 m_Normal;
Vector4 m_Tangent;
Vector2 m_UV0;
Vector2 m_UV2;
Vector4 m_UV3;
Vector4 m_UV4;
VertexAttributes m_Attributes;
/// <value>
/// The position in model space.
/// </value>
public Vector3 position
{
get { return m_Position; }
set
{
hasPosition = true;
m_Position = value;
}
}
/// <value>
/// Vertex color.
/// </value>
public Color color
{
get { return m_Color; }
set
{
hasColor = true;
m_Color = value;
}
}
/// <value>
/// Unit vector normal.
/// </value>
public Vector3 normal
{
get { return m_Normal; }
set
{
hasNormal = true;
m_Normal = value;
}
}
/// <value>
/// Vertex tangent (sometimes called binormal).
/// </value>
public Vector4 tangent
{
get { return m_Tangent; }
set
{
hasTangent = true;
m_Tangent = value;
}
}
/// <value>
/// UV 0 channel. Also called textures.
/// </value>
public Vector2 uv0
{
get { return m_UV0; }
set
{
hasUV0 = true;
m_UV0 = value;
}
}
/// <value>
/// UV 2 channel.
/// </value>
public Vector2 uv2
{
get { return m_UV2; }
set
{
hasUV2 = true;
m_UV2 = value;
}
}
/// <value>
/// UV 3 channel.
/// </value>
public Vector4 uv3
{
get { return m_UV3; }
set
{
hasUV3 = true;
m_UV3 = value;
}
}
/// <value>
/// UV 4 channel.
/// </value>
public Vector4 uv4
{
get { return m_UV4; }
set
{
hasUV4 = true;
m_UV4 = value;
}
}
/// <summary>
/// Find if a vertex attribute has been set.
/// </summary>
/// <param name="attribute">The attribute or attributes to test for.</param>
/// <returns>True if this vertex has the specified attributes set, false if they are default values.</returns>
public bool HasArrays(VertexAttributes attribute)
{
return (m_Attributes & attribute) == attribute;
}
public bool hasPosition
{
get { return (m_Attributes & VertexAttributes.Position) == VertexAttributes.Position; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Position) : (m_Attributes & ~(VertexAttributes.Position)); }
}
public bool hasColor
{
get { return (m_Attributes & VertexAttributes.Color) == VertexAttributes.Color; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Color) : (m_Attributes & ~(VertexAttributes.Color)); }
}
public bool hasNormal
{
get { return (m_Attributes & VertexAttributes.Normal) == VertexAttributes.Normal; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Normal) : (m_Attributes & ~(VertexAttributes.Normal)); }
}
public bool hasTangent
{
get { return (m_Attributes & VertexAttributes.Tangent) == VertexAttributes.Tangent; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Tangent) : (m_Attributes & ~(VertexAttributes.Tangent)); }
}
public bool hasUV0
{
get { return (m_Attributes & VertexAttributes.Texture0) == VertexAttributes.Texture0; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Texture0) : (m_Attributes & ~(VertexAttributes.Texture0)); }
}
public bool hasUV2
{
get { return (m_Attributes & VertexAttributes.Texture1) == VertexAttributes.Texture1; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Texture1) : (m_Attributes & ~(VertexAttributes.Texture1)); }
}
public bool hasUV3
{
get { return (m_Attributes & VertexAttributes.Texture2) == VertexAttributes.Texture2; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Texture2) : (m_Attributes & ~(VertexAttributes.Texture2)); }
}
public bool hasUV4
{
get { return (m_Attributes & VertexAttributes.Texture3) == VertexAttributes.Texture3; }
private set { m_Attributes = value ? (m_Attributes | VertexAttributes.Texture3) : (m_Attributes & ~(VertexAttributes.Texture3)); }
}
public void Flip()
{
if(hasNormal)
m_Normal *= -1f;
if (hasTangent)
m_Tangent *= -1f;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eace57ffc03f348e48d541e3ac67ae90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
namespace UnityEngine.ProBuilder.Csg
{
/// <summary>
/// Mesh attributes bitmask.
/// </summary>
[System.Flags]
enum VertexAttributes
{
/// <summary>
/// Vertex positions.
/// </summary>
Position = 0x1,
/// <summary>
/// First UV channel.
/// </summary>
Texture0 = 0x2,
/// <summary>
/// Second UV channel. Commonly called UV2 or Lightmap UVs in Unity terms.
/// </summary>
Texture1 = 0x4,
/// <summary>
/// Second UV channel. Commonly called UV2 or Lightmap UVs in Unity terms.
/// </summary>
Lightmap = 0x4,
/// <summary>
/// Third UV channel.
/// </summary>
Texture2 = 0x8,
/// <summary>
/// Vertex UV4.
/// </summary>
Texture3 = 0x10,
/// <summary>
/// Vertex colors.
/// </summary>
Color = 0x20,
/// <summary>
/// Vertex normals.
/// </summary>
Normal = 0x40,
/// <summary>
/// Vertex tangents.
/// </summary>
Tangent = 0x80,
/// <summary>
/// All stored mesh attributes.
/// </summary>
All = 0xFF
};
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7aeb98aaff5054383b10b45f4518f968
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,327 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEngine.ProBuilder.Csg
{
static class VertexUtility
{
/// <summary>
/// Allocate and fill all attribute arrays. This method will fill all arrays, regardless of whether or not real data populates the values (check what attributes a Vertex contains with HasAttribute()).
/// </summary>
/// <remarks>
/// If you are using this function to rebuild a mesh, use SetMesh instead. SetMesh handles setting null arrays where appropriate for you.
/// </remarks>
/// <seealso cref="SetMesh"/>
/// <param name="vertices">The source vertices.</param>
/// <param name="position">A new array of the vertex position values.</param>
/// <param name="color">A new array of the vertex color values.</param>
/// <param name="uv0">A new array of the vertex uv0 values.</param>
/// <param name="normal">A new array of the vertex normal values.</param>
/// <param name="tangent">A new array of the vertex tangent values.</param>
/// <param name="uv2">A new array of the vertex uv2 values.</param>
/// <param name="uv3">A new array of the vertex uv3 values.</param>
/// <param name="uv4">A new array of the vertex uv4 values.</param>
public static void GetArrays(
IList<Vertex> vertices,
out Vector3[] position,
out Color[] color,
out Vector2[] uv0,
out Vector3[] normal,
out Vector4[] tangent,
out Vector2[] uv2,
out List<Vector4> uv3,
out List<Vector4> uv4)
{
GetArrays(vertices, out position, out color, out uv0, out normal, out tangent, out uv2, out uv3, out uv4, VertexAttributes.All);
}
/// <summary>
/// Allocate and fill the requested attribute arrays.
/// </summary>
/// <remarks>
/// If you are using this function to rebuild a mesh, use SetMesh instead. SetMesh handles setting null arrays where appropriate for you.
/// </remarks>
/// <seealso cref="SetMesh"/>
/// <param name="vertices">The source vertices.</param>
/// <param name="position">A new array of the vertex position values if requested by the attributes parameter, or null.</param>
/// <param name="color">A new array of the vertex color values if requested by the attributes parameter, or null.</param>
/// <param name="uv0">A new array of the vertex uv0 values if requested by the attributes parameter, or null.</param>
/// <param name="normal">A new array of the vertex normal values if requested by the attributes parameter, or null.</param>
/// <param name="tangent">A new array of the vertex tangent values if requested by the attributes parameter, or null.</param>
/// <param name="uv2">A new array of the vertex uv2 values if requested by the attributes parameter, or null.</param>
/// <param name="uv3">A new array of the vertex uv3 values if requested by the attributes parameter, or null.</param>
/// <param name="uv4">A new array of the vertex uv4 values if requested by the attributes parameter, or null.</param>
/// <param name="attributes">A flag with the MeshAttributes requested.</param>
/// <seealso cref="HasArrays"/>
public static void GetArrays(
IList<Vertex> vertices,
out Vector3[] position,
out Color[] color,
out Vector2[] uv0,
out Vector3[] normal,
out Vector4[] tangent,
out Vector2[] uv2,
out List<Vector4> uv3,
out List<Vector4> uv4,
VertexAttributes attributes)
{
if (vertices == null)
throw new ArgumentNullException("vertices");
int vc = vertices.Count;
var first = vc < 1 ? new Vertex() : vertices[0];
bool hasPosition = ((attributes & VertexAttributes.Position) == VertexAttributes.Position) && first.hasPosition;
bool hasColor = ((attributes & VertexAttributes.Color) == VertexAttributes.Color) && first.hasColor;
bool hasUv0 = ((attributes & VertexAttributes.Texture0) == VertexAttributes.Texture0) && first.hasUV0;
bool hasNormal = ((attributes & VertexAttributes.Normal) == VertexAttributes.Normal) && first.hasNormal;
bool hasTangent = ((attributes & VertexAttributes.Tangent) == VertexAttributes.Tangent) && first.hasTangent;
bool hasUv2 = ((attributes & VertexAttributes.Texture1) == VertexAttributes.Texture1) && first.hasUV2;
bool hasUv3 = ((attributes & VertexAttributes.Texture2) == VertexAttributes.Texture2) && first.hasUV3;
bool hasUv4 = ((attributes & VertexAttributes.Texture3) == VertexAttributes.Texture3) && first.hasUV4;
position = hasPosition ? new Vector3[vc] : null;
color = hasColor ? new Color[vc] : null;
uv0 = hasUv0 ? new Vector2[vc] : null;
normal = hasNormal ? new Vector3[vc] : null;
tangent = hasTangent ? new Vector4[vc] : null;
uv2 = hasUv2 ? new Vector2[vc] : null;
uv3 = hasUv3 ? new List<Vector4>(vc) : null;
uv4 = hasUv4 ? new List<Vector4>(vc) : null;
for (int i = 0; i < vc; i++)
{
if (hasPosition)
position[i] = vertices[i].position;
if (hasColor)
color[i] = vertices[i].color;
if (hasUv0)
uv0[i] = vertices[i].uv0;
if (hasNormal)
normal[i] = vertices[i].normal;
if (hasTangent)
tangent[i] = vertices[i].tangent;
if (hasUv2)
uv2[i] = vertices[i].uv2;
if (hasUv3)
uv3.Add(vertices[i].uv3);
if (hasUv4)
uv4.Add(vertices[i].uv4);
}
}
public static Vertex[] GetVertices(this Mesh mesh)
{
if (mesh == null)
return null;
int vertexCount = mesh.vertexCount;
Vertex[] v = new Vertex[vertexCount];
Vector3[] positions = mesh.vertices;
Color[] colors = mesh.colors;
Vector3[] normals = mesh.normals;
Vector4[] tangents = mesh.tangents;
Vector2[] uv0s = mesh.uv;
Vector2[] uv2s = mesh.uv2;
List<Vector4> uv3s = new List<Vector4>();
List<Vector4> uv4s = new List<Vector4>();
mesh.GetUVs(2, uv3s);
mesh.GetUVs(3, uv4s);
bool _hasPositions = positions != null && positions.Length == vertexCount;
bool _hasColors = colors != null && colors.Length == vertexCount;
bool _hasNormals = normals != null && normals.Length == vertexCount;
bool _hasTangents = tangents != null && tangents.Length == vertexCount;
bool _hasUv0 = uv0s != null && uv0s.Length == vertexCount;
bool _hasUv2 = uv2s != null && uv2s.Length == vertexCount;
bool _hasUv3 = uv3s.Count == vertexCount;
bool _hasUv4 = uv4s.Count == vertexCount;
for (int i = 0; i < vertexCount; i++)
{
v[i] = new Vertex();
if (_hasPositions)
v[i].position = positions[i];
if (_hasColors)
v[i].color = colors[i];
if (_hasNormals)
v[i].normal = normals[i];
if (_hasTangents)
v[i].tangent = tangents[i];
if (_hasUv0)
v[i].uv0 = uv0s[i];
if (_hasUv2)
v[i].uv2 = uv2s[i];
if (_hasUv3)
v[i].uv3 = uv3s[i];
if (_hasUv4)
v[i].uv4 = uv4s[i];
}
return v;
}
/// <summary>
/// Replace mesh values with vertex array. Mesh is cleared during this function, so be sure to set the triangles after calling.
/// </summary>
/// <param name="mesh">The target mesh.</param>
/// <param name="vertices">The vertices to replace the mesh attributes with.</param>
public static void SetMesh(Mesh mesh, IList<Vertex> vertices)
{
if (mesh == null)
throw new ArgumentNullException("mesh");
if (vertices == null)
throw new ArgumentNullException("vertices");
Vector3[] positions = null;
Color[] colors = null;
Vector2[] uv0s = null;
Vector3[] normals = null;
Vector4[] tangents = null;
Vector2[] uv2s = null;
List<Vector4> uv3s = null;
List<Vector4> uv4s = null;
GetArrays(vertices, out positions,
out colors,
out uv0s,
out normals,
out tangents,
out uv2s,
out uv3s,
out uv4s);
mesh.Clear();
Vertex first = vertices[0];
if (first.hasPosition) mesh.vertices = positions;
if (first.hasColor) mesh.colors = colors;
if (first.hasUV0) mesh.uv = uv0s;
if (first.hasNormal) mesh.normals = normals;
if (first.hasTangent) mesh.tangents = tangents;
if (first.hasUV2) mesh.uv2 = uv2s;
if (first.hasUV3)
if (uv3s != null)
mesh.SetUVs(2, uv3s);
if (first.hasUV4)
if (uv4s != null)
mesh.SetUVs(3, uv4s);
}
/// <summary>
/// Linearly interpolate between two vertices.
/// </summary>
/// <param name="x">Left parameter.</param>
/// <param name="y">Right parameter.</param>
/// <param name="weight">The weight of the interpolation. 0 is fully x, 1 is fully y.</param>
/// <returns>A new vertex interpolated by weight between x and y.</returns>
public static Vertex Mix(this Vertex x, Vertex y, float weight)
{
float i = 1f - weight;
Vertex v = new Vertex();
v.position = x.position * i + y.position * weight;
if (x.hasColor && y.hasColor)
v.color = x.color * i + y.color * weight;
else if (x.hasColor)
v.color = x.color;
else if (y.hasColor)
v.color = y.color;
if (x.hasNormal && y.hasNormal)
v.normal = x.normal * i + y.normal * weight;
else if (x.hasNormal)
v.normal = x.normal;
else if (y.hasNormal)
v.normal = y.normal;
if (x.hasTangent && y.hasTangent)
v.tangent = x.tangent * i + y.tangent * weight;
else if (x.hasTangent)
v.tangent = x.tangent;
else if (y.hasTangent)
v.tangent = y.tangent;
if (x.hasUV0 && y.hasUV0)
v.uv0 = x.uv0 * i + y.uv0 * weight;
else if (x.hasUV0)
v.uv0 = x.uv0;
else if (y.hasUV0)
v.uv0 = y.uv0;
if (x.hasUV2 && y.hasUV2)
v.uv2 = x.uv2 * i + y.uv2 * weight;
else if (x.hasUV2)
v.uv2 = x.uv2;
else if (y.hasUV2)
v.uv2 = y.uv2;
if (x.hasUV3 && y.hasUV3)
v.uv3 = x.uv3 * i + y.uv3 * weight;
else if (x.hasUV3)
v.uv3 = x.uv3;
else if (y.hasUV3)
v.uv3 = y.uv3;
if (x.hasUV4 && y.hasUV4)
v.uv4 = x.uv4 * i + y.uv4 * weight;
else if (x.hasUV4)
v.uv4 = x.uv4;
else if (y.hasUV4)
v.uv4 = y.uv4;
return v;
}
/// <summary>
/// Transform a vertex into world space.
/// </summary>
/// <param name="transform">The transform to apply.</param>
/// <param name="vertex">A model space vertex.</param>
/// <returns>A new vertex in world coordinate space.</returns>
public static Vertex TransformVertex(this Transform transform, Vertex vertex)
{
var v = new Vertex();
if (vertex.HasArrays(VertexAttributes.Position))
v.position = transform.TransformPoint(vertex.position);
if (vertex.HasArrays(VertexAttributes.Color))
v.color = vertex.color;
if (vertex.HasArrays(VertexAttributes.Normal))
v.normal = transform.TransformDirection(vertex.normal);
if (vertex.HasArrays(VertexAttributes.Tangent))
v.tangent = transform.rotation * vertex.tangent;
if (vertex.HasArrays(VertexAttributes.Texture0))
v.uv0 = vertex.uv0;
if (vertex.HasArrays(VertexAttributes.Texture1))
v.uv2 = vertex.uv2;
if (vertex.HasArrays(VertexAttributes.Texture2))
v.uv3 = vertex.uv3;
if (vertex.HasArrays(VertexAttributes.Texture3))
v.uv4 = vertex.uv4;
return v;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a629cb73b331b40449fd411043caf7d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,12 @@
{
"name": "Unity.ProBuilder.Csg",
"references": [],
"optionalUnityReferences": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": []
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 26434c0544da24d83a23c99deaa60965
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: