Created
October 30, 2020 23:49
-
-
Save lyuma/165ccb5af08c54282cd2faa982ae1deb to your computer and use it in GitHub Desktop.
Convert Godot spherical harmonics to Unity SH9 coefficients (e.g. ShadeSH9)
This file contains 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
// Global temporary variables in GLSL, and access to ambient/reflection/SH9 in shaders: | |
// Requires these patches: | |
// https://github.com/lyuma/godot/tree/shader_improvements_meta (master) | |
// https://github.com/lyuma/godot/tree/shader_global_arrays_3.2 (3.2) | |
// https://github.com/lyuma/godot/tree/shader_npr_lighting_3.2 (3.2) | |
vec4 unity_SHAr = vec4(0.0); | |
vec4 unity_SHAg = vec4(0.0); | |
vec4 unity_SHAb = vec4(0.0); | |
vec4 unity_SHBr = vec4(0.0); | |
vec4 unity_SHBg = vec4(0.0); | |
vec4 unity_SHBb = vec4(0.0); | |
vec4 unity_SHC = vec4(0.0); | |
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) | |
// normal should be normalized, w=1.0 | |
vec3 SHEvalLinearL0L1 (vec4 normal) | |
{ | |
vec3 x; | |
// Linear (L1) + constant (L0) polynomial terms | |
x.r = dot(unity_SHAr,normal); | |
x.g = dot(unity_SHAg,normal); | |
x.b = dot(unity_SHAb,normal); | |
return x; | |
} | |
// normal should be normalized, w=1.0 | |
vec3 SHEvalLinearL2 (vec4 normal) | |
{ | |
vec3 x1, x2; | |
// 4 of the quadratic (L2) polynomials | |
vec4 vB = normal.xyzz * normal.yzzx; | |
x1.r = dot(unity_SHBr,vB); | |
x1.g = dot(unity_SHBg,vB); | |
x1.b = dot(unity_SHBb,vB); | |
// Final (5th) quadratic (L2) polynomial | |
float vC = normal.x*normal.x - normal.y*normal.y; | |
x2 = unity_SHC.rgb * vC; | |
return x1 + x2; | |
} | |
// normal should be normalized, w=1.0 | |
// output in active color space | |
vec3 ShadeSH9 (vec4 normal) | |
{ | |
// Linear + constant polynomial terms | |
vec3 res = SHEvalLinearL0L1 (normal); | |
// Quadratic polynomials | |
res += SHEvalLinearL2 (normal); | |
return res; | |
} | |
// Godot conversion operations, followed by user code. | |
void fragment() { | |
// Initialize SH coefficiens. | |
LightmapCapture lc; | |
if (GET_LIGHTMAP_SH(lc)) { | |
const float c1 = 0.429043; | |
const float c2 = 0.511664; | |
const float c3 = 0.743125; | |
const float c4 = 0.886227; | |
const float c5 = 0.247708; | |
// multiplying by constants as in: | |
// https://github.com/mrdoob/three.js/pull/16275/files | |
vec3 constterm = c4 * SH_COEF(lc, uint(0)).rgb - c5 * SH_COEF(lc, uint(6)).rgb; | |
vec3 shaX = 2.0 * c2 * SH_COEF(lc, uint(3)).rgb; | |
vec3 shaY = 2.0 * c2 * SH_COEF(lc, uint(1)).rgb; | |
vec3 shaZ = 2.0 * c2 * SH_COEF(lc, uint(2)).rgb; | |
vec3 shbX = 2.0 * c1 * SH_COEF(lc, uint(4)).rgb; | |
vec3 shbY = 2.0 * c1 * SH_COEF(lc, uint(5)).rgb; | |
vec3 shbZ = c3 * SH_COEF(lc, uint(6)).rgb; | |
vec3 shbW = 2.0 * c1 * SH_COEF(lc, uint(7)).rgb; | |
vec3 shc = c1 * SH_COEF(lc, uint(8)).rgb; | |
unity_SHAr = vec4(shaX.r, shaY.r, shaZ.r, constterm.r); | |
unity_SHAg = vec4(shaX.g, shaY.g, shaZ.g, constterm.g); | |
unity_SHAb = vec4(shaX.b, shaY.b, shaZ.b, constterm.b); | |
unity_SHBr = vec4(shbX.r, shbY.r, shbZ.r, shbW.r); | |
unity_SHBg = vec4(shbX.g, shbY.g, shbZ.g, shbW.g); | |
unity_SHBb = vec4(shbX.b, shbY.b, shbZ.b, shbW.b); | |
unity_SHC = vec4(shc, 0.0); | |
} else { | |
// Emulate L0&L1 Coefficients, assuming top-down lighting. | |
// Indirect Light | |
vec4 reflection_accum; | |
vec4 ambient_accum; | |
vec3 env_reflection_light = vec3(0.0); | |
vec3 world_space_up = vec3(0.0,1.0,0.0); | |
vec3 up_normal = mat3(INV_CAMERA_MATRIX) * world_space_up; | |
vec3 ambient_light_up; | |
vec3 diffuse_light_up; | |
vec3 specular_light_up; | |
reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); | |
ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); | |
AMBIENT_PROCESS(VERTEX, up_normal, ROUGHNESS, SPECULAR, false, VIEW, vec2(0.0), ambient_light_up, diffuse_light_up, specular_light_up); | |
for (uint idx = uint(0); idx < REFLECTION_PROBE_COUNT(CLUSTER_CELL); idx++) { | |
REFLECTION_PROCESS(CLUSTER_CELL, idx, VERTEX, up_normal, ROUGHNESS, ambient_light_up, specular_light_up, ambient_accum, reflection_accum); | |
} | |
if (ambient_accum.a > 0.0) { | |
ambient_light_up = ambient_accum.rgb / ambient_accum.a; | |
} | |
vec3 ambient_light_down; | |
vec3 diffuse_light_down; | |
vec3 specular_light_down; | |
reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); | |
ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); | |
AMBIENT_PROCESS(VERTEX, -up_normal, ROUGHNESS, SPECULAR, false, VIEW, vec2(0.0), ambient_light_down, diffuse_light_down, specular_light_down); | |
for (uint idx = uint(0); idx < REFLECTION_PROBE_COUNT(CLUSTER_CELL); idx++) { | |
REFLECTION_PROCESS(CLUSTER_CELL, idx, VERTEX, -up_normal, ROUGHNESS, ambient_light_down, specular_light_down, ambient_accum, reflection_accum); | |
} | |
if (ambient_accum.a > 0.0) { | |
ambient_light_down = ambient_accum.rgb / ambient_accum.a; | |
} | |
vec3 const_term = mix(ambient_light_down, ambient_light_up, 0.5); | |
vec3 delta_term = 0.5*(ambient_light_up - ambient_light_down); | |
unity_SHAr = vec4(world_space_up * delta_term.r, const_term.r); | |
unity_SHAg = vec4(world_space_up * delta_term.g, const_term.g); | |
unity_SHAb = vec4(world_space_up * delta_term.b, const_term.b); | |
} | |
... code here ... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment