我想将3D对象加载到具有透明背景的OpenGL窗口中。我在使用Nvidia Quadro K3000M的Ubuntu 16.04计算机上使用C ++(安装的驱动程序是最近的375.66 NVIDIA二进制驱动程序)。我已经让两个目标独立工作 - 我可以使用this thread中的X11创建一个透明背景的OpenGL窗口,并使用来自this tutorial的Assimp和GLFW加载对象。
现在我想要将它们结合起来并且它至少可以工作 - 我可以导入一个对象并将其加载到透明的X11窗口中,但是现在有些纹理是透明的,这很奇怪:
GLFW结果:
X11结果:
所以要明确我的问题:我不明白为什么导入的对象在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 :(得分: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不是窗口管理器。不确定您使用的是哪个窗口管理器/合成器,但有几种支持透明度的替代方案。另一方面,你肯定无法对我的系统产生影响,这正是我想要的结果。