我正在编写一个程序来绘制3D曲面图。它使用CUDA进行渲染,然后使用OpenGL来显示结果。它工作正常并呈现漂亮而准确的结果,但它无法正确更新窗口。这是我的伪代码程序:
void display() {
//render stuff
glutSwapBuffers();
glutPostRedisplay();
}
int main() {
//set up OpenGL and CUDA
glutMainLoop();
return 0;
}
这应该不断更新,但它没有。它正确调用显示方法并且CUDA呈现结果,但在窗口调整大小之前它不会在窗口中显示结果。因此它将显示功能称为每秒30次,但窗口在调整大小或最小化之前实际上并未显示结果。
这是我的整个计划。因为我一直在学习OpenGL,所以它非常混乱,没有任何评论。
#define GL_GLEXT_PROTOTYPES
#include <GL/freeglut_std.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <stdlib.h>
#include <stdio.h>
#include <cuda_gl_interop.h>
#define XSIZE 1280
#define YSIZE 640
float theta = .15;
float phi = 1;
float r = 10;
float3 lightDirection = make_float3(9, 5, -5);
float delta = .001;
GLuint pbo; // OpenGL pixel buffer object
struct cudaGraphicsResource *cuda_pbo_resource; // handles OpenGL-CUDA exchange
GLuint texid; // Texture
GLuint shader;
__host__ __device__ float3 operator+(float3 a, float3 b) {
return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);
}
__host__ __device__ float3 operator-(float3 a, float3 b) {
return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);
}
__host__ __device__ float3 operator*(float3 a, float b) {
return make_float3(a.x * b, a.y * b, a.z * b);
}
__host__ __device__ float3 operator/(float3 a, float b) {
return make_float3(a.x / b, a.y / b, a.z / b);
}
__host__ __device__ float operator*(float3 a, float3 b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
__host__ __device__ float magnitude(float3 a) {
return std::sqrt(a * a);
}
__host__ __device__ float3 normalize(float3 a) {
return a / magnitude(a);
}
__device__ float valueAt(float3 a) {
return std::sin(a.x) + std::sin(a.y) + std::sin(a.z);
}
__device__ float3 normalAt(float3 a) {
float x = valueAt(make_float3(a.x + .001, a.y, a.z)) - valueAt(a);
float y = valueAt(make_float3(a.x, a.y + .001, a.z)) - valueAt(a);
float z = valueAt(make_float3(a.x, a.y, a.z + .001)) - valueAt(a);
return make_float3(x, y, z) / .001;
}
__device__ float estimateDistance(float3 a) {
return std::abs(valueAt(a) / magnitude(normalAt(a)));
}
__device__ float3 trace(float3 from, float3 direction) {
float totalDistance = 0;
float3 v = from;
for(int steps = 0; steps < 256; steps++) {
if(magnitude(v) < 5) break;
totalDistance += 1;
v = from + direction * totalDistance;
}
for(int steps = 0; steps < 256; steps++) {
v = from + direction * totalDistance;
float distance = estimateDistance(v);
totalDistance += distance * .1;
if(distance < .1 && magnitude(v) < 5) return v;
}
return make_float3(0, 0, 0);
}
__device__ uchar4 colorAt(float3 v, float3 lightDirection, float3 viewDirection) {
float3 normal = normalize(normalAt(v));
float3 h = normalize(viewDirection + lightDirection);
float specular = std::abs(std::pow(h * normal, 15)) * .5;
float diffuse = std::abs(lightDirection * normal) * .5;
float lighting = (specular + diffuse) * .9;
lighting += .1;
float3 color;
if((fmod(v.x + 1000, 1) < .5 && fmod(v.y + 1000, 1) < .5) || (fmod(v.x + 1000, 1) > .5 && fmod(v.y + 1000, 1) > .5)) {
color.x = 1;
color.y = .5;
color.z = .25;
}
else {
color.x = .75;
color.y = .5;
color.z = .25;
}
color = color * lighting;
return make_uchar4((unsigned char)(color.x * 255), (unsigned char)(color.y * 255), (unsigned char)(color.z * 255), 255);
}
__global__ void eval(float3 position, float3 direction, float3 right, float3 up, float3 lightDirection, float delta, uchar4* dev_pixels) {
int x = blockIdx.x * blockDim.x + threadIdx.x;
int y = blockIdx.y * blockDim.y + threadIdx.y;
int offset = x + y * XSIZE;
float rAngle = (x - XSIZE / 2) * delta;
float uAngle = (-y + YSIZE / 2) * delta;
float3 rayDirection = direction + right * rAngle + up * uAngle;
rayDirection = normalize(rayDirection);
float3 v = trace(position, rayDirection);
uchar4 color;
if(magnitude(v) != 0) color = colorAt(v, lightDirection, direction);
dev_pixels[offset] = color;
}
void display() {
uchar4* dev_pixels;
cudaGLRegisterBufferObject(pbo);
cudaGLMapBufferObject((void**)&dev_pixels, pbo);
dim3 dim_block(16, 16);
dim3 dim_grid(XSIZE / 16, YSIZE / 16);
float3 position = make_float3(std::cos(theta) * std::sin(phi) * r, std::sin(theta) * std::sin(phi) * r, std::cos(phi) * r);
float3 direction = normalize(position) * -1;
float3 right = make_float3(-std::sin(theta), std::cos(theta), 0);
right = normalize(right);
float3 up = make_float3(-std::cos(phi) * std::cos(theta), -std::cos(phi) * std::sin(theta), std::sin(phi));
up = normalize(up);
eval<<<dim_grid, dim_block>>>(position, direction, right, up, lightDirection, delta, dev_pixels);
cudaGLUnmapBufferObject(pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBindTexture(GL_TEXTURE_2D, texid);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, XSIZE, YSIZE, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBegin(GL_QUADS);
glTexCoord2f(0.0f,1.0f); glVertex3f(0.0f,0.0f,0.0f);
glTexCoord2f(0.0f,0.0f); glVertex3f(0.0f,1.0f,0.0f);
glTexCoord2f(1.0f,0.0f); glVertex3f(1.0f,1.0f,0.0f);
glTexCoord2f(1.0f,1.0f); glVertex3f(1.0f,0.0f,0.0f);
glEnd();
glutSwapBuffers();
theta += .01;
glutPostRedisplay();
}
int main(int argc, char **argv) {
lightDirection = normalize(lightDirection);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(XSIZE, YSIZE);
glutCreateWindow("Grapher");
glutDisplayFunc(display);
glViewport(0, 0, XSIZE, YSIZE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1.0f, 0, 1.0f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.5f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, XSIZE * YSIZE * 4, NULL, GL_DYNAMIC_COPY);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texid);
glBindTexture(GL_TEXTURE_2D, texid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, XSIZE, YSIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glutMainLoop();
return 0;
}
我在Ubuntu 12.04上使用了NSight Eclipse。
答案 0 :(得分:3)
在display
例程结束时,添加以下两行:
...
glTexCoord2f(1.0f,1.0f); glVertex3f(1.0f,0.0f,0.0f);
glEnd();
glutSwapBuffers();
glClear(GL_DEPTH_BUFFER_BIT); // add this line
cudaGLUnregisterBufferObject(pbo); // add this line
theta += .01;
glutPostRedisplay();
...
第一次添加允许动画逐帧进行。 (第一帧之后的帧将正确呈现。)
第二次添加使得如果关闭动画窗口,则不会出现seg错误。在释放基础OpenGL资源之前,必须在任何先前注册的对象上调用cudaGLUnregisterBufferObject
(否则会出现seg错误)。当您单击X关闭窗口时,OpenGL缓冲区对象(pbo
)将在OpenGL上下文消失时被释放。