网上有好多3D渲染的例子,包括IOS、Android以及带Linux、windows上带窗口的。linux下真正离屏渲染的例子少之又少,我这里说的离屏是不依赖X Server,即ssh即可运行,当然渲染得到的图片要保存下来,否则没有意义。
回顾
我之前进行openGL渲染使用的是glew、glfw库,其中有以下这样一段代码:
GLFWwindow* window;
TextureHelper texHelper;
//window
if (!glfwInit())
{
std::cout << "Error::GLFW could not initialize GLFW!" << std::endl;
return false;
}
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
window = glfwCreateWindow(windowWidth, windowHeight, "demo", NULL, NULL);
if (!window)
{
std::cout << "Error::GLFW could not create window!" << std::endl;
glfwTerminate();
return false;
}
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
if(glewInit()!=GLEW_OK)
{
std::cout<<"Error::GLEW init failed!"<<std::endl;
glfwTerminate();
return false;
}
下面接着就可以添加自己的渲染代码了,在连着屏幕的电脑上可正常运行。但问题是我用ssh远程操作时,在不构建X Server时,总会爆出 “Error::GLFW could not create window!”。Google后才明白glfw的主要作用是构建渲染所需的上下文,而glfw是依赖X Server的,也就是我们不能用glfw,但要创建一个上下文。
正题
找了好久终于找到了它,EGL库,接下来直接上代码。
#include <stdio.h>
#include <string.h>
#include <EGL/egl.h>
using namespace std;
class CreateContext {
private:
const EGLint configAttribs[13] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_DEPTH_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
};
const int pbufferWidth = 9;
const int pbufferHeight = 9;
const EGLint pbufferAttribs[5] = {
EGL_WIDTH, pbufferWidth,
EGL_HEIGHT, pbufferHeight,
EGL_NONE,
};
public:
struct context {
EGLDisplay display;
EGLContext gl_context;
EGLSurface surface;
}ctx;
bool setup_context(context& ctx)
{
// 1. Initialize EGL
ctx.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EGLint major, minor;
eglInitialize(ctx.display, &major, &minor);
// 2. Select an appropriate configuration
EGLint numConfigs;
EGLConfig eglCfg;
eglChooseConfig(ctx.display, configAttribs, &eglCfg, 1, &numConfigs);
// 3. Create a surface
ctx.surface = eglCreatePbufferSurface(ctx.display, eglCfg, pbufferAttribs);
// 4. Bind the API
eglBindAPI(EGL_OPENGL_API);
// 5. Create a context and make it current
ctx.gl_context = eglCreateContext(ctx.display, eglCfg, EGL_NO_CONTEXT, NULL);
if (ctx.gl_context == EGL_NO_CONTEXT)
return false;
if (!eglMakeCurrent(ctx.display, ctx.surface, ctx.surface, ctx.gl_context))
return false;
return true;
}
void cleanup(context& ctx)
{
eglDestroySurface(ctx.display, ctx.surface);
eglDestroyContext(ctx.display, ctx.gl_context);
eglTerminate(ctx.display);
}
};
仅需要EGL库,作用就是创建上下文以便接下来的渲染。需要注意的是,这里仅代替了glfwInit(),在编写渲染代码之前,还需要glewInit()。
至于渲染并截图,网上有很多例子,也可以参考: IOS opengl离屏渲染并截图,有些函数名字不太一样,需要稍做改动。