unity自制光追不渲染场景中的物体,渲染用时越来越长
RTRP.cs
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections.Generic;
public class RTRP : RenderPipeline
{
public RTRPAsset asset;
public RTRP(RTRPAsset asset)
{
this.asset = asset;
}
protected override void Render(ScriptableRenderContext context, Camera[] cameras)
{
MeshFilter[] Filters = GameObject.FindObjectsByType<MeshFilter>(FindObjectsSortMode.None);
List<MeshObject> objs = new();
List<Vector3> vertices = new();
List<int> indexes = new();
int regeditedindexcount = 0;
foreach (MeshFilter f in Filters)
{
if (f.sharedMesh != null)
{
objs.Add(MeshObject.FromMesh(f.sharedMesh, f.transform.localToWorldMatrix, regeditedindexcount));
regeditedindexcount += f.sharedMesh.triangles.Length;
foreach (var v in f.sharedMesh.vertices)
{
vertices.Add(v);
}
foreach (var i in f.sharedMesh.triangles)
{
indexes.Add(i + regeditedindexcount);
}
}
}
ComputeBuffer VB = new(vertices.Count, 12);
ComputeBuffer IB = new(indexes.Count, 4);
ComputeBuffer OB = new(objs.Count, 80);
foreach (var cam in cameras)
{
CommandBuffer cmd = new();
context.SetupCameraProperties(cam);
RenderTexture texture = new(Screen.width, Screen.height, 0, RenderTextureFormat.ARGBFloat, RenderTextureReadWrite.Linear)
{
enableRandomWrite = true
};
asset.RTMain.SetTexture(0, "Result", texture);
asset.RTMain.SetInt("AAL", asset.AAL);
asset.RTMain.SetInt("MaxTraceTime", asset.MaxTraceTime);
asset.RTMain.SetMatrix("CTW", cam.cameraToWorldMatrix);
asset.RTMain.SetMatrix("CIP", cam.projectionMatrix.inverse);
asset.RTMain.SetBuffer(0, "vertices", VB);
asset.RTMain.SetBuffer(0, "indexes", IB);
asset.RTMain.SetBuffer(0, "MeshObjects", OB);
cmd.DispatchCompute(asset.RTMain, 0, Mathf.CeilToInt(Screen.width / 8f), Mathf.CeilToInt(Screen.height / 8f), 1);
cmd.Blit(texture, new(BuiltinRenderTextureType.CameraTarget));
context.ExecuteCommandBuffer(cmd);
cmd.Release();
}
context.Submit();
}
}
RTMain.compute
#pragma kernel CSMain
static const float EPSILON = 1e-8;
static const float PI = 3.1415927f;
RWTexture2D<float4> Result;
int AAL, MaxTraceTime;
float4x4 CTW, CIP;
struct Ray
{
float3 origin, direction, energy;
};
struct RayHit
{
float3 position, normal, v0, v1, v2;
float2 uv;
float distance;
};
class MeshObject
{
float4x4 LTW;
int i_o, i_c;
};
Buffer<float3> vertices;
Buffer<int> indexes;
StructuredBuffer<MeshObject> MeshObjects;
Ray NewRay(float3 o, float3 d, float3 e)
{
Ray r;
r.origin = o;
r.direction = d;
r.energy = e;
return r;
}
RayHit NewHit()
{
RayHit h;
h.distance = 1.#INF;
h.position = 0.f;
h.normal = 0.f;
h.uv = 0.f;
h.v0 = 0.f;
h.v1 = 0.f;
h.v2 = 0.f;
return h;
}
Ray CamRay(float2 uv)
{
float3 origin = mul(CTW, float4(0.0f, 0.0f, 0.0f, 1.0f)).xyz;
float3 direction = mul(CIP, float4(uv * 2.f - 1.f, 0.f, 1.f)).xyz;
direction = mul(CTW, float4(direction, 0.0f)).xyz;
direction = normalize(direction);
return NewRay(origin, direction, 1.f);
}
bool IntersectTriangle(Ray ray, float3 vert0, float3 vert1, float3 vert2, inout float t, inout float u, inout float v)
{
float3 edge1 = vert1 - vert0;
float3 edge2 = vert2 - vert0;
float3 pvec = cross(ray.direction, edge2);
float det = dot(edge1, pvec);
if (det < EPSILON) return false;
float inv_det = 1.0f / det;
float3 tvec = ray.origin - vert0;
u = dot(tvec, pvec) * inv_det;
if (u < 0.0 || u > 1.0f) return false;
float3 qvec = cross(tvec, edge1);
v = dot(ray.direction, qvec) * inv_det;
if (v < 0.0 || u + v > 1.0f) return false;
t = dot(edge2, qvec) * inv_det;
return true;
}
void IntersectSphere(Ray ray, inout RayHit bestHit, float4 sphere)
{
float3 d = ray.origin - sphere.xyz;
float p1 = -dot(ray.direction, d);
float p2sqr = p1 * p1 - dot(d, d) + sphere.w * sphere.w;
if (p2sqr < 0) return;
float p2 = sqrt(p2sqr);
float t = p1 - p2 > 0 ? p1 - p2 : p1 + p2;
if (t > 0 && t < bestHit.distance)
{
bestHit.distance = t;
bestHit.position = ray.origin + t * ray.direction;
bestHit.normal = normalize(bestHit.position - sphere.xyz);
}
}
void IntersectMesh(Ray r, inout RayHit h, MeshObject obj)
{
uint o = obj.i_o;
uint c = obj.i_o + obj.i_c;
for (uint a = o; a < c; a += 3)
{
float3 v0 = (mul(obj.LTW, float4(vertices[indexes[a]], 1.f))).xyz;
float3 v1 = (mul(obj.LTW, float4(vertices[indexes[a + 1]], 1.f))).xyz;
float3 v2 = (mul(obj.LTW, float4(vertices[indexes[a + 2]], 1.f))).xyz;
float t, u, v;
if (IntersectTriangle(r, v0, v1, v2, t, u, v))
{
if (t < h.distance)
{
h.distance = t;
h.position = r.origin + r.direction * t;
h.normal = normalize(cross(v1 - v0, v2 - v0));
h.uv = float2(u, v);
h.v0 = v0;
h.v1 = v1;
h.v2 = v2;
}
}
}
}
RayHit Trace(Ray r)
{
RayHit h = NewHit();
uint l, s;
MeshObjects.GetDimensions(l, s);
for (uint a = 0; a < l; a++)
{
IntersectMesh(r, h, MeshObjects[a]);
}
return h;
}
float4 Shade(inout Ray r, RayHit h)
{
if (h.distance > 0 && h.distance < 1.#INF)
{
r.origin = h.position + h.normal * 0.00001f;
r.direction = reflect(r.direction, h.normal);
r.energy *= 0.8f;
float size = distance(cross(h.v1 - h.v0, h.v2 - h.v0), 0);
float size0 = distance(cross(h.v1 - h.position, h.v2 - h.position), 0);
float size1 = distance(cross(h.v2 - h.position, h.v0 - h.position), 0);
float size2 = distance(cross(h.v0 - h.position, h.v1 - h.position), 0);
return float4(size0 / size, size1 / size, size2 / size, 1.f);
}
else
{
return 0.f;
}
}
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
uint w, h;
Result.GetDimensions(w, h);
float4 col = 0.f;
for (int a = 0; a < AAL; a++)
{
for (int b = 0; b < AAL; b++)
{
Ray r = CamRay((id.xy + float2(a, b) / AAL) / float2(w, h));
RayHit h = Trace(r);
col += Shade(r, h);
}
}
col /= AAL * AAL;
Result[id.xy] = float4(col.x, col.y, col.z, col.w);
}