/* * Copyright 1993-2015 NVIDIA Corporation. All rights reserved. * * Please refer to the NVIDIA end user license agreement (EULA) associated * with this source code for terms and conditions that govern your use of * this software. Any use, reproduction, disclosure, or distribution of * this software and related documentation outside the terms of the EULA * is strictly prohibited. * */ /* Volume rendering sample This sample loads a 3D volume from disk and displays it using ray marching and 3D textures. Note - this is intended to be an example of using 3D textures in CUDA, not an optimized volume renderer. Changes sgg 22/3/2010 - updated to use texture for display instead of glDrawPixels. - changed to render from front-to-back rather than back-to-front. */ // OpenGL Graphics includes #include #if defined (__APPLE__) || defined(MACOSX) #pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #ifndef glutCloseFunc #define glutCloseFunc glutWMCloseFunc #endif #else #include #endif // CUDA Runtime, Interop, and includes #include #include #include #include #include #include // CUDA utilities #include // Helper functions #include #include #include typedef unsigned int uint; typedef unsigned char uchar; #define MAX_EPSILON_ERROR 5.00f #define THRESHOLD 0.30f // Define the files that are to be save and the reference images for validation const char *sOriginal[] = { "volume.ppm", NULL }; const char *sReference[] = { "ref_volume.ppm", NULL }; const char *sSDKsample = "CUDA 3D Volume Render"; const char *volumeFilename = "Bucky.raw"; cudaExtent volumeSize = make_cudaExtent(32, 32, 32); typedef unsigned char VolumeType; //char *volumeFilename = "mrt16_angio.raw"; //cudaExtent volumeSize = make_cudaExtent(416, 512, 112); //typedef unsigned short VolumeType; uint width = 512, height = 512; dim3 blockSize(16, 16); dim3 gridSize; float3 viewRotation; float3 viewTranslation = make_float3(0.0, 0.0, -4.0f); float invViewMatrix[12]; float density = 0.05f; float brightness = 1.0f; float transferOffset = 0.0f; float transferScale = 1.0f; bool linearFiltering = true; GLuint pbo = 0; // OpenGL pixel buffer object GLuint tex = 0; // OpenGL texture object struct cudaGraphicsResource *cuda_pbo_resource; // CUDA Graphics Resource (to transfer PBO) StopWatchInterface *timer = 0; // Auto-Verification Code const int frameCheckNumber = 2; int fpsCount = 0; // FPS count for averaging int fpsLimit = 1; // FPS limit for sampling int g_Index = 0; unsigned int frameCount = 0; int *pArgc; char **pArgv; #ifndef MAX #define MAX(a,b) ((a > b) ? a : b) #endif extern "C" void setTextureFilterMode(bool bLinearFilter); extern "C" void initCuda(void *h_volume, cudaExtent volumeSize); extern "C" void freeCudaBuffers(); extern "C" void render_kernel(dim3 gridSize, dim3 blockSize, uint *d_output, uint imageW, uint imageH, float density, float brightness, float transferOffset, float transferScale); extern "C" void copyInvViewMatrix(float *invViewMatrix, size_t sizeofMatrix); void initPixelBuffer(); void computeFPS() { frameCount++; fpsCount++; if (fpsCount == fpsLimit) { char fps[256]; float ifps = 1.f / (sdkGetAverageTimerValue(&timer) / 1000.f); sprintf(fps, "Volume Render: %3.1f fps", ifps); glutSetWindowTitle(fps); fpsCount = 0; fpsLimit = (int)MAX(1.f, ifps); sdkResetTimer(&timer); } } // render image using CUDA void render() { copyInvViewMatrix(invViewMatrix, sizeof(float4)*3); // map PBO to get CUDA device pointer uint *d_output; // map PBO to get CUDA device pointer checkCudaErrors(cudaGraphicsMapResources(1, &cuda_pbo_resource, 0)); size_t num_bytes; checkCudaErrors(cudaGraphicsResourceGetMappedPointer((void **)&d_output, &num_bytes, cuda_pbo_resource)); //printf("CUDA mapped PBO: May access %ld bytes\n", num_bytes); // clear image checkCudaErrors(cudaMemset(d_output, 0, width*height*4)); // call CUDA kernel, writing results to PBO render_kernel(gridSize, blockSize, d_output, width, height, density, brightness, transferOffset, transferScale); getLastCudaError("kernel failed"); checkCudaErrors(cudaGraphicsUnmapResources(1, &cuda_pbo_resource, 0)); } // display results using OpenGL (called by GLUT) void display() { sdkStartTimer(&timer); // use OpenGL to build view matrix GLfloat modelView[16]; glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glRotatef(-viewRotation.x, 1.0, 0.0, 0.0); glRotatef(-viewRotation.y, 0.0, 1.0, 0.0); glTranslatef(-viewTranslation.x, -viewTranslation.y, -viewTranslation.z); glGetFloatv(GL_MODELVIEW_MATRIX, modelView); glPopMatrix(); invViewMatrix[0] = modelView[0]; invViewMatrix[1] = modelView[4]; invViewMatrix[2] = modelView[8]; invViewMatrix[3] = modelView[12]; invViewMatrix[4] = modelView[1]; invViewMatrix[5] = modelView[5]; invViewMatrix[6] = modelView[9]; invViewMatrix[7] = modelView[13]; invViewMatrix[8] = modelView[2]; invViewMatrix[9] = modelView[6]; invViewMatrix[10] = modelView[10]; invViewMatrix[11] = modelView[14]; render(); // display results glClear(GL_COLOR_BUFFER_BIT); // draw image from PBO glDisable(GL_DEPTH_TEST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #if 0 // draw using glDrawPixels (slower) glRasterPos2i(0, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); #else // draw using texture // copy from pbo to texture glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); glBindTexture(GL_TEXTURE_2D, tex); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); // draw textured quad glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(0, 0); glTexCoord2f(1, 0); glVertex2f(1, 0); glTexCoord2f(1, 1); glVertex2f(1, 1); glTexCoord2f(0, 1); glVertex2f(0, 1); glEnd(); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); #endif glutSwapBuffers(); glutReportErrors(); sdkStopTimer(&timer); computeFPS(); } void idle() { glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case 27: #if defined (__APPLE__) || defined(MACOSX) exit(EXIT_SUCCESS); #else glutDestroyWindow(glutGetWindow()); return; #endif break; case 'f': linearFiltering = !linearFiltering; setTextureFilterMode(linearFiltering); break; case '+': density += 0.01f; break; case '-': density -= 0.01f; break; case ']': brightness += 0.1f; break; case '[': brightness -= 0.1f; break; case ';': transferOffset += 0.01f; break; case '\'': transferOffset -= 0.01f; break; case '.': transferScale += 0.01f; break; case ',': transferScale -= 0.01f; break; default: break; } printf("density = %.2f, brightness = %.2f, transferOffset = %.2f, transferScale = %.2f\n", density, brightness, transferOffset, transferScale); glutPostRedisplay(); } int ox, oy; int buttonState = 0; void mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) { buttonState |= 1<