Optimize decal rendering

This commit is contained in:
Nahuel Rocchetti 2024-08-04 15:04:06 -03:00
parent ca6f51c493
commit 925ef2de1b
3 changed files with 156 additions and 4 deletions

View file

@ -11,6 +11,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using static UnityEditor.FilePathAttribute;
namespace OpenTS2.Scenes.ParticleEffects
{
@ -22,6 +23,7 @@ namespace OpenTS2.Scenes.ParticleEffects
private Vector3 _position;
private Vector3 _rotation;
private Material _material;
private Mesh _decalMesh;
private void Start()
{
@ -47,12 +49,11 @@ namespace OpenTS2.Scenes.ParticleEffects
var meshFilter = GetComponent<MeshFilter>();
var meshRenderer = GetComponent<MeshRenderer>();
meshFilter.sharedMesh = terrainMeshFilter.sharedMesh;
BuildDecalMesh(terrainMeshFilter.sharedMesh);
meshFilter.sharedMesh = _decalMesh;
_material = new Material(Shader.Find("OpenTS2/NeighborhoodDecal"));
_material = new Material(Shader.Find("OpenTS2/BakedDecal"));
_material.mainTexture = _textureAsset.GetSelectedImageAsUnityTexture();
_material.SetVector(Location, _position);
_material.SetVector(Rotation, _rotation);
meshRenderer.sharedMaterial = _material;
transform.SetParent(null);
@ -61,10 +62,89 @@ namespace OpenTS2.Scenes.ParticleEffects
transform.localScale = Vector3.one;
}
private Vector2 RotateUV(Vector2 uv, float angle)
{
var cos = Mathf.Cos(angle);
var sin = Mathf.Sin(angle);
var x = uv.x * cos - uv.y * sin;
var y = uv.x * sin + uv.y * cos;
return new Vector2(x, y);
}
private Vector2 GetUV(Vector3 point)
{
var radius = 80f;
var radiusHalf = radius * 0.5f;
var minPos = _position;
minPos -= new Vector3(radiusHalf, radiusHalf, radiusHalf);
var maxPos = minPos + new Vector3(radius, radius, radius);
point -= minPos;
point /= radius;
var uv = new Vector2(point.x - 0.5f, point.z - 0.5f);
uv = RotateUV(GetUV(uv), _rotation.y * Mathf.Deg2Rad);
uv += new Vector2(0.5f, 0.5f);
return uv;
}
private void BuildDecalMesh(Mesh terrainMesh)
{
_decalMesh = new Mesh();
var vertices = terrainMesh.vertices;
var uvs = new Vector2[terrainMesh.vertices.Length];
var oTriangles = terrainMesh.triangles;
var triangles = new List<int>();
var radius = 80f;
var radiusHalf = radius * 0.5f;
var decalPositionMatrix = Matrix4x4.Translate(new Vector3(-_position.x + radiusHalf, 0f, -_position.z + radiusHalf));
var decalRotationMatrix = Matrix4x4.Rotate(Quaternion.Euler(0f, _rotation.y, 0f));
for(var i = 0; i < vertices.Length; i++)
{
var v = decalPositionMatrix.MultiplyPoint(vertices[i]);
v /= radius;
v.x -= 0.5f;
v.z -= 0.5f;
v = decalRotationMatrix.MultiplyPoint(v);
v.x += 0.5f;
v.z += 0.5f;
uvs[i] = new Vector2(v.x, v.z);
}
for (var i = 0; i < oTriangles.Length; i += 3)
{
var v1i = oTriangles[i];
var v2i = oTriangles[i + 1];
var v3i = oTriangles[i + 2];
var v1 = uvs[v1i];
var v2 = uvs[v2i];
var v3 = uvs[v3i];
if ((v1.x < 1f && v1.y < 1f && v1.x > 0f && v1.y > 0f) ||
(v2.x < 1f && v2.y < 1f && v2.x > 0f && v2.y > 0f) ||
(v3.x < 1f && v3.y < 1f && v3.x > 0f && v3.y > 0f))
{
triangles.Add(v1i);
triangles.Add(v2i);
triangles.Add(v3i);
}
}
_decalMesh.SetVertices(vertices);
_decalMesh.SetUVs(0, uvs);
_decalMesh.SetTriangles(triangles, 0);
}
private void OnDestroy()
{
if (_material != null)
_material.Free();
if (_decalMesh != null)
_decalMesh.Free();
}
}
}

View file

@ -0,0 +1,62 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "OpenTS2/BakedDecal"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType" = "Transparent" "Queue" = "Transparent-2" }
LOD 100
Pass
{
ZWrite Off
Offset -1, -1
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.uv = v.uv;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
if (i.uv.x < 0 || i.uv.y < 0 || i.uv.x > 1 || i.uv.y > 1)
clip(-1);
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}

View file

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: cd1c2fe69305d6340a8e116e63955e26
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant: