gpuray_glsl

view src/rend.cc @ 5:000017955721

fixed the cone normal
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 11 Nov 2014 20:25:59 +0200
parents f234630e38ff
children
line source
1 #include <stdio.h>
2 #include <assert.h>
3 #include <algorithm>
4 #include "scene.h"
5 #include "image.h"
6 #include "rend.h"
7 #include "opengl.h"
8 #include "glsdr.h"
10 enum {
11 TEX_RAYDIR,
12 TEX_SPHERES,
13 TEX_PLANES,
14 TEX_BOXES,
15 TEX_CONES,
16 TEX_TEXTURES,
17 TEX_ENV,
18 TEX_XFORM,
20 NUM_SDR_TEXTURES
21 };
23 bool reload_shader();
24 void gen_ray_texture(unsigned int tex, int xsz, int ysz, float vfov);
25 static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg);
26 static int round_pow2(int x);
28 static GPUScene *scn;
30 static unsigned int sdr;
31 static unsigned int textures[NUM_SDR_TEXTURES];
33 bool init_renderer(GPUScene *s, int xsz, int ysz)
34 {
35 scn = s;
37 int max_tex_units;
38 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_tex_units);
39 printf("maximum texture units: %d\n", max_tex_units);
40 if(NUM_SDR_TEXTURES > max_tex_units) {
41 fprintf(stderr, "not enough texture units available!\n");
42 return false;
43 }
45 glGenTextures(1, textures + TEX_RAYDIR);
46 glBindTexture(GL_TEXTURE_2D, textures[TEX_RAYDIR]);
47 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
48 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
49 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
50 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
52 if(!(s->create_textures())) {
53 fprintf(stderr, "failed to create scene textures\n");
54 return false;
55 }
57 textures[TEX_SPHERES] = s->get_texture(GPUScene::TEX_SPHERE);
58 textures[TEX_PLANES] = s->get_texture(GPUScene::TEX_PLANE);
59 textures[TEX_BOXES] = s->get_texture(GPUScene::TEX_BOX);
60 textures[TEX_CONES] = s->get_texture(GPUScene::TEX_CONE);
61 textures[TEX_TEXTURES] = s->get_texture(GPUScene::TEX_TEXTURE);
62 textures[TEX_ENV] = s->get_texture(GPUScene::TEX_ENV);
63 textures[TEX_XFORM] = s->get_texture(GPUScene::TEX_XFORM);
65 if(!reload_shader()) {
66 return false;
67 }
69 resize_renderer(xsz, ysz);
71 return true;
72 }
74 bool reload_shader()
75 {
76 if(sdr) {
77 free_program(sdr);
78 }
80 printf("loading shader...\n");
82 if(!(sdr = create_program_load("sdr/vertex.glsl", "sdr/rt.glsl"))) {
83 return false;
84 }
85 set_uniform_int(sdr, "tex_raydir", TEX_RAYDIR);
86 set_uniform_int(sdr, "tex_spheres", TEX_SPHERES);
87 set_uniform_int(sdr, "tex_planes", TEX_PLANES);
88 set_uniform_int(sdr, "tex_boxes", TEX_BOXES);
89 set_uniform_int(sdr, "tex_cones", TEX_CONES);
90 set_uniform_int(sdr, "tex_megatex", TEX_TEXTURES);
91 set_uniform_int(sdr, "tex_env", TEX_ENV);
92 set_uniform_int(sdr, "tex_xforms", TEX_XFORM);
94 set_uniform_int(sdr, "num_lights", scn->get_light_count());
96 for(int i=0; i<scn->get_light_count(); i++) {
97 const Light *lt = scn->get_light(i);
99 char name[64];
100 sprintf(name, "lights[%d].pos", i);
101 set_uniform_float3(sdr, name, lt->pos.x, lt->pos.y, lt->pos.z);
103 sprintf(name, "lights[%d].color", i);
104 set_uniform_float3(sdr, name, lt->color.x, lt->color.y, lt->color.z);
105 }
107 Vector2 fog;
108 scn->get_fog(&fog.x, &fog.y);
109 if(fog.x < 0.0 && fog.y < 0.0) {
110 fog.x = 0.0;
111 fog.y = 100000.0;
112 }
113 set_uniform_float2(sdr, "fog", fog.x, fog.y);
114 return true;
115 }
117 void destroy_renderer()
118 {
119 free_program(sdr);
120 sdr = 0;
121 }
123 void resize_renderer(int xsz, int ysz)
124 {
125 gen_ray_texture(textures[TEX_RAYDIR], xsz, ysz, 45.0f);
126 }
128 float *render_frame(long msec)
129 {
130 scn->prepare_xform(msec);
131 scn->update_xform_texture();
133 Camera *cam = scn->get_camera();
134 glMatrixMode(GL_MODELVIEW);
135 glLoadIdentity();
136 Vector3 cpos = cam->get_position();
137 glTranslatef(cpos.x, cpos.y, cpos.z);
138 Matrix4x4 cmat = cam->get_matrix();
139 glMultTransposeMatrixf(cmat[0]);
141 for(int i=0; i<NUM_SDR_TEXTURES; i++) {
142 glActiveTexture(GL_TEXTURE0 + i);
143 if(i == TEX_ENV) {
144 glBindTexture(GL_TEXTURE_CUBE_MAP, textures[i]);
145 } else {
146 glBindTexture(GL_TEXTURE_2D, textures[i]);
147 }
148 }
149 glActiveTexture(GL_TEXTURE0);
151 glUseProgram(sdr);
153 glBegin(GL_QUADS);
154 glTexCoord2f(0, 1);
155 glVertex2f(-1, -1);
156 glTexCoord2f(1, 1);
157 glVertex2f(1, -1);
158 glTexCoord2f(1, 0);
159 glVertex2f(1, 1);
160 glTexCoord2f(0, 0);
161 glVertex2f(-1, 1);
162 glEnd();
164 glUseProgram(0);
166 assert(glGetError() == GL_NO_ERROR);
167 return 0;
168 }
170 void gen_ray_texture(unsigned int tex, int xsz, int ysz, float vfov)
171 {
172 int tex_xsz = round_pow2(xsz);
173 int tex_ysz = round_pow2(ysz);
174 float *teximg, *dir;
176 teximg = new float[3 * tex_xsz * tex_ysz];
177 dir = teximg;
179 for(int i=0; i<tex_ysz; i++) {
180 for(int j=0; j<tex_xsz; j++) {
181 if(j < xsz && i < ysz) {
182 Vector3 rdir = get_primary_ray_dir(j, i, xsz, ysz, vfov);
183 dir[0] = rdir.x;
184 dir[1] = rdir.y;
185 dir[2] = rdir.z;
186 } else {
187 dir[0] = dir[1] = 0.0f;
188 dir[2] = 1.0f;
189 }
191 dir += 3;
192 }
193 }
195 glBindTexture(GL_TEXTURE_2D, tex);
196 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, teximg);
197 delete [] teximg;
198 }
200 static Vector3 calc_sample_pos(int x, int y, int xsz, int ysz)
201 {
202 float ppos[2];
203 float aspect = (float)xsz / (float)ysz;
205 float pwidth = 2.0 * aspect / (float)xsz;
206 float pheight = 2.0 / (float)ysz;
208 ppos[0] = (float)x * pwidth - aspect;
209 ppos[1] = 1.0 - (float)y * pheight;
211 return Vector3(ppos[0], ppos[1], 0.0f);
212 }
215 static Vector3 get_primary_ray_dir(int x, int y, int w, int h, float vfov_deg)
216 {
217 float vfov = M_PI * vfov_deg / 180.0;
219 Vector3 dir = calc_sample_pos(x, y, w, h);
220 dir.z = 1.0 / tan(vfov / 2.0);
221 dir.normalize();
223 return dir;
224 }
226 static int round_pow2(int x)
227 {
228 x--;
229 x = (x >> 1) | x;
230 x = (x >> 2) | x;
231 x = (x >> 4) | x;
232 x = (x >> 8) | x;
233 x = (x >> 16) | x;
234 return x + 1;
235 }
238 #if 0
239 Color trace_ray(const Scene *scn, const Ray &ray, int rdepth)
240 {
241 HitPoint hit;
243 if(scn->intersect(ray, &hit)) {
244 float t;
245 if(scn->fog_start >= 0.0 && (t = (hit.dist - scn->fog_start) / (scn->fog_end - scn->fog_start)) > 0.0) {
246 return lerp(shade(scn, ray, hit, rdepth), scn->env_color(ray), t > 1.0 ? 1.0 : t);
247 }
248 return shade(scn, ray, hit, rdepth);
249 }
251 return scn->env_color(ray);
252 }
254 Color shade(const Scene *scn, const Ray &ray, const HitPoint &hit, int rdepth)
255 {
256 const Material *mat = &hit.obj->material;
258 // if we're leaving the object, we need to invert the normal (and ior)
259 Vector3 normal;
260 bool entering;
261 if(dot_product(hit.normal, ray.dir) <= 0.0) {
262 normal = hit.normal;
263 entering = true;
264 } else {
265 normal = -hit.normal;
266 entering = false;
267 }
269 Vector3 vdir = -ray.dir;
271 Color diffuse_color = mat->diffuse;
272 Color tex_color{1, 1, 1};
273 if(mat->tex) {
274 tex_color *= mat->tex->sample(hit);
275 diffuse_color *= tex_color;
276 }
278 Color color = mat->emission * tex_color;
280 // image-based lighting
281 if(scn->envmap_conv) {
282 // pick a random direction and create a sampling ray
283 Ray envray;
284 envray.origin = hit.pos;
285 rand_dir(&envray.dir.x, &envray.dir.y, &envray.dir.z, (unsigned int*)ray.user);
286 if(dot_product(envray.dir, normal) < 0.0) {
287 envray.dir = -envray.dir;
288 }
290 HitPoint env_hit;
291 if(!scn->intersect(envray, &env_hit)) {
292 Vector3 dir = envray.dir;
293 color += scn->envmap_conv->sample(dir.x, dir.y, dir.z) * diffuse_color;
294 }
295 }
297 for(Light *lt: scn->lights) {
299 /* construct a shadow ray to determine if there is an uninterrupted
300 * path between the intersection point and the light source
301 */
302 Ray shadow_ray = ray;
303 shadow_ray.origin = hit.pos;
304 shadow_ray.dir = lt->pos - hit.pos;
306 /* the interval [0, 1] represents the part of the ray from the origin
307 * to the light. We don't care about intersections behind the origin
308 * of the shadow ray (behind the surface of the object), or after the
309 * light source. We only care if there's something in between hiding the
310 * light.
311 */
312 HitPoint shadow_hit;
313 if(scn->intersect(shadow_ray, &shadow_hit) && shadow_hit.dist < 1.0f) {
314 continue; // skip this light, it's hidden from view
315 }
317 // calculate the light direction
318 Vector3 ldir = shadow_ray.dir.normalized();
319 // calculate the reflected light direction
320 Vector3 lref = ldir.reflection(normal);
322 float diffuse = std::max(dot_product(ldir, normal), 0.0f);
323 float specular = pow(std::max(dot_product(lref, vdir), 0.0f), mat->shininess);
325 color += (diffuse_color * diffuse + mat->specular * specular) * lt->color;
326 }
328 Color spec_col;
330 if(mat->reflectivity > 0.001f && rdepth < MAX_RAY_DEPTH) {
331 Ray refl_ray{ray};
332 refl_ray.origin = hit.pos;
333 refl_ray.dir = -ray.dir.reflection(normal);
335 spec_col += trace_ray(scn, refl_ray, rdepth + 1) * mat->reflectivity;
336 }
338 if(mat->transparency > 0.001f && rdepth < MAX_RAY_DEPTH) {
339 float from_ior = entering ? 1.0 : mat->ior;
340 float to_ior = entering ? mat->ior : 1.0;
342 Ray refr_ray{ray};
343 refr_ray.origin = hit.pos;
344 refr_ray.dir = ray.dir.refraction(normal, from_ior / to_ior);
346 Color tcol = trace_ray(scn, refr_ray, rdepth + 1) * mat->transparency;
348 float fres = fresnel(ray.dir, refr_ray.dir, normal, from_ior, to_ior);
349 spec_col = spec_col * fres + tcol * (1.0 - fres);
350 }
352 return color + spec_col;
353 }
356 static void rand_dir(float *x, float *y, float *z, unsigned int *seedp)
357 {
358 float u = (float)rand_r(seedp) / RAND_MAX;
359 float v = (float)rand_r(seedp) / RAND_MAX;
361 float theta = 2.0 * M_PI * u;
362 float phi = acos(2.0 * v - 1.0);
364 *x = cos(theta) * sin(phi);
365 *y = sin(theta) * sin(phi);
366 *z = cos(phi);
367 }
369 static float fresnel(const Vector3 &inc, const Vector3 &trans, const Vector3 &norm, float ior_inc, float ior_trans)
370 {
371 float cos_inc = dot_product(-inc, norm);
372 float cos_trans = dot_product(-trans, norm);
374 return fresnel(cos_inc, cos_trans, ior_inc, ior_trans);
375 }
377 static float fresnel(float cos_inc, float cos_trans, float ior_inc, float ior_trans)
378 {
379 float r0 = ((ior_trans * cos_inc) - (ior_inc * cos_trans)) /
380 ((ior_trans * cos_inc) + (ior_inc * cos_trans));
381 float r1 = ((ior_inc * cos_inc) - (ior_trans * cos_trans)) /
382 ((ior_inc * cos_inc) + (ior_trans * cos_trans));
383 return (r0 * r0 + r1 * r1) * 0.5f;
384 }
385 #endif