forked from Shirakumo/trial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshadow-map.lisp
105 lines (93 loc) · 3.74 KB
/
shadow-map.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#|
This file is a part of trial
(c) 2019 Shirakumo http://tymoon.eu ([email protected])
Author: Nicolas Hafner <[email protected]>
|#
(in-package #:org.shirakumo.fraf.trial)
(define-shader-pass shadow-map-pass (per-object-pass)
((shadow :port-type output
:attachment :depth-attachment
:texspec (:width 2048
:height 2048
:min-filter :nearest
:mag-filter :nearest
:wrapping :clamp-to-border
:border-color #.(vec 1 1 1 1)))
(projection-matrix :initarg :projection-matrix :accessor shadow-projection-matrix)
(view-matrix :initarg :view-matrix :accessor shadow-view-matrix))
(:inhibit-shaders (shader-entity :fragment-shader)))
(define-class-shader (shadow-map-pass :fragment-shader)
"#version 330 core
void main(){}")
(defmethod coerce-pass-shader ((pass shadow-map-pass) class (type (eql :fragment-shader)))
(effective-shader type pass))
(defmethod render ((pass shadow-map-pass) target)
(with-pushed-matrix ((projection-matrix (shadow-projection-matrix pass))
(view-matrix (shadow-view-matrix pass)))
;(gl:cull-face :front)
(call-next-method)
(gl:cull-face :back)))
(define-shader-pass shadow-render-pass ()
((shadow-map :port-type input)
(shadow-map-pass :initarg :shadow-map-pass
:initform (error "SHADOW-MAP-PASS required.")
:accessor shadow-map-pass)))
;; FIXME: how do we do this with the new render system?
(defmethod render :before ((pass shadow-render-pass) thing)
(let ((program (shader-program-for-pass pass thing))
(shadow (shadow-map-pass pass)))
(setf (uniform program "light_space_matrix") (m* (shadow-projection-matrix shadow)
(shadow-view-matrix shadow)))))
(define-class-shader (shadow-render-pass :fragment-shader 10)
"
#define SHADOW_SAMPLES 4
#define SHADOW_SAMPLE_SPREAD 0.0002
uniform sampler2D shadow_map;
uniform mat4 light_space_matrix;
vec2 poisson_disk[16] = vec2[](
vec2( -0.94201624, -0.39906216 ),
vec2( 0.94558609, -0.76890725 ),
vec2( -0.094184101, -0.92938870 ),
vec2( 0.34495938, 0.29387760 ),
vec2( -0.91588581, 0.45771432 ),
vec2( -0.81544232, -0.87912464 ),
vec2( -0.38277543, 0.27676845 ),
vec2( 0.97484398, 0.75648379 ),
vec2( 0.44323325, -0.97511554 ),
vec2( 0.53742981, -0.47373420 ),
vec2( -0.26496911, -0.41893023 ),
vec2( 0.79197514, 0.19090188 ),
vec2( -0.24188840, 0.99706507 ),
vec2( -0.81409955, 0.91437590 ),
vec2( 0.19984126, 0.78641367 ),
vec2( 0.14383161, -0.14100790 )
);
float random(vec4 seed4){
float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673));
return fract(sin(dot_product) * 43758.5453);
}
float shadow_factor(vec3 position, float bias){
vec4 light_space_position = light_space_matrix * vec4(position, 1);
vec3 projected = light_space_position.xyz / light_space_position.w;
projected = (projected+1)*0.5;
if(projected.z > 1) return 0.0;
float closest = texture(shadow_map, projected.xy).r;
float current = projected.z;
float shadow = 0;
vec2 texel_size = 0.5 / textureSize(shadow_map, 0);
for(int i=0; i<SHADOW_SAMPLES; ++i){
int index = int(16*random(vec4(gl_FragCoord.xyy, i)))%16;
vec2 poisson = poisson_disk[index]*SHADOW_SAMPLE_SPREAD;
for(int x=-1; x<=1; ++x){
for(int y=-1; y<=1; ++y){
float closest = texture(shadow_map, projected.xy + poisson + vec2(x, y)*texel_size).r;
if((current - bias) > closest)
shadow+=(1.0 / (SHADOW_SAMPLES*8.0));
}
}
}
return clamp(shadow, 0.0, 1.0);
}
float shadow_bias(vec3 normal, vec3 light_direction){
return clamp(0.005*tan(acos(dot(normal, light_direction))), 0.0, 0.001);
}")