Last active
July 11, 2025 14:43
-
-
Save AYANO-TFT/7b4818f024c797e03b10db2cadf20111 to your computer and use it in GitHub Desktop.
LightVolumesCustom.cginc
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef VRC_LIGHT_VOLUMES_INCLUDED | |
| uniform float _UdonLightVolumeEnabled; | |
| uniform float _UdonLightVolumeCount; | |
| uniform float _UdonLightVolumeAdditiveMaxOverdraw; | |
| uniform float _UdonLightVolumeAdditiveCount; | |
| uniform float _UdonLightVolumeProbesBlend; | |
| uniform float _UdonLightVolumeSharpBounds; | |
| uniform sampler3D _UdonLightVolume; | |
| uniform float4x4 _UdonLightVolumeInvWorldMatrix[32]; | |
| uniform float3 _UdonLightVolumeRotation[64]; | |
| uniform float3 _UdonLightVolumeInvLocalEdgeSmooth[32]; | |
| uniform float3 _UdonLightVolumeUvw[192]; | |
| uniform float4 _UdonLightVolumeColor[32]; | |
| #endif | |
| // https://huwahuwa2017.hatenablog.com/entry/2024/12/05/021616 | |
| float4x4 Inverse(float4x4 m) | |
| { | |
| float4 det1 = mad(m._33_31_13_11, m._44_42_24_22, -m._34_32_14_12 * m._43_41_23_21); | |
| float4 det2 = mad(m._23_21_13_11, m._44_42_34_32, -m._24_22_14_12 * m._43_41_33_31); | |
| float4 det3 = mad(m._23_21_13_11, m._34_32_44_42, -m._24_22_14_12 * m._33_31_43_41); | |
| float4x4 im; | |
| im._11_21_31_41 = mad(m._22_21_24_23, det1.xxyy, mad(-m._32_31_34_33, det2.xxyy, m._42_41_44_43 * det3.xxyy)); | |
| im._12_22_32_42 = mad(m._12_11_14_13, det1.xxyy, mad(-m._32_31_34_33, det3.zzww, m._42_41_44_43 * det2.zzww)); | |
| im._13_23_33_43 = mad(m._12_11_14_13, det2.xxyy, mad(-m._22_21_24_23, det3.zzww, m._42_41_44_43 * det1.zzww)); | |
| im._14_24_34_44 = mad(m._12_11_14_13, det3.xxyy, mad(-m._22_21_24_23, det2.zzww, m._32_31_34_33 * det1.zzww)); | |
| im._21_41 = -im._21_41; | |
| im._12_32 = -im._12_32; | |
| im._23_43 = -im._23_43; | |
| im._14_34 = -im._14_34; | |
| float invDet = rcp(dot(m[0], im._11_21_31_41)); | |
| im._11_21_31_41 *= invDet; | |
| im._12_22_32_42 *= invDet; | |
| im._13_23_33_43 *= invDet; | |
| im._14_24_34_44 *= invDet; | |
| return im; | |
| } | |
| // LV_LocalFromVolumeの逆変換 | |
| // volumeIDはSH計算のマテリアルで0など決め打ちする想定 | |
| float3 LV_VolumeFromLocal(uint volumeID, float3 localUVW) { | |
| return mul(Inverse(_UdonLightVolumeInvWorldMatrix[volumeID]), float4(localUVW, 1.0)).xyz; | |
| } | |
| // LV_LocalToIslandの逆変換 | |
| // islandUVW(atlasUVW)からlocalUVWとtexIDを返す | |
| // volumeIDはSH計算のマテリアルで0など決め打ちする想定 | |
| float3 LV_IslandToLocal(uint volumeID, float3 islandUVW, out uint outTexID) | |
| { | |
| const float3 eps = 1e-6.xxx; // 0 除算回避 | |
| const float bound = 0.5001; // 判定マージン | |
| [unroll] | |
| for (uint i = 0; i < 3; ++i) // texID = 0–2 | |
| { | |
| uint uvwID = volumeID * 6 + i * 2; | |
| float3 uvwMin = _UdonLightVolumeUvw[uvwID ].xyz; | |
| float3 uvwMax = _UdonLightVolumeUvw[uvwID + 1].xyz; | |
| float3 range = max(uvwMax - uvwMin, eps); | |
| float3 localUVW = (islandUVW - uvwMin) / range - 0.5; | |
| // 全成分が [-0.5,0.5] に収まっているか | |
| if (all(abs(localUVW) <= bound.xxx)) | |
| { | |
| outTexID = i; | |
| return localUVW; | |
| } | |
| } | |
| // 失敗 | |
| outTexID = 0xFFFFFFFFu; | |
| return 0.0.xxx; | |
| } | |
| // IDが不要なケース | |
| float3 LV_IslandToLocalNoID(uint volumeID, float3 islandUVW) | |
| { | |
| const float3 eps = 1e-6.xxx; // 0 除算回避 | |
| const float bound = 0.5001; // 判定マージン | |
| [unroll] | |
| for (uint i = 0; i < 3; ++i) // texID = 0–2 | |
| { | |
| uint uvwID = volumeID * 6 + i * 2; | |
| float3 uvwMin = _UdonLightVolumeUvw[uvwID ].xyz; | |
| float3 uvwMax = _UdonLightVolumeUvw[uvwID + 1].xyz; | |
| float3 range = max(uvwMax - uvwMin, eps); | |
| float3 localUVW = (islandUVW - uvwMin) / range - 0.5; | |
| // 全成分が [-0.5,0.5] に収まっているか | |
| if (all(abs(localUVW) <= bound.xxx)) | |
| { | |
| return localUVW; | |
| } | |
| } | |
| // 失敗 | |
| return 0.0.xxx; | |
| } | |
| // SH書き込み用Geometry Shaderとそれの読み取りで使った | |
| float4 LV_IslandToClipPos(float3 islandUVW, float3 atlasResolution) | |
| { | |
| float y = floor(islandUVW.y * atlasResolution.y + 0.5) / atlasResolution.y; | |
| float2 uv = float2(islandUVW.x / atlasResolution.y + y, | |
| islandUVW.z); | |
| return float4(uv * 2.0 - 1.0, 0.0, 1.0); | |
| } | |
| float4 ComputeSH1_PointLight( | |
| float3 lightPos, float3 color, float intensity, | |
| float3 worldPos, uint texID) | |
| { | |
| const float k0 = 0.282095; // 1/(2√π) | |
| const float k1 = 0.488603; // √3/(2√π) | |
| // ベクトルと距離・減衰 | |
| float3 toLight = lightPos - worldPos; | |
| float distSq = max(dot(toLight, toLight), 1e-1); // 0 除算回避、ちょっと大きめ | |
| float atten = intensity / distSq; // 逆二乗減衰 | |
| float3 dir = toLight * rsqrt(distSq); // normalize(toLight) | |
| // 減衰 | |
| float3 c = color * atten; | |
| // L0 | |
| float3 L0 = k0 * c; | |
| // L1 | |
| float3 B1 = k1 * dir; | |
| float3 L1r = B1 * c.r; | |
| float3 L1g = B1 * c.g; | |
| float3 L1b = B1 * c.b; | |
| if(texID == 0) return float4(L0, L1r.z); | |
| if(texID == 1) return float4(L1r.x, L1g.x, L1b.x, L1g.z); | |
| if(texID == 2) return float4(L1r.y, L1g.y, L1b.y, L1b.z); | |
| return float4(0,0,0,0); | |
| } | |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
VRC Light Volume : https://github.com/REDSIM/VRCLightVolumes
のリアルタイム化拡張に使っている関数群です。
LightVolumeAtlasのUVWからworldPosを復元できるとライティング情報の計算がしやすいと思います。