gpuray_glsl

view src/rend.cc @ 0:f234630e38ff

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