/
IBL-Pathtracer.frag
285 lines (214 loc) · 6.48 KB
/
IBL-Pathtracer.frag
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
#donotrun
#include "3D.frag"
#group Raytracer
// Distance to object at which raymarching stops.
uniform float Detail;slider[-7,-2.3,0];
// Lower this if the system is missing details
uniform float FudgeFactor;slider[0,1,1];
float minDist = pow(10.0,Detail);
// Maximum number of raymarching steps.
uniform int MaxRaySteps; slider[0,56,2000]
vec4 orbitTrap = vec4(10000.0);
#group Light
#group Coloring
float DE(vec3 pos) ; // Must be implemented in other file
#ifdef providesNormal
vec3 normal(vec3 pos, float normalDistance);
#else
vec3 normal(vec3 pos, float normalDistance) {
normalDistance = max(normalDistance*0.5, 1.0e-7);
vec3 e = vec3(0.0,normalDistance,0.0);
vec3 n = vec3(DE(pos+e.yxx)-DE(pos-e.yxx),
DE(pos+e.xyx)-DE(pos-e.xyx),
DE(pos+e.xxy)-DE(pos-e.xxy));
n = normalize(n);
return n;
}
#endif
#group Coloring
// This is the pure color of object (in white light)
uniform vec3 BaseColor; color[1.0,1.0,1.0];
// Determines the mix between pure light coloring and pure orbit trap coloring
uniform float OrbitStrength; slider[0,0,1]
// Closest distance to YZ-plane during orbit
uniform vec4 X; color[-1,0.7,1,0.5,0.6,0.6];
// Closest distance to XZ-plane during orbit
uniform vec4 Y; color[-1,0.4,1,1.0,0.6,0.0];
// Closest distance to XY-plane during orbit
uniform vec4 Z; color[-1,0.5,1,0.8,0.78,1.0];
// Closest distance to origin during orbit
uniform vec4 R; color[-1,0.12,1,0.4,0.7,1.0];
uniform bool CycleColors; checkbox[false]
uniform float Cycles; slider[0.1,1.1,32.3]
#group Raytracer
uniform sampler2D EnvironmentMap; file[Ditch-River_env.hdr]
uniform float RotateMap; slider[0.00,0,6.28]
// Can be used to remove banding
uniform float Dither;slider[0,0.5,1];
#define PI 3.14159265358979323846264
vec2 spherical(vec3 dir) {
return vec2( acos(dir.z)/PI, atan(dir.y,dir.x)/(2.0*PI) );
}
vec3 fromPhiTheta(vec2 p) {
return vec3(
cos(p.x)*sin(p.y),
sin(p.x)*sin(p.y),
cos(p.y));
}
float rand(vec2 co){
// implementation found at: lumina.sourceforge.net/Tutorials/Noise.html
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
#ifdef providesColor
vec3 baseColor(vec3 point, vec3 normal);
#endif
bool trace(vec3 from, vec3 dir, inout vec3 hit, inout vec3 hitNormal) {
vec3 direction = normalize(dir);
float eps = minDist;
float dist = 1000.0;
float totalDist = 0.0;
for (int steps=0; steps<MaxRaySteps && dist > eps; steps++) {
hit = from + totalDist * direction;
dist = DE(hit) * FudgeFactor;
// if (steps == 0)
dist*=(Dither*rand(dir.xy))+(1.0-Dither);
totalDist += dist;
}
if (dist < eps) {
hit = from + (totalDist-eps) * direction;
hitNormal = normal(hit, eps);
return true;
}
return false;
}
uniform float reflectivity; slider[0,0.2,1.0]
uniform bool debugLast; checkbox[false]
uniform bool Stratify; checkbox[false]
uniform bool WhiteBackground; checkbox[false]
uniform int RayDepth; slider[0,2,5] Locked
uniform float Albedo; slider[0,1,1]
vec3 ortho(vec3 d) {
if (abs(d.x)>0.00001 || abs(d.y)>0.00001) {
return vec3(d.y,-d.x,0.0);
} else {
return vec3(0.0,d.z,-d.y);
}
}
vec2 cx=
vec2(
floor(mod(float(subframe)*1.0,10.)),
floor(mod(float(subframe)*0.1,10.))
)/10.0;
vec3 getSampleBiased(vec3 dir, float power) {
dir = normalize(dir);
// create orthogonal vector
vec3 o1 = normalize(ortho(dir));
vec3 o2 = normalize(cross(dir, o1));
// Convert to spherical coords aligned to dir;
vec2 r = rand2(viewCoord*(float(subframe)+1.0));
if (Stratify) {r*=0.1; r+= cx;}
r.x=r.x*2.*PI;
// This is cosine^n weighted.
// See, e.g. http://people.cs.kuleuven.be/~philip.dutre/GI/TotalCompendium.pdf
// Item 36
r.y=pow(r.y,1.0/(power+1.0));
float oneminus = sqrt(1.0-r.y*r.y);
vec3 sdir = cos(r.x)*oneminus*o1+
sin(r.x)*oneminus*o2+
r.y*dir;
return sdir;
}
vec3 getSample(vec3 dir, float extent) {
// Create orthogonal vector (fails for z,y = 0)
dir = normalize(dir);
vec3 o1 = normalize(ortho(dir));
vec3 o2 = normalize(cross(dir, o1));
// Convert to spherical coords aligned to dir
vec2 r = rand2(viewCoord*(float(subframe)+1.0));
if (Stratify) {r*=0.1; r+= cx;}
r.x=r.x*2.*PI;
// r.y=1.0-r.y*extent;
float oneminus = sqrt(1.0-r.y*r.y);
return cos(r.x)*oneminus*o1+sin(r.x)*oneminus*o2+r.y*dir;
}
vec3 equirectangularMap(sampler2D sampler, vec3 dir) {
// Convert (normalized) dir to spherical coordinates.
dir = normalize(dir);
vec2 longlat = vec2(atan(dir.y,dir.x)+RotateMap,acos(dir.z));
// Normalize, and lookup in equirectangular map.
return texture2D(sampler,longlat/vec2(2.0*PI,PI)).xyz;
}
vec3 getBackground(vec3 dir) {
return WhiteBackground ? vec3(1.0) : equirectangularMap(EnvironmentMap,dir);
}
vec3 cycle(vec3 c, float s) {
return vec3(0.5)+0.5*vec3(cos(s*Cycles+c.x),cos(s*Cycles+c.y),cos(s*Cycles+c.z));
}
vec3 getColor() {
orbitTrap.w = sqrt(orbitTrap.w);
vec3 orbitColor;
if (CycleColors) {
orbitColor = cycle(X.xyz,orbitTrap.x)*X.w*orbitTrap.x +
cycle(Y.xyz,orbitTrap.y)*Y.w*orbitTrap.y +
cycle(Z.xyz,orbitTrap.z)*Z.w*orbitTrap.z +
cycle(R.xyz,orbitTrap.w)*R.w*orbitTrap.w;
} else {
orbitColor = X.xyz*X.w*orbitTrap.x +
Y.xyz*Y.w*orbitTrap.y +
Z.xyz*Z.w*orbitTrap.z +
R.xyz*R.w*orbitTrap.w;
}
vec3 color = mix(BaseColor, 3.0*orbitColor, OrbitStrength);
return color;
}
float rand() {
return rand(viewCoord*(float(subframe)+1.0));
}
uniform bool BiasedSampling; checkbox[true]
vec3 color(vec3 from, vec3 dir)
{
vec3 hit = vec3(0.0);
vec3 hitNormal = vec3(0.0);
vec3 color = vec3(1.0);
for( int i=0; i <RayDepth; i++ )
{
if (trace(from,dir,hit,hitNormal)) {
// We hit something
if (rand() > reflectivity ) {
#ifdef providesColor
color *= baseColor(hit, hitNormal);
#else
color *= getColor();
#endif
color *= (1.0-reflectivity);
if (!BiasedSampling) {
// Unbiased sampling:
// PDF = 1/(2*PI), BRDF = Albedo/PI
dir =getSample( hitNormal,1.0);
// modulate color with: BRDF*CosAngle/PDF
color *= 2.0*Albedo*max(0.0,dot(dir,hitNormal));
}
else {
// Biased sampling (cosine weighted):
// PDF = CosAngle / PI, BRDF = Albedo/PI
dir =getSampleBiased( hitNormal, 1.0 );
// modulate color with: BRDF*CosAngle/PDF
color *= Albedo;
}
}
else {
color *=reflectivity;
dir=reflect(dir,hitNormal);
color *= max(0.0, dot(dir, hitNormal));
}
// Choose new starting point for ray
from = hit + dir*minDist*3.0;
} else {
if (debugLast && i!=RayDepth-1) {
return vec3(0.0);
}
return color * getBackground( dir );
}
}
return vec3(0.0);
}