我正在尝试使用OpenGL创建我自己设计的3D环境模拟器,但是我的设计要求我能够直接控制运行时循环.
我正在尝试学习如何在OpenGL中实现VBO,但我很难找到足够的资源.根据我的发现,几乎每个人都以某种方式使用FreeGLUT或GLEW或GLFW或GL3.h来解决一些特定于平台的问题.
虽然这些选项可能很棒,但我根本不想将其他人的包用于此代码.我想弄清楚如何使用大多数机器上开箱即用的标准的vanilla OpenGL来使用VBO.我可以使用一些帮助来寻找OpenGL中不使用任何外部包的VBO教程.
......在有人建议之前,关于VBO的NeHe第45课使用的折旧代码(glaux)甚至不再编译,所以这不是一个选择.:\
编辑:也许我不清楚,或者我被控制,无论如何......问题的关键在于找到示例,教程或其他资源来教授OpenGL中不支持这些附加包的VBO.认真的人,告诉我"放弃"或"只使用GLEW"......这没有帮助.
当你使用GLUT或GLFW时,使用VBO的方式并没有什么不同,如果你手动加载函数指针并不重要(为什么你首先要这样做?那是受虐狂,是的,它可以做到......但为什么你应该吗?)或使用像GLEW这样的包装器.
我认为你需要你的概念正确GLUT,GLFW和GLEW实际上是什么.
GLUT(旧的,Free ...和Open ...)和GLFW是框架:它们创建一个窗口,为连接OpenGL上下文做准备,创建一个OpenGL上下文,然后给予控制权(或多或少).GLUT接管事件循环.GLFW要求您实现事件循环.您当然可以自己完成整个设置.但是如果你这样做,那么当涉及到底层操作和图形系统的低级API时,你需要坚定地站稳脚跟.更好地使用框架.你不仅限于GLUT或GLFW,还有其他:Qt,GTK +,SDL,SMFL,FLTK,wxWidgets,Fox Toolkit等等.
GLEW是一个扩展和函数指针加载器库,负责处理(真正)令人毛骨悚然的细节.opengl32.dll或libGL.so只公开了OpenGL的更高版本提供的所有函数的一小部分.必须在运行时动态加载所有高级内容.这就是GLEW的用途,因为手动操作真的很糟糕.
没有人有任何东西做与驻国际中心组织!如果你这么想,你就会有一些严重的误解.
那么如何手动加载扩展.嗯,这真的很讨厌.首先,您必须在源代码中定义所需的函数指针.为了帮助您,ARB发布了一个名为的头文件glext.h.在这里你可以找到像这样的线
typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC) (GLuint buffer);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data);
typedef GLvoid* (APIENTRYP PFNGLMAPBUFFERPROC) (GLenum target, GLenum access);
typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC) (GLenum target);
typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params);
typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC) (GLenum target, GLenum pname, GLvoid* *params);
Run Code Online (Sandbox Code Playgroud)
那些为函数指针提供类型.因此,您将glext.h加入扩展加载器模块
#include "myextensionloader.h"
Run Code Online (Sandbox Code Playgroud)
然后,对于您打算使用的每个函数,您都可以定义一个函数指针变量.但重要的是:这些变量是程序的一部分,因此必须将它们限制在自己的命名空间中; 你不能只使用可能存在的名称.所以他们不会被召唤gl…但是会被称为PROGRAMNAME_PRIVATE_gl….
PFNBINDBUFFERPROC myprogram_PRIVATE_glBindBuffer;
PFNDELETEBUFFERPROC myprogram_PRIVATE_glDeleteBuffer;
Run Code Online (Sandbox Code Playgroud)
… 等等.你真的想用OpenGL的后期版本提供的大量功能吗?
实际上,对于Windows的情况来说,这甚至都不完全正确,因为OpenGL函数指针与OpenGL上下文活动相关联.不同线程中的多个OpenGL上下文同时处于活动状态=>灾难配方.那些函数指针变量实际上属于线程本地存储.
然后添加一个函数指针加载器,它为每个需要加载它的OpenGL函数加载它
void load_extension_function_pointers()
{
#ifdef USE_WGL
#define GETGLPROCADDRESS(name) (wglGetProcAddress(name))
#else ifdef USE_GLX
#define GETGLPROCADDRESS(name) (glXGetProcAddress(name))
#endif
#define LOAD_POINTER(name) myprogram_PRIVATE_##name = GETGLPROCADDRESS(#name)
LOAD_POINTER(glBindBuffer)
LOAD_POINTER(glDeleteBuffer)
}
Run Code Online (Sandbox Code Playgroud)
无论如何,现在你想让它可用于其他模块.因此,您有一个myextensionloader.h用于包含的头文件glext.h,将函数指针变量作为外部函数提供给程序的其余部分,并且有一大组C预处理器宏,它们将您的私有函数名称命名为OpenGL函数名:
#pragma once
#ifndef MYEXTENSIONLOADER_H
#define MYEXTENSIONLOADER_H
#include <GL/gl.h>
#include <GL/glext.h>
extern PFNBINDBUFFERPROC myprogram_PRIVATE_glBindBuffer;
#define glBindBuffer myprogram_PRIVATE_glBindBuffer;
extern PFNDELETEBUFFERPROC myprogram_PRIVATE_glDeleteBuffer;
#define glDeleteBuffer myprogram_PRIVATE_glDeleteBuffer;
Run Code Online (Sandbox Code Playgroud)
并且这个方案仍然缺少一些细节:在Windows中,函数指针实际上与活动的OpenGL上下文相关联,因此从技术上讲,您需要以某种方式覆盖wglMakeCurrent以在切换上下文时更新所有函数指针.并且由于不同的OpenGL上下文可以在不同的线程中处于活动状态,因此这些函数指针实际上应该在线程本地存储(TLS)中才是正确的.GLX更加理智,但你可能仍然在不同GPU供应商的多台X服务器上运行,所以你要应对不同的libGL.so和libGLX.so以及那些可以咬你的东西.
你真的想要自己照顾这一切吗?如果您是该代码的唯一用户,为什么?真的是为什么?写这一切的过程非常繁琐,以至于GLEW的维护者从未写过任何实际的GLEW库.他们所做的是编写一个代码生成器,自动从规范文件中生成库源代码.
| 归档时间: |
|
| 查看次数: |
1902 次 |
| 最近记录: |