197 lines
8.9 KiB
C#
197 lines
8.9 KiB
C#
using System;
|
|
using System.IO;
|
|
using Unity.Mathematics;
|
|
using UnityEngine.PathTracing.Core;
|
|
using UnityEngine.PathTracing.Lightmapping;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Sampling;
|
|
using UnityEngine.Rendering.UnifiedRayTracing;
|
|
|
|
namespace UnityEngine.PathTracing.Integration
|
|
{
|
|
internal static class UVFallbackBufferBuilderShaderIDs
|
|
{
|
|
public static readonly int VertexBuffer = Shader.PropertyToID("g_VertexBuffer");
|
|
public static readonly int Width = Shader.PropertyToID("g_Width");
|
|
public static readonly int Height = Shader.PropertyToID("g_Height");
|
|
public static readonly int WidthScale = Shader.PropertyToID("g_WidthScale");
|
|
public static readonly int HeightScale = Shader.PropertyToID("g_HeightScale");
|
|
|
|
public static readonly int UvFallback = Shader.PropertyToID("g_UvFallback");
|
|
public static readonly int InstanceWidth = Shader.PropertyToID("g_InstanceWidth");
|
|
public static readonly int InstanceHeight = Shader.PropertyToID("g_InstanceHeight");
|
|
public static readonly int InstanceOffsetX = Shader.PropertyToID("g_InstanceOffsetX");
|
|
public static readonly int InstanceOffsetY = Shader.PropertyToID("g_InstanceOffsetY");
|
|
public static readonly int ChunkOffsetX = Shader.PropertyToID("g_ChunkOffsetX");
|
|
public static readonly int ChunkOffsetY = Shader.PropertyToID("g_ChunkOffsetY");
|
|
public static readonly int ChunkSize = Shader.PropertyToID("g_ChunkSize");
|
|
public static readonly int InstanceWidthScale = Shader.PropertyToID("g_InstanceWidthScale");
|
|
public static readonly int InstanceHeightScale = Shader.PropertyToID("g_InstanceHeightScale");
|
|
}
|
|
|
|
internal class UVFallbackBufferBuilder : IDisposable
|
|
{
|
|
private GraphicsBuffer _vertexBuffer;
|
|
private Material _uvFallbackBufferMaterial;
|
|
|
|
public void Dispose()
|
|
{
|
|
_vertexBuffer?.Dispose();
|
|
_vertexBuffer = null;
|
|
}
|
|
|
|
public void Prepare(Material uvFallbackBufferMaterial)
|
|
{
|
|
_uvFallbackBufferMaterial = uvFallbackBufferMaterial;
|
|
}
|
|
|
|
public void Build(
|
|
CommandBuffer cmd,
|
|
RenderTexture uvFallbackRT,
|
|
int width,
|
|
int height,
|
|
float widthScale,
|
|
float heightScale,
|
|
Mesh uvMesh)
|
|
{
|
|
cmd.BeginSample("Build UVFallbackBuffer");
|
|
|
|
Debug.Assert((UInt64)width * (UInt64)height < uint.MaxValue);
|
|
Debug.Assert(uvFallbackRT.format == RenderTextureFormat.RGFloat);
|
|
Debug.Assert(uvFallbackRT.depth > 0);
|
|
|
|
// Clear the fallback buffer to -1, indicating no valid texels
|
|
cmd.SetRenderTarget(uvFallbackRT);
|
|
cmd.ClearRenderTarget(false, true, new Color(-1.0f, -1.0f, -1.0f, -1.0f));
|
|
|
|
// Expand vertices so we can do conservative rasterization
|
|
var originalVertices = uvMesh.vertices;
|
|
var originalIndices = uvMesh.triangles;
|
|
var vertices = new Vector2[originalIndices.Length];
|
|
for (int i = 0; i < originalIndices.Length; i++)
|
|
{
|
|
vertices[i] = originalVertices[originalIndices[i]];
|
|
}
|
|
|
|
// Reallocate the vertex buffer if necessary, write the vertices
|
|
if (_vertexBuffer == null || _vertexBuffer.count < vertices.Length)
|
|
{
|
|
_vertexBuffer?.Dispose();
|
|
_vertexBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, vertices.Length, 2 * sizeof(float));
|
|
}
|
|
cmd.SetBufferData(_vertexBuffer, vertices);
|
|
|
|
// Build the fallback buffer using conservative rasterization
|
|
cmd.SetGlobalBuffer(UVFallbackBufferBuilderShaderIDs.VertexBuffer, _vertexBuffer);
|
|
cmd.SetGlobalInteger(UVFallbackBufferBuilderShaderIDs.Width, width);
|
|
cmd.SetGlobalInteger(UVFallbackBufferBuilderShaderIDs.Height, height);
|
|
cmd.SetGlobalFloat(UVFallbackBufferBuilderShaderIDs.WidthScale, widthScale);
|
|
cmd.SetGlobalFloat(UVFallbackBufferBuilderShaderIDs.HeightScale, heightScale);
|
|
cmd.DrawProcedural(Matrix4x4.identity, _uvFallbackBufferMaterial, 0, MeshTopology.Triangles, (int)uvMesh.GetTotalIndexCount());
|
|
|
|
cmd.EndSample("Build UVFallbackBuffer");
|
|
|
|
GraphicsHelpers.Flush(cmd);
|
|
}
|
|
}
|
|
|
|
internal class UVFallbackBuffer : IDisposable
|
|
{
|
|
public RenderTexture UVFallbackRT;
|
|
public float WidthScale;
|
|
public float HeightScale;
|
|
public int Width => UVFallbackRT.width;
|
|
public int Height => UVFallbackRT.height;
|
|
|
|
public void Dispose()
|
|
{
|
|
UVFallbackRT?.Release();
|
|
if (UVFallbackRT != null)
|
|
CoreUtils.Destroy(UVFallbackRT);
|
|
UVFallbackRT = null;
|
|
}
|
|
|
|
public bool Build(
|
|
CommandBuffer commandBuffer,
|
|
UVFallbackBufferBuilder builder,
|
|
int width,
|
|
int height,
|
|
UVMesh uvMesh)
|
|
{
|
|
if (width == 0 || height == 0)
|
|
return false;
|
|
// Assume that the largest edge of UV bounds can fit into the texture,
|
|
// and calculate the scale factor for each dimension to achieve this.
|
|
// This is accounting for the aspect ratio of the UV bounds.
|
|
var uvAspectRatio = uvMesh.UVAspectRatio;
|
|
if (uvAspectRatio >= 1.0f) // width >= height
|
|
{
|
|
WidthScale = 1.0f;
|
|
HeightScale = (width / uvAspectRatio) / height;
|
|
}
|
|
else // width < height
|
|
{
|
|
WidthScale = (height * uvAspectRatio) / width;
|
|
HeightScale = 1.0f;
|
|
}
|
|
|
|
// If we find that the scaled UV bounds still don't fit into the texture,
|
|
// then we uniformly scale down the bounds to fit.
|
|
// This is accounting for the aspect ratio of the texture.
|
|
if (HeightScale > 1)
|
|
{
|
|
WidthScale /= HeightScale;
|
|
HeightScale = 1.0f;
|
|
}
|
|
if (WidthScale > 1)
|
|
{
|
|
HeightScale /= WidthScale;
|
|
WidthScale = 1.0f;
|
|
}
|
|
|
|
UVFallbackRT = new RenderTexture(width, height, 24, RenderTextureFormat.RGFloat, RenderTextureReadWrite.Linear)
|
|
{
|
|
name = "UVFallbackRT",
|
|
hideFlags = HideFlags.HideAndDontSave,
|
|
enableRandomWrite = true,
|
|
useMipMap = false,
|
|
autoGenerateMips = false,
|
|
};
|
|
UVFallbackRT.Create();
|
|
|
|
builder.Build(commandBuffer, UVFallbackRT, width, height, WidthScale, HeightScale, uvMesh.Mesh);
|
|
return true;
|
|
}
|
|
|
|
public void Bind(CommandBuffer cmd, IRayTracingShader shader, Vector2Int instanceOffset)
|
|
{
|
|
shader.SetTextureParam(cmd, UVFallbackBufferBuilderShaderIDs.UvFallback, UVFallbackRT);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.InstanceWidth, UVFallbackRT.width);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.InstanceHeight, UVFallbackRT.height);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.InstanceOffsetX, instanceOffset.x);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.InstanceOffsetY, instanceOffset.y);
|
|
shader.SetFloatParam(cmd, UVFallbackBufferBuilderShaderIDs.InstanceWidthScale, WidthScale);
|
|
shader.SetFloatParam(cmd, UVFallbackBufferBuilderShaderIDs.InstanceHeightScale, HeightScale);
|
|
}
|
|
|
|
public void BindChunked(CommandBuffer cmd, IRayTracingShader shader, Vector2Int instanceOffset, uint2 chunkOffset, uint chunkSize)
|
|
{
|
|
Bind(cmd, shader, instanceOffset);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.ChunkOffsetX, (int)chunkOffset.x);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.ChunkOffsetY, (int)chunkOffset.y);
|
|
shader.SetIntParam(cmd, UVFallbackBufferBuilderShaderIDs.ChunkSize, (int)chunkSize);
|
|
}
|
|
|
|
public void Bind(CommandBuffer cmd, ComputeShader shader, int kernelIndex, Vector2Int instanceOffset)
|
|
{
|
|
cmd.SetComputeTextureParam(shader, kernelIndex, UVFallbackBufferBuilderShaderIDs.UvFallback, UVFallbackRT);
|
|
cmd.SetComputeIntParam(shader, UVFallbackBufferBuilderShaderIDs.InstanceWidth, UVFallbackRT.width);
|
|
cmd.SetComputeIntParam(shader, UVFallbackBufferBuilderShaderIDs.InstanceHeight, UVFallbackRT.height);
|
|
cmd.SetComputeIntParam(shader, UVFallbackBufferBuilderShaderIDs.InstanceOffsetX, instanceOffset.x);
|
|
cmd.SetComputeIntParam(shader, UVFallbackBufferBuilderShaderIDs.InstanceOffsetY, instanceOffset.y);
|
|
cmd.SetComputeFloatParam(shader, UVFallbackBufferBuilderShaderIDs.InstanceWidthScale, WidthScale);
|
|
cmd.SetComputeFloatParam(shader, UVFallbackBufferBuilderShaderIDs.InstanceHeightScale, HeightScale);
|
|
}
|
|
}
|
|
}
|