rayfract
diff sdr/julia.p.glsl @ 0:09bb67c000bc
ray-fract repository
author | John Tsiombikas <nuclear@siggraph.org> |
---|---|
date | Thu, 21 Oct 2010 23:39:26 +0300 |
parents | |
children | 03022062c464 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/sdr/julia.p.glsl Thu Oct 21 23:39:26 2010 +0300 1.3 @@ -0,0 +1,289 @@ 1.4 +/* vim: set ft=glsl:ts=4:sw=4 */ 1.5 +uniform vec4 seed; 1.6 +uniform sampler2D ray_tex; 1.7 +uniform float err_thres; 1.8 +uniform int iter; 1.9 + 1.10 +#define quat(s, x, y, z) vec4(x, y, z, s) 1.11 +#define quat_identity() vec4(0.0, 0.0, 0.0, 1.0) 1.12 + 1.13 +#define vec2quat(v) (v).wxyz 1.14 + 1.15 +struct Ray { 1.16 + vec3 origin; 1.17 + vec3 dir; 1.18 +}; 1.19 + 1.20 +struct Julia { 1.21 + bool inside; 1.22 + vec4 q; 1.23 + vec4 qprime; 1.24 +}; 1.25 + 1.26 +struct ISect { 1.27 + bool hit; 1.28 + float t; 1.29 + vec3 pos; 1.30 + vec3 normal; 1.31 + vec3 color; 1.32 + float kr; 1.33 +}; 1.34 + 1.35 +ISect find_intersection(Ray ray); 1.36 +vec3 shade(Ray ray, ISect isect); 1.37 +float amboc(ISect isect); 1.38 +vec3 sky(Ray ray); 1.39 +Julia julia(vec4 q, vec4 c); 1.40 +float julia_dist(vec4 z); 1.41 +vec3 julia_grad(vec4 z); 1.42 +vec4 quat_mul(vec4 q1, vec4 q2); 1.43 +vec4 quat_sq(vec4 q); 1.44 +float quat_length_sq(vec4 q); 1.45 +ISect ray_julia(Ray ray); 1.46 +ISect ray_sphere(Ray ray, float rad); 1.47 +ISect ray_floor(Ray ray); 1.48 +Ray get_primary_ray(); 1.49 + 1.50 + 1.51 +void main() 1.52 +{ 1.53 + Ray ray = get_primary_ray(); 1.54 + 1.55 + float energy = 1.0; 1.56 + vec3 color = vec3(0.0, 0.0, 0.0); 1.57 + 1.58 + while(energy > 0.001) { 1.59 + ISect res = find_intersection(ray); 1.60 + 1.61 + if(res.hit) { 1.62 + color += shade(ray, res) * energy; 1.63 + energy *= res.kr; 1.64 + 1.65 + ray.origin = res.pos; 1.66 + ray.dir = reflect(ray.dir, res.normal); 1.67 + } else { 1.68 + color += sky(ray) * energy; 1.69 + break; 1.70 + } 1.71 + } 1.72 + 1.73 + gl_FragColor = vec4(color, 1.0); 1.74 +} 1.75 + 1.76 + 1.77 +ISect find_intersection(Ray ray) 1.78 +{ 1.79 + ISect res; 1.80 + res.hit = false; 1.81 + 1.82 + ISect bhit = ray_sphere(ray, 2.0); 1.83 + if(bhit.hit) { 1.84 + ray.origin = bhit.pos; 1.85 + res = ray_julia(ray); 1.86 + } 1.87 + 1.88 + if(!res.hit) { 1.89 + res = ray_floor(ray); 1.90 + } 1.91 + return res; 1.92 +} 1.93 + 1.94 +vec3 shade(Ray ray, ISect isect) 1.95 +{ 1.96 + vec3 ldir = normalize(vec3(10.0, 10.0, -10.0) - isect.pos); 1.97 + vec3 vdir = -ray.dir; 1.98 + vec3 hdir = normalize(ldir + vdir); 1.99 + 1.100 + float ndotl = dot(ldir, isect.normal); 1.101 + float ndoth = dot(hdir, isect.normal); 1.102 + 1.103 + vec3 dcol = /*isect.color * max(ndotl, 0.0) */ amboc(isect); 1.104 + vec3 scol = vec3(1.0, 1.0, 1.0) * pow(max(ndoth, 0.0), 40.0); 1.105 + 1.106 + return /*vec3(0.05, 0.05, 0.05) + */dcol;// + scol; 1.107 +} 1.108 + 1.109 +#define AO_STEP 0.04 1.110 +#define AO_MAGIC 8.0 1.111 +float amboc(ISect isect) 1.112 +{ 1.113 + float sum = 0.0; 1.114 + 1.115 + for(float fi=0.0; fi<5.0; fi+=1.0) { 1.116 + float sample_dist = fi * AO_STEP; 1.117 + vec3 pt = isect.pos + isect.normal * sample_dist; 1.118 + float jdist = julia_dist(quat(pt.x, pt.y, pt.z, 0.0)); 1.119 + 1.120 + sum += 1.0 / pow(2.0, fi) * (sample_dist - jdist); 1.121 + } 1.122 + 1.123 + return 1.0 - AO_MAGIC * sum; 1.124 +} 1.125 + 1.126 +vec3 sky(Ray ray) 1.127 +{ 1.128 + vec3 col1 = vec3(0.75, 0.78, 0.8); 1.129 + vec3 col2 = vec3(0.56, 0.7, 1.0); 1.130 + 1.131 + float t = max(ray.dir.y, -0.5); 1.132 + return mix(col1, col2, t); 1.133 +} 1.134 + 1.135 +Julia julia(vec4 q, vec4 c) 1.136 +{ 1.137 + Julia res; 1.138 + res.inside = true; 1.139 + 1.140 + res.q = q; 1.141 + res.qprime = quat_identity(); 1.142 + 1.143 + for(int i=0; i<iter; i++) { 1.144 + res.qprime = 2.0 * quat_mul(res.q, res.qprime); 1.145 + res.q = quat_sq(res.q) + c; 1.146 + 1.147 + if(dot(res.q, res.q) > 8.0) { 1.148 + res.inside = false; 1.149 + break; 1.150 + } 1.151 + } 1.152 + return res; 1.153 +} 1.154 + 1.155 +float julia_dist(vec4 z) 1.156 +{ 1.157 + Julia jres = julia(z, seed); 1.158 + 1.159 + float lenq = length(jres.q); 1.160 + float lenqprime = length(jres.qprime); 1.161 + 1.162 + return 0.5 * lenq * log(lenq) / lenqprime; 1.163 +} 1.164 + 1.165 +#define OFFS 1e-4 1.166 +vec3 julia_grad(vec4 z) 1.167 +{ 1.168 + vec3 grad; 1.169 + grad.x = julia_dist(z + quat(OFFS, 0.0, 0.0, 0.0)) - julia_dist(z - quat(OFFS, 0.0, 0.0, 0.0)); 1.170 + grad.y = julia_dist(z + quat(0.0, OFFS, 0.0, 0.0)) - julia_dist(z - quat(0.0, OFFS, 0.0, 0.0)); 1.171 + grad.z = julia_dist(z + quat(0.0, 0.0, OFFS, 0.0)) - julia_dist(z - quat(0.0, 0.0, OFFS, 0.0)); 1.172 + return grad; 1.173 +} 1.174 + 1.175 +vec4 quat_mul(vec4 q1, vec4 q2) 1.176 +{ 1.177 + vec4 res; 1.178 + res.w = q1.w * q2.w - dot(q1.xyz, q2.xyz); 1.179 + res.xyz = q1.w * q2.xyz + q2.w * q1.xyz + cross(q1.xyz, q2.xyz); 1.180 + return res; 1.181 +} 1.182 + 1.183 +vec4 quat_sq(vec4 q) 1.184 +{ 1.185 + vec4 res; 1.186 + res.w = q.w * q.w - dot(q.xyz, q.xyz); 1.187 + res.xyz = 2.0 * q.w * q.xyz; 1.188 + return res; 1.189 +} 1.190 + 1.191 +ISect ray_julia(Ray inray) 1.192 +{ 1.193 + float dist_acc = 0.0; 1.194 + Ray ray = inray; 1.195 + ISect res; 1.196 + 1.197 + for(float fi=0.0; ; fi+=0.1) { 1.198 + vec4 q = quat(ray.origin.x, ray.origin.y, ray.origin.z, 0.0); 1.199 + 1.200 + float dist = julia_dist(q); 1.201 + 1.202 + ray.origin += ray.dir * dist; 1.203 + dist_acc += dist; 1.204 + 1.205 + if(dist < err_thres) { 1.206 + res.hit = true; 1.207 + res.t = dist_acc; 1.208 + res.pos = ray.origin; 1.209 + res.normal = normalize(julia_grad(quat(res.pos.x, res.pos.y, res.pos.z, 0.0))); 1.210 + res.color = vec3(0.75, 0.8, 0.9);//abs(res.normal) * 0.2; 1.211 + //res.kr = 0.6; 1.212 + res.kr = 0.0; 1.213 + break; 1.214 + } 1.215 + 1.216 + if(dot(ray.origin, ray.origin) > 100.0) { 1.217 + res.hit = false; 1.218 + break; 1.219 + } 1.220 + } 1.221 + 1.222 + return res; 1.223 +} 1.224 + 1.225 +ISect ray_sphere(Ray ray, float rad) 1.226 +{ 1.227 + ISect res; 1.228 + res.hit = false; 1.229 + 1.230 + float a = dot(ray.dir, ray.dir); 1.231 + float b = 2.0 * dot(ray.dir, ray.origin); 1.232 + float c = dot(ray.origin, ray.origin) - rad * rad; 1.233 + 1.234 + float d = b * b - 4.0 * a * c; 1.235 + if(d < 0.0) return res; 1.236 + 1.237 + float sqrt_d = sqrt(d); 1.238 + float t1 = (-b + sqrt_d) / (2.0 * a); 1.239 + float t2 = (-b - sqrt_d) / (2.0 * a); 1.240 + 1.241 + if((t1 >= 0.0 || t2 >= 0.0)) { 1.242 + if(t1 < 0.0) t1 = t2; 1.243 + if(t2 < 0.0) t2 = t1; 1.244 + 1.245 + res.hit = true; 1.246 + res.t = min(t1, t2); 1.247 + res.pos = ray.origin + ray.dir * res.t; 1.248 + res.color = vec3(1.0, 0.3, 0.2); 1.249 + res.normal = res.pos / rad; 1.250 + } 1.251 + 1.252 + return res; 1.253 +} 1.254 + 1.255 +#define FLOOR_HEIGHT (-2.0) 1.256 + 1.257 +ISect ray_floor(Ray ray) 1.258 +{ 1.259 + ISect res; 1.260 + res.hit = false; 1.261 + 1.262 + if(ray.origin.y < FLOOR_HEIGHT || ray.dir.y >= 0.0) { 1.263 + return res; 1.264 + } 1.265 + 1.266 + res.normal = vec3(0.0, 1.0, 0.0); 1.267 + float ndotdir = dot(res.normal, ray.dir); 1.268 + 1.269 + float t = (FLOOR_HEIGHT - ray.origin.y) / ndotdir; 1.270 + res.pos = ray.origin + ray.dir * t; 1.271 + 1.272 + if(abs(res.pos.x) > 8.0 || abs(res.pos.z) > 8.0) { 1.273 + res.hit = false; 1.274 + } else { 1.275 + res.hit = true; 1.276 + 1.277 + float chess = mod(floor(res.pos.x) + floor(res.pos.z), 2.0); 1.278 + res.color = mix(vec3(0.498, 0.165, 0.149), vec3(0.776, 0.851, 0.847), chess); 1.279 + res.kr = 0.0; 1.280 + } 1.281 + return res; 1.282 +} 1.283 + 1.284 +Ray get_primary_ray() 1.285 +{ 1.286 + Ray ray; 1.287 + vec2 tc = gl_TexCoord[0].xy; 1.288 + ray.dir = gl_NormalMatrix * normalize(texture2D(ray_tex, tc).xyz); 1.289 + ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 1.290 + return ray; 1.291 +} 1.292 +