Skip to content

Instantly share code, notes, and snippets.

@findstr

findstr/Decal.cs

Created Jun 17, 2018
Embed
What would you like to do?
Decal(Mesh Projector)
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
class MeshBuilder {
private readonly List<Vector3> vertices = new List<Vector3>();
private readonly List<Vector3> normals = new List<Vector3>();
private readonly List<Vector2> texCoords = new List<Vector2>();
private readonly List<int> indices = new List<int>();
private int FindVertex(Vector3 vertex) {
for (int i = 0; i < vertices.Count; i++) {
if (Vector3.Distance( vertices[i], vertex ) < 0.01f) return i;
}
return -1;
}
private void AddTexCoord(Vector3 ver) {
float u = Mathf.Lerp(0.0f, 1.0f, ver.x + 0.5f);
float v = Mathf.Lerp(0.0f, 1.0f, ver.z + 0.5f);
texCoords.Add( new Vector2( u, v ) );
}
private int AddVertex(Vector3 vertex, Vector3 normal) {
int index = FindVertex(vertex);
if (index == -1) {
vertices.Add(vertex);
normals.Add(normal);
AddTexCoord(vertex);
return vertices.Count - 1;
} else {
normals[index] = (normals[index] + normal).normalized;
return index;
}
}
public void AddPolygon(Vector3[] poly, Vector3 normal) {
int ind1 = AddVertex( poly[0], normal);
for (int i = 1; i < poly.Length - 1; i++) {
int ind2 = AddVertex( poly[i], normal);
int ind3 = AddVertex( poly[i + 1], normal);
indices.Add( ind1 );
indices.Add( ind2 );
indices.Add( ind3 );
}
}
public void Push(float distance) {
for (int i = 0; i < vertices.Count; i++) {
vertices[i] += normals[i] * distance;
}
}
public void ToMesh(Mesh mesh) {
mesh.Clear( true );
if (indices.Count == 0) return;
mesh.vertices = vertices.ToArray();
mesh.normals = normals.ToArray();
mesh.uv = texCoords.ToArray();
mesh.uv2 = texCoords.ToArray();
mesh.triangles = indices.ToArray();
vertices.Clear();
normals.Clear();
texCoords.Clear();
indices.Clear();
}
}
static class PolygonClippingUtils {
private static readonly Plane right = new Plane( Vector3.right, 0.5f );
private static readonly Plane left = new Plane( Vector3.left, 0.5f );
private static readonly Plane top = new Plane( Vector3.up, 0.5f );
private static readonly Plane bottom = new Plane( Vector3.down, 0.5f );
private static readonly Plane front = new Plane( Vector3.forward, 0.5f );
private static readonly Plane back = new Plane( Vector3.back, 0.5f );
public static Vector3[] Clip(params Vector3[] poly) {
poly = Clip( poly, right ).ToArray();
poly = Clip( poly, left ).ToArray();
poly = Clip( poly, top ).ToArray();
poly = Clip( poly, bottom ).ToArray();
poly = Clip( poly, front ).ToArray();
poly = Clip( poly, back ).ToArray();
return poly;
}
private static IEnumerable<Vector3> Clip(Vector3[] poly, Plane plane) {
for (int i = 0; i < poly.Length; i++) {
int next = (i + 1) % poly.Length;
Vector3 v1 = poly[i];
Vector3 v2 = poly[next];
if (plane.GetSide( v1 )) {
yield return v1;
}
if (plane.GetSide( v1 ) != plane.GetSide( v2 )) {
yield return PlaneLineCast( plane, v1, v2 );
}
}
}
private static Vector3 PlaneLineCast(Plane plane, Vector3 a, Vector3 b) {
float dis;
Ray ray = new Ray( a, b - a );
plane.Raycast( ray, out dis );
return ray.GetPoint( dis );
}
}
[RequireComponent( typeof( MeshFilter ) )]
[RequireComponent( typeof( MeshRenderer ) )]
[ExecuteInEditMode]
public class Decal : MonoBehaviour {
public Sprite sprite;
public Material material;
private readonly MeshBuilder builder = new MeshBuilder();
private Vector3 radius = new Vector3(1, 1, 1);
// Use this for initialization
void Start () {
}
private static bool HasLayer(LayerMask mask, int layer) {
return (mask.value & 1 << layer) != 0;
}
public MeshFilter[] GetAffectObjects() {
Bounds bounds = new Bounds(transform.position, radius);
return GameObject.FindObjectsOfType<MeshRenderer>()
.Where( obj => obj.gameObject.isStatic )
.Where( obj => obj.GetComponent<Decal>() == null )
.Where( obj => bounds.Intersects( obj.bounds ) )
.Select( obj => obj.GetComponent<MeshFilter>() )
.Where( obj => obj != null && obj.sharedMesh != null )
.ToArray();
}
private Rect To01(Rect rect, Texture2D texture) {
rect.x /= texture.width;
rect.y /= texture.height;
rect.width /= texture.width;
rect.height /= texture.height;
return rect;
}
private void AddTriangle(MeshBuilder builder, Vector3 v1, Vector3 v2, Vector3 v3) {
Vector3 normal = Vector3.Cross( v2 - v1, v3 - v1 ).normalized;
if (Vector3.Angle( Vector3.forward, -normal ) <= 90.0f) {
var poly = PolygonClippingUtils.Clip( v1, v2, v3 );
if (poly.Length > 0) {
builder.AddPolygon(poly, normal);
}
}
}
private string PV(Vector3 v) {
return ":x:" + v.x + ":y:" + v.y + ":z:" + v.z;
}
private void Build(MeshBuilder builder, MeshFilter filter) {
Matrix4x4 tolocal = transform.worldToLocalMatrix * filter.transform.localToWorldMatrix;
Mesh mesh = filter.sharedMesh;
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;
Debug.Log("Build:" + triangles.Length);
for (int i = 0; i < triangles.Length; i += 3) {
int i1 = triangles[i];
int i2 = triangles[i + 1];
int i3 = triangles[i + 2];
Vector3 v1l = vertices[i1];
Vector3 v2l = vertices[i2];
Vector3 v3l = vertices[i3];
Vector3 v1 = tolocal.MultiplyPoint(vertices[i1]);
Vector3 v2 = tolocal.MultiplyPoint(vertices[i2]);
Vector3 v3 = tolocal.MultiplyPoint(vertices[i3]);
AddTriangle(builder, v1, v2, v3);
}
}
// Update is called once per frame
void Update () {
if (transform.hasChanged == false)
return ;
MeshFilter filter = GetComponent<MeshFilter>();
MeshRenderer renderer = GetComponent<MeshRenderer>();
transform.hasChanged = false;
if (filter.sharedMesh != null && !filter.sharedMesh.isReadable)
return ;
var objects = GetAffectObjects();
foreach (var obj in objects) {
Debug.Log("___:" + obj);
Build(builder, obj);
}
if (filter.sharedMesh == null) {
filter.sharedMesh = new Mesh();
filter.sharedMesh.name = "DecalGGG";
}
builder.Push(0.009f);
builder.ToMesh( filter.sharedMesh );
renderer.sharedMaterial = material;
return ;
}
void OnDrawGizmosSelected() {
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = Color.yellow;
Gizmos.DrawWireCube(new Vector3(0, 0, 0), radius);
}
[DrawGizmo(GizmoType.InSelectionHierarchy | GizmoType.NotInSelectionHierarchy)]
static void DrawGameObjectName(Transform transform, GizmoType gizmoType)
{
/*
GUIStyle style = new GUIStyle();
style.normal.textColor = Color.red;
Handles.Label(transform.position, transform.gameObject.name, style);
*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment