glutPostRedisplay调用显示方法但不重绘窗口

时间:2014-03-13 02:05:11

标签: opengl cuda

我正在编写一个程序来绘制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。

1 个答案:

答案 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上下文消失时被释放。