Files
Ipseity-Demo/Assets/OctoDemo/Shaders/Include/PortalClipping.hlsl
T
2026-03-09 17:55:23 +01:00

89 lines
3.1 KiB
HLSL

#ifndef PORTAL_PROJECTION_MASK_INCLUDED
#define PORTAL_PROJECTION_MASK_INCLUDED
// Global matrices set by Portal.cs via Shader.SetGlobalMatrix
float4x4 _PortalMatrix;
float4x4 _CameraMatrix;
// URP includes (Core pulls in the right per-draw declarations for SRP).
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl"
uint GetMyRenderingLayerMask()
{
// Returns asuint(unity_RenderingLayer.x) in URP.
return GetMeshRenderingLayer();
}
bool HasRenderingLayer(uint mask, uint layerIndex /* 0..31 */)
{
return (mask & (1u << layerIndex)) != 0u;
}
void PortalProjectionMask_float(
float3 WorldPos,
out float ClipValue
//out float3 DebugColor
)
{
// Detect shadow pass by comparing camera positions
// In shadow pass: UNITY_MATRIX_I_V contains light camera, not Main Camera
float3 currentCamPos = UNITY_MATRIX_I_V._m03_m13_m23;
float3 mainCamPos = float3(_CameraMatrix[0][3], _CameraMatrix[1][3], _CameraMatrix[2][3]);
float distanceBetweenCams = length(currentCamPos - mainCamPos);
bool isShadowPass = (distanceBetweenCams > 0.01); // Threshold for comparison
if (isShadowPass) // For viewport preview
{
if ((UNITY_MATRIX_P[0][0] != _CameraMatrix[0][0])) // Is scene view
isShadowPass = false;
}
// Don't clip in shadow pass
if (isShadowPass)
{
ClipValue = 1;
return;
}
else
{
// Extract camera world position from the matrix
float3 camPosWorld = float3(_CameraMatrix[0][3], _CameraMatrix[1][3], _CameraMatrix[2][3]);
// Transform to portal local space
float3 localPixelPos = mul(_PortalMatrix, float4(WorldPos, 1)).xyz;
float3 localCamPos = mul(_PortalMatrix, float4(camPosWorld, 1)).xyz;
// Perspective projection of the pixel onto the portal plane (z=0)
float3 rayDir = localPixelPos - localCamPos;
float t = -localCamPos.z / rayDir.z;
float3 projectedPos = localCamPos + rayDir * t;
// Check if projected point is inside the quad frame [-0.5, 0.5]
bool insideFrame = (abs(projectedPos.x) < .5 && abs(projectedPos.y) < 0.5 && t > 0);
// Check if pixel is behind the portal (z > 0 in local space)
bool pixelBehind = localPixelPos.z > 0;
// Check if camera is behind the portal (z > 0 in local space)
bool camBehind = localCamPos.z < 0;
uint renderingLayer = GetMeshRenderingLayer();
//DebugColor = float3(renderingLayer & 1u, (renderingLayer >> 1) & 1u, (renderingLayer >> 2) & 1u);
if (HasRenderingLayer(renderingLayer, 1u)) // Is behind portal
{
// Next room: visible ONLY through the frame AND behind the portal
ClipValue = (insideFrame && pixelBehind && camBehind) ? 1 : 0;
}
else
{
// Active room: visible everywhere EXCEPT through the frame when behind portal
ClipValue = (insideFrame && pixelBehind && camBehind) ? 0 : 1;
}
}
}
#endif