April 2013
Real time visualization of 3D vector field with CUDA
2 Prerequisites
2.1 Dataset
2.2 Loading input
1 2 3 4 5 6 7 8 9 | NRRD0001 type: float dimension: 4 sizes: 3 800 400 300 spacings: 1 1.0012515783 1.0025062561 0.50167226791 axis mins: 0 -150 -200 -50 labels: "Vx;Vy;Vz" "x" "y" "z" endian: little encoding: raw |
1 2 3 4 5 6 7 8 9 10 11 12 13 | std::ifstream inputStream(filePath, std::ios::binary); // Reading of header information skipped. // ... float3 size initialized with size of VF size_t totalSize = size.x * size.y * size.z; float4* data = new float4[totalSize]; for (size_t i = 0; i < totalSize; ++i) { float4* f4Ptr = &(data[i]); // Read x, y, z. inputStream.read((char*)f4Ptr, sizeof(float3)); // Compute magnitude as w. curr->w = std::sqrtf(f4Ptr->x * f4Ptr->x + f4Ptr->y * f4Ptr->y + f4Ptr->z * f4Ptr->z); } |
2.3 Fast reading of volumetric data using CUDA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | texture<float4, cudaTextureType3D, cudaReadModeElementType> vectorFieldTex; cudaArray* d_volumeArray = nullptr; void initCuda(const float4* h_volume, cudaExtent volumeSize) { // Allocate 3D array. cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float4>(); cudaMalloc3DArray(&d_volumeArray, &channelDesc, volumeSize); // Copy data to 3D array using pitched ptr. cudaMemcpy3DParms copyParams = {0}; copyParams.srcPtr = make_cudaPitchedPtr((void*)h_volume, volumeSize.width * sizeof(float4), volumeSize.width, volumeSize.height); copyParams.dstArray = d_volumeArray; copyParams.extent = volumeSize; copyParams.kind = cudaMemcpyHostToDevice; // Set texture parameters. vectorFieldTex.normalized = false; vectorFieldTex.filterMode = cudaFilterModeLinear; vectorFieldTex.addressMode[0] = cudaAddressModeClamp; vectorFieldTex.addressMode[1] = cudaAddressModeClamp; vectorFieldTex.addressMode[2] = cudaAddressModeClamp; // Bind 3D array to 3D texture. cudaBindTextureToArray(vectorFieldTex, d_volumeArray, channelDesc); } |
2.4 Color gradient for magnitude visualization
Figure 2: Color gradient used for visualization of vector magnitudes
2.5 OpenGL CUDA interoperability
1 2 3 4 5 6 7 8 9 | cudaError_t createCudaSharedVbo(GLuint* vbo, GLenum target, uint size, cudaGraphicsResource** cudaResource) { glGenBuffers(1, vbo); glBindBuffer(target, *vbo); glBufferData(target, size, 0, GL_DYNAMIC_DRAW); glBindBuffer(target, 0); return cudaGraphicsGLRegisterBuffer(cudaResource, *vbo, cudaGraphicsMapFlagsNone); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | void allocate() { createCudaSharedVbo(&m_verticesVbo, GL_ARRAY_BUFFER, verticesCount * sizeof(float3), &m_cudaVerticesVboResource); createCudaSharedVbo(&m_colorsVbo, GL_ARRAY_BUFFER, verticesCount * sizeof(float3), &m_cudaColorsVboResource); } void recompute() { size_t bytesCount; float3* d_glyphs; cudaGraphicsMapResources(1, &m_cudaVerticesVboResource); cudaGraphicsResourceGetMappedPointer((void**)&d_glyphs, &bytesCount, m_cudaVerticesVboResource); float3* d_colors; cudaGraphicsMapResources(1, &m_cudaColorsVboResource); cudaGraphicsResourceGetMappedPointer((void**)&d_colors, &bytesCount, m_cudaColorsVboResource); runCudaKernel(..., d_glyphs, d_colors, m_glyphsCount, ...); cudaGraphicsUnmapResources(1, &m_cudaColorsVboResource); cudaGraphicsUnmapResources(1, &m_cudaVerticesVboResource); } void displayCallback() { glBindBuffer(GL_ARRAY_BUFFER, m_verticesVbo); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, m_colorsVbo); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(3, GL_FLOAT, 0, NULL); glDrawArrays(GL_LINES, 0, 2 * m_glyphsCount.x * m_glyphsCount.y); } |