mirror of
https://github.com/mmp/pbrt-v4
synced 2026-09-27 00:29:35 +03:00
record frames / print camera WIP
This commit is contained in:
parent
9e0c78621c
commit
d70dce2e1e
4 changed files with 110 additions and 27 deletions
|
|
@ -63,12 +63,13 @@ class CUDAOutputBuffer {
|
|||
void setDevice(int32_t device_idx) { m_device_idx = device_idx; }
|
||||
void setStream(CUstream stream) { m_stream = stream; }
|
||||
|
||||
void resize(int32_t width, int32_t height);
|
||||
|
||||
// Allocate or update device pointer as necessary for CUDA access
|
||||
PIXEL_FORMAT* map();
|
||||
PIXEL_FORMAT *map();
|
||||
void unmap();
|
||||
|
||||
void StartAsynchronousReadback();
|
||||
const PIXEL_FORMAT *GetReadbackPixels();
|
||||
|
||||
int32_t width() const { return m_width; }
|
||||
int32_t height() const { return m_height; }
|
||||
|
||||
|
|
@ -82,9 +83,13 @@ class CUDAOutputBuffer {
|
|||
int32_t m_width = 0u;
|
||||
int32_t m_height = 0u;
|
||||
|
||||
cudaGraphicsResource* m_cuda_gfx_resource = nullptr;
|
||||
cudaGraphicsResource *m_cuda_gfx_resource = nullptr;
|
||||
GLuint m_pbo = 0u;
|
||||
PIXEL_FORMAT* m_device_pixels = nullptr;
|
||||
PIXEL_FORMAT *m_device_pixels = nullptr;
|
||||
PIXEL_FORMAT *m_host_pixels = nullptr;
|
||||
|
||||
bool readbackActive = false;
|
||||
cudaEvent_t readbackFinishedEvent;
|
||||
|
||||
CUstream m_stream = 0u;
|
||||
int32_t m_device_idx = 0;
|
||||
|
|
@ -102,26 +107,6 @@ CUDAOutputBuffer<PIXEL_FORMAT>::CUDAOutputBuffer(int32_t width, int32_t height)
|
|||
if (!is_display_device)
|
||||
LOG_FATAL("GL interop is only available on display device.");
|
||||
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
template <typename PIXEL_FORMAT>
|
||||
CUDAOutputBuffer<PIXEL_FORMAT>::~CUDAOutputBuffer() {
|
||||
makeCurrent();
|
||||
|
||||
if (m_pbo != 0u) {
|
||||
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL_CHECK(glDeleteBuffers(1, &m_pbo));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PIXEL_FORMAT>
|
||||
void CUDAOutputBuffer<PIXEL_FORMAT>::resize(int32_t width, int32_t height) {
|
||||
CHECK(width > 0 && height > 0);
|
||||
|
||||
if (m_width == width && m_height == height)
|
||||
return;
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
|
|
@ -136,6 +121,19 @@ void CUDAOutputBuffer<PIXEL_FORMAT>::resize(int32_t width, int32_t height) {
|
|||
|
||||
CUDA_CHECK(cudaGraphicsGLRegisterBuffer(&m_cuda_gfx_resource, m_pbo,
|
||||
cudaGraphicsMapFlagsWriteDiscard));
|
||||
|
||||
CUDA_CHECK(cudaEventCreate(&readbackFinishedEvent));
|
||||
CUDA_CHECK(cudaMallocHost(&m_host_pixels, m_width * m_height * sizeof(PIXEL_FORMAT)));
|
||||
}
|
||||
|
||||
template <typename PIXEL_FORMAT>
|
||||
CUDAOutputBuffer<PIXEL_FORMAT>::~CUDAOutputBuffer() {
|
||||
makeCurrent();
|
||||
|
||||
if (m_pbo != 0u) {
|
||||
GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
GL_CHECK(glDeleteBuffers(1, &m_pbo));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PIXEL_FORMAT>
|
||||
|
|
@ -171,6 +169,31 @@ void CUDAOutputBuffer<PIXEL_FORMAT>::deletePBO() {
|
|||
m_pbo = 0;
|
||||
}
|
||||
|
||||
template <typename PIXEL_FORMAT>
|
||||
void CUDAOutputBuffer<PIXEL_FORMAT>::StartAsynchronousReadback() {
|
||||
CHECK(!readbackActive);
|
||||
|
||||
makeCurrent();
|
||||
|
||||
CUDA_CHECK(cudaMemcpyAsync(m_host_pixels, m_device_pixels,
|
||||
m_width * m_height * sizeof(PIXEL_FORMAT),
|
||||
cudaMemcpyDeviceToHost));
|
||||
CUDA_CHECK(cudaEventRecord(readbackFinishedEvent));
|
||||
readbackActive = true;
|
||||
}
|
||||
|
||||
template <typename PIXEL_FORMAT>
|
||||
const PIXEL_FORMAT *CUDAOutputBuffer<PIXEL_FORMAT>::GetReadbackPixels() {
|
||||
if (!readbackActive)
|
||||
return nullptr;
|
||||
|
||||
makeCurrent();
|
||||
|
||||
CUDA_CHECK(cudaEventSynchronize(readbackFinishedEvent));
|
||||
readbackActive = false;
|
||||
return m_host_pixels;
|
||||
}
|
||||
|
||||
} // end namespace pbrt
|
||||
|
||||
#endif // PBRT_GPU_CUDAGL_H
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
#include <pbrt/gpu/util.h>
|
||||
#endif PBRT_BUILD_GPU_RENDERER
|
||||
#include <pbrt/util/error.h>
|
||||
#include <pbrt/util/image.h>
|
||||
#include <pbrt/util/parallel.h>
|
||||
|
||||
#define GL_CHECK(call) \
|
||||
do { \
|
||||
|
|
@ -297,7 +299,7 @@ static void glfwErrorCallback(int error, const char* desc) {
|
|||
LOG_ERROR("GLFW [%d]: %s", error, desc);
|
||||
}
|
||||
|
||||
void GUI::keyboardCallback(GLFWwindow* window, int key, int scan, int action, int mods) {
|
||||
void GUI::keyboardCallback(GLFWwindow *window, int key, int scan, int action, int mods) {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
|
||||
|
|
@ -318,14 +320,22 @@ void GUI::keyboardCallback(GLFWwindow* window, int key, int scan, int action, in
|
|||
doKey(GLFW_KEY_W, 'w');
|
||||
doKey(GLFW_KEY_Q, 'q');
|
||||
doKey(GLFW_KEY_E, 'e');
|
||||
|
||||
doKey(GLFW_KEY_B, (mods & GLFW_MOD_SHIFT) ? 'B' : 'b');
|
||||
doKey(GLFW_KEY_R, 'r');
|
||||
doKey(GLFW_KEY_C, 'c');
|
||||
doKey(GLFW_KEY_EQUAL, '=');
|
||||
doKey(GLFW_KEY_MINUS, '-');
|
||||
|
||||
doKey(GLFW_KEY_LEFT, 'L');
|
||||
doKey(GLFW_KEY_RIGHT, 'R');
|
||||
doKey(GLFW_KEY_UP, 'U');
|
||||
doKey(GLFW_KEY_DOWN, 'D');
|
||||
|
||||
if (key == GLFW_KEY_R && action == GLFW_PRESS &&
|
||||
glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS)
|
||||
recordFrames = !recordFrames;
|
||||
else
|
||||
doKey(GLFW_KEY_R, 'r');
|
||||
}
|
||||
|
||||
bool GUI::processKeys() {
|
||||
|
|
@ -361,6 +371,10 @@ bool GUI::processKeys() {
|
|||
handleNeedsReset('r', [&](Transform t) { return Transform(); });
|
||||
|
||||
// No reset needed for these.
|
||||
if (keysDown.find('c') != keysDown.end()) {
|
||||
keysDown.erase(keysDown.find('c'));
|
||||
printCameraTransform = true;
|
||||
}
|
||||
if (keysDown.find('b') != keysDown.end()) {
|
||||
keysDown.erase(keysDown.find('b'));
|
||||
exposure *= 1.125f;
|
||||
|
|
@ -452,6 +466,34 @@ DisplayState GUI::RefreshDisplay() {
|
|||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
||||
if (recordFrames) {
|
||||
const RGB *fb = nullptr;
|
||||
#ifdef PBRT_BUILD_GPU_RENDERER
|
||||
if (cudaFramebuffer)
|
||||
fb = cudaFramebuffer->GetReadbackPixels();
|
||||
else
|
||||
#endif
|
||||
fb = cpuFramebuffer;
|
||||
|
||||
if (fb) {
|
||||
Image image(PixelFormat::Float, {width, height}, {"R", "G", "B"});
|
||||
std::memcpy(image.RawPointer({0, 0}), fb, width * height * sizeof(RGB));
|
||||
|
||||
//CO RunAsync([](Image image, int frameNumber) {
|
||||
// TODO: set metadata for e.g. current camera position...
|
||||
ImageMetadata metadata;
|
||||
image.Write(StringPrintf("pbrt-frame%05d.exr", frameNumber), metadata);
|
||||
//CO return 0; // FIXME: RunAsync() doesn't like lambdas that return void..
|
||||
//CO }, std::move(image), frameNumber);
|
||||
|
||||
++frameNumber;
|
||||
}
|
||||
#ifdef PBRT_BUILD_GPU_RENDERER
|
||||
if (cudaFramebuffer)
|
||||
cudaFramebuffer->StartAsynchronousReadback();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (glfwWindowShouldClose(window))
|
||||
return DisplayState::EXIT;
|
||||
else if (processKeys())
|
||||
|
|
|
|||
|
|
@ -48,8 +48,12 @@ class GUI {
|
|||
|
||||
DisplayState RefreshDisplay();
|
||||
|
||||
// It's a little messy that the state of values controlled via the UI
|
||||
// are just public variables here but it's probably not worth putting
|
||||
// an abstraction layer on top of all this at this point.
|
||||
Transform GetCameraTransform() const { return movingFromCamera; }
|
||||
Float exposure = 1.f;
|
||||
bool printCameraTransform = false;
|
||||
|
||||
void keyboardCallback(GLFWwindow *window, int key, int scan, int action, int mods);
|
||||
|
||||
|
|
@ -60,6 +64,8 @@ class GUI {
|
|||
Float moveScale = 1.f;
|
||||
Transform movingFromCamera;
|
||||
Vector2i resolution;
|
||||
bool recordFrames = false;
|
||||
int frameNumber = 0;
|
||||
|
||||
#ifdef PBRT_BUILD_GPU_RENDERER
|
||||
CUDAOutputBuffer<RGB> *cudaFramebuffer = nullptr;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include <pbrt/wavefront/aggregate.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
|
@ -293,6 +294,7 @@ Float WavefrontPathIntegrator::Render() {
|
|||
// FIXME: camera animation; whatever...
|
||||
Transform renderFromCamera = camera.GetCameraTransform().RenderFromCamera().startTransform;
|
||||
Transform cameraFromRender = Inverse(renderFromCamera);
|
||||
Transform cameraFromWorld = camera.GetCameraTransform().CameraFromWorld(camera.SampleTime(0.f));
|
||||
if (Options->interactive) {
|
||||
if (!Options->displayServer.empty())
|
||||
ErrorExit("--interactive and --display-server cannot be used at the same time.");
|
||||
|
|
@ -432,6 +434,16 @@ Float WavefrontPathIntegrator::Render() {
|
|||
UpdateFramebufferFromFilm(pixelBounds, gui->exposure, rgb);
|
||||
gui->UnmapFramebuffer();
|
||||
|
||||
if (gui->printCameraTransform) {
|
||||
SquareMatrix<4> cfw = (Inverse(gui->GetCameraTransform()) * cameraFromWorld).GetMatrix();
|
||||
Printf("Current camera transform:\nTransform [ ");
|
||||
for (int i = 0; i < 16; ++i)
|
||||
Printf("%f ", cfw[i % 4][i / 4]);
|
||||
Printf("]\n");
|
||||
std::fflush(stdout);
|
||||
gui->printCameraTransform = false;
|
||||
}
|
||||
|
||||
DisplayState state = gui->RefreshDisplay();
|
||||
if (state == DisplayState::EXIT)
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue