# HG changeset patch # User John Tsiombikas # Date 1455830143 -7200 # Node ID b469e6a72636ff005e5de81d4a1d17ec970552e8 initial commit diff -r 000000000000 -r b469e6a72636 Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,18 @@ +obj = refmod_test.o sdr.o +bin = refmod_test +distfile = refmod_test.tar.gz + +CC = gcc +CFLAGS = -pedantic -Wall -g +LDFLAGS = -lglut -lGL -lGLU + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) + +.PHONY: dist +dist: clean + cd ..; tar czvf $(distfile) refmod_test && mv $(distfile) refmod_test/$(distfile) diff -r 000000000000 -r b469e6a72636 refmod_test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/refmod_test.c Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,387 @@ +#include +#include +#include +#include +#include "sdr.h" + +#ifdef FREEGLUT +#include +#define MOUSEWHEEL +#endif + +void redraw(void); +void set_material_color(float r, float g, float b, float a); +void setup_lights(void); +void key_handler(unsigned char key, int x, int y); +void key_up_handler(unsigned char key, int x, int y); +void skey_handler(int key, int x, int y); +void button_handler(int bn, int state, int x, int y); +void mouse_handler(int x, int y); +void reshape(int x, int y); +#ifdef MOUSEWHEEL +void wheel_handler(int unk, int dir, int x, int y); +#endif +void menu_handler(int val); +void init_sdr(void); + +int xres, yres; + +float cam_x, cam_y = 0.6, cam_z = 4; +float cam_rot, cam_pitch = 35.0; + +float pan_offs = 0.025; + +unsigned int prog; + +float roughness = 0.24; +float specularity = 0.86; +float ior = 3.2; +float spec_pow = 60.0; + +enum {DSDR_LAMBERT, DSDR_OREN_NAYAR}; +enum {SSDR_PHONG, SSDR_BLINN, SSDR_COOK_TORR}; + +int dif_sdr = DSDR_OREN_NAYAR; +int spec_sdr = SSDR_COOK_TORR; + +int main(int argc, char **argv) +{ + unsigned int vs, ps, pslib; + int dif_menu, spec_menu, i; + + for(i=1; i (b) ? (a) : (b)) + +void mouse_handler(int x, int y) +{ + if(pbn == GLUT_LEFT_BUTTON) { + if(mod_rough || mod_spec || mod_ior || mod_spow) { + float dx = (float)(x - prev_x) / (float)xres; + + if(mod_rough) { + roughness = MAX(0.0, MIN(roughness + dx, 1.0)); + printf("roughness: %.3f\n", roughness); + } + if(mod_spec) { + specularity = MAX(0.0, MIN(specularity + dx, 1.0)); + printf("specularity: %.3f\n", specularity); + } + if(mod_ior) { + ior = MAX(ior + dx, 0.0); + printf("ior: %.3f\n", ior); + } + if(mod_spow) { + spec_pow = MAX(spec_pow + dx * 50.0, 0.01); + printf("specular power: %.3f\n", spec_pow); + } + } else { + /* + cam_x += (float)(prev_x - x) * pan_offs; + cam_y += (float)(y - prev_y) * pan_offs; + */ + } + + prev_x = x; + prev_y = y; + glutPostRedisplay(); + + } else if(pbn == GLUT_MIDDLE_BUTTON) { + cam_rot += (float)(x - prev_x) / 2.0f; + cam_pitch += (float)(y - prev_y) / 2.0f; + if(cam_pitch > 90.0) cam_pitch = 90.0; + if(cam_pitch < -90.0) cam_pitch = -90.0; + + prev_x = x; + prev_y = y; + glutPostRedisplay(); + + } else if(pbn == GLUT_RIGHT_BUTTON) { + /* + cam_z -= (float)(prev_y - y) / 2.0f; + prev_y = y; + glutPostRedisplay(); + */ + } +} + +void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + xres = x; + yres = y; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0, (float)xres / (float)yres, 1.0, 100.0); + glMatrixMode(GL_MODELVIEW); +} + +#ifdef MOUSEWHEEL +void wheel_handler(int unk, int dir, int x, int y) +{ + if(dir > 0) { + cam_z -= pan_offs * 5.0; + } else { + cam_z += pan_offs * 5.0; + } + glutPostRedisplay(); +} +#endif + +void menu_handler(int val) +{ + if(val < 10) { + dif_sdr = val; + } else { + spec_sdr = val - 10; + } + glutPostRedisplay(); +} diff -r 000000000000 -r b469e6a72636 sdr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr.c Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,417 @@ +#include +#include +#include +#include +#include + +#if defined(unix) || defined(__unix__) +#include +#include +#include +#endif /* unix */ + +#if defined(WIN32) || defined(__WIN32__) +#include + +#define glXGetProcAddress wglGetProcAddress +#endif /* windows */ + +#define GL_GLEXT_LEGACY +#include + +#include "sdr.h" + +#ifndef GL_VERSION_2_0 + +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_LINK_STATUS 0x8B82 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_CURRENT_PROGRAM 0x8B8D + +typedef char GLchar; + +GLuint (*glCreateProgram)(void); +GLuint (*glCreateShader)(GLenum); +void (*glDeleteProgram)(GLuint); +void (*glDeleteShader)(GLuint); +void (*glCompileShader)(GLuint); +void (*glAttachShader)(GLuint, GLuint); +void (*glGetShaderiv)(GLuint, GLenum, GLint *); +void (*glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); +void (*glGetProgramiv)(GLuint, GLenum, GLint *); +void (*glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); +void (*glLinkProgram)(GLuint); +void (*glShaderSource)(GLuint, GLsizei, const GLchar* *, const GLint *); +void (*glUseProgram)(GLuint); +GLint (*glGetUniformLocation)(GLuint, const GLchar *); +void (*glUniform1f)(GLint, GLfloat); +void (*glUniform2f)(GLint, GLfloat, GLfloat); +void (*glUniform3f)(GLint, GLfloat, GLfloat, GLfloat); +void (*glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); +void (*glUniform1i)(GLint, GLint); +void (*glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *); +GLint (*glGetAttribLocation)(GLuint, const GLchar *); +void (*glVertexAttrib3f)(GLint, GLfloat, GLfloat, GLfloat); + +void init_sdr(void) +{ + glCreateProgram = glXGetProcAddress("glCreateProgramObjectARB"); + glCreateShader = glXGetProcAddress("glCreateShaderObjectARB"); + glDeleteProgram = glXGetProcAddress("glDeleteObjectARB"); + glDeleteShader = glXGetProcAddress("glDeleteObjectARB"); + glCompileShader = glXGetProcAddress("glCompileShaderARB"); + glAttachShader = glXGetProcAddress("glAttachObjectARB"); + glGetShaderiv = glXGetProcAddress("glGetObjectParameterivARB"); + glGetShaderInfoLog = glXGetProcAddress("glGetInfoLogARB"); + glGetProgramiv = glXGetProcAddress("glGetObjectParameterivARB"); + glGetProgramInfoLog = glXGetProcAddress("glGetInfoLogARB"); + glLinkProgram = glXGetProcAddress("glLinkProgramARB"); + glShaderSource = glXGetProcAddress("glShaderSourceARB"); + glUseProgram = glXGetProcAddress("glUseProgramObjectARB"); + glGetUniformLocation = glXGetProcAddress("glGetUniformLocationARB"); + glUniform1f = glXGetProcAddress("glUniform1fARB"); + glUniform2f = glXGetProcAddress("glUniform2fARB"); + glUniform3f = glXGetProcAddress("glUniform3fARB"); + glUniform4f = glXGetProcAddress("glUniform4fARB"); + glUniform1i = glXGetProcAddress("glUniform1iARB"); + glUniformMatrix4fv = glXGetProcAddress("glUniformMatrix4fvARB"); + glGetAttribLocation = glXGetProcAddress("glGetAttribLocationARB"); + glVertexAttrib3f = glXGetProcAddress("glVertexAttrib3fARB"); +} +#else +void init_sdr(void) {} +#endif + +unsigned int create_vertex_shader(const char *src) +{ + return create_shader(src, GL_VERTEX_SHADER); +} + +unsigned int create_pixel_shader(const char *src) +{ + return create_shader(src, GL_FRAGMENT_SHADER); +} + +unsigned int create_shader(const char *src, unsigned int sdr_type) +{ + unsigned int sdr; + int success, info_len; + char *info_str = 0; + GLenum err; + + sdr = glCreateShader(sdr_type); + assert(glGetError() == GL_NO_ERROR); + glShaderSource(sdr, 1, &src, 0); + err = glGetError(); + assert(err == GL_NO_ERROR); + glCompileShader(sdr); + assert(glGetError() == GL_NO_ERROR); + + glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); + assert(glGetError() == GL_NO_ERROR); + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); + assert(glGetError() == GL_NO_ERROR); + + if(info_len) { + if((info_str = malloc(info_len + 1))) { + glGetShaderInfoLog(sdr, info_len, 0, info_str); + assert(glGetError() == GL_NO_ERROR); + } + } + + if(success) { + fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); + } else { + fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); + glDeleteShader(sdr); + sdr = 0; + } + + free(info_str); + return sdr; +} + +void free_shader(unsigned int sdr) +{ + glDeleteShader(sdr); +} + +unsigned int load_vertex_shader(const char *fname) +{ + return load_shader(fname, GL_VERTEX_SHADER); +} + +unsigned int load_pixel_shader(const char *fname) +{ + return load_shader(fname, GL_FRAGMENT_SHADER); +} + +unsigned int load_shader(const char *fname, unsigned int sdr_type) +{ +#if defined(unix) || defined(__unix__) + struct stat st; +#endif + unsigned int sdr; + size_t filesize; + FILE *fp; + char *src; + + if(!(fp = fopen(fname, "r"))) { + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); + return 0; + } + +#if defined(unix) || defined(__unix__) + fstat(fileno(fp), &st); + filesize = st.st_size; +#else + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); +#endif /* unix */ + + if(!(src = malloc(filesize + 1))) { + fclose(fp); + return 0; + } + fread(src, 1, filesize, fp); + src[filesize] = 0; + fclose(fp); + + fprintf(stderr, "compiling %s shader: %s... ", (sdr_type == GL_VERTEX_SHADER ? "vertex" : "pixel"), fname); + sdr = create_shader(src, sdr_type); + + free(src); + return sdr; +} + + +unsigned int get_vertex_shader(const char *fname) +{ + return get_shader(fname, GL_VERTEX_SHADER); +} + +unsigned int get_pixel_shader(const char *fname) +{ + return get_shader(fname, GL_FRAGMENT_SHADER); +} + +unsigned int get_shader(const char *fname, unsigned int sdr_type) +{ + unsigned int sdr; +#if 0 + if((res = get_resource(sdrman, fname))) { + /* TODO: validate that the shader matches sdr_type? */ + return (uintptr_t)res; + } +#endif + + if(!(sdr = load_shader(fname, sdr_type))) { + return 0; + } + add_shader(fname, sdr); + return sdr; +} + +int add_shader(const char *fname, unsigned int sdr) +{ + return 0;/*add_resource(sdrman, fname, (void*)(uintptr_t)sdr);*/ +} + +int remove_shader(const char *fname) +{ + return 0;/*remove_resource(sdrman, fname);*/ +} + + +/* ---- gpu programs ---- */ + +unsigned int create_program(void) +{ + unsigned int prog = glCreateProgram(); + assert(glGetError() == GL_NO_ERROR); + return prog; +} + +unsigned int create_program_link(unsigned int vs, unsigned int ps) +{ + unsigned int prog; + + if(!(prog = create_program())) { + return 0; + } + + attach_shader(prog, vs); + assert(glGetError() == GL_NO_ERROR); + attach_shader(prog, ps); + assert(glGetError() == GL_NO_ERROR); + + if(link_program(prog) == -1) { + free_program(prog); + return 0; + } + return prog; +} + +unsigned int create_program_load(const char *vfile, const char *pfile) +{ + unsigned int vs, ps; + + if(!(vs = get_vertex_shader(vfile)) || !(ps = get_pixel_shader(pfile))) { + return 0; + } + return create_program_link(vs, ps); +} + +void free_program(unsigned int sdr) +{ + glDeleteProgram(sdr); +} + +void attach_shader(unsigned int prog, unsigned int sdr) +{ + glAttachShader(prog, sdr); + assert(glGetError() == GL_NO_ERROR); +} + +int link_program(unsigned int prog) +{ + int linked, info_len, retval = 0; + char *info_str = 0; + + glLinkProgram(prog); + assert(glGetError() == GL_NO_ERROR); + glGetProgramiv(prog, GL_LINK_STATUS, &linked); + assert(glGetError() == GL_NO_ERROR); + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); + assert(glGetError() == GL_NO_ERROR); + + if(info_len) { + if((info_str = malloc(info_len + 1))) { + glGetProgramInfoLog(prog, info_len, 0, info_str); + assert(glGetError() == GL_NO_ERROR); + } + } + + if(linked) { + fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); + } else { + fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); + retval = -1; + } + + free(info_str); + return retval; +} + +int bind_program(unsigned int prog) +{ + GLenum err; + + glUseProgram(prog); + if(prog && (err = glGetError()) != GL_NO_ERROR) { + /* maybe the program is not linked, try to link first */ + if(err == GL_INVALID_OPERATION) { + if(link_program(prog) == -1) { + return -1; + } + glUseProgram(prog); + return glGetError() == GL_NO_ERROR ? 0 : -1; + } + return -1; + } + return 0; +} + +/* ugly but I'm not going to write the same bloody code over and over */ +#define BEGIN_UNIFORM_CODE \ + int loc, curr_prog; \ + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ + if(curr_prog != prog && bind_program(prog) == -1) { \ + return -1; \ + } \ + if((loc = glGetUniformLocation(prog, name)) != -1) + +#define END_UNIFORM_CODE \ + if(curr_prog != prog) { \ + bind_program(curr_prog); \ + } \ + return loc == -1 ? -1 : 0 + +int set_uniform_int(unsigned int prog, const char *name, int val) +{ + BEGIN_UNIFORM_CODE { + glUniform1i(loc, val); + } + END_UNIFORM_CODE; +} + +int set_uniform_float(unsigned int prog, const char *name, float val) +{ + BEGIN_UNIFORM_CODE { + glUniform1f(loc, val); + } + END_UNIFORM_CODE; +} + +int set_uniform_vec2(unsigned int prog, const char *name, vec2_t val) +{ + BEGIN_UNIFORM_CODE { + glUniform2f(loc, val.x, val.y); + } + END_UNIFORM_CODE; +} + +int set_uniform_vec3(unsigned int prog, const char *name, vec3_t val) +{ + BEGIN_UNIFORM_CODE { + glUniform3f(loc, val.x, val.y, val.z); + } + END_UNIFORM_CODE; +} + +int set_uniform_vec4(unsigned int prog, const char *name, vec4_t val) +{ + BEGIN_UNIFORM_CODE { + glUniform4f(loc, val.x, val.y, val.z, val.w); + } + END_UNIFORM_CODE; +} + +int set_uniform_mat4(unsigned int prog, const char *name, mat4_t val) +{ + BEGIN_UNIFORM_CODE { + glUniformMatrix4fv(loc, 1, 1, (float*)val); + } + END_UNIFORM_CODE; +} + + +int get_attrib_loc(unsigned int prog, const char *name) +{ + int loc, curr_prog; + + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); + if(curr_prog != prog && bind_program(prog) == -1) { + return -1; + } + + loc = glGetAttribLocation(prog, (char*)name); + + if(curr_prog != prog) { + bind_program(curr_prog); + } + return loc; +} + +void set_attrib_vec3(int attr_loc, vec3_t val) +{ + glVertexAttrib3f(attr_loc, val.x, val.y, val.z); +} + +void set_attrib_float3(int attr_loc, float x, float y, float z) +{ + glVertexAttrib3f(attr_loc, x, y, z); +} diff -r 000000000000 -r b469e6a72636 sdr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr.h Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,55 @@ +#ifndef _SDR_H_ +#define _SDR_H_ + +typedef struct vec2 {float x, y;} vec2_t; +typedef struct vec3 {float x, y, z;} vec3_t; +typedef struct vec4 {float x, y, z, w;} vec4_t; +typedef float mat4_t[4][4]; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* ---- shaders ---- */ +unsigned int create_vertex_shader(const char *src); +unsigned int create_pixel_shader(const char *src); +unsigned int create_shader(const char *src, unsigned int sdr_type); +void free_shader(unsigned int sdr); + +unsigned int load_vertex_shader(const char *fname); +unsigned int load_pixel_shader(const char *fname); +unsigned int load_shader(const char *src, unsigned int sdr_type); + +unsigned int get_vertex_shader(const char *fname); +unsigned int get_pixel_shader(const char *fname); +unsigned int get_shader(const char *fname, unsigned int sdr_type); + +int add_shader(const char *fname, unsigned int sdr); +int remove_shader(const char *fname); + +/* ---- gpu programs ---- */ +unsigned int create_program(void); +unsigned int create_program_link(unsigned int vs, unsigned int ps); +unsigned int create_program_load(const char *vfile, const char *pfile); +void free_program(unsigned int sdr); + +void attach_shader(unsigned int prog, unsigned int sdr); +int link_program(unsigned int prog); +int bind_program(unsigned int prog); + +int set_uniform_int(unsigned int prog, const char *name, int val); +int set_uniform_float(unsigned int prog, const char *name, float val); +int set_uniform_vec2(unsigned int prog, const char *name, vec2_t val); +int set_uniform_vec3(unsigned int prog, const char *name, vec3_t val); +int set_uniform_vec4(unsigned int prog, const char *name, vec4_t val); +int set_uniform_mat4(unsigned int prog, const char *name, mat4_t val); + +int get_attrib_loc(unsigned int prog, const char *name); +void set_attrib_vec3(int attr_loc, vec3_t val); +void set_attrib_float3(int attr_loc, float x, float y, float z); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _SDR_H_ */ diff -r 000000000000 -r b469e6a72636 sdr.ps.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr.ps.glsl Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,58 @@ +#version 110 + +varying vec3 pos, normal; + +uniform float rough, specularity, ior; +uniform float dif_sdr, spec_sdr; + +#define DSDR_LAMBERT 0.0 +#define DSDR_OREN_NAYAR 1.0 + +#define SSDR_PHONG 0.0 +#define SSDR_BLINN 1.0 +#define SSDR_COOK_TORR 2.0 + +#define EQ(a, b) (abs((a) - (b)) < 0.5) + +float lambert(vec3 norm, vec3 ldir); +float oren_nayar(vec3 view, vec3 norm, vec3 ldir, float rough); + +float phong(vec3 view, vec3 norm, vec3 ldir, float spow); +float blinn(vec3 norm, vec3 hvec, float spow); +float cook_torrance(vec3 view, vec3 norm, vec3 ldir, vec3 hvec, float rough, float ior); + +void main() +{ + vec4 color = vec4(1.0, 1.0, 1.0, 1.0); + float idiff, ispec; + + vec3 view = -normalize(pos); + vec3 norm = normalize(normal); + vec3 ldir = normalize(gl_LightSource[0].position.xyz - pos); + + if(EQ(dif_sdr, DSDR_LAMBERT)) { + idiff = lambert(norm, ldir); + } else if(EQ(dif_sdr, DSDR_OREN_NAYAR)) { + idiff = oren_nayar(view, norm, ldir, rough); + } else { + idiff = 0.0; + } + + vec4 mcolor = gl_FrontMaterial.diffuse; + + if(EQ(spec_sdr, SSDR_PHONG)) { + ispec = phong(view, norm, ldir, gl_FrontMaterial.shininess); + color = mcolor * idiff + vec4(specularity, specularity, specularity, 1.0) * ispec; + } else if(EQ(spec_sdr, SSDR_BLINN)) { + ispec = blinn(norm, gl_LightSource[0].halfVector.xyz, gl_FrontMaterial.shininess); + color = mcolor * idiff + vec4(specularity, specularity, specularity, 1.0) * ispec; + } else if(EQ(spec_sdr, SSDR_COOK_TORR)) { + ispec = cook_torrance(view, norm, ldir, gl_LightSource[0].halfVector.xyz, rough, ior); + color = specularity * ispec * mcolor + (1.0 - specularity) * idiff * mcolor; + } else { + color = vec4(1.0, 0.0, 0.0, 1.0); + } + color.a = 1.0; + + gl_FragColor = color; +} diff -r 000000000000 -r b469e6a72636 sdr.vs.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr.vs.glsl Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,9 @@ +varying vec3 pos, normal; + +void main() +{ + gl_Position = ftransform(); + + pos = (gl_ModelViewMatrix * gl_Vertex).xyz; + normal = (gl_NormalMatrix * gl_Normal).xyz; +} diff -r 000000000000 -r b469e6a72636 sdr_ref_models.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr_ref_models.glsl Thu Feb 18 23:15:43 2016 +0200 @@ -0,0 +1,102 @@ +#version 110 + +#define SQ(x) ((x) * (x)) +#define PI 3.141592653 + +/* -- Lambert's cosine law + * J. H. Lambert, Photometria sive de mensura de gratibus luminis, colorum et umbrae. + * Eberhard Klett, 1760. + */ +float lambert(vec3 norm, vec3 ldir) +{ + return max(dot(norm, ldir), 0.0); +} + +/* -- Phong specular model + * B. T. Phong, "Illumination for Computer Generated Pictures" + * Communications of the ACM, 1975. + */ +float phong(vec3 view, vec3 norm, vec3 ldir, float spow) +{ + vec3 lref = reflect(-ldir, norm); + return pow(max(dot(lref, view), 0.0), spow); +} + +/* -- Blinn-Phong specular model + * J. F. Blinn, "Models of Light Reflection for Computer Synthesized Pictures" + * in Proceedings of SIGGRAPH 1977 + */ +float blinn(vec3 norm, vec3 hvec, float spow) +{ + return pow(max(dot(norm, hvec), 0.0), spow); +} + +/* -- Cook & Torrance model. + * R. L. Cook and K. E. Torrance, "A Reflectance Model for Computer Graphics" + * in Proceedings of SIGGRAPH 1981. + */ +float cook_torrance(vec3 view, vec3 norm, vec3 ldir, vec3 hvec, float rough, float ior) +{ + float m = max(rough, 0.0001); + + // various useful dot products + float ndoth = max(dot(norm, hvec), 0.0); + float ndotv = max(dot(norm, view), 0.0); + float ndotl = dot(norm, ldir); + float vdoth = max(dot(view, hvec), 0.0); + float ndoth_sq = SQ(ndoth); + + // geometric term (shadowing/masking) + float geom_a = (2.0 * ndoth * ndotv) / vdoth; + float geom_b = (2.0 * ndoth * ndotl) / vdoth; + float geom = min(1.0, min(geom_a, geom_b)); + + // beckmann microfacet distribution term + float sin2_ang = 1.0 - ndoth_sq; // sin^2(a) = 1 - cos^2(a) + float tan2_ang = sin2_ang / ndoth_sq; // tan^2(a) = sin^2(a) / cos^2(a) + float d_mf = exp(-tan2_ang / SQ(m)) / (SQ(m) * SQ(ndoth_sq)); + + // fresnel term + float c = vdoth; + float g = sqrt(SQ(ior) + SQ(c) - 1.0); + float ftmp = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); + float fres = 0.5 * (SQ(g - c) / SQ(g + c)) * (1.0 + SQ(ftmp)); + + return (fres / PI) * (d_mf / ndotl) * (geom / ndotv); +} + +/* -- Oren & Nayar model + * M. Oren and S. K. Nayar, "Generalization of Lambert's Reflectance Model" + * in Proceedings of SIGGRAPH 1994. + */ +float oren_nayar(vec3 view, vec3 norm, vec3 ldir, float rough) +{ + float vdotn = max(dot(view, norm), 0.0); + float ldotn = max(dot(ldir, norm), 0.0); + + float theta_r = acos(vdotn); + float theta_i = acos(ldotn); + float cos_pr_minus_pi = dot(normalize(view - norm * vdotn), normalize(ldir - norm * ldotn)); + float alpha = max(theta_r, theta_i); + float beta = min(theta_r, theta_i); + + float sigma_sq = SQ(rough); + float a = 1.0 - 0.5 * sigma_sq / (sigma_sq + 0.33); + float b = 0.45 * sigma_sq / (sigma_sq + 0.09); + + if(cos_pr_minus_pi >= 0.0) { + b *= cos_pr_minus_pi * sin(alpha) * tan(beta); + } else { + b = 0.0; + } + + return ldotn * (a + b); +} + +/* TODO: need tangent/bitangent +float ward(vec3 view, vec3 norm, vec3 ldir, vec3 hvec, vec3 tang, vec3 bitan, float ax, float ay) +{ + float vdotn = dot(view, norm); + float ldotn = dot(light, norm); +} +*/