Skip to content

Commit 4789c13

Browse files
committed
Sobol sampler (xor scrambled)
1 parent 93f6ac9 commit 4789c13

File tree

7 files changed

+70
-57
lines changed

7 files changed

+70
-57
lines changed

sobol_10k_200.bin

7.63 MB
Binary file not shown.

src/common.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
#pragma once
22
#include <iostream>
33

4-
#define MESH_DATA_STRUCT_OF_ARRAY false
5-
#define MESH_DATA_INDEXED false
6-
7-
#define DEV_SCENE_PASS_BY_CONST_MEM false
4+
#define SAMPLER_USE_SOBOL true
85

96
#define SCENE_LIGHT_SINGLE_SIDED true
107

src/material.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ __device__ inline float smithG(float cosWo, float cosWi, float alpha) {
6767
return schlickG(glm::abs(cosWo), alpha) * schlickG(glm::abs(cosWi), alpha);
6868
}
6969

70-
__device__ static float ggxDistrib(float cosTheta, float alpha) {
70+
__device__ static float GTR2Distrib(float cosTheta, float alpha) {
7171
if (cosTheta < 1e-6f) {
7272
return 0.f;
7373
}
@@ -78,18 +78,19 @@ __device__ static float ggxDistrib(float cosTheta, float alpha) {
7878
return nom / denom;
7979
}
8080

81-
__device__ static float ggxPdf(glm::vec3 n, glm::vec3 m, glm::vec3 wo, float alpha) {
82-
return ggxDistrib(glm::dot(n, m), alpha) * schlickG(glm::dot(n, wo), alpha) *
81+
__device__ static float GTR2Pdf(glm::vec3 n, glm::vec3 m, glm::vec3 wo, float alpha) {
82+
return GTR2Distrib(glm::dot(n, m), alpha) * schlickG(glm::dot(n, wo), alpha) *
8383
Math::absDot(m, wo) / Math::absDot(n, wo);
8484
}
8585

8686
/**
87-
* Sample GGX microfacet distribution, but only visible normals.
87+
* Sampling (Trowbridge-Reitz/GTR2/GGX) microfacet distribution, but only visible normals.
8888
* This reduces invalid samples and make pdf values at grazing angles more stable
8989
* See [Sampling the GGX Distribution of Visible Normals, Eric Heitz, JCGT 2018]:
9090
* https://jcgt.org/published/0007/04/01/
91+
* Note:
9192
*/
92-
__device__ static glm::vec3 ggxSample(glm::vec3 n, glm::vec3 wo, float alpha, glm::vec2 r) {
93+
__device__ static glm::vec3 GTR2Sample(glm::vec3 n, glm::vec3 wo, float alpha, glm::vec2 r) {
9394
glm::mat3 transMat = Math::localRefMatrix(n);
9495
glm::mat3 transInv = glm::inverse(transMat);
9596

@@ -175,9 +176,9 @@ struct Material {
175176
return glm::vec3(0.f);
176177
}
177178

178-
glm::vec3 f = fresnelSchlick(glm::dot(h, wo), baseColor * metallic);
179+
glm::vec3 f = fresnelSchlick(glm::dot(h, wo), glm::mix(glm::vec3(.08f), baseColor, metallic));
179180
float g = smithG(cosO, cosI, alpha);
180-
float d = ggxDistrib(glm::dot(n, h), alpha);
181+
float d = GTR2Distrib(glm::dot(n, h), alpha);
181182

182183
return glm::mix(baseColor * PiInv * (1.f - metallic), glm::vec3(g * d / (4.f * cosI * cosO)), f);
183184
}
@@ -186,7 +187,7 @@ struct Material {
186187
glm::vec3 h = glm::normalize(wo + wi);
187188
return glm::mix(
188189
Math::satDot(n, wi) * PiInv,
189-
ggxPdf(n, h, wo, roughness * roughness) / (4.f * Math::absDot(h, wo)),
190+
GTR2Pdf(n, h, wo, roughness * roughness) / (4.f * Math::absDot(h, wo)),
190191
1.f / (2.f - metallic)
191192
);
192193
}
@@ -198,7 +199,7 @@ struct Material {
198199
sample.dir = Math::sampleHemisphereCosine(n, r.x, r.y);
199200
}
200201
else {
201-
glm::vec3 h = ggxSample(n, wo, alpha, glm::vec2(r));
202+
glm::vec3 h = GTR2Sample(n, wo, alpha, glm::vec2(r));
202203
sample.dir = -glm::reflect(wo, h);
203204
}
204205

src/pathtrace.cu

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,17 @@ __device__ Ray sampleCamera(const Camera& cam, int x, int y, glm::vec4 r) {
141141
* motion blur - jitter rays "in time"
142142
* lens effect - jitter ray origin positions based on a lens
143143
*/
144-
__global__ void generateRayFromCamera(Camera cam, int iter, int traceDepth, PathSegment* pathSegments) {
144+
__global__ void generateRayFromCamera(
145+
DevScene* scene, Camera cam, int iter, int traceDepth, PathSegment* pathSegments
146+
) {
145147

146148
int x = (blockIdx.x * blockDim.x) + threadIdx.x;
147149
int y = (blockIdx.y * blockDim.y) + threadIdx.y;
148150

149151
if (x < cam.resolution.x && y < cam.resolution.y) {
150152
int index = x + (y * cam.resolution.x);
151153
PathSegment& segment = pathSegments[index];
152-
thrust::default_random_engine rng = makeSeededRandomEngine(iter, index, 0);
154+
Sampler rng = makeSeededRandomEngine(iter, index, traceDepth, scene->sampleSequence);
153155

154156
segment.ray = sampleCamera(cam, x, y, sample4D(rng));
155157
segment.throughput = glm::vec3(1.f);
@@ -171,7 +173,7 @@ __global__ void previewGBuffer(
171173
return;
172174
}
173175
int index = y * width + x;
174-
thrust::default_random_engine rng = makeSeededRandomEngine(iter, index, 0);
176+
Sampler rng = makeSeededRandomEngine(iter, index, 0, scene->sampleSequence);
175177

176178
Ray ray = sampleCamera(cam, x, y, sample4D(rng));
177179
Intersection intersec;
@@ -256,7 +258,7 @@ __global__ void pathIntegSampleSurface(
256258
int numPaths,
257259
bool sortMaterial
258260
) {
259-
const int SamplesConsumedOneIter = 10;
261+
const int SamplesOneIter = 7;
260262

261263
int idx = blockDim.x * blockIdx.x + threadIdx.x;
262264
if (idx >= numPaths) {
@@ -289,7 +291,7 @@ __global__ void pathIntegSampleSurface(
289291
return;
290292
}
291293

292-
thrust::default_random_engine rng = makeSeededRandomEngine(iter, idx, 4 + depth * SamplesConsumedOneIter);
294+
Sampler rng = makeSeededRandomEngine(iter, idx, 4 + depth * SamplesOneIter, scene->sampleSequence);
293295

294296
Material material = scene->getTexturedMaterialAndSurface(intersec);
295297

@@ -380,7 +382,7 @@ __global__ void singleKernelPT(
380382
glm::vec3 accRadiance(0.f);
381383

382384
int index = y * width + x;
383-
thrust::default_random_engine rng = makeSeededRandomEngine(iter, index, 0);
385+
Sampler rng = makeSeededRandomEngine(iter, index, 0, scene->sampleSequence);
384386

385387
Ray ray = sampleCamera(cam, x, y, sample4D(rng));
386388
Intersection intersec;
@@ -486,7 +488,7 @@ __global__ void BVHVisualize(int iter, DevScene* scene, Camera cam, glm::vec3* i
486488
}
487489
int index = y * width + x;
488490

489-
thrust::default_random_engine rng = makeSeededRandomEngine(iter, index, 0);
491+
Sampler rng = makeSeededRandomEngine(iter, index, 0, scene->sampleSequence);
490492
Ray ray = sampleCamera(cam, x, y, sample4D(rng));
491493

492494
Intersection intersec;
@@ -527,7 +529,7 @@ void pathTrace(uchar4* pbo, int frame, int iter) {
527529
(cam.resolution.x + blockSize2D.x - 1) / blockSize2D.x,
528530
(cam.resolution.y + blockSize2D.y - 1) / blockSize2D.y);
529531

530-
generateRayFromCamera<<<blocksPerGrid2D, blockSize2D>>>(cam, iter, Settings::traceDepth, devPaths);
532+
generateRayFromCamera<<<blocksPerGrid2D, blockSize2D>>>(hstScene->devScene, cam, iter, Settings::traceDepth, devPaths);
531533
checkCUDAError("PT::generateRayFromCamera");
532534
cudaDeviceSynchronize();
533535

src/sampler.h

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,49 @@
44
#include <thrust/random.h>
55
#include "mathUtil.h"
66
#include "cudaUtil.h"
7-
8-
#define SAMPLER_USE_SOBOL false
7+
#include "common.h"
98

109
#if SAMPLER_USE_SOBOL
10+
#define SobolSampleNum 10000
11+
#define SobolSampleDim 200
12+
13+
struct Sampler {
14+
__device__ Sampler() = default;
15+
16+
__device__ Sampler(int ptr, uint32_t scramble, uint32_t* data) :
17+
ptr(ptr), scramble(scramble), data(data) {}
18+
19+
__device__ float sample() {
20+
uint32_t r = data[ptr++] ^ scramble;
21+
scramble = Math::utilhash(scramble);
22+
return r * 0x1p-32f;
23+
}
24+
25+
uint32_t* data;
26+
uint32_t scramble;
27+
int ptr;
28+
};
29+
30+
__device__ static Sampler makeSeededRandomEngine(int iter, int index, int dim, uint32_t* data) {
31+
return Sampler(iter * SobolSampleDim + dim, Math::utilhash(index), data);
32+
}
33+
34+
__device__ inline float sample1D(Sampler& sampler) {
35+
return sampler.sample();
36+
}
37+
1138
#else
1239
using Sampler = thrust::default_random_engine;
13-
#endif
1440

15-
__host__ __device__
16-
static thrust::default_random_engine makeSeededRandomEngine(int iter, int index, int depth) {
17-
int h = Math::utilhash((1 << 31) | (depth << 22) | iter) ^ Math::utilhash(index);
18-
return thrust::default_random_engine(h);
41+
__device__ static Sampler makeSeededRandomEngine(int iter, int index, int dim, uint32_t* data) {
42+
int h = Math::utilhash((1 << 31) | (dim << 22) | iter) ^ Math::utilhash(index);
43+
return Sampler(h);
1944
}
2045

21-
__device__ inline float sample1D(thrust::default_random_engine& rng) {
22-
return thrust::uniform_real_distribution<float>(0.f, 1.f)(rng);
46+
__device__ inline float sample1D(Sampler& sampler) {
47+
return thrust::uniform_real_distribution<float>(0.f, 1.f)(sampler);
2348
}
49+
#endif
2450

2551
__device__ inline glm::vec2 sample2D(Sampler& sampler) {
2652
return glm::vec2(sample1D(sampler), sample1D(sampler));

src/scene.cpp

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,6 @@ MeshData* Resource::loadOBJMesh(const std::string& filename) {
3838
}
3939
bool hasTexcoord = !attrib.texcoords.empty();
4040

41-
#if MESH_DATA_INDEXED
42-
model->vertices.resize(attrib.vertices.size() / 3);
43-
model->normals.resize(attrib.normals.size() / 3);
44-
memcpy(model->vertices.data(), attrib.vertices.data(), attrib.vertices.size() * sizeof(float));
45-
memcpy(model->normals.data(), attrib.normals.data(), attrib.normals.size() * sizeof(float));
46-
if (hasTexcoord) {
47-
model->texcoord.resize(attrib.texcoords.size() / 2);
48-
memcpy(model->texcoords.data(), attrib.texcoords.data(), attrib.texcoords.size() * sizeof(float));
49-
}
50-
else {
51-
model->texcoord.resize(attrib.vertices.size() / 3);
52-
}
53-
54-
for (const auto& shape : shapes) {
55-
for (auto idx : shape.mesh.indices) {
56-
model->indices.push_back({ idx.vertex_index, idx.normal_index,
57-
hasTexcoord ? idx.texcoord_index : idx.vertex_index });
58-
}
59-
}
60-
#else
6141
for (const auto& shape : shapes) {
6242
for (auto idx : shape.mesh.indices) {
6343
model->vertices.push_back(*((glm::vec3*)attrib.vertices.data() + idx.vertex_index));
@@ -68,7 +48,7 @@ MeshData* Resource::loadOBJMesh(const std::string& filename) {
6848
);
6949
}
7050
}
71-
#endif
51+
7252
std::cout << "\t\t[Vertex count = " << model->vertices.size() << "]" << std::endl;
7353
meshDataPool[filename] = model;
7454
return model;
@@ -163,8 +143,6 @@ void Scene::createLightSampler() {
163143
}
164144

165145
void Scene::buildDevData() {
166-
#if MESH_DATA_INDEXED
167-
#else
168146
int primId = 0;
169147
for (const auto& inst : modelInstances) {
170148
const auto& material = materials[inst.materialId];
@@ -196,7 +174,7 @@ void Scene::buildDevData() {
196174
}
197175
}
198176
}
199-
#endif
177+
200178
if (primId == 0) {
201179
std::cout << "[No mesh data loaded, quit]" << std::endl;
202180
exit(-1);
@@ -503,6 +481,14 @@ void DevScene::create(const Scene& scene) {
503481
}
504482

505483
checkCUDAError("DevScene::meshData");
484+
485+
#if SAMPLER_USE_SOBOL
486+
std::ifstream sobolFile("sobol_10k_200.bin", std::ios::in | std::ios::binary);
487+
std::vector<char> sobolData(SobolSampleNum * SobolSampleDim * sizeof(uint32_t));
488+
sobolFile.read(sobolData.data(), byteSizeOf(sobolData));
489+
cudaMalloc(&sampleSequence, byteSizeOf(sobolData));
490+
cudaMemcpyHostToDev(sampleSequence, sobolData.data(), byteSizeOf(sobolData));
491+
#endif
506492
}
507493

508494
void DevScene::destroy() {
@@ -524,4 +510,6 @@ void DevScene::destroy() {
524510
cudaSafeFree(lightUnitRadiance);
525511
lightSampler.destroy();
526512
envMapSampler.destroy();
513+
514+
cudaSafeFree(sampleSequence);
527515
}

src/scene.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ struct MeshData {
2626
std::vector<glm::vec3> vertices;
2727
std::vector<glm::vec3> normals;
2828
std::vector<glm::vec2> texcoords;
29-
#if MESH_DATA_INDEXED
30-
std::vector<glm::ivec3> indices;
31-
#endif
3229
};
3330

3431
struct ModelInstance {
@@ -423,6 +420,8 @@ struct DevScene {
423420
float sumLightPowerInv;
424421
DevTextureObj* envMap = nullptr;
425422
DevDiscreteSampler1D<float> envMapSampler;
423+
424+
uint32_t* sampleSequence = nullptr;
426425
};
427426

428427
class Scene {

0 commit comments

Comments
 (0)