2017-08-04 114 views
0

我想将3D对象加载到具有透明背景的OpenGL窗口中。我在配有Nvidia Quadro K3000M的Ubuntu 16.04机器上使用C++(安装的驱动程序是最新的375.66 NVIDIA二进制驱动程序)。我有两个目标独立工作 - 我可以创建一个透明背景的OpenGL窗口,从this thread X11和加载对象与Assimp和GLFW从this tutorial在透明背景的OpenGL窗口中加载带有assimp的对象

现在我想两者结合起来,它的作品至少一点 - 我可以导入的对象,并将其装入透明的X11窗口,但一些质地是透明的现在,这是奇怪的:

GLFW结果:

GLFW result

X11结果:

X11 result

所以为了清楚我的问题:我不明白为什么导入的对象在X11窗口内而不在GLFW窗口内有透明胶片。我正在寻找一种解决方案,该模型在X11窗口中正确显示(基本上它可以是任何窗口管理器,但X11似乎是唯一能够显示透明背景的窗口)。

我使用LearnOpenGL教程中的网格和模型类,以及它们的着色器。我希望@datenwolf也许能够提供帮助。这里是我的代码:

#include "GL/glew.h" 

#include <GL/gl.h> 
#include <GL/glx.h> 
#include <GL/glxext.h> 
#include <X11/Xatom.h> 
#include <X11/extensions/Xrender.h> 
#include <X11/Xutil.h> 

#include <GLFW/glfw3.h> 

#include <glm/glm.hpp> 
#include <glm/gtc/matrix_transform.hpp> 
#include <glm/gtc/type_ptr.hpp> 

#include <includes/learnopengl/filesystem.h> 
#include <includes/learnopengl/shader_m.h> 
#include <includes/learnopengl/camera.h> 
#include <includes/learnopengl/model.h> 

#include <iostream> 
//---------------------------- 
//----- RGBA X11 ------------- 
//---------------------------- 
#define USE_CHOOSE_FBCONFIG 

static void fatalError(const char *why) 
{ 
    fprintf(stderr, "%s", why); 
    exit(0x666); 
} 

static int Xscreen; 
static Atom del_atom; 
static Colormap cmap; 
static Display *Xdisplay; 
static XVisualInfo *visual; 
static XRenderPictFormat *pict_format; 
static GLXFBConfig *fbconfigs, fbconfig; 
static int numfbconfigs; 
static GLXContext render_context; 
static Window Xroot, window_handle; 
static GLXWindow glX_window_handle; 
static int width, height; 

std::string window_choice = "GLFW"; //X11 or GLFW 

static int VisData[] = { 
GLX_RENDER_TYPE, GLX_RGBA_BIT, 
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 
GLX_DOUBLEBUFFER, True, 
GLX_RED_SIZE, 8, 
GLX_GREEN_SIZE, 8, 
GLX_BLUE_SIZE, 8, 
GLX_ALPHA_SIZE, 8, 
GLX_DEPTH_SIZE, 16, 
None 
}; 

static int isExtensionSupported(const char *extList, const char *extension) 
{ 
    const char *start; 
    const char *where, *terminator; 

    /* Extension names should not have spaces. */ 
    where = strchr(extension, ' '); 
    if (where || *extension == '\0') 
    return 0; 

    /* It takes a bit of care to be fool-proof about parsing the 
    OpenGL extensions string. Don't be fooled by sub-strings, 
    etc. */ 
    for (start = extList; ;) { 
    where = strstr(start, extension); 

    if (!where) 
     break; 

    terminator = where + strlen(extension); 

    if (where == start || *(where - 1) == ' ') 
     if (*terminator == ' ' || *terminator == '\0') 
     return 1; 

    start = terminator; 
    } 
    return 0; 
} 

static Bool WaitForMapNotify(Display *d, XEvent *e, char *arg) 
{ 
    return d && e && arg && (e->type == MapNotify) && (e->xmap.window == *(Window*)arg); 
} 

static void describe_fbconfig(GLXFBConfig fbconfig) 
{ 
    int doublebuffer; 
    int red_bits, green_bits, blue_bits, alpha_bits, depth_bits; 

    glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_DOUBLEBUFFER, &doublebuffer); 
    glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_RED_SIZE, &red_bits); 
    glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_GREEN_SIZE, &green_bits); 
    glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_BLUE_SIZE, &blue_bits); 
    glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_ALPHA_SIZE, &alpha_bits); 
    glXGetFBConfigAttrib(Xdisplay, fbconfig, GLX_DEPTH_SIZE, &depth_bits); 

    fprintf(stderr, "FBConfig selected:\n" 
     "Doublebuffer: %s\n" 
     "Red Bits: %d, Green Bits: %d, Blue Bits: %d, Alpha Bits: %d, Depth Bits: %d\n", 
     doublebuffer == True ? "Yes" : "No", 
     red_bits, green_bits, blue_bits, alpha_bits, depth_bits); 
} 

static void createTheWindow() 
{ 
    XEvent event; 
    int x,y, attr_mask; 
    XSizeHints hints; 
    XWMHints *startup_state; 
    XTextProperty textprop; 
    XSetWindowAttributes attr = {0,}; 
    static char *title = "ARGB OpenGL Window"; 

    Xdisplay = XOpenDisplay(NULL); 
    if (!Xdisplay) { 
     fatalError("Couldn't connect to X server\n"); 
    } 
    Xscreen = DefaultScreen(Xdisplay); 
    Xroot = RootWindow(Xdisplay, Xscreen); 

    fbconfigs = glXChooseFBConfig(Xdisplay, Xscreen, VisData, &numfbconfigs); 
    fbconfig = 0; 
    for(int i = 0; i<numfbconfigs; i++) { 
     visual = (XVisualInfo*) glXGetVisualFromFBConfig(Xdisplay, fbconfigs[i]); 
     if(!visual) 
      continue; 

     pict_format = XRenderFindVisualFormat(Xdisplay, visual->visual); 
     if(!pict_format) 
      continue; 

     fbconfig = fbconfigs[i]; 
     if(pict_format->direct.alphaMask > 0) { 
      break; 
     } 
    } 

    if(!fbconfig) { 
     fatalError("No matching FB config found"); 
    } 

    describe_fbconfig(fbconfig); 

    /* Create a colormap - only needed on some X clients, eg. IRIX */ 
    cmap = XCreateColormap(Xdisplay, Xroot, visual->visual, AllocNone); 

    attr.colormap = cmap; 
    attr.background_pixmap = None; 
    attr.border_pixmap = None; 
    attr.border_pixel = 0; 
    attr.event_mask = 
     StructureNotifyMask | 
     EnterWindowMask | 
     LeaveWindowMask | 
     ExposureMask | 
     ButtonPressMask | 
     ButtonReleaseMask | 
     OwnerGrabButtonMask | 
     KeyPressMask | 
     KeyReleaseMask; 

    attr_mask = 
     CWBackPixmap| 
     CWColormap| 
     CWBorderPixel| 
     CWEventMask; 

    width = 1920; //DisplayWidth(Xdisplay, DefaultScreen(Xdisplay))/2; 
    height = 1080; //DisplayHeight(Xdisplay, DefaultScreen(Xdisplay))/2; 
    x=width/2, y=height/2; 

    window_handle = XCreateWindow( Xdisplay, 
        Xroot, 
        x, y, width, height, 
        0, 
        visual->depth, 
        InputOutput, 
        visual->visual, 
        attr_mask, &attr); 

    if(!window_handle) { 
     fatalError("Couldn't create the window\n"); 
    } 

#if USE_GLX_CREATE_WINDOW 
    int glXattr[] = { None }; 
    glX_window_handle = glXCreateWindow(Xdisplay, fbconfig, window_handle, glXattr); 
    if(!glX_window_handle) { 
     fatalError("Couldn't create the GLX window\n"); 
    } 
#else 
    glX_window_handle = window_handle; 
#endif 

    textprop.value = (unsigned char*)title; 
    textprop.encoding = XA_STRING; 
    textprop.format = 8; 
    textprop.nitems = strlen(title); 

    hints.x = x; 
    hints.y = y; 
    hints.width = width; 
    hints.height = height; 
    hints.flags = USPosition|USSize; 

    startup_state = XAllocWMHints(); 
    startup_state->initial_state = NormalState; 
    startup_state->flags = StateHint; 

    XSetWMProperties(Xdisplay, window_handle,&textprop, &textprop, 
      NULL, 0, 
      &hints, 
      startup_state, 
      NULL); 

    XFree(startup_state); 

    XMapWindow(Xdisplay, window_handle); 
    XIfEvent(Xdisplay, &event, WaitForMapNotify, (char*)&window_handle); 

    if ((del_atom = XInternAtom(Xdisplay, "WM_DELETE_WINDOW", 0)) != None) { 
     XSetWMProtocols(Xdisplay, window_handle, &del_atom, 1); 
    } 
} 

static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) 
{ 
    fputs("Error at context creation", stderr); 
    return 0; 
} 

static void createTheRenderContext() 
{ 
    int dummy; 
    if (!glXQueryExtension(Xdisplay, &dummy, &dummy)) { 
     fatalError("OpenGL not supported by X server\n"); 
    } 

#if USE_GLX_CREATE_CONTEXT_ATTRIB 
    #define GLX_CONTEXT_MAJOR_VERSION_ARB  0x2091 
    #define GLX_CONTEXT_MINOR_VERSION_ARB  0x2092 
    render_context = NULL; 
    if(isExtensionSupported(glXQueryExtensionsString(Xdisplay, DefaultScreen(Xdisplay)), "GLX_ARB_create_context")) { 
     typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); 
     glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB"); 
     if(glXCreateContextAttribsARB) { 
      int context_attribs[] = 
      { 
       GLX_CONTEXT_MAJOR_VERSION_ARB, 3, 
       GLX_CONTEXT_MINOR_VERSION_ARB, 0, 
       //GLX_CONTEXT_FLAGS_ARB  , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 
       None 
      }; 

      int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler); 

      render_context = glXCreateContextAttribsARB(Xdisplay, fbconfig, 0, True, context_attribs); 

      XSync(Xdisplay, False); 
      XSetErrorHandler(oldHandler); 

      fputs("glXCreateContextAttribsARB failed", stderr); 
     } else { 
      fputs("glXCreateContextAttribsARB could not be retrieved", stderr); 
     } 
    } else { 
      fputs("glXCreateContextAttribsARB not supported", stderr); 
    } 

    if(!render_context) 
    { 
#else 
    { 
#endif 
     render_context = glXCreateNewContext(Xdisplay, fbconfig, GLX_RGBA_TYPE, 0, True); //GLX_RGBA_TYPE 
     if (!render_context) { 
      fatalError("Failed to create a GL context\n"); 
     } 
    } 

    if (!glXMakeContextCurrent(Xdisplay, glX_window_handle, glX_window_handle, render_context)) { 
     fatalError("glXMakeCurrent failed for window\n"); 
    } 
} 

static int updateTheMessageQueue() 
{ 
    XEvent event; 
    XConfigureEvent *xc; 

    while (XPending(Xdisplay)) 
    { 
     XNextEvent(Xdisplay, &event); 
     switch (event.type) 
     { 
     case ClientMessage: 
      if (event.xclient.data.l[0] == del_atom) 
      { 
       return 0; 
      } 
     break; 

     case ConfigureNotify: 
      xc = &(event.xconfigure); 
      width = xc->width; 
      height = xc->height; 
      break; 
     } 
    } 
    return 1; 
} 
//---------------------------- 
//----- GLFW ----------------- 
//---------------------------- 

// settings 
const unsigned int SCR_WIDTH = 1920; 
const unsigned int SCR_HEIGHT = 1080; 

// camera 
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); 
float lastX = SCR_WIDTH/2.0f; 
float lastY = SCR_HEIGHT/2.0f; 
bool firstMouse = true; 

// timing 
float deltaTime = 0.0f; 
float lastFrame = 0.0f; 

int main(int argc, char *argv[]) 
{ 
    GLFWwindow* window; 

    if (window_choice == "X11") 
    { 
     createTheWindow(); 
     createTheRenderContext(); 
    } 
    else if (window_choice == "GLFW") 
    { 
     // glfw: initialize and configure 
     glfwInit(); 
     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 
     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 
     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 

     #ifdef __APPLE__ 
      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X 
     #endif 

     // glfw window creation 
     window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL); 
     if (window == NULL) 
     { 
      std::cout << "Failed to create GLFW window" << std::endl; 
      glfwTerminate(); 
      return -1; 
     } 
     glfwMakeContextCurrent(window); 
    } 

    //Load GLEW 
    GLenum err = glewInit(); 
    if (GLEW_OK != err) 
    { 
     // Problem: glewInit failed, something is seriously wrong 
     fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); 
    } 
    fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); 

    // configure global opengl state 
    // ----------------------------- 
    glEnable(GL_DEPTH_TEST); 

    //Build and compile shaders 
    Shader ourShader("/home/daniel/aureate/tools/Testing/assimp/1.model_loading.vs", "/home/daniel/aureate/tools/Testing/assimp/1.model_loading.fs"); 

    //Load models 
    Model ourModel(FileSystem::getPath("resources/objects/nanosuit/nanosuit.obj")); 

    if (window_choice == "X11") 
    { 
     while (updateTheMessageQueue()) 
     { 
      //RGBA 
      glClearColor(0.0, 0.0, 0.0, 0.0); 
      glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 

      ourShader.use(); 

      glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), 1.777f, 0.1f, 100.0f); //1920/1080 = 1.777 
      glm::mat4 view = camera.GetViewMatrix(); 
      ourShader.setMat4("projection", projection); 
      ourShader.setMat4("view", view); 

      // render the loaded model 
      glm::mat4 model; 
      model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f)); // translate it down so it's at the center of the scene 
      model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); // it's a bit too big for our scene, so scale it down 
      ourShader.setMat4("model", model); 
      ourModel.Draw(ourShader); 

      glXSwapBuffers(Xdisplay, glX_window_handle); 
     } 
    } 
    else if (window_choice == "GLFW") 
    { 
     while (!glfwWindowShouldClose(window)) 
     { 
      // per-frame time logic 
      // -------------------- 
      float currentFrame = glfwGetTime(); 
      deltaTime = currentFrame - lastFrame; 
      lastFrame = currentFrame; 

      // render 
      // ------ 
      glClearColor(0.2f, 0.3f, 0.3f, 0.0f); 
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

      // don't forget to enable shader before setting uniforms 
      ourShader.use(); 

      // view/projection transformations 
      glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH/(float)SCR_HEIGHT, 0.1f, 100.0f); 
      glm::mat4 view = camera.GetViewMatrix(); 
      ourShader.setMat4("projection", projection); 
      ourShader.setMat4("view", view); 

      // render the loaded model 
      glm::mat4 model; 
      model = glm::translate(model, glm::vec3(0.0f, -1.75f, 0.0f)); // translate it down so it's at the center of the scene 
      model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); // it's a bit too big for our scene, so scale it down 
      ourShader.setMat4("model", model); 
      ourModel.Draw(ourShader); 

      glfwSwapBuffers(window); 
     } 

     glfwTerminate(); 
     return 0; 
    } 
} 

回答

0

因此,为了使我的问题明确表示:我不明白为什么导入的对象具有X11窗口内的透明胶片,而不是GLFW窗口内。

当您制作一个透明的X11窗口时,该窗口的alpha通道将被用作透明通道。当渲染到用GLFW创建的非透明窗口时,帧缓冲区的Alpha通道不会产生任何效果。

现在你在这里看到的是一些纹理有透明的部分。但只要你不启用GL自己的混合,这些alpha值永远不会有任何可观察到的效果。但是你的着色器仍然将alpha值从纹理复制到输出帧缓冲区。在GLFW的情况下,甚至不清楚在默认帧缓冲区中是否有alpha通道(你可以明确地请求它,但不能确定它不存在,如果你不这样做),但它是完全不相关的因为这个alpha通道没有被使用。

在透明的X11窗口代码路径中,您绝对需要在默认帧缓冲区中有一个alpha通道,并且在那里结束的alpha值实际上会有效果。

如果你不希望这些胶片,你可以做两件事情:

  • 修改着色器,以便取代他们输出(r,g,b,1) (r,g,b,a)
  • 使用GL_RGB基于格式纹理,忽略文件中的alpha值
  • 修复纹理/材质描述为不包含任何透明胶片

X11窗口(基本上它可以是任何窗口管理器,但X11似乎是唯一能够显示透明背景的窗口)。

不,X11不是窗口管理器。不知道你使用的是什么窗口管理器/合成器,但有几个选择支持透明度。另一方面,你肯定无法在我的系统上获得效果,而这正是我想要的效果。

+0

嗨,感谢您的详细回复:)看起来像这个模型确实有些奇怪 - 我已经用Blender渲染了完全相同的对象来进行仔细检查,并且它没有显示任何透明度。但是,感谢您的提示,我现在已经尝试了其他3D模型,并且它们在X11窗口中显示得很好。 – slisystem