forked from Shirakumo/trial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
phong.lisp
143 lines (119 loc) · 4.76 KB
/
phong.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#|
This file is a part of trial
(c) 2017 Shirakumo http://tymoon.eu (shinmera@tymoon.eu)
Author: Nicolas Hafner <shinmera@tymoon.eu>
|#
(in-package #:org.shirakumo.fraf.trial)
(define-shader-entity phong (vertex-entity)
((diffuse :initarg :diffuse :accessor diffuse)
(specular :initarg :specular :accessor specular)
(normal :initarg :normal :accessor normal)))
(defmethod render :before ((obj phong) (shader shader-program))
(gl:active-texture :texture0)
(gl:bind-texture :texture-2d (gl-name (diffuse obj)))
(gl:active-texture :texture1)
(gl:bind-texture :texture-2d (gl-name (specular obj)))
(gl:active-texture :texture2)
(gl:bind-texture :texture-2d (gl-name (normal obj)))
(setf (uniform shader "material.diffuse") 0)
(setf (uniform shader "material.specular") 1)
(setf (uniform shader "material.normal") 2)
(setf (uniform shader "material.shininess") 0.1)
(setf (uniform shader "light.color") (vec3 1 1 1))
(setf (uniform shader "light.ambient") 0.3)
(setf (uniform shader "light.position") (vec 40 0 20))
(setf (uniform shader "light.direction") (vec -100 0 0))
(setf (uniform shader "light.cutoff") (coerce (cos (deg->rad 60)) 'single-float))
(setf (uniform shader "light.outer") (coerce (cos (deg->rad 70)) 'single-float))
(setf (uniform shader "camera_pos") (location (unit :camera *scene*))))
(define-class-shader (phong :vertex-shader)
"layout (location = 0) in vec3 position;
layout (location = 1) in vec2 in_texcoord;
layout (location = 2) in vec3 in_normal;
uniform vec3 camera_pos;
uniform mat4 model_matrix;
out vec2 texcoord;
out vec3 fragment_pos;
out vec3 normal;
void main(){
fragment_pos = vec3(model_matrix * vec4(position, 1.0));
texcoord = in_texcoord;
normal = mat3(transpose(inverse(model_matrix))) * in_normal;
}")
(define-class-shader (phong :fragment-shader)
"
struct Material {
sampler2D diffuse;
sampler2D specular;
sampler2D normal;
float shininess;
};
struct Light {
vec3 position;
vec3 direction;
float cutoff;
float outer;
vec3 color;
float ambient;
};
uniform vec3 camera_pos;
uniform Light light;
uniform Material material;
in vec2 texcoord;
in vec3 fragment_pos;
in vec3 normal;
out vec4 color;
mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv ){
// get edge vectors of the pixel triangle
vec3 dp1 = dFdx( p );
vec3 dp2 = dFdy( p );
vec2 duv1 = dFdx( uv );
vec2 duv2 = dFdy( uv );
// solve the linear system
vec3 dp2perp = cross( dp2, N );
vec3 dp1perp = cross( N, dp1 );
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
// construct a scale-invariant frame
float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
return mat3( T * invmax, B * invmax, N );
}
vec3 shade_pointlight(Light light, Material material, vec3 normal){
vec3 light_dir = normalize(light.position - fragment_pos);
vec3 view_dir = normalize(camera_pos - fragment_pos);
vec3 reflect_dir = reflect(-light_dir, normal);
float distance = length(light.position - fragment_pos);
float attenuation = 1.0 / (1.0 + 0.014 * distance + 0.0007 * distance * distance);
vec3 ambient = vec3(texture(material.diffuse, texcoord)) * light.ambient;
vec3 diffuse = vec3(texture(material.diffuse, texcoord)) * max(dot(normal, light_dir), 0);
vec3 specular = vec3(texture(material.specular, texcoord)) * pow(max(dot(view_dir, reflect_dir), 0.0), 32);
return light.color * attenuation * (ambient+diffuse+specular);
}
vec3 shade_spotlight(Light light, Material material, vec3 normal){
vec3 light_dir = normalize(light.position - fragment_pos);
vec3 view_dir = normalize(camera_pos - fragment_pos);
vec3 reflect_dir = reflect(-light_dir, normal);
float distance = length(light.position - fragment_pos);
float attenuation = 1.0 / (1.0 + 0.0014 * distance + 0.000007 * distance * distance);
float theta = dot(light_dir, normalize(-light.direction));
vec3 ambient = vec3(texture(material.diffuse, texcoord)) * light.ambient;
vec3 diffuse = vec3(0,0,0);
vec3 specular = vec3(0,0,0);
if(theta > light.outer) {
float epsilon = light.cutoff - light.outer;
float intensity = clamp((theta - light.outer) / epsilon, 0.0, 1.0);
diffuse = intensity * vec3(texture(material.diffuse, texcoord)) * max(dot(normal, light_dir), 0);
specular = intensity * vec3(texture(material.specular, texcoord)) * pow(max(dot(view_dir, reflect_dir), 0.0), 32);
}
return light.color * attenuation * (ambient+diffuse+specular);
}
void main(){
vec3 n = texture(material.normal, texcoord).rgb;
//n = n * 255./127. - 128./127.;
//n.y = -n.y;
n = cotangent_frame(normal, fragment_pos-camera_pos, texcoord) * n;
n = normalize(n);
color.rgb = vec3(0,0,0);
color.rgb += shade_spotlight(light, material, n);
color.rgb += shade_pointlight(light, material, n);
}")