init: create git repo
This commit is contained in:
143
src/buffer.cpp
Normal file
143
src/buffer.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#include "../include/buffer.hpp"
|
||||
#include <string>
|
||||
|
||||
void bg_fg(v3* cols, v3& bg, v3& fg, const char*& c)
|
||||
{
|
||||
// 0 0 0 0
|
||||
// | | | |
|
||||
// | | | \_ top left
|
||||
// | | \_ top right
|
||||
// | \_ bottom left
|
||||
// \_ bottom right
|
||||
|
||||
static const char8_t* chars[16] = {
|
||||
u8"░", // 0000
|
||||
u8"▝", // 0001
|
||||
u8"▘", // 0010
|
||||
u8"▀", // 0011
|
||||
u8"▖", // 0100
|
||||
u8"▌", // 0101
|
||||
u8"▞", // 0110
|
||||
u8"▛", // 0111
|
||||
u8"▗", // 1000
|
||||
u8"▚", // 1001
|
||||
u8"▐", // 1010
|
||||
u8"▜", // 1011
|
||||
u8"▄", // 1100
|
||||
u8"▙", // 1101
|
||||
u8"▟", // 1110
|
||||
u8"▓", // 1111
|
||||
};
|
||||
|
||||
v3 ava = cols[0];
|
||||
v3 avb = cols[1];
|
||||
{
|
||||
choice_t max = -1.0;
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
choice_t len = (cols[i] - cols[0]).lensquared();
|
||||
if (len > max) {
|
||||
max = len;
|
||||
avb = cols[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
int m = 0b0000;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
v3 nava {};
|
||||
v3 navb {};
|
||||
int na = 0;
|
||||
int nb = 0;
|
||||
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
float lena = (ava - cols[j]).len();
|
||||
float lenb = (avb - cols[j]).len();
|
||||
|
||||
if (lena > lenb) {
|
||||
m |= 1 << j;
|
||||
nava += cols[j];
|
||||
++na;
|
||||
} else {
|
||||
m &= ~(1 << j);
|
||||
navb += cols[j];
|
||||
++nb;
|
||||
}
|
||||
}
|
||||
|
||||
ava = nava / na;
|
||||
avb = navb / nb;
|
||||
}
|
||||
|
||||
bg = ava;
|
||||
fg = avb;
|
||||
c = (const char*) chars[m];
|
||||
// c = (const char*) chars[15];
|
||||
}
|
||||
|
||||
void display_frame(const Screen& screen, const Frame& frame)
|
||||
{
|
||||
char chr[64];
|
||||
for (int y = 0; y < screen.H; y += 2) {
|
||||
std::string text;
|
||||
for (int x = 0; x < screen.W; x += 2) {
|
||||
v3 cols[4] = {
|
||||
frame.data[(y + 0) * screen.W + (x + 0)],
|
||||
frame.data[(y + 0) * screen.W + (x + 1)],
|
||||
frame.data[(y + 1) * screen.W + (x + 0)],
|
||||
frame.data[(y + 1) * screen.W + (x + 1)]
|
||||
};
|
||||
|
||||
const char* c;
|
||||
v3 bg;
|
||||
v3 fg;
|
||||
|
||||
bg_fg(cols, bg, fg, c);
|
||||
|
||||
snprintf(chr, 64, "\033[38;2;%d;%d;%dm\033[48;2;%d;%d;%dm%s",
|
||||
colcvt(bg.x), colcvt(bg.y), colcvt(bg.z),
|
||||
colcvt(fg.x), colcvt(fg.y), colcvt(fg.z),
|
||||
c
|
||||
);
|
||||
text += chr;
|
||||
}
|
||||
printf("%.*s\033[0m\n", (int)text.size(), text.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void render_frame(const Screen& screen, Camera& camera, Frame& frame,
|
||||
const std::vector<Renderable*>& scene,
|
||||
const std::vector<Renderable*>& objects,
|
||||
const std::vector<Renderable*>& lights)
|
||||
{
|
||||
Matrix m1; m1.init_rotate({camera.rotation.x,0,0});
|
||||
Matrix m2; m2.init_rotate({0,camera.rotation.y,0});
|
||||
|
||||
// The translation vector tells us where to translate the camera,
|
||||
// in 'camera tangent space'. So, we rotate the translation vector,
|
||||
// add it to camera's position, and then reset it to 0.
|
||||
camera.pos += m2.transform(m1.transform(camera.translation));
|
||||
camera.translation = {};
|
||||
|
||||
#pragma omp parallel for
|
||||
for(int y = 0; y < screen.H; y++) {
|
||||
for (int x = 0; x < screen.W; x++) {
|
||||
v3 camray = {
|
||||
(choice_t)x / (choice_t)(screen.W) - 0.5f,
|
||||
(choice_t)y / (choice_t)(screen.H) - 0.5f,
|
||||
camera.zoom
|
||||
};
|
||||
camray.x *= screen.ASPECT_RATIO; // aspect ratio correction
|
||||
camray = m2.transform(m1.transform(camray.norm()));
|
||||
|
||||
v3 pix = ray_trace(camera.pos, camray, scene, objects, lights, 3);
|
||||
pix = pix.htan(camera.exposure);
|
||||
|
||||
if (pix.x == 0.0) {
|
||||
frame.data[y * screen.W + x] = v3 {0.0, 0.0, 0.0};
|
||||
} else {
|
||||
frame.data[y * screen.W + x] = pix;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
176
src/main.cpp
Normal file
176
src/main.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdio.h>
|
||||
#include "../include/objects.hpp"
|
||||
#include "../include/buffer.hpp"
|
||||
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
|
||||
static std::vector<Renderable*> lights {
|
||||
new Light(v3{0, 0, 19}, 2, v3{1, 1, 1}),
|
||||
new Light(v3{-7, 15, 0}, 2, v3{1, 1, 1}),
|
||||
new Light(v3{17, -9, 16}, 2, v3{1, 1, 1}),
|
||||
|
||||
// new Light(v3{0, 0, 19}, 2, v3{0.8, 0.8, 0.9}),
|
||||
// new Light(v3{-7, 15, 0}, 2, v3{0.5, 0.8, 0.9}),
|
||||
// new Light(v3{17, -9, 16}, 2, v3{0.1, 0.8, 0.4}),
|
||||
};
|
||||
|
||||
static const Material PLANE_MAT = {
|
||||
.specular = 0.12,
|
||||
.roughness = 0.55,
|
||||
.ior = 2,
|
||||
.transparency = 0,
|
||||
.colour = {1, 1, 1},
|
||||
};
|
||||
|
||||
static const Material SPHERE_MAT_TRANS = {
|
||||
.specular = 0.85,
|
||||
.roughness = 0.5,
|
||||
.ior = 1.2,
|
||||
.transparency = 0.95,
|
||||
.colour = {0, 1, 0},
|
||||
};
|
||||
|
||||
static const Material SPHERE_MAT_METAL = {
|
||||
.specular = 0.87,
|
||||
.roughness = 0.53,
|
||||
.ior = 2.3,
|
||||
.transparency = 0.0,
|
||||
.colour = {0, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
static std::vector<Renderable*> objects
|
||||
{
|
||||
new Sphere(v3{10, 0, 6}, 3.0, SPHERE_MAT_TRANS, 1),
|
||||
new Sphere(v3{2, -2, 6}, 3.0, SPHERE_MAT_METAL, 1),
|
||||
|
||||
new Plane{v3{1, 0, 0}, -30, PLANE_MAT},
|
||||
new Plane{v3{-1, 0, 0}, -30, PLANE_MAT},
|
||||
new Plane{v3{0, 1, 0}, -30, PLANE_MAT},
|
||||
new Plane{v3{0, -1, 0}, -30, PLANE_MAT},
|
||||
new Plane{v3{0, 0, 1}, -30, PLANE_MAT},
|
||||
new Plane{v3{0, 0, -1}, -30, PLANE_MAT},
|
||||
};
|
||||
|
||||
static std::vector<Renderable*> scene;
|
||||
|
||||
// static constexpr int W = 294*2, H = 82*2;
|
||||
// static constexpr int W = 2 * 640 * 2.9 * 1.8, H = 2 * 480 * 1.5 * 2.5;
|
||||
static constexpr int W = 2*80, H = 2*24;
|
||||
static constexpr choice_t ASPECT_RATIO = W/(H * 1.9);
|
||||
|
||||
static constexpr Screen screen = {W, H, ASPECT_RATIO};
|
||||
static Camera camera = { {15.31, -3.3, 7.72}, {0.56, 1.84, 0}, {} };
|
||||
|
||||
static inline void gotoxy(int x, int y)
|
||||
{ printf("%c[%d;%dH",0x1B, (y+1), (x+1)); }
|
||||
|
||||
char getch()
|
||||
{
|
||||
char c;
|
||||
// lseek(0, 0, SEEK_END);
|
||||
read(0, &c, 1);
|
||||
// tcflush(0, TCIFLUSH);
|
||||
return c;
|
||||
}
|
||||
|
||||
inline void clrscr() { printf("\x1B[2J\x1B[H"); }
|
||||
|
||||
int main()
|
||||
{
|
||||
termios old, current;
|
||||
tcgetattr(0, &old);
|
||||
current = old;
|
||||
current.c_lflag &= ~ICANON & ~ECHO; /* disable buffered i/o, no echo */
|
||||
current.c_cc[VMIN] = 1; // control chars (MIN value) = 1
|
||||
current.c_cc[VTIME] = 0; // control chars (TIME value) = 0 (No time)
|
||||
tcsetattr(0, TCSANOW, ¤t);
|
||||
|
||||
std::copy(objects.begin(), objects.end(), std::back_inserter(scene));
|
||||
std::copy(lights.begin(), lights.end(), std::back_inserter(scene));
|
||||
|
||||
Frame frame;
|
||||
frame.data = new v3[W * H];
|
||||
|
||||
printf("\e[?1049h");
|
||||
|
||||
// choice_t times = 0;
|
||||
// int samples = 0;
|
||||
|
||||
char c='\n';
|
||||
do {
|
||||
// clrscr();
|
||||
gotoxy(0,0);
|
||||
|
||||
switch(c) {
|
||||
case 65: // Up
|
||||
camera.rotation.x -= 0.08 * (0.5 / camera.zoom);
|
||||
break;
|
||||
case 66: // Down
|
||||
camera.rotation.x += 0.08 * (0.5 / camera.zoom);
|
||||
break;
|
||||
case 67: // Right
|
||||
camera.rotation.y -= 0.08 * (0.5 / camera.zoom);
|
||||
break;
|
||||
case 68: // Left
|
||||
camera.rotation.y += 0.08 * (0.5 / camera.zoom);
|
||||
break;
|
||||
case 'a':
|
||||
camera.translation.x -= 0.5;
|
||||
break;
|
||||
case 'd':
|
||||
camera.translation.x += 0.5;;
|
||||
break;
|
||||
case 'w':
|
||||
camera.translation.z += 0.5;;
|
||||
break;
|
||||
case 's':
|
||||
camera.translation.z -= 0.5;;
|
||||
break;
|
||||
case ' ':
|
||||
camera.translation.y -= 0.5;
|
||||
break;
|
||||
case 'z':
|
||||
camera.translation.y += 0.5;
|
||||
break;
|
||||
case '+':
|
||||
camera.exposure -= 0.015;
|
||||
break;
|
||||
case '-':
|
||||
camera.exposure += 0.015;
|
||||
break;
|
||||
case 'i':
|
||||
camera.zoom *= 1.015;
|
||||
break;
|
||||
case 'o':
|
||||
camera.zoom /= 1.015;
|
||||
break;
|
||||
case 'p':
|
||||
printf("pos: " V3_FMT "\nrot: " V3_FMT, V3_ARG(camera.pos), V3_ARG(camera.rotation));
|
||||
break;
|
||||
case '\n':
|
||||
case 'q':
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// const auto before = std::chrono::high_resolution_clock::now();
|
||||
render_frame(screen, camera, frame, scene, objects, lights);
|
||||
// const auto after = std::chrono::high_resolution_clock::now();
|
||||
// times += std::chrono::duration<choice_t, std::milli>(after - before).count();
|
||||
// samples++;
|
||||
display_frame(screen, frame);
|
||||
//std::cout << 1000/(times/samples) << " FPS" << std::endl;
|
||||
} while((c = getch()) != 'q');
|
||||
|
||||
printf("\e[?1049l");
|
||||
tcsetattr(0, TCSANOW, &old);
|
||||
return 0;
|
||||
}
|
70
src/objects.cpp
Normal file
70
src/objects.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "../include/objects.hpp"
|
||||
|
||||
/* Plane */
|
||||
|
||||
Plane::Plane(const v3& n, choice_t offset, const Material& specs, int surface_type)
|
||||
: Renderable(specs), n(n), offset(offset), surface_type(surface_type) {}
|
||||
Plane::Plane(const v3& n, choice_t offset, const Material& specs) : Plane(n, offset, specs, 2) {}
|
||||
|
||||
int Plane::intersect(const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
|
||||
{
|
||||
const choice_t d = dir ^ n;
|
||||
if(d <= 0) return 0;
|
||||
|
||||
const choice_t k = -((eye ^ n) + offset) / d;
|
||||
|
||||
hit_loc = eye + dir * k;
|
||||
hit_normal = n;
|
||||
hit_dist = (hit_loc - eye).len();
|
||||
return surface_type;
|
||||
}
|
||||
|
||||
/* Sphere */
|
||||
|
||||
Sphere::Sphere(const v3& origin, choice_t r, const Material& specs, int surface_type)
|
||||
: Renderable(specs), o(origin), r(r), surface_type(surface_type) {}
|
||||
Sphere::Sphere(const v3& origin, choice_t r) : Sphere(origin, r, Material(), 1) {}
|
||||
|
||||
template<int K = 1>
|
||||
static inline int _sphere_intersect(Sphere& self, const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
|
||||
{
|
||||
const v3 d = self.o - eye;
|
||||
const choice_t dist_above_o = dir ^ d;
|
||||
|
||||
// We're facing directly away from the sphere
|
||||
if(dist_above_o < 0) { return -1; }
|
||||
|
||||
// The ray is pointing directly at the center of the sphere
|
||||
// if(fabs(dist_above_o - d.len()) < 1e-5) {
|
||||
// hit_loc = eye + d.norm() * (d.len() - self.r);
|
||||
// hit_normal = self.normal(hit_loc);
|
||||
// hit_dist = (hit_loc - eye).len();
|
||||
// return self.surface_type;
|
||||
// }
|
||||
|
||||
const choice_t rejection = sqrtf(d.len() * d.len() - dist_above_o * dist_above_o);
|
||||
// The ray is tangent/missing the sphere
|
||||
if(rejection >= self.r) return -1;
|
||||
|
||||
choice_t inside = sqrt(self.r*self.r - rejection*rejection) * K;
|
||||
|
||||
hit_dist = dist_above_o - inside;
|
||||
hit_loc = eye + dir * hit_dist;
|
||||
hit_normal = self.normal(hit_loc);
|
||||
return self.surface_type;
|
||||
}
|
||||
|
||||
int Sphere::intersect(const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
|
||||
{ return _sphere_intersect(*this, eye, dir, hit_dist, hit_loc, hit_normal); }
|
||||
|
||||
int Sphere::transmit(const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
|
||||
{ return _sphere_intersect<-1>(*this, eye, dir, hit_dist, hit_loc, hit_normal); }
|
||||
|
||||
|
||||
/* Light */
|
||||
|
||||
Light::Light(const v3& origin, choice_t r, const v3& colour) : Light(origin, r,
|
||||
Material{ .specular = 0,
|
||||
.roughness = 1,
|
||||
.colour = colour }) {}
|
||||
Light::Light(const v3& origin, choice_t r, const Material& specs) : Sphere(origin, r, specs, 0) {}
|
164
src/raytrace.cpp
Normal file
164
src/raytrace.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "../include/raytrace.hpp"
|
||||
#include "../include/objects.hpp"
|
||||
#include <math.h>
|
||||
#include <random>
|
||||
|
||||
Renderable::Renderable(const Material& specs) : specs(specs) {}
|
||||
|
||||
Renderable* shoot_ray_into_objects(const v3& eye, const v3& dir, const std::vector<Renderable*>& objs,
|
||||
choice_t& hit_dist, v3& hit_loc, v3& hit_normal, int& hit_type,
|
||||
Renderable* self)
|
||||
{
|
||||
hit_type = -1;
|
||||
Renderable* hit_object = nullptr;
|
||||
|
||||
// Iterate across objects to find the closest hit
|
||||
for(auto* r : objs) {
|
||||
if(r == self) continue;
|
||||
|
||||
choice_t dist = 1e10;
|
||||
v3 loc, normal;
|
||||
int type = -1;
|
||||
|
||||
type = r->intersect(eye, dir, dist, loc, normal);
|
||||
|
||||
// Hit is closer than closest hit
|
||||
if(type != -1 && dist < 1e9 && dist < hit_dist) {
|
||||
hit_dist = dist; hit_loc = loc;
|
||||
hit_normal = normal; hit_type = type;
|
||||
hit_object = r;
|
||||
}
|
||||
}
|
||||
|
||||
return hit_object;
|
||||
}
|
||||
|
||||
v3 ray_trace(const v3& eye, const v3& dir,
|
||||
const std::vector<Renderable*>& scene,
|
||||
const std::vector<Renderable*>& objects,
|
||||
const std::vector<Renderable*>& lights, int depth,
|
||||
Renderable* skip, choice_t* dist_to_hit)
|
||||
{
|
||||
choice_t hit_dist = 1e10;
|
||||
v3 hit_loc, hit_normal;
|
||||
int hit_type;
|
||||
Renderable* hit_obj = shoot_ray_into_objects(eye, dir, scene, hit_dist, hit_loc, hit_normal, hit_type, skip);
|
||||
|
||||
if(dist_to_hit != nullptr) *dist_to_hit = hit_dist;
|
||||
|
||||
v3 colour = v3{0.05, 0.05, 0.05};
|
||||
|
||||
if (hit_type == 0) {
|
||||
Light *l = (Light *)hit_obj;
|
||||
|
||||
const choice_t kDistance = powf((eye - l->o).norm() ^ hit_normal, 3);
|
||||
|
||||
colour += ((Light*)hit_obj)->specs.colour * 8 * kDistance;
|
||||
if(depth > 0) colour += ray_trace(eye, dir, scene, objects, lights, depth - 1, l) * (1 - kDistance);
|
||||
} else if (hit_type > 0) {
|
||||
// Figure out which lights are visible from the hit location
|
||||
choice_t dist;
|
||||
v3 loc, normal;
|
||||
v3 light_dir;
|
||||
int type;
|
||||
|
||||
Light *l = nullptr;
|
||||
|
||||
for (auto* _l : lights) {
|
||||
l = (Light *)_l;
|
||||
const v3 to_light = l->o - hit_loc;
|
||||
light_dir = to_light.norm();
|
||||
dist = to_light.len();
|
||||
shoot_ray_into_objects(hit_loc, light_dir, objects,
|
||||
dist, loc, normal, type, hit_obj);
|
||||
|
||||
// We hit the light directly: shade the pixel.
|
||||
if (type == -1) {
|
||||
const choice_t kDistance = to_light.lensquared() / 1000;
|
||||
colour += cook_torrance(dir, hit_normal, light_dir, hit_obj->specs.specular,
|
||||
hit_obj->specs.roughness, hit_obj->specs.ior,
|
||||
hit_obj->specs.colour, l->specs.colour)
|
||||
* (1 - hit_obj->specs.transparency) / kDistance;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the colour from the reflection, if we have enough depth
|
||||
const choice_t kReflectionAtt = hit_obj->specs.specular * (1 - hit_obj->specs.roughness);
|
||||
if(kReflectionAtt > 1e-4 && depth > 0) {
|
||||
colour += ray_trace(hit_loc, -(dir).ref(hit_normal),
|
||||
scene, objects, lights, depth-1)
|
||||
* kReflectionAtt;
|
||||
}
|
||||
|
||||
if (hit_obj->specs.transparency >= 1e-3 && depth > 0) {
|
||||
choice_t dist = 1e10; v3 loc, normal, light_dir;
|
||||
const v3 refract_dir = -dir.refract(hit_normal, 1/hit_obj->specs.ior);
|
||||
if(hit_obj->transmit(hit_loc, refract_dir, dist, loc, normal) != -1) {
|
||||
colour += ray_trace(loc, dir, scene, objects, lights, depth-1, hit_obj)
|
||||
* hit_obj->specs.transparency * (hit_obj->specs.colour + 0.75).norm();
|
||||
}
|
||||
}
|
||||
|
||||
// // Random sample
|
||||
// std::random_device rd;
|
||||
// std::mt19937 gen(rd());
|
||||
// std::uniform_real_distribution<> dis(0.0, 1.0);
|
||||
// const v3 y = hit_normal.cross(dir);
|
||||
// for(int i = 0; i < 2; ++i) {
|
||||
// const v3 sample_dir = (hit_normal + dir * dis(gen) + y * dis(gen)).norm();
|
||||
// choice_t dist = 1;
|
||||
// const v3 hit_colour = ray_trace(hit_loc, sample_dir, scene, objects, lights, 0, hit_obj, &dist);
|
||||
// colour += hit_colour / (dist * dist);
|
||||
// }
|
||||
}
|
||||
|
||||
return colour;
|
||||
}
|
||||
|
||||
static constexpr inline choice_t chi(choice_t x) { return x > 0 ? 1 : 0; }
|
||||
|
||||
choice_t ggx_ndf(const v3& dir, const v3& h, const v3& normal, choice_t roughness)
|
||||
{
|
||||
const choice_t alpha_sq = powf(roughness, 2);
|
||||
const choice_t mn_sq = powf(-dir ^ normal, 2);
|
||||
// return alpha_sq * chi(h ^ normal) / (M_PI * powf((1 - mn_sq * (1 + alpha_sq)), 2));
|
||||
return alpha_sq * chi(h ^ normal) / (M_PI * powf(mn_sq * (alpha_sq + (1 - mn_sq) / mn_sq), 2));
|
||||
}
|
||||
|
||||
choice_t blinn_phong_ndf(const v3& dir, const v3& h, const v3& normal, choice_t roughness)
|
||||
{
|
||||
const choice_t alpha_sq = powf(roughness, 4);
|
||||
return 1 / (M_PI * alpha_sq) * powf(normal ^ h, 2 / alpha_sq - 2);
|
||||
}
|
||||
|
||||
choice_t ggx_gaf_partial(const v3& dir, const v3& normal, const v3& light)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
choice_t ggx_gaf(const v3& dir, const v3& normal, const v3& light)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
choice_t cook_torrance_gaf(const v3& dir, const v3& h, const v3& normal, const v3& light)
|
||||
{
|
||||
const choice_t fac = 2 * (h ^ normal) / (-dir ^ h);
|
||||
return fmin(1, fmin(fac * (-dir ^ normal), fac * (light ^ normal)));
|
||||
}
|
||||
|
||||
choice_t cook_torrance_fresnel(const v3& dir, const v3& h, choice_t ior)
|
||||
{
|
||||
const choice_t f_naught = powf(ior - 1, 2) / powf(ior + 1, 2);
|
||||
return f_naught + (1 - f_naught) * powf(1 - (-dir ^ h), 5);
|
||||
}
|
||||
|
||||
v3 cook_torrance(const v3& dir, const v3& normal, const v3& light, choice_t specular, choice_t roughness, choice_t ior,
|
||||
const v3& light_colour, const v3& surface_colour)
|
||||
{
|
||||
const v3 h = (light - dir).norm();
|
||||
const choice_t r_spec = ggx_ndf(dir, h, light, roughness) *
|
||||
cook_torrance_gaf(dir, h, normal, light) * cook_torrance_fresnel(dir, h, ior) /
|
||||
(4 * (normal ^ light) * (-dir ^ normal));
|
||||
return (surface_colour * (1 - specular) / M_PI + light_colour * (specular * r_spec)) * fabs(normal ^ light);
|
||||
}
|
Reference in New Issue
Block a user