Files
CartoonRPG/Assets/StixGames/GrassShader/Scripts/RenderTextureInteraction.cs
Caleb Sandford deQuincey 02c4b5ab66 Adding in new packages
2025-06-05 22:59:18 +01:00

261 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace StixGames.GrassShader
{
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
[AddComponentMenu("Stix Games/Interaction/Render Texture Interaction", 0)]
public class RenderTextureInteraction : MonoBehaviour
{
[Tooltip("The size your interaction texture will have. Higher texture sizes will use more graphics memory and increase the performance cost, but will allow more detailed interaction.")]
public int TextureSize = 1024;
[Tooltip("Outside of the interaction cameras render area no interaction information is available for the shader. This setting creates a smooth transition between the interaction area and the outside area.")]
public float BorderSmoothingArea = 2;
[Tooltip("If you want to debug the interaction texture during build, you can enable this option to replace the screen.")]
public bool DebugMode = false;
private Camera cam;
private RenderTexture backInteraction, interaction, backBurn, burn;
private CommandBuffer commandBuffer;
private static HashSet<IInteractionMesh> interactionMeshes = new HashSet<IInteractionMesh>();
private static HashSet<IInteractionRenderer> interactionRenderers = new HashSet<IInteractionRenderer>();
private static readonly int GrabInteraction = Shader.PropertyToID("_GrabInteraction");
private static readonly int GrabBurn = Shader.PropertyToID("_GrabBurn");
private static readonly int GrassRenderTextureBurn = Shader.PropertyToID("_GrassRenderTextureBurn");
private static readonly int GrassRenderTextureInteraction = Shader.PropertyToID("_GrassRenderTextureInteraction");
private static readonly int GrassRenderTextureArea = Shader.PropertyToID("_GrassRenderTextureArea");
private static readonly int GrassInteractionBorderArea = Shader.PropertyToID("_GrassInteractionBorderArea");
public static RenderTextureInteraction Instance { get; private set; }
private CommandBuffer debugBuffer;
private readonly RenderTargetIdentifier[] renderTargetIdentifiers= new RenderTargetIdentifier[2];
public static void AddInteractionObject(IInteractionMesh obj)
{
interactionMeshes.Add(obj);
}
public static void RemoveInteractionObject(IInteractionMesh obj)
{
interactionMeshes.Remove(obj);
}
public static void AddInteractionObject(IInteractionRenderer obj)
{
interactionRenderers.Add(obj);
}
public static void RemoveInteractionObject(IInteractionRenderer obj)
{
interactionRenderers.Remove(obj);
}
public void Awake()
{
if (Instance != null)
{
throw new InvalidOperationException("There may only be one RenderTextureinteraction camera");
}
Instance = this;
cam = GetComponent<Camera>();
}
// Use this for initialization
private void OnEnable()
{
cam.orthographic = true;
cam.clearFlags = CameraClearFlags.Nothing;
cam.aspect = 1;
cam.enabled = false;
//Create render textures
backInteraction = RenderTexture.GetTemporary(TextureSize, TextureSize, 0, RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear, 1);
interaction = RenderTexture.GetTemporary(TextureSize, TextureSize, 0, RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear, 1);
backBurn = RenderTexture.GetTemporary(TextureSize, TextureSize, 0, RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear, 1);
burn = RenderTexture.GetTemporary(TextureSize, TextureSize, 0, RenderTextureFormat.ARGB32,
RenderTextureReadWrite.Linear, 1);
commandBuffer = new CommandBuffer();
commandBuffer.name = "Grass interaction command buffer";
//Set shader values
Shader.EnableKeyword("GRASS_RENDERTEXTURE_INTERACTION");
}
private void OnDisable()
{
Instance = null;
//Set shader values
Shader.DisableKeyword("GRASS_RENDERTEXTURE_INTERACTION");
//Destroy render textures
RenderTexture.ReleaseTemporary(backInteraction);
RenderTexture.ReleaseTemporary(interaction);
RenderTexture.ReleaseTemporary(backBurn);
RenderTexture.ReleaseTemporary(burn);
}
private void LateUpdate()
{
Shader.SetGlobalFloat(GrassInteractionBorderArea, BorderSmoothingArea);
//Save original position and set camera to be pixel perfect
Vector3 realPosition = transform.position;
float pixelSize = (2 * cam.orthographicSize) / TextureSize;
Vector3 pos = realPosition;
pos.x -= pos.x % pixelSize;
pos.z -= pos.z % pixelSize;
transform.position = pos;
//Update camera rotation
transform.rotation = Quaternion.Euler(90, 0, 0);
Vector3 bottomLeft = cam.ScreenToWorldPoint(Vector3.zero);
float size = 2 * cam.orthographicSize;
Vector4 renderArea = new Vector4(bottomLeft.x, bottomLeft.z, size, size);
Shader.SetGlobalVector(GrassRenderTextureArea, renderArea);
//Render Textures
RenderInteractionTextures();
}
private void RenderInteractionTextures()
{
interactionMeshes.RemoveWhere(x => x == null || x.GetMesh() == null);
interactionRenderers.RemoveWhere(x => x == null || x.GetRenderer() == null);
//Create command buffer
commandBuffer.Clear();
commandBuffer.BeginSample("Grass Interaction Rendering");
commandBuffer.SetViewProjectionMatrices(cam.worldToCameraMatrix, cam.projectionMatrix);
commandBuffer.SetViewport(new Rect(0, 0, TextureSize, TextureSize));
//Clear textures
commandBuffer.SetRenderTarget(backInteraction);
commandBuffer.ClearRenderTarget(true, true, new Color(0.5f, 0.5f, 1.0f, 0.0f));
commandBuffer.SetRenderTarget(interaction);
commandBuffer.ClearRenderTarget(true, true, new Color(0.5f, 0.5f, 1.0f, 0.0f));
commandBuffer.SetRenderTarget(backBurn);
commandBuffer.ClearRenderTarget(false, true, Color.white);
commandBuffer.SetRenderTarget(burn);
commandBuffer.ClearRenderTarget(false, true, Color.white);
//Set back buffer
commandBuffer.SetGlobalTexture(GrabInteraction, backInteraction);
commandBuffer.SetGlobalTexture(GrabBurn, backBurn);
//Set render target
renderTargetIdentifiers[0] = interaction;
renderTargetIdentifiers[1] = burn;
//var backBuffers = new RenderTargetIdentifier[]
//{
// backInteraction,
// backBurn
//};
var backInteractionIdentifier = new RenderTargetIdentifier(backInteraction);
var backBurnIdentifier = new RenderTargetIdentifier(backBurn);
var interactionIdentifier = new RenderTargetIdentifier(interaction);
var burnIdentifier = new RenderTargetIdentifier(burn);
//Render all meshes
foreach (var o in interactionMeshes)
{
//Blit back
commandBuffer.Blit(interactionIdentifier, backInteractionIdentifier);
commandBuffer.Blit(burnIdentifier, backBurnIdentifier);
//Reset back buffer
commandBuffer.SetGlobalTexture(GrabInteraction, backInteractionIdentifier);
commandBuffer.SetGlobalTexture(GrabBurn, backBurnIdentifier);
commandBuffer.SetRenderTarget(renderTargetIdentifiers, interactionIdentifier);
//Render
commandBuffer.DrawMesh(o.GetMesh(), o.GetMatrix(), o.GetMaterial());
//TODO: Try to get ping pong working
////Ping pong
//var tempBuffer = backBuffers;
//backBuffers = buffers;
//buffers = tempBuffer;
//var tempIdentifier = backInteractionIdentifier;
//backInteractionIdentifier = interactionIdentifier;
//interactionIdentifier = tempIdentifier;
//tempIdentifier = backBurnIdentifier;
//backBurnIdentifier = burnIdentifier;
//burnIdentifier = tempIdentifier;
}
//Render all renderers
foreach (var o in interactionRenderers)
{
//Blit back
commandBuffer.Blit(interactionIdentifier, backInteractionIdentifier);
commandBuffer.Blit(burnIdentifier, backBurnIdentifier);
//Reset back buffer
commandBuffer.SetGlobalTexture(GrabInteraction, backInteractionIdentifier);
commandBuffer.SetGlobalTexture(GrabBurn, backBurnIdentifier);
commandBuffer.SetRenderTarget(renderTargetIdentifiers, interactionIdentifier);
//Render
var r = o.GetRenderer();
commandBuffer.DrawRenderer(r, r.sharedMaterial);
////Ping pong
//var tempBuffer = backBuffers;
//backBuffers = buffers;
//buffers = tempBuffer;
//var tempIdentifier = backInteractionIdentifier;
//backInteractionIdentifier = interactionIdentifier;
//interactionIdentifier = tempIdentifier;
//tempIdentifier = backBurnIdentifier;
//backBurnIdentifier = burnIdentifier;
//burnIdentifier = tempIdentifier;
}
commandBuffer.EndSample("Grass Interaction Rendering");
//Not sure if a command buffer actually helps here, but it won't hurt either way
Graphics.ExecuteCommandBuffer(commandBuffer);
#if DEBUG
if (DebugMode)
{
debugBuffer = new CommandBuffer();
debugBuffer.Blit(interaction, BuiltinRenderTextureType.CameraTarget);
Camera.main.AddCommandBuffer(CameraEvent.AfterEverything, debugBuffer);
}
else if (debugBuffer != null)
{
Camera.main.RemoveCommandBuffer(CameraEvent.AfterEverything, debugBuffer);
}
#endif
Shader.SetGlobalTexture(GrassRenderTextureInteraction, interaction);
Shader.SetGlobalTexture(GrassRenderTextureBurn, burn);
}
}
}