Initial commit
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
/build/*
|
||||||
|
/dist/*
|
||||||
|
!/dist/*.xyz
|
||||||
|
!/dist/*.txt
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
project(cloud_tracer)
|
||||||
|
|
||||||
|
file(GLOB SOURCES "src/*.cpp")
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dist)
|
||||||
|
add_executable(cloud_tracer ${SOURCES})
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
class defer_finalizer {
|
||||||
|
F f;
|
||||||
|
bool moved;
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
defer_finalizer(T && f_) : f(std::forward<T>(f_)), moved(false) { }
|
||||||
|
|
||||||
|
defer_finalizer(const defer_finalizer &) = delete;
|
||||||
|
|
||||||
|
defer_finalizer(defer_finalizer && other) : f(std::move(other.f)), moved(other.moved) {
|
||||||
|
other.moved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~defer_finalizer() {
|
||||||
|
if (!moved) f();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
template<typename F>
|
||||||
|
defer_finalizer<F> operator<<(F && f) {
|
||||||
|
return defer_finalizer<F>(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
} deferrer;
|
||||||
|
|
||||||
|
|
||||||
|
#define concat(x, y) x ## y
|
||||||
|
#define label(x, y) concat(x, y)
|
||||||
|
#define defer auto label(__deferred_lambda_call, __COUNTER__) = deferrer << [&]
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
#include "dt_pathtrace.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#define INFO(...) printf("INFO: " __VA_ARGS__);
|
||||||
|
|
||||||
|
#ifndef pi
|
||||||
|
# define pi 3.1415926535897932384626433832795
|
||||||
|
# define piOverTwo 1.5707963267948966192313216916398
|
||||||
|
# define inverseOfPi 0.31830988618379067153776752674503
|
||||||
|
# define inverseOfTwoPi 0.15915494309189533576888376337251
|
||||||
|
# define two_pi 6.283185307179586476925286766559
|
||||||
|
#endif
|
||||||
|
namespace Random {
|
||||||
|
struct rng_state {
|
||||||
|
uint32_t x;
|
||||||
|
uint32_t y;
|
||||||
|
uint32_t z;
|
||||||
|
uint32_t w;
|
||||||
|
};
|
||||||
|
|
||||||
|
static rng_state RNG_STATE;
|
||||||
|
|
||||||
|
uint TausStep(uint z, int S1, int S2, int S3, uint M) {
|
||||||
|
uint b = (((z << S1) ^ z) >> S2);
|
||||||
|
return ((z & M) << S3) ^ b;
|
||||||
|
}
|
||||||
|
uint LCGStep(uint z, uint A, uint C) {
|
||||||
|
return A * z + C;
|
||||||
|
}
|
||||||
|
|
||||||
|
float HybridTaus() {
|
||||||
|
RNG_STATE.x = TausStep(RNG_STATE.x, 13, 19, 12, 4294967294);
|
||||||
|
RNG_STATE.y = TausStep(RNG_STATE.y, 2, 25, 4, 4294967288);
|
||||||
|
RNG_STATE.z = TausStep(RNG_STATE.z, 3, 11, 17, 4294967280);
|
||||||
|
RNG_STATE.w = LCGStep(RNG_STATE.w, 1664525, 1013904223);
|
||||||
|
|
||||||
|
return 2.3283064365387e-10 * (RNG_STATE.x ^ RNG_STATE.y ^ RNG_STATE.z ^ RNG_STATE.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
float random() {
|
||||||
|
return HybridTaus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitRNG(uint32_t seed) {
|
||||||
|
|
||||||
|
RNG_STATE.x = seed;
|
||||||
|
RNG_STATE.y = seed;
|
||||||
|
RNG_STATE.z = seed;
|
||||||
|
RNG_STATE.w = seed;
|
||||||
|
|
||||||
|
for (int i = 0; i < 23 + seed % 13; i++)
|
||||||
|
random();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
inline double max(double a, double b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double min(double a, double b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float max(float a, float b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float min(float a, float b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float max(float a, float b, float c) {
|
||||||
|
return max(a, max(b, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float min(float a, float b, float c) {
|
||||||
|
return min(a, min(b, c));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t max(uint32_t a, uint32_t b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t min(uint32_t a, uint32_t b) {
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float Lerp(float a, float t, float b) {
|
||||||
|
return a + t * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Sample3DTexture(texture3D Grid, float3 P) {
|
||||||
|
// cubic interpolation
|
||||||
|
|
||||||
|
#define IDX(x, y, z) ((x * Grid.h * Grid.d) + (y * Grid.d) + z)
|
||||||
|
|
||||||
|
float fw = Grid.w * P.x;
|
||||||
|
float fh = Grid.h * P.y;
|
||||||
|
float fd = Grid.d * P.z;
|
||||||
|
|
||||||
|
float tw = fw - (int)fw;
|
||||||
|
float th = fh - (int)fh;
|
||||||
|
float td = fd - (int)fd;
|
||||||
|
|
||||||
|
uint32_t idx_w_left = floor(fw);
|
||||||
|
uint32_t idx_h_low = floor(fh);
|
||||||
|
uint32_t idx_d_near = floor(fd);
|
||||||
|
|
||||||
|
uint32_t idx_w_right = ceil(fw);
|
||||||
|
uint32_t idx_h_high = ceil(fh);
|
||||||
|
uint32_t idx_d_far = ceil(fd);
|
||||||
|
|
||||||
|
float left_low_near = Grid.Data[IDX(idx_w_left, idx_h_low, idx_d_near)];
|
||||||
|
float left_low_far = Grid.Data[IDX(idx_w_left, idx_h_low, idx_d_far)];
|
||||||
|
float left_high_near = Grid.Data[IDX(idx_w_left, idx_h_high, idx_d_near)];
|
||||||
|
float left_high_far = Grid.Data[IDX(idx_w_left, idx_h_high, idx_d_far)];
|
||||||
|
float right_low_near = Grid.Data[IDX(idx_w_right, idx_h_low, idx_d_near)];
|
||||||
|
float right_low_far = Grid.Data[IDX(idx_w_right, idx_h_low, idx_d_far)];
|
||||||
|
float right_high_near = Grid.Data[IDX(idx_w_right, idx_h_high, idx_d_near)];
|
||||||
|
float right_high_far = Grid.Data[IDX(idx_w_right, idx_h_high, idx_d_far)];
|
||||||
|
|
||||||
|
float low_near = Lerp(left_low_near, tw, right_low_near);
|
||||||
|
float low_far = Lerp(left_low_far, tw, right_low_far);
|
||||||
|
float low = Lerp(low_near, td, low_far);
|
||||||
|
|
||||||
|
float high_near = Lerp(left_high_near, tw, right_high_near);
|
||||||
|
float high_far = Lerp(left_high_far, tw, right_high_far);
|
||||||
|
float high = Lerp(high_near, td, high_far);
|
||||||
|
|
||||||
|
return Lerp(low, th, high);
|
||||||
|
|
||||||
|
#undef IDX
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateOrthonormalBasis(float3 D, float3& B, float3& T) {
|
||||||
|
float3 other = fabs(D.z) >= 0.999 ? float3{1, 0, 0} : float3{0, 0, 1};
|
||||||
|
B = Normalize(Cross(other, D));
|
||||||
|
T = Normalize(Cross(D, B));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateOrthonormalBasis2(float3 D, float3& B, float3& T) {
|
||||||
|
float3 other = fabs(D.z) >= 0.999 ? float3{1, 0, 0} : float3{0, 0, 1};
|
||||||
|
B = Normalize(Cross(other, D));
|
||||||
|
T = Normalize(Cross(D, B));
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 RandomDirection(float3 D) {
|
||||||
|
float r1 = Random::random();
|
||||||
|
float r2 = Random::random() * 2 - 1;
|
||||||
|
float sqrR2 = r2 * r2;
|
||||||
|
float two_pi_by_r1 = two_pi * r1;
|
||||||
|
float sqrt_of_one_minus_sqrR2 = sqrt(1.0 - sqrR2);
|
||||||
|
float x = cos(two_pi_by_r1) * sqrt_of_one_minus_sqrR2;
|
||||||
|
float y = sin(two_pi_by_r1) * sqrt_of_one_minus_sqrR2;
|
||||||
|
float z = r2;
|
||||||
|
|
||||||
|
float3 t0, t1;
|
||||||
|
CreateOrthonormalBasis2(D, t0, t1);
|
||||||
|
|
||||||
|
return t0 * x + t1 * y + D * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float invertcdf(float GFactor, float xi) {
|
||||||
|
#define one_minus_g2 (1.0 - (GFactor) * (GFactor))
|
||||||
|
#define one_plus_g2 (1.0 + (GFactor) * (GFactor))
|
||||||
|
#define one_over_2g (0.5 / (GFactor))
|
||||||
|
|
||||||
|
float t = (one_minus_g2) / (1.0f - GFactor + 2.0f * GFactor * xi);
|
||||||
|
return one_over_2g * (one_plus_g2 - t * t);
|
||||||
|
|
||||||
|
#undef one_minus_g2
|
||||||
|
#undef one_plus_g2
|
||||||
|
#undef one_over_2g
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 ImportanceSamplePhase(float GFactor, float3 D) {
|
||||||
|
if (fabs(GFactor) < 0.001) {
|
||||||
|
return RandomDirection(-D);
|
||||||
|
}
|
||||||
|
|
||||||
|
float phi = Random::random() * 2 * pi;
|
||||||
|
float cosTheta = invertcdf(GFactor, Random::random());
|
||||||
|
float sinTheta = sqrt(max(0, 1.0f - cosTheta * cosTheta));
|
||||||
|
|
||||||
|
float3 t0, t1;
|
||||||
|
CreateOrthonormalBasis(D, t0, t1);
|
||||||
|
|
||||||
|
return sinTheta * sin(phi) * t0 + sinTheta * cos(phi) * t1 +
|
||||||
|
cosTheta * D;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetGridBox(texture3D grid, float3& minim, float3& maxim) {
|
||||||
|
float maxDim = max(grid.w, grid.h, grid.d);
|
||||||
|
maxim = float3{(float)grid.w, (float)grid.h, (float)grid.d} / maxDim * 0.5;
|
||||||
|
minim = -maxim;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BoxIntersect(float3 bMin, float3 bMax, float3 P, float3 D, float& tMin, float& tMax) {
|
||||||
|
float2x3 C = float2x3{ bMin - P, bMax - P };
|
||||||
|
float2x3 D2 = float2x3{ D, D };
|
||||||
|
|
||||||
|
float2x3 T =
|
||||||
|
Abs(D2) <= 0.000001
|
||||||
|
? float2x3{float3{-1000, -1000, -1000}, float3{1000, 1000, 1000}}
|
||||||
|
: C / D2;
|
||||||
|
|
||||||
|
tMin = max(min(T.v1.v[0], T.v2.v[0]),
|
||||||
|
min(T.v1.v[1], T.v2.v[1]),
|
||||||
|
min(T.v1.v[2], T.v2.v[2]));
|
||||||
|
|
||||||
|
tMin = max(0.0f, tMin);
|
||||||
|
|
||||||
|
tMax = min(max(T.v1.v[0], T.v2.v[0]),
|
||||||
|
max(T.v1.v[1], T.v2.v[1]),
|
||||||
|
max(T.v1.v[2], T.v2.v[2]));
|
||||||
|
|
||||||
|
if (tMax < tMin || tMax < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DTPathtrace(path_info PathInfo, volume_info VolumeInfo, ray_pack* RayPack) {
|
||||||
|
|
||||||
|
int PassNumber = PathInfo.PassNumber;
|
||||||
|
float3 x = PathInfo.x;
|
||||||
|
float3 w = PathInfo.w;
|
||||||
|
|
||||||
|
float density = VolumeInfo.Extinction.v[PassNumber % 3]; // extinction coefficient multiplier.
|
||||||
|
INFO(" density: %f\n", density);
|
||||||
|
|
||||||
|
float3 bMin, bMax;
|
||||||
|
GetGridBox(VolumeInfo.Grid, bMin, bMax);
|
||||||
|
|
||||||
|
float3 W = { 0 }; // weight
|
||||||
|
W.v[PassNumber % 3] = 3; // Wavelenght dependent importance multiplier
|
||||||
|
|
||||||
|
float tMin, tMax;
|
||||||
|
if (!BoxIntersect(bMin, bMax, x, w, tMin, tMax))
|
||||||
|
return;
|
||||||
|
|
||||||
|
RayPack->start_new_ray();
|
||||||
|
RayPack->add_vertex(x);
|
||||||
|
|
||||||
|
|
||||||
|
float d = tMax - tMin;
|
||||||
|
x += w * tMin;
|
||||||
|
|
||||||
|
RayPack->add_vertex(x);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
float t =
|
||||||
|
density <= 0.00001
|
||||||
|
? 10000000
|
||||||
|
: -log(max(0.00000000001, 1.0 - Random::random())) / density; // majorant of all volume data
|
||||||
|
|
||||||
|
INFO(" t: %f\n", t);
|
||||||
|
INFO(" d: %f\n", d);
|
||||||
|
|
||||||
|
if (t >= d) {
|
||||||
|
INFO("->Ray left the volume\n");
|
||||||
|
RayPack->add_vertex(x + (w * t));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += w * t; // move to next event position or border
|
||||||
|
RayPack->add_vertex(x);
|
||||||
|
|
||||||
|
float3 tSamplePosition = (x - bMin) / (bMax - bMin);
|
||||||
|
float probExt = Sample3DTexture(VolumeInfo.Grid, tSamplePosition);
|
||||||
|
INFO(" sample pos: %f %f %f\n", tSamplePosition.x, tSamplePosition.y, tSamplePosition.z);
|
||||||
|
INFO(" density there: %f\n", probExt);
|
||||||
|
|
||||||
|
float m_t = probExt * density; // extinction coef
|
||||||
|
float m_s = m_t * VolumeInfo.ScatteringAlbedo.v[PassNumber % 3]; // scattering coef
|
||||||
|
float m_a = m_t - m_s; // absorption coef
|
||||||
|
float m_n = density - m_t; // null coef
|
||||||
|
|
||||||
|
float xi = Random::random();
|
||||||
|
|
||||||
|
float Pa = m_a / density;
|
||||||
|
float Ps = m_s / density;
|
||||||
|
float Pn = m_n / density;
|
||||||
|
|
||||||
|
if (xi < Pa) { // absorption
|
||||||
|
INFO("->absorbtion\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xi < 1 - Pn) { // scattering
|
||||||
|
INFO("->scatter\n");
|
||||||
|
w = ImportanceSamplePhase(VolumeInfo.G.v[PassNumber % 3], w); // scattering event...
|
||||||
|
|
||||||
|
if (!BoxIntersect(bMin, bMax, x, w, tMin, tMax))
|
||||||
|
return;
|
||||||
|
|
||||||
|
d = tMax - tMin;
|
||||||
|
x += w * tMin;
|
||||||
|
} else {
|
||||||
|
INFO("->null collision\n");
|
||||||
|
// if no absorption and no scattering null collision occurred
|
||||||
|
d -= t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "vector.hpp"
|
||||||
|
#include "texture3d.hpp"
|
||||||
|
#include "ray_pack.hpp"
|
||||||
|
|
||||||
|
struct volume_info {
|
||||||
|
texture3D Grid;
|
||||||
|
float3 Extinction;
|
||||||
|
float3 ScatteringAlbedo;
|
||||||
|
float3 G;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct path_info {
|
||||||
|
float3 x;
|
||||||
|
float3 w;
|
||||||
|
int PassNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
void GetGridBox(texture3D grid, float3& minim, float3& maxim);
|
||||||
|
void DTPathtrace(path_info PathInfo, volume_info VolumeInfo, ray_pack* RayPack);
|
||||||
|
|
||||||
|
namespace Random {
|
||||||
|
void InitRNG(uint32_t seed);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
template <typename type>
|
||||||
|
struct list {
|
||||||
|
uint32_t count;
|
||||||
|
uint32_t length;
|
||||||
|
type* data;
|
||||||
|
|
||||||
|
inline void alloc(uint32_t initial_length = 16) {
|
||||||
|
count = 0;
|
||||||
|
length = initial_length;
|
||||||
|
data = (type*)malloc(sizeof(type) * length);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void dealloc() {
|
||||||
|
free(data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void clear() {
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(type element) {
|
||||||
|
if (count == length) {
|
||||||
|
length *= 2;
|
||||||
|
data = (type*)realloc(data, length * sizeof(type));
|
||||||
|
}
|
||||||
|
data[count] = element;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline type* begin() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline type* end() {
|
||||||
|
return data+(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
type& operator[](uint32_t index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "vector.hpp"
|
||||||
|
#include "texture3d.hpp"
|
||||||
|
#include "list.hpp"
|
||||||
|
#include "defer.hpp"
|
||||||
|
#include "dt_pathtrace.hpp"
|
||||||
|
#include "ray_pack.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
void WriteDomainAndRayPackToOBJFile(texture3D Grid, ray_pack* RayPack,
|
||||||
|
const char* OBJFileName)
|
||||||
|
{
|
||||||
|
FILE* out = fopen(OBJFileName, "w");
|
||||||
|
if (!out) {
|
||||||
|
fprintf(stderr, "ERROR: file %s could not be opened\n", OBJFileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
defer {
|
||||||
|
fclose(out);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (float3 v : RayPack->vertices) {
|
||||||
|
fprintf(out, "v %f %f %f\n", v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain Box
|
||||||
|
float3 maxim;
|
||||||
|
float3 minim;
|
||||||
|
GetGridBox(Grid, minim, maxim);
|
||||||
|
fprintf(out, "v %f %f %f\n", maxim.x, maxim.y, maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", maxim.x, maxim.y, -maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", maxim.x, -maxim.y, maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", maxim.x, -maxim.y, -maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", -maxim.x, maxim.y, maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", -maxim.x, maxim.y, -maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", -maxim.x, -maxim.y, maxim.z);
|
||||||
|
fprintf(out, "v %f %f %f\n", -maxim.x, -maxim.y, -maxim.z);
|
||||||
|
|
||||||
|
fprintf(out, "g Rays\n");
|
||||||
|
uint32_t start = 0;
|
||||||
|
uint32_t end;
|
||||||
|
// all but the last sample:
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (; i < RayPack->ray_starts.count-1; ++i) {
|
||||||
|
end = RayPack->ray_starts[i+1];
|
||||||
|
fprintf(out, "o Ray_%u\n", i);
|
||||||
|
|
||||||
|
for (uint32_t j = start; j < end-1; ++j) {
|
||||||
|
// NOTE(Felix): +1 because obj vertex ids start counting at 1
|
||||||
|
fprintf(out, "l %u %u\n", j+1, j+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
start = end;
|
||||||
|
}
|
||||||
|
// NOTE(Felix): the last sample;
|
||||||
|
end = RayPack->vertices.count;
|
||||||
|
fprintf(out, "o Ray_%u\n", i);
|
||||||
|
printf("start %u end %u\n", start, end);
|
||||||
|
for (uint32_t j = start; j < end-1; ++j) {
|
||||||
|
// NOTE(Felix): +1 because obj vertex ids start counting at 1
|
||||||
|
fprintf(out, "l %u %u\n", j+1, j+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
end++;
|
||||||
|
fprintf(out, "g Domain\n");
|
||||||
|
fprintf(out, "o Domain\n");
|
||||||
|
fprintf(out, "l %u %u\n", end+0, end+1);
|
||||||
|
fprintf(out, "l %u %u\n", end+2, end+3);
|
||||||
|
fprintf(out, "l %u %u\n", end+4, end+5);
|
||||||
|
fprintf(out, "l %u %u\n", end+6, end+7);
|
||||||
|
|
||||||
|
fprintf(out, "l %u %u\n", end+0, end+2);
|
||||||
|
fprintf(out, "l %u %u\n", end+1, end+3);
|
||||||
|
fprintf(out, "l %u %u\n", end+4, end+6);
|
||||||
|
fprintf(out, "l %u %u\n", end+5, end+7);
|
||||||
|
|
||||||
|
fprintf(out, "l %u %u\n", end+0, end+4);
|
||||||
|
fprintf(out, "l %u %u\n", end+1, end+5);
|
||||||
|
fprintf(out, "l %u %u\n", end+2, end+6);
|
||||||
|
fprintf(out, "l %u %u\n", end+3, end+7);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ray_pack RayPack;
|
||||||
|
RayPack.alloc();
|
||||||
|
defer {
|
||||||
|
RayPack.dealloc();
|
||||||
|
};
|
||||||
|
|
||||||
|
path_info PI = { };
|
||||||
|
PI.x = {-2, -2, -2};
|
||||||
|
PI.w = Normalize(float3{0.4,0.4,0} - PI.x);
|
||||||
|
PI.PassNumber = 0;
|
||||||
|
|
||||||
|
volume_info VI = { };
|
||||||
|
VI.Grid = ReadXYZFile("cloud-049.xyz");
|
||||||
|
VI.Extinction = {20, 20, 20};
|
||||||
|
VI.G = {0.3, 0.3, 0.3};
|
||||||
|
VI.ScatteringAlbedo = {0.9, 0.9, 0.9};
|
||||||
|
|
||||||
|
Random::InitRNG(1);
|
||||||
|
for (int i = 0; i < 30; ++i) {
|
||||||
|
DTPathtrace(PI, VI, &RayPack);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteDomainAndRayPackToOBJFile(VI.Grid, &RayPack, "RayPack.obj");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "list.hpp"
|
||||||
|
#include "vector.hpp"
|
||||||
|
|
||||||
|
struct ray_pack {
|
||||||
|
list<float3> vertices;
|
||||||
|
list<uint32_t> ray_starts;
|
||||||
|
|
||||||
|
void alloc() {
|
||||||
|
vertices.alloc();
|
||||||
|
ray_starts.alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dealloc() {
|
||||||
|
vertices.dealloc();
|
||||||
|
ray_starts.dealloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_vertex(float3 vert) {
|
||||||
|
vertices.append(vert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_new_ray() {
|
||||||
|
ray_starts.append(vertices.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dt_pathtrace.hpp"
|
||||||
|
|
||||||
|
struct scene {
|
||||||
|
const char* SceneFile;
|
||||||
|
|
||||||
|
volume_info VolInfo;
|
||||||
|
|
||||||
|
float3 CameraPos;
|
||||||
|
float3 CameraLookAt;
|
||||||
|
float CameraFOV;
|
||||||
|
uint32_t ResX;
|
||||||
|
uint32_t ResY;
|
||||||
|
};
|
||||||
|
|
||||||
|
scene LoadSceneFromFile(const char* FilePath);
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include "texture3d.hpp"
|
||||||
|
#include "defer.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
texture3D ReadXYZFile(const char* Path) {
|
||||||
|
uint32_t Buffer[9];
|
||||||
|
|
||||||
|
FILE* XYZFile = fopen(Path, "rb");
|
||||||
|
|
||||||
|
if (!XYZFile) {
|
||||||
|
fprintf(stderr, "ERROR: File %s could not be opened\n", Path);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
defer {
|
||||||
|
fclose(XYZFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
size_t Read = fread(Buffer, sizeof(uint32_t)*9, 1, XYZFile);
|
||||||
|
|
||||||
|
if (!Read) {
|
||||||
|
fprintf(stderr, "ERROR: Header could not be read\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
texture3D Result;
|
||||||
|
Result.w = Buffer[0];
|
||||||
|
Result.h = Buffer[1];
|
||||||
|
Result.d = Buffer[2];
|
||||||
|
|
||||||
|
printf("INFO: Reading density map %u x %u x %u\n",
|
||||||
|
Result.w, Result.h, Result.d);
|
||||||
|
|
||||||
|
uint32_t FloatsCount = Result.w * Result.h * Result.d;
|
||||||
|
Result.Data = (float*)malloc(FloatsCount * sizeof(float));
|
||||||
|
|
||||||
|
Read = fread(Result.Data, FloatsCount * sizeof(float), 1, XYZFile);
|
||||||
|
|
||||||
|
if (!Read) {
|
||||||
|
fprintf(stderr, "ERROR: Data could not be read\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
struct texture3D {
|
||||||
|
uint32_t w;
|
||||||
|
uint32_t h;
|
||||||
|
uint32_t d;
|
||||||
|
float* Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
texture3D ReadXYZFile(const char* Path);
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
#include "vector.hpp"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
|
||||||
|
float3 operator/(float3 v, float s) {
|
||||||
|
float3 result;
|
||||||
|
result.x = v.x / s;
|
||||||
|
result.y = v.y / s;
|
||||||
|
result.z = v.z / s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 operator*(float3 v, float s) {
|
||||||
|
float3 result;
|
||||||
|
result.x = v.x * s;
|
||||||
|
result.y = v.y * s;
|
||||||
|
result.z = v.z * s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 operator*(float s, float3 v) {
|
||||||
|
float3 result;
|
||||||
|
result.x = v.x * s;
|
||||||
|
result.y = v.y * s;
|
||||||
|
result.z = v.z * s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 operator+(float3 v1, float3 v2) {
|
||||||
|
float3 result;
|
||||||
|
result.x = v1.x + v2.x;
|
||||||
|
result.y = v1.y + v2.y;
|
||||||
|
result.z = v1.z + v2.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 operator-(float3 v1) {
|
||||||
|
float3 result;
|
||||||
|
result.x = -v1.x;
|
||||||
|
result.y = -v1.y;
|
||||||
|
result.z = -v1.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 operator-(float3 v1, float3 v2) {
|
||||||
|
float3 result;
|
||||||
|
result.x = v1.x - v2.x;
|
||||||
|
result.y = v1.y - v2.y;
|
||||||
|
result.z = v1.z - v2.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 operator/(float3 v1, float3 v2) {
|
||||||
|
float3 result;
|
||||||
|
result.x = v1.x / v2.x;
|
||||||
|
result.y = v1.y / v2.y;
|
||||||
|
result.z = v1.z / v2.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3& operator*=(float3& v, float s) {
|
||||||
|
v = v * s;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3& operator+=(float3& v1, float3 v2) {
|
||||||
|
v1 = v1 + v2;
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3& operator-=(float3& v1, float3 v2) {
|
||||||
|
v1 = v1 - v2;
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3& operator/=(float3& v1, float3 v2) {
|
||||||
|
v1 = v1 / v2;
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 Cross(float3 a, float3 b) {
|
||||||
|
float3 result;
|
||||||
|
|
||||||
|
result.x = a.y*b.z - a.z*b.y;
|
||||||
|
result.y = a.z*b.x - a.x*b.z;
|
||||||
|
result.z = a.x*b.y - a.y*b.x;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Dot(float3 a, float3 b) {
|
||||||
|
return
|
||||||
|
a.x * b.x +
|
||||||
|
a.y * b.y +
|
||||||
|
a.z * b.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SquaredLength(float3 v) {
|
||||||
|
return Dot(v, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 Normalize(float3 v) {
|
||||||
|
float3 result { 0 };
|
||||||
|
|
||||||
|
float squaredLength = SquaredLength(v);
|
||||||
|
if(squaredLength > 0.000001f) {
|
||||||
|
result = v * (1.0f / sqrt(squaredLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 Abs(float3 v) {
|
||||||
|
float3 result;
|
||||||
|
result.x = fabs(v.x);
|
||||||
|
result.y = fabs(v.y);
|
||||||
|
result.z = fabs(v.z);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2x3 Abs(float2x3 M) {
|
||||||
|
float2x3 result;
|
||||||
|
result.v1 = Abs(M.v1);
|
||||||
|
result.v2 = Abs(M.v2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(float3 v, float s) {
|
||||||
|
return
|
||||||
|
v.x <= s &&
|
||||||
|
v.y <= s &&
|
||||||
|
v.z <= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(float2x3 M, float s) {
|
||||||
|
return M.v1 <= s && M.v2 <= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
float2x3 operator/(float2x3 M1, float2x3 M2) {
|
||||||
|
float2x3 result;
|
||||||
|
result.v1 = M1.v1 / M2.v1;
|
||||||
|
result.v2 = M1.v2 / M2.v2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
float x, y, z;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
float r, g, b;
|
||||||
|
};
|
||||||
|
float v[3];
|
||||||
|
} float3;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float3 v1;
|
||||||
|
float3 v2;
|
||||||
|
} float2x3;
|
||||||
|
|
||||||
|
|
||||||
|
float3 Cross(float3, float3);
|
||||||
|
float3 Normalize(float3);
|
||||||
|
|
||||||
|
|
||||||
|
float3 Abs(float3);
|
||||||
|
float2x3 Abs(float2x3);
|
||||||
|
|
||||||
|
float2x3 operator/(float2x3, float2x3);
|
||||||
|
bool operator<=(float2x3, float);
|
||||||
|
|
||||||
|
float3 operator-(float3);
|
||||||
|
float3 operator*(float3, float);
|
||||||
|
float3 operator*(float, float3);
|
||||||
|
float3 operator/(float3, float);
|
||||||
|
float3 operator+(float3, float3);
|
||||||
|
float3 operator-(float3, float3);
|
||||||
|
float3 operator/(float3, float3);
|
||||||
|
|
||||||
|
float3& operator*=(float3&, float);
|
||||||
|
float3& operator/=(float3&, float3);
|
||||||
|
float3& operator+=(float3&, float3);
|
||||||
|
float3& operator-=(float3&, float3);
|
||||||
Reference in New Issue
Block a user