Skip to content

Commit 4e44aa6

Browse files
committed
material sorting
1 parent 859de4c commit 4e44aa6

File tree

9 files changed

+129
-57
lines changed

9 files changed

+129
-57
lines changed

src/common.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
#include "common.h"
2+
3+
int Settings::toneMapping = ToneMapping::ACES;
4+
bool Settings::visualizeBVH = false;
5+
bool Settings::sortMaterial = false;

src/common.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,24 @@
1+
#pragma once
12
#include <iostream>
3+
4+
#define MESH_DATA_STRUCT_OF_ARRAY false
5+
#define MESH_DATA_INDEXED false
6+
7+
#define DEV_SCENE_PASS_BY_CONST_MEM false
8+
9+
#define SCENE_LIGHT_SINGLE_SIDED true
10+
11+
#define BVH_DEBUG_VISUALIZATION false
12+
#define BVH_DISABLE false
13+
14+
struct ToneMapping {
15+
enum {
16+
None = 0, Filmic = 1, ACES = 2
17+
};
18+
};
19+
20+
struct Settings {
21+
static int toneMapping;
22+
static bool visualizeBVH;
23+
static bool sortMaterial;
24+
};

src/main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ void saveImage() {
159159
for (int y = 0; y < height; y++) {
160160
int index = x + (y * width);
161161
glm::vec3 color = renderState->image[index] / samples;
162-
switch (ToneMapping::method) {
162+
switch (Settings::toneMapping) {
163163
case ToneMapping::Filmic:
164164
color = Math::filmic(color);
165165
break;
@@ -243,7 +243,7 @@ void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods
243243
saveImage();
244244
break;
245245
case GLFW_KEY_T:
246-
ToneMapping::method = (ToneMapping::method + 1) % 3;
246+
Settings::toneMapping = (Settings::toneMapping + 1) % 3;
247247
break;
248248
case GLFW_KEY_SPACE:
249249
camChanged = true;

src/pathtrace.cu

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <thrust/random.h>
66
#include <thrust/remove.h>
77
#include <thrust/device_ptr.h>
8+
#include <thrust/sort.h>
89

910
#include "sceneStructs.h"
1011
#include "material.h"
@@ -18,10 +19,6 @@
1819
#include "mathUtil.h"
1920
#include "sampler.h"
2021

21-
#define BVH_DEBUG_VISUALIZATION false
22-
23-
int ToneMapping::method = ToneMapping::ACES;
24-
2522
//Kernel that writes the image to the OpenGL PBO directly.
2623
__global__ void sendImageToPBO(uchar4* pbo, glm::ivec2 resolution,
2724
int iter, glm::vec3* Image, int toneMapping) {
@@ -63,10 +60,16 @@ static glm::vec3* devImage = nullptr;
6360
static PathSegment* devPaths = nullptr;
6461
static PathSegment* devTerminatedPaths = nullptr;
6562
static Intersection* devIntersections = nullptr;
63+
static int* devIntersecMatKeys = nullptr;
64+
static int* devSegmentMatKeys = nullptr;
6665
// TODO: static variables for device memory, any extra info you need, etc
6766
// ...
6867
static thrust::device_ptr<PathSegment> devPathsThr;
6968
static thrust::device_ptr<PathSegment> devTerminatedPathsThr;
69+
70+
static thrust::device_ptr<Intersection> devIntersectionsThr;
71+
static thrust::device_ptr<int> devIntersecMatKeysThr;
72+
static thrust::device_ptr<int> devSegmentMatKeysThr;
7073

7174
void InitDataContainer(GuiDataContainer* imGuiData) {
7275
guiData = imGuiData;
@@ -88,6 +91,12 @@ void pathTraceInit(Scene* scene) {
8891

8992
cudaMalloc(&devIntersections, pixelcount * sizeof(Intersection));
9093
cudaMemset(devIntersections, 0, pixelcount * sizeof(Intersection));
94+
devIntersectionsThr = thrust::device_ptr<Intersection>(devIntersections);
95+
96+
cudaMalloc(&devIntersecMatKeys, pixelcount * sizeof(int));
97+
cudaMalloc(&devSegmentMatKeys, pixelcount * sizeof(int));
98+
devIntersecMatKeysThr = thrust::device_ptr<int>(devIntersecMatKeys);
99+
devSegmentMatKeysThr = thrust::device_ptr<int>(devSegmentMatKeys);
91100

92101
checkCUDAError("pathTraceInit");
93102
}
@@ -97,6 +106,8 @@ void pathTraceFree() {
97106
cudaFree(devPaths);
98107
cudaFree(devTerminatedPaths);
99108
cudaFree(devIntersections);
109+
cudaFree(devIntersecMatKeys);
110+
cudaFree(devSegmentMatKeys);
100111
}
101112

102113
/**
@@ -152,17 +163,23 @@ __global__ void computeIntersections(
152163
int numPaths,
153164
PathSegment* pathSegments,
154165
DevScene* scene,
155-
Intersection* intersections
166+
Intersection* intersections,
167+
int* materialKeys,
168+
bool sortMaterial
156169
) {
157170
int pathIdx = blockIdx.x * blockDim.x + threadIdx.x;
158171

159-
if (pathIdx < numPaths) {
160-
#if BVH_DEBUG_VISUALIZATION
161-
scene->visualizedIntersect(pathSegments[pathIdx].ray, intersections[pathIdx]);
162-
#else
172+
if (pathIdx >= numPaths) {
173+
return;
174+
}
175+
163176
Intersection intersec;
164177
PathSegment segment = pathSegments[pathIdx];
178+
#if BVH_DISABLE
179+
scene->naiveIntersect(segment.ray, intersec);
180+
#else
165181
scene->intersect(segment.ray, intersec);
182+
#endif
166183

167184
if (intersec.primId != NullPrimitive) {
168185
if (scene->devMaterials[intersec.matId].type == Material::Type::Light) {
@@ -176,15 +193,20 @@ __global__ void computeIntersections(
176193
// If not first ray, preserve previous sampling information for
177194
// MIS calculation
178195
intersec.prevPos = segment.ray.origin;
196+
intersec.prev = segment.prev;
179197
}
180198
}
181199
else {
182200
intersec.wo = -segment.ray.direction;
183201
}
202+
if (sortMaterial) {
203+
materialKeys[pathIdx] = intersec.matId;
204+
}
184205
}
185-
intersections[pathIdx] = intersec;
186-
#endif
206+
else if (sortMaterial) {
207+
materialKeys[pathIdx] = -1;
187208
}
209+
intersections[pathIdx] = intersec;
188210
}
189211

190212
__global__ void computeTerminatedRays(
@@ -248,17 +270,19 @@ __global__ void pathIntegSampleSurface(
248270
glm::vec3 accRadiance(0.f);
249271

250272
if (material.type == Material::Type::Light) {
273+
PrevBSDFSampleInfo prev = intersec.prev;
274+
251275
glm::vec3 radiance = material.baseColor * material.emittance;
252276
if (depth == 0) {
253277
accRadiance += radiance;
254278
}
255-
else if (segment.deltaSample) {
279+
else if (prev.deltaSample) {
256280
accRadiance += radiance * segment.throughput;
257281
}
258282
else {
259283
float lightPdf = Math::pdfAreaToSolidAngle(Math::luminance(radiance) * scene->sumLightPowerInv,
260284
intersec.prevPos, intersec.pos, intersec.norm);
261-
float BSDFPdf = segment.BSDFPdf;
285+
float BSDFPdf = prev.BSDFPdf;
262286
accRadiance += radiance * segment.throughput * Math::powerHeuristic(BSDFPdf, lightPdf);
263287
}
264288
segment.remainingBounces = 0;
@@ -293,8 +317,7 @@ __global__ void pathIntegSampleSurface(
293317
segment.throughput *= sample.bsdf / sample.pdf *
294318
(deltaSample ? 1.f : Math::absDot(intersec.norm, sample.dir));
295319
segment.ray = makeOffsetedRay(intersec.pos, sample.dir);
296-
segment.BSDFPdf = sample.pdf;
297-
segment.deltaSample = deltaSample;
320+
segment.prev = { sample.pdf, deltaSample };
298321
segment.remainingBounces--;
299322
}
300323
}
@@ -403,14 +426,22 @@ void pathTrace(uchar4* pbo, int frame, int iter) {
403426
numPaths,
404427
devPaths,
405428
hstScene->devScene,
406-
devIntersections
429+
devIntersections,
430+
devIntersecMatKeys,
431+
Settings::sortMaterial
407432
);
408433
checkCUDAError("PT::computeInteractions");
409434
cudaDeviceSynchronize();
410435

411436
// TODO: compare between directly shading the path segments and shading
412437
// path segments that have been reshuffled to be contiguous in memory.
413438

439+
if (Settings::sortMaterial) {
440+
cudaMemcpyDevToDev(devSegmentMatKeys, devIntersecMatKeys, numPaths * sizeof(int));
441+
thrust::sort_by_key(devIntersecMatKeysThr, devIntersecMatKeysThr + numPaths, devIntersectionsThr);
442+
thrust::sort_by_key(devSegmentMatKeysThr, devSegmentMatKeysThr + numPaths, devPathsThr);
443+
}
444+
414445
pathIntegSampleSurface<<<numBlocksPathSegmentTracing, blockSize1D>>>(
415446
iter, depth, devPaths, devIntersections, hstScene->devScene, numPaths
416447
);
@@ -440,7 +471,7 @@ void pathTrace(uchar4* pbo, int frame, int iter) {
440471
///////////////////////////////////////////////////////////////////////////
441472

442473
// Send results to OpenGL buffer for rendering
443-
sendImageToPBO<<<blocksPerGrid2D, blockSize2D>>>(pbo, cam.resolution, iter, devImage, ToneMapping::method);
474+
sendImageToPBO<<<blocksPerGrid2D, blockSize2D>>>(pbo, cam.resolution, iter, devImage, Settings::toneMapping);
444475

445476
// Retrieve image from GPU
446477
cudaMemcpy(hstScene->state.image.data(), devImage,

src/pathtrace.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,7 @@
33
#include <device_launch_parameters.h>
44
#include <vector>
55
#include "scene.h"
6-
7-
class ToneMapping {
8-
public:
9-
enum {
10-
None = 0, Filmic = 1, ACES = 2
11-
};
12-
static int method;
13-
};
6+
#include "common.h"
147

158
void InitDataContainer(GuiDataContainer* guiData);
169
void pathTraceInit(Scene *scene);

src/preview.cpp

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -210,24 +210,18 @@ void RenderImGui()
210210
static float f = 0.0f;
211211
static int counter = 0;
212212

213-
ImGui::Begin("Path Tracer Analytics"); // Create a window called "Hello, world!" and append into it.
214-
215-
// LOOK: Un-Comment to check the output window and usage
216-
//ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
217-
//ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
218-
//ImGui::Checkbox("Another Window", &show_another_window);
219-
220-
//ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
221-
//ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
222-
223-
//if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
224-
// counter++;
225-
//ImGui::SameLine();
226-
//ImGui::Text("counter = %d", counter);
227-
ImGui::Text("Traced Depth %d", imguiData->TracedDepth);
228-
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
229-
ImGui::End();
213+
ImGui::Begin("Path Tracer Analytics"); {
214+
ImGui::Text("Traced Depth %d", imguiData->TracedDepth);
215+
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
230216

217+
ImGui::End();
218+
}
219+
220+
ImGui::Begin("Options"); {
221+
ImGui::Checkbox("Sort material", &Settings::sortMaterial);
222+
223+
ImGui::End();
224+
}
231225

232226
ImGui::Render();
233227
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

src/preview.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "common.h"
4+
35
extern GLuint pbo;
46

57
std::string currentTimeString();

src/scene.h

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,7 @@
1515
#include "image.h"
1616
#include "bvh.h"
1717
#include "sampler.h"
18-
19-
#define MESH_DATA_STRUCT_OF_ARRAY false
20-
#define MESH_DATA_INDEXED false
21-
22-
#define DEV_SCENE_PASS_BY_CONST_MEM false
23-
24-
#define SCENE_LIGHT_SINGLE_SIDED true
18+
#include "common.h"
2519

2620
struct MeshData {
2721
void clear() {
@@ -190,6 +184,24 @@ struct DevScene {
190184
}
191185
}
192186

187+
__device__ bool naiveTestOcclusion(glm::vec3 x, glm::vec3 y) {
188+
const float Eps = 1e-4f;
189+
190+
glm::vec3 dir = y - x;
191+
float dist = glm::length(dir);
192+
dir /= dist;
193+
dist -= Eps;
194+
195+
Ray ray = makeOffsetedRay(x, dir);
196+
197+
for (int i = 0; i < (BVHSize + 1) / 2; i++) {
198+
if (intersectPrimitive(i, ray, dist)) {
199+
return true;
200+
}
201+
}
202+
return false;
203+
}
204+
193205
__device__ void intersect(Ray ray, Intersection& intersec) {
194206
float closestDist = FLT_MAX;
195207
int closestPrimId = NullPrimitive;
@@ -243,7 +255,6 @@ struct DevScene {
243255
dist -= Eps;
244256

245257
Ray ray = makeOffsetedRay(x, dir);
246-
bool hit = false;
247258

248259
MTBVHNode* nodes = devBVHNodes[getMTBVHId(-ray.direction)];
249260
int node = 0;
@@ -255,15 +266,17 @@ struct DevScene {
255266
if (boundHit && boundDist < dist) {
256267
int primId = nodes[node].primitiveId;
257268
if (primId != NullPrimitive) {
258-
hit |= intersectPrimitive(primId, ray, dist);
269+
if (intersectPrimitive(primId, ray, dist)) {
270+
return true;
271+
}
259272
}
260273
node++;
261274
}
262275
else {
263276
node = nodes[node].nextNodeIfMiss;
264277
}
265278
}
266-
return hit;
279+
return false;
267280
}
268281

269282
__device__ void visualizedIntersect(Ray ray, Intersection& intersec) {
@@ -323,7 +336,12 @@ struct DevScene {
323336
glm::vec3 v2 = devVertices[primId * 3 + 2];
324337
glm::vec3 sampled = Math::sampleTriangleUniform(v0, v1, v2, r.z, r.w);
325338

326-
if (testOcclusion(pos, sampled)) {
339+
#if BVH_DISABLE
340+
bool occ = naiveTestOcclusion(pos, sampled);
341+
#else
342+
bool occ = testOcclusion(pos, sampled);
343+
#endif
344+
if (occ) {
327345
return InvalidPdf;
328346
}
329347
glm::vec3 normal = Math::triangleNormal(v0, v1, v2);

0 commit comments

Comments
 (0)