Files
VR-WuKong/Assets/ThirdParty/BruteForce/Scripts/BF_AddSnow.cs

339 lines
9.9 KiB
C#
Raw Normal View History

2025-11-14 18:44:06 +08:00
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class BF_AddSnow : MonoBehaviour
{
public Material snowMaterial;
public float angle = 80f;
public bool isAuto = false;
public float intersectionOffset = 0.25f;
public bool useIntersection = false;
public bool useUpdatedRotation = false;
private Mesh originalMesh;
private MeshFilter meshFilter;
private Mesh newMesh;
private GameObject newGO;
private float yIntersection = 0f;
private Quaternion ySlope = Quaternion.identity;
private float zNormal = 0;
private Vector3 normalHit = Vector3.zero;
private float oldyIntersection = -1f;
private int[] oldTri;
private Vector3[] oldVert;
private Vector3[] oldNorm;
private Vector3[] oldNormWorld;
private Vector2[] oldUV;
private Color[] oldCol;
private List<int> triangles = new List<int>();
private List<Vector3> vertexs = new List<Vector3>();
private List<Vector2> uvs = new List<Vector2>();
private List<Color> cols = new List<Color>();
void Start()
{
CheckValues();
BuildInitialGeometry();
}
private void Update()
{
if (useIntersection)
{
CheckIntersection();
}
if (useUpdatedRotation)
{
UpdateVertexColor();
}
}
private void CheckValues()
{
meshFilter = gameObject.GetComponent<MeshFilter>();
originalMesh = meshFilter.mesh;
oldTri = originalMesh.triangles;
oldVert = originalMesh.vertices;
oldNorm = originalMesh.normals;
oldNormWorld = oldNorm;
if (isAuto)
{
int k = 0;
foreach (Vector3 norm in oldNorm)
{
oldNormWorld[k] = this.transform.localToWorldMatrix.MultiplyVector(norm).normalized;
k++;
}
oldCol = new Color[oldVert.Length];
}
else
{
oldCol = originalMesh.colors;
}
oldUV = originalMesh.uv;
}
private void CheckIntersection()
{
int layerMask = 1 << 0 | 1 << 4;
RaycastHit hit;
RaycastHit hitIfHit;
if (Physics.Raycast(transform.position + Vector3.up*5f, Vector3.down, out hit, 200, layerMask))
{
if (hit.transform != this.transform)
{
yIntersection = hit.point.y + intersectionOffset;
//Vector3 tangent = Vector3.ProjectOnPlane(Vector3.down, hit.normal).normalized;
ySlope = Quaternion.LookRotation(hit.normal, Vector3.forward);
zNormal = ((hit.normal.normalized.z) + 1f) / 2f;
normalHit = hit.normal.normalized;
if (yIntersection != oldyIntersection)
{
UpdateSlopeColor();
}
oldyIntersection = yIntersection;
}
else
{
if (Physics.Raycast(hit.point + Vector3.up * -0.05f, Vector3.down, out hitIfHit, 200, layerMask))
{
if (hitIfHit.transform != this.transform)
{
yIntersection = hitIfHit.point.y + intersectionOffset;
//Vector3 tangent = Vector3.ProjectOnPlane(Vector3.down, hitIfHit.normal).normalized;
ySlope = Quaternion.LookRotation(hitIfHit.normal, Vector3.forward);
zNormal = ((hitIfHit.normal.normalized.z) + 1f) / 2f;
normalHit = hitIfHit.normal.normalized;
if (yIntersection != oldyIntersection)
{
UpdateSlopeColor();
}
oldyIntersection = yIntersection;
}
}
}
}
}
private void ClearGeometry()
{
triangles.Clear();
triangles.TrimExcess();
vertexs.Clear();
vertexs.TrimExcess();
uvs.Clear();
uvs.TrimExcess();
cols.Clear();
cols.TrimExcess();
}
private void BuildInitialGeometry()
{
if (meshFilter == null)
{
meshFilter = gameObject.GetComponent<MeshFilter>();
}
newMesh = new Mesh();
newGO = new GameObject();
MeshFilter mF = newGO.AddComponent<MeshFilter>();
MeshRenderer mR = newGO.AddComponent<MeshRenderer>();
mF.mesh = newMesh;
mR.material = snowMaterial;
snowMaterial.SetFloat("_ISADD", 1);
snowMaterial.EnableKeyword("IS_ADD");
if (useIntersection)
{
if (snowMaterial.GetFloat("_USEINTER") == 0)
{
snowMaterial.SetFloat("_USEINTER", 1);
snowMaterial.EnableKeyword("USE_INTER");
}
}
else
{
if (snowMaterial.GetFloat("_USEINTER") == 1)
{
snowMaterial.SetFloat("_USEINTER", 0);
snowMaterial.DisableKeyword("USE_INTER");
}
}
newGO.transform.parent = this.transform;
newGO.transform.localPosition = Vector3.zero;
newGO.transform.localScale = Vector3.one;
newGO.transform.localRotation = Quaternion.identity;
int indexNewV = 0;
foreach (Vector3 v in oldVert)
{
vertexs.Add(v + new Vector3(0,0,0));
uvs.Add(oldUV[indexNewV]);
indexNewV++;
}
indexNewV = 0;
foreach (int innt in oldTri)
{
triangles.Add(oldTri[indexNewV]);
indexNewV++;
}
if (isAuto)
{
int j = 0;
foreach (Vector3 norm in oldNormWorld)
{
if(j>= oldCol.Length)
{
break;
}
oldCol[j] = Color.red;
float theAngle = Vector3.Angle(Vector3.up, norm);
if (theAngle < (angle+10f))
{
Color lerpedColor = Color.Lerp(Color.white, Color.red, Mathf.Max(0f,theAngle- angle/2f) / (angle / 2f));
oldCol[j] = lerpedColor;
}
j++;
}
}
cols = oldCol.ToList();
newMesh.vertices = vertexs.ToArray();
newMesh.triangles = triangles.ToArray();
newMesh.uv = uvs.ToArray();
newMesh.colors = cols.ToArray();
newMesh.normals = originalMesh.normals;
RecalculateNormalsSeamless(newMesh);
newMesh.RecalculateBounds();
newMesh.Optimize();
}
private void UpdateVertexColor()
{
Color[] updatedColors = newMesh.colors;
Vector3[] newNormWorld = newMesh.normals;
if (isAuto)
{
int k = 0;
foreach (Vector3 norm in newMesh.normals)
{
newNormWorld[k] = this.transform.localToWorldMatrix.MultiplyVector(norm).normalized;
k++;
}
}
if (isAuto)
{
int j = 0;
foreach (Vector3 norm in newNormWorld)
{
if (j >= updatedColors.Length)
{
break;
}
float theAngle = Vector3.Angle(Vector3.up, norm);
if (theAngle < (angle + 10f))
{
Color lerpedColor = Color.Lerp(new Color(1,1,1, updatedColors[j].a), new Color(1, 0, 0, updatedColors[j].a), Mathf.Max(0f, theAngle - angle / 2f) / (angle / 2f));
updatedColors[j].r = lerpedColor.r;
updatedColors[j].g = lerpedColor.g;
updatedColors[j].b = lerpedColor.b;
updatedColors[j].a = lerpedColor.a;
}
j++;
}
}
newMesh.colors = updatedColors;
}
private void UpdateSlopeColor()
{
// This is not perfect for now but gets the job done... //
int j = 0;
Color[] updatedColors = newMesh.colors;
Vector2[] updatedUV4 = new Vector2[updatedColors.Count()];
Vector2[] updatedUV5 = new Vector2[updatedColors.Count()];
Vector2[] updatedUV6 = new Vector2[updatedColors.Count()];
Vector2[] updatedUV7 = new Vector2[updatedColors.Count()];
foreach (Color norm in newMesh.colors)
{
updatedColors[j].a = yIntersection;
updatedUV4[j] = new Vector2(normalHit.x, normalHit.y);
updatedUV5[j] = new Vector2(zNormal, normalHit.z);
updatedUV6[j] = new Vector2(ySlope.x, ySlope.y);
updatedUV7[j] = new Vector2(ySlope.z, ySlope.w);
j++;
}
newMesh.colors = updatedColors;
newMesh.uv4 = updatedUV4;
newMesh.uv5 = updatedUV5;
newMesh.uv6 = updatedUV6;
newMesh.uv7 = updatedUV7;
}
private void RecalculateNormalsSeamless(Mesh mesh)
{
var trianglesOriginal = mesh.triangles;
var triangles = trianglesOriginal.ToArray();
var vertices = mesh.vertices;
var mergeIndices = new Dictionary<int, int>();
for (int i = 0; i < vertices.Length; i++)
{
var vertexHash = vertices[i].GetHashCode();
if (mergeIndices.TryGetValue(vertexHash, out var index))
{
for (int j = 0; j < triangles.Length; j++)
if (triangles[j] == i)
triangles[j] = index;
}
else
mergeIndices.Add(vertexHash, i);
}
mesh.triangles = triangles;
var normals = new Vector3[vertices.Length];
mesh.RecalculateNormals();
var newNormals = mesh.normals;
for (int i = 0; i < vertices.Length; i++)
if (mergeIndices.TryGetValue(vertices[i].GetHashCode(), out var index))
normals[i] = newNormals[index];
mesh.triangles = trianglesOriginal;
mesh.normals = normals;
}
}