Skip to content

Instantly share code, notes, and snippets.

@pema99
Created March 21, 2024 23:04
Show Gist options
  • Save pema99/e04be4961f5ee7b5ce2a45b02324af84 to your computer and use it in GitHub Desktop.
Save pema99/e04be4961f5ee7b5ce2a45b02324af84 to your computer and use it in GitHub Desktop.
Analytical polygonal irradiance
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteAlways]
public class QuadLightEmitter : MonoBehaviour
{
[ColorUsage(false, true)]
public Color color = Color.white;
public Transform[] verts;
void OnEnable()
{
if (verts == null || verts.Length < 4)
{
verts = new Transform[4];
for (int i = 0; i < 4; i++)
{
verts[i] = transform.GetChild(i);
}
}
}
void Update()
{
for (int i = 0; i < 4; i++)
{
Vector3 vert = verts[i].position;
Shader.SetGlobalVector($"_QuadLightVert{i}", vert);
Shader.SetGlobalVector("_QuadLightColor", color);
}
}
}
Shader "Unlit/PolygonLight"
{
Properties
{
_Albedo ("Albedo", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 normal : NORMAL;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.normal = normalize(UnityObjectToWorldNormal(v.normal));
return o;
}
float3 _QuadLightVert0;
float3 _QuadLightVert1;
float3 _QuadLightVert2;
float3 _QuadLightVert3;
float3 _QuadLightColor;
float3 _Albedo;
float3x3 OrthoBasisFromVector(float3 n)
{
float sign = n.z >= 0.0 ? 1.0 : -1.0;
const float a = -1.0 / (sign + n.z);
const float b = n.x * n.y * a;
float3 b1 = float3(1.0 + sign * n.x * n.x * a, sign * b, -sign * n.x);
float3 b2 = float3(b, sign + n.y * n.y * a, -n.y);
return float3x3(b1, b2, n);
}
float4 frag (v2f i) : SV_Target
{
float3 verts[4] = { _QuadLightVert0, _QuadLightVert1, _QuadLightVert2, _QuadLightVert3 };
float3 worldPos = mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz;
float3x3 toTangentSpace = OrthoBasisFromVector(i.normal);
float sum = 0.0;
for (uint idx = 0; idx < 4; idx++)
{
// Transform world space verts into object space coordinates, but dont apply rotation
float3 objectSpaceV0 = verts[idx] - worldPos;
float3 objectSpaceV1 = verts[(idx + 1) % 4] - worldPos;
// Transform object space verts into tangent space
float3 v0 = mul(toTangentSpace, normalize(objectSpaceV0));
float3 v1 = mul(toTangentSpace, normalize(objectSpaceV1));
// Calculate analytical contribution to irradiance
sum += acos(dot(v0, v1)) * dot(normalize(cross(v0, v1)) , float3(0, 0, 1));
}
sum *= 1.0 / (2.0 * 3.14159265359);
return float4(sum * _QuadLightColor * saturate(_Albedo), 1);
}
ENDCG
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment