- Reference
- Graphics Rants
- Optimizing GGX Shaders with dot(L,H) by John Hable
Test code
//----------------------------------------------------------------------------------------------------
// Geometric shadow test shader by hanecci
//
// This software is released under the Unlicense. ( http://unlicense.org/ )
//
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any means.
//
//----------------------------------------------------------------------------------------------------
in vec3 normal;
in vec3 half_vec;
uniform vec3 light_dir;
uniform vec3 eye_dir;
uniform float roughness;
#define GEOM_SHADOW_MODE ( 0 )
#define GEOM_SHADOW_NONE ( 0 )
#define GEOM_SHADOW_NEUMANN ( 1 )
#define GEOM_SHADOW_KELEMEN ( 2 )
#define GEOM_SHADOW_SMITH_GGX ( 3 )
#define GEOM_SHADOW_SCHLICK_GGX ( 4 )
#define GEOM_SHADOW_JOHN_HABLE_GGX_OPT1 ( 5 )
#define GEOM_SHADOW_JOHN_HABLE_GGX_OPT2 ( 6 )
void main( void )
{
vec4 color = vec4( 0.0, 0.0, 0.0, 0.0 );
float dot_n_l = clamp( dot( normal, light_dir ), 0.0, 1.0 );
float dot_n_v = clamp( dot( normal, eye_dir ) , 0.0, 1.0 );
float dot_l_v = clamp( dot( normal, eye_dir ) , 0.0, 1.0 );
float dot_l_h = clamp( dot( half_vec, light_dir ), 0.0, 1.0 );
float alpha = roughness * roughness;
#if ( GEOM_SHADOW_MODE == GEOM_SHADOW_NONE )
// if : G = dot_n_l * dot_n_v
// then : G / ( 4 dot_n_l * dot_n_v ) = 0.25;
float geom_shadow = 0.25;
#elif ( GEOM_SHADOW_MODE == GEOM_SHADOW_NEUMANN )
float geom_shadow = rcp( max( dot_n_l, dot_n_v ) );
#elif ( GEOM_SHADOW_MODE == GEOM_SHADOW_KELEMEN )
float geom_shadow = rcp( 1.0 + dot_l_v );
#elif ( GEOM_SHADOW_MODE == GEOM_SHADOW_SMITH_GGX )
float alpha2 = alpha * alpha;
float g_v = dot_n_v * sqrt( ( dot_n_v - dot_n_v * alpha2 ) * dot_n_v + alpha2 );
float g_l = dot_n_l * sqrt( ( dot_n_l - dot_n_l * alpha2 ) * dot_n_l + alpha2 );
float geom_shadow = rcp( g_v * g_l );
#elif ( GEOM_SHADOW_MODE == GEOM_SHADOW_SCHLICK_GGX )
// k = alpha / 2;
float tmp = 2 - alpha;
float g_v = dot_n_v * tmp + alpha;
float g_l = dot_n_l * tmp + alpha;
float geom_shadow = rcp( g_v * g_l );
#elif ( GEOM_SHADOW_MODE == GEOM_SHADOW_JOHN_HABLE_GGX_OPT1 )
// Replace dotNV and dotNL by dotLH
float tmp = 2 - alpha;
float g_v_l = dot_l_h * tmp + alpha;
float geom_shadow = rcp( g_v_l * g_v_l );
#elif ( GEOM_SHADOW_MODE == GEOM_SHADOW_JOHN_HABLE_GGX_OPT2 )
float k = alpha / 2.0f;
float k2 = k * k;
float inv_k2 = 1.0f - k2;
float geom_shadow = rcp( dot_l_h * dot_l_h * inv_k2 + k2 );
#endif
gl_FragColor.rgb = vec3( geom_shadow );
}
None
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(3)
0 x: MOV R0.x, (0x3E800000, 0.25f).x
w: MOV R0.w, 1.0f
01 EXP_DONE: PIX0, R0.xxxw
END_OF_PROGRAM
Neumann
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(13)
0 x: DOT4 R1.x, R0.x, C1.x CLAMP
y: DOT4 ____, R0.y, C1.y CLAMP
z: DOT4 ____, R0.z, C1.z CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
t: MOV R2.w, 1.0f
1 x: DOT4 ____, R0.x, C0.x CLAMP
y: DOT4 ____, R0.y, C0.y CLAMP
z: DOT4 ____, R0.z, C0.z CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
2 y: MAX ____, R1.x, PV1.x
3 t: RCP_e R2.x, PV2.y
01 EXP_DONE: PIX0, R2.xxxw
END_OF_PROGRAM
Kelemen
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(8)
0 x: DOT4 ____, R0.x, C0.x CLAMP
y: DOT4 ____, R0.y, C0.y CLAMP
z: DOT4 ____, R0.z, C0.z CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
t: MOV R0.w, 1.0f
1 y: ADD ____, PV0.x, 1.0f
2 t: RCP_e R0.x, PV1.y
01 EXP_DONE: PIX0, R0.xxxw
END_OF_PROGRAM
Smith-GGX
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(24)
0 x: MUL ____, C2.x, C2.x
w: MOV R1.w, 1.0f
t: MUL ____, R0.z, C1.z
1 x: DOT4 ____, R0.x, C1.x CLAMP
y: DOT4 R1.y, R0.y, C1.y CLAMP
z: DOT4 ____, PS0, 1.0f CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
t: MUL R1.z, PV0.x, PV0.x
2 x: DOT4 ____, R0.x, C0.x CLAMP
y: DOT4 ____, R0.y, C0.y CLAMP
z: DOT4 ____, R0.z, C0.z CLAMP
w: DOT4 R0.w, (0x80000000, -0.0f).x, 0.0f CLAMP
t: MULADD R126.x, -PV1.x, PS1, PV1.x
3 y: MULADD R127.y, -PV2.x, R1.z, PV2.x
w: MULADD R127.w, R1.y, PS2, R1.z
4 w: MULADD R127.w, R0.w, PV3.y, R1.z
t: SQRT_e ____, PV3.w
5 z: MUL R1.z, R1.y, PS4
t: SQRT_e ____, PV4.w
6 z: MUL ____, R0.w, PS5
7 y: MUL ____, PV6.z, R1.z
8 t: RCP_e R1.x, PV7.y
01 EXP_DONE: PIX0, R1.xxxw
END_OF_PROGRAM
Schlick-GGX
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(18)
0 x: MUL ____, R0.z, C1.z
y: MUL R1.y, C2.x, C2.x
w: MOV R1.w, 1.0f
1 x: DOT4 ____, R0.x, C1.x CLAMP
y: DOT4 ____, R0.y, C1.y CLAMP
z: DOT4 ____, PV0.x, 1.0f CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
t: ADD R0.w, -PV0.y, (0x40000000, 2.0f).y
2 x: DOT4 ____, R0.x, C0.x CLAMP
y: DOT4 ____, R0.y, C0.y CLAMP VEC_120
z: DOT4 ____, R0.z, C0.z CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
t: MULADD R0.z, PV1.x, PS1, R1.y
3 x: MULADD R127.x, PV2.x, R0.w, R1.y
4 y: MUL ____, PV3.x, R0.z
5 t: RCP_e R1.x, PV4.y
01 EXP_DONE: PIX0, R1.xxxw
END_OF_PROGRAM
Schlick-GGX opt by John Hable : LightingFuncGGX_OPT1()
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(12)
0 x: MUL ____, R0.z, C1.z
y: MOV R1.y, 1.0f
w: MUL R0.w, C2.x, C2.x
1 x: DOT4 ____, R0.x, C1.x CLAMP
y: DOT4 ____, R0.y, C1.y CLAMP
z: DOT4 ____, PV0.x, 1.0f CLAMP
w: DOT4 ____, (0x80000000, -0.0f).x, 0.0f CLAMP
t: ADD ____, -PV0.w, (0x40000000, 2.0f).y
2 z: MULADD R127.z, PV1.x, PS1, R0.w
3 y: MUL ____, PV2.z, PV2.z
4 t: RCP_e R1.x, PV3.y
01 EXP_DONE: PIX0, R1.xxxy
END_OF_PROGRAM
Schlick-GGX opt by John Hable : LightingFuncGGX_OPT2()
; -------- Disassembly --------------------
00 ALU: ADDR(32) CNT(11)
0 x: MUL ____, R0.z, C1.z
z: MUL ____, C2.x, C2.x
w: MOV R1.w, 1.0f
1 x: MULADD R127.x, R0.y, C1.y, PV0.x
y: MUL_e ____, PV0.z, 0.5
2 x: MULADD R127.x, R0.x, C1.x, PV1.x CLAMP
w: MUL R0.w, PV1.y, PV1.y
3 x: ADD ____, -PV2.w, 1.0f
z: MUL ____, PV2.x, PV2.x
4 y: MULADD R127.y, PV3.x, PV3.z, R0.w
5 t: RCP_e R1.x, PV4.y
01 EXP_DONE: PIX0, R1.xxxw
END_OF_PROGRAM