`
Jason_gang
  • 浏览: 16721 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论
阅读更多
Android OpenGL ES 分析与实践
Android OpenGL ES 分析与实践
1.        OpenGL ES 简介
Android 3D引擎采用的是OpenGL ES。OpenGL ES是一套为手持和嵌入式系统设计的3D引擎API,由Khronos公司维护。在PC领域,一直有两种标准的3D API进行竞争,OpenGL 和 DirectX。一般主流的游戏和显卡都支持这两种渲染方式,DirectX在Windows平台上有很大的优势,但是OpenGL具有更好的跨平台性。
由于嵌入式系统和PC相比,一般说来,CPU、内存等都比PC差很多,而且对能耗有着特殊的要求,许多嵌入式设备并没有浮点运算协处理器,针对嵌入式系统的以上特点,Khronos对标准的OpenGL系统进行了维护和改动,以期望满足嵌入式设备对3D绘图的要求。
2.        Android OpenGL ES简介
Android系统使用OpenGL的标准接口来支持3D图形功能,android 3D图形系统也分为java框架和本地代码两部分。本地代码主要实现的OpenGL接口的库,在Java框架层,javax.microedition.khronos.opengles是java标准的OpenGL包,android.opengl包提供了 OpenGL系统和Android GUI系统之间的联系。
Android的本地代码位于frameworks/base/opengl下,JNI代码位于frameworks/base/core /com_google_android_gles_jni_GLImpl.cpp和frameworks/base/core /com_google_android_gles_jni_EGLImpl.cpp,java类位于opengl/java/javax /microedition/khronos下
3.        OpenGL的本地代码分析
3.1 OpenGL ES测试代码
frameworks/base/opengl/tests下有OpenGL的本地测试代码。包括angeles、fillrate等14个测试代码,这些代码都可以通过终端进行本地调用测试(模拟器中使用adb shell)。在本文中,主要使用了tritex这个测试用例。
在tests文件夹中执行mm,打印出以下信息
Install: out/target/product/generic/system/bin/angeles

Install: out/target/product/generic/system/bin/test-opengl-tritex
        由以上信息可知,测试用例被安装在了out/target/product/generic/system/bin/目录下,将之拷贝到nfs文件系统中,以便测试。我把这些测试用例都单独放在android的根文件系统的gltest文件夹中了。

3.2        OpenGL ES的编译
编译libagl下的源码生成Install: out/target/product/generic/system/lib/egl/libGLES_android.so
编译libs下的生成了
Install: out/target/product/generic/system/lib/libGLESv2.so
Install: out/target/product/generic/system/lib/libGLESv1_CM.so
Install: out/target/product/generic/system/lib/libEGL.so
3.3 使用OpenGL ES画图必经的步骤  
1、获取Display,Display代表显示器。
    函数原型:
  
    EGLDisplay eglGetDisplay(NativeDisplayType display);

    display参数是native系统的窗口显示ID值,一般为 EGL_DEFAULT_DISPLAY 。该参数实际的意义是平台实现相关的,在X-Window下是XDisplay ID,在MS Windows下是Window DC。


2、初始化egl库。
    函数原型:
  
    EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);

    其中dpy应该是一个有效的 EGLDisplay 。函数返回时,major和minor将被赋予当前EGL版本号。


3、选择一个合适的EGL Configuration FrameBuffer,实际指的是FrameBuffer的参数
    函数原型:
  
    EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,EGLConfig *configs, EGLint config_size,
                           EGLint *num_config);

    参数attrib_list:指定了选择配置时需要参照的属性。
    参数configs:    将返回一个按照attrib_list排序的平台有效的所有EGL framebuffer配置列表。
    参数config_size:指定了可以返回到configs的总配置个数。
    参数num_config: 返回了实际匹配的配置总数。


4、创建一个可实际显示的EGLSurface,实际上就是一个FrameBuffer
    函数原型:
  
    EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
                                  NativeWindowType win,
                                  const EGLint *attrib_list);


5、创建Context
    函数原型:
  
    EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
                            EGLContext share_context,
                            const EGLint *attrib_list);



6、绑定Display、Surface、Context
    函数原型:
  
    EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
                          EGLSurface read, EGLContext ctx);

3.4 OpenGL ES 执行过程
运行android操作系统之后,输入logcat命令,然后执行gltest中的test-opengl-tritex,屏幕上打印了以下信息
D/libEGL  ( 1962): egl.cfg not found, using default config
D/libEGL  ( 1962): loaded /system/lib/egl/libGLES_android.so
可以看出,在执行OpenGL调用的过程中,会自动加载libGLES_android.so动态链接库。后面将会通过分析和修改源码的方式,了解 OpenGL ES系统的调用过程。
通过3.3中的说明,我们在tritex测试程序中插入一些调试信息,查看OpenGL ES的调用过程。
在调用eglGetDisplay之前会执行early_egl_init函数,这是一个静态的函数。

在eglGetDisplay中会去初始化驱动,最终调用到egl_init_drivers_locked函数中。这个函数的主要内容如下

EGLBoolean egl_init_drivers_locked()
{
    if (sEarlyInitState) {
        // initialized by static ctor. should be set here.
        return EGL_FALSE;
    }

    // get our driver loader
    Loader& loader(Loader::getInstance());
  
    // dynamically load all our EGL implementations for all displays
    // and retrieve the corresponding EGLDisplay
    // if that fails, don't use this driver.
    // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
    egl_connection_t* cnx;
    egl_display_t* d = &gDisplay[0];

    cnx = &gEGLImpl[IMPL_SOFTWARE];
    if (cnx->dso == 0) {
        cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
        cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
        cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
        if (cnx->dso) {
            EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
            LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
            d->disp[IMPL_SOFTWARE].dpy = dpy;
            if (dpy == EGL_NO_DISPLAY) {
                loader.close(cnx->dso);
                cnx->dso = NULL;
            }
        }
    }

    cnx = &gEGLImpl[IMPL_HARDWARE];
    if (cnx->dso == 0) {
        char value[PROPERTY_VALUE_MAX];
        property_get("debug.egl.hw", value, "1");
        if (atoi(value) != 0) {
            cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
            cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
            cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
            if (cnx->dso) {
                EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
                LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
                d->disp[IMPL_HARDWARE].dpy = dpy;
                if (dpy == EGL_NO_DISPLAY) {
                    loader.close(cnx->dso);
                    cnx->dso = NULL;
                }
            }
        } else {
            LOGD("3D hardware acceleration is disabled");
        }
    }

    if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
        return EGL_FALSE;
    }

    return EGL_TRUE;
}
由此代码可以看出,egl_init_drivers_locked函数主要的工作就是填充gEGLImp数组变量,这个变量是 egl_connection_t类型。还有一个工作就是填充gDisplay数组(只有一个元素)的disp[IMPL_HARDWARE].dpy以及disp[IMPLSOFTWAREWARE].dpy,填充的来源来自gEGLImpl【soft or hard】.egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);

在Loader.cpp中的Loader:pen中会加载对应的硬件和软件加速的驱动(动态链接库)。软件的对应的是/system/lib/egl /libEGL_android.so,没有默认的硬件so,因此在硬件加速时,返回值hnd会指向NULL,在需要硬件加速时这个动态链接库需要进行实现。

LoadDriver函数会根据其第三个参数,决定加载egl/gles,glesv1_cm,glesv2驱动。。。

加载几个动态链接库的过程如下图




由我以上图表可以看出,加载驱动的时候,会尝试先从libGLES_android.so中加载EGL、GLESV1_CM、GLESV2三个部分的函数,如
果加载失败,则会尝试从libEGL_android.so,libGLESV1_cm.so,libGLESV2.so三个动态库中对应的函数。在这部分代码中,我们可以看到一个非常重要的结构体,egl_connection_t,
struct egl_connection_t
{
    void *              dso;
    gl_hooks_t *        hooks[2];
    EGLint              major;
    EGLint              minor;
    egl_t               egl;
};到处都有他的身影,对这几个变量进行一下解释。


struct soinfo
{
    const char name[SOINFO_NAME_LEN];
    Elf32_Phdr *phdr;
    int phnum;
    unsigned entry;
    unsigned base;
    unsigned size;
    // buddy-allocator index, negative for prelinked libraries
    int ba_index;

    unsigned *dynamic;

    unsigned wrprotect_start;
    unsigned wrprotect_end;

    soinfo *next;
    unsigned flags;

    const char *strtab;
    Elf32_Sym *symtab;

    unsigned nbucket;
    unsigned nchain;
    unsigned *bucket;
    unsigned *chain;

    unsigned *plt_got;

    Elf32_Rel *plt_rel;
    unsigned plt_rel_count;

    Elf32_Rel *rel;
    unsigned rel_count;

    unsigned *preinit_array;
    unsigned preinit_array_count;

    unsigned *init_array;
    unsigned init_array_count;
    unsigned *fini_array;
    unsigned fini_array_count;

    void (*init_func)(void);
    void (*fini_func)(void);

#ifdef ANDROID_ARM_LINKER
    /* ARM EABI section used for stack unwinding. */
    unsigned *ARM_exidx;
    unsigned ARM_exidx_count;
#endif

    unsigned refcount;
    struct link_map linkmap;
};

看一下load_driver中到底做了什么手脚。
1.首先调用dlopen打开动态链接库,返回值是void*,这个void*指向的是什么内容呢?追踪到bionic/linker/Dlfcn.c 中。其中调用了find_library函数,这个函数是一个奇怪的函数,因为它虽然叫做find_library,在其实现中,不但在系统的so链表中去查找指定的文件名的动态链接库信息,而且对其动态链接库进行加载并返回。至此我们明白了,这个void* 指向的是一个soinfo类型的结构体
这是man dlopen的说明。一个标准的linux函数。
The function dlopen() loads the dynamic library file named by the null-
       terminated  string  filename  and  returns  an  opaque "handle" for the
       dynamic library.  If filename is NULL, then the returned handle is  for
       the  main  program.   If  filename  contains  a slash ("/"), then it is
       interpreted as a  (relative  or  absolute)  pathname. 


2. 由上一步的分析,我们知道了egl_connection_t的第一个变量dso,是指向的一个soinfo结构体(discover/decompress shared 
object的缩写???)
Printf("HAHA Let me print the so infomation\n");
    Printf("name=%s:phdr=%x:entry=%x:base=%x:size=%x\n",soi->name,soi->phdr,soi->entry,soi->base,soi->size);
这是上一条语句打印的一些信息。
name=libGLES_android.so:phdr=acc80034:entry=0:base=acc80000:size=1c000

3.dlsym可以根据dlopen的返回值,查找第二个参数指定的函数名的地址并返回
The  function dlsym() takes a "handle" of a dynamic library returned by
       dlopen() and the null-terminated symbol  name,  returning  the  address
       where  that  symbol is loaded into memory.  If the symbol is not found,
       in the specified library or any of the libraries  that  were  automati-
       cally  loaded by dlopen() when that library was loaded, dlsym() returns
       NULL.  (The search performed by dlsym() is breadth  first  through  the
       dependency  tree  of  these  libraries.)  Since the value of the symbol
       could actually be NULL (so that a NULL return  from  dlsym()  need  not
       indicate  an  error),  the  correct way to test for an error is to call
       dlerror() to clear any old error conditions,  then  call  dlsym(),  and
       then call dlerror() again, saving its return value into a variable, and
       check whether this saved value is not NULL.


getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
        Printf("eglGetProcAddress's location is %x\n",getProcAddress);
打印信息如下,可以和刚才的打印信息比较一下。我们确实找到了一个函数。
eglGetProcAddress's location is acc930b1

Printf("curr=%x,it's address is %x\n",curr,f);
打印如下
eglGetProcAddress's location is acc930b1
*api=eglGetDisplay
curr=ac708a60,it's address is acc931a5
*api=eglInitialize
curr=ac708a64,it's address is acc93c9d
*api=eglTerminate
curr=ac708a68,it's address is acc93cdd
*api=eglGetConfigs
curr=ac708a6c,it's address is acc93d41
*api=eglChooseConfig
curr=ac708a70,it's address is acc9472d
*api=eglGetConfigAttrib
curr=ac708a74,it's address is acc94325
*api=eglCreateWindowSurface
curr=ac708a78,it's address is acc94689
*api=eglCreatePixmapSurface
curr=ac708a7c,it's address is acc945d5
*api=eglCreatePbufferSurface
curr=ac708a80,it's address is acc9451d
*api=eglDestroySurface
curr=ac708a84,it's address is acc93a1d
*api=eglQuerySurface
curr=ac708a88,it's address is acc94341
*api=eglCreateContext
curr=ac708a8c,it's address is acc9415d
*api=eglDestroyContext
curr=ac708a90,it's address is acc93d09
*api=eglMakeCurrent
curr=ac708a94,it's address is acc93a6d
*api=eglGetCurrentContext
curr=ac708a98,it's address is acc93055
*api=eglGetCurrentSurface
curr=ac708a9c,it's address is acc941a1
*api=eglGetCurrentDisplay
curr=ac708aa0,it's address is acc93061
*api=eglQueryContext
curr=ac708aa4,it's address is acc942ed
*api=eglWaitGL
curr=ac708aa8,it's address is acc9307d
*api=eglWaitNative
curr=ac708aac,it's address is acc93081
*api=eglSwapBuffers
curr=ac708ab0,it's address is acc93bf5
*api=eglCopyBuffers
curr=ac708ab4,it's address is acc93d71
*api=eglGetError
curr=ac708ab8,it's address is acc93125
*api=eglQueryString
curr=ac708abc,it's address is acc9373d
*api=eglGetProcAddress
curr=ac708ac0,it's address is acc930b1
*api=eglSurfaceAttrib
curr=ac708ac4,it's address is acc93d89
*api=eglBindTexImage
curr=ac708ac8,it's address is acc93da5
*api=eglReleaseTexImage
curr=ac708acc,it's address is acc93dc1
*api=eglSwapInterval
curr=ac708ad0,it's address is acc93ddd
*api=eglBindAPI
curr=ac708ad4,it's address is acc93df9
*api=eglQueryAPI
curr=ac708ad8,it's address is acc93085
*api=eglWaitClient
curr=ac708adc,it's address is acc930e5
*api=eglReleaseThread
curr=ac708ae0,it's address is acc9308d
*api=eglCreatePbufferFromClientBuffer
curr=ac708ae4,it's address is acc941e5
*api=eglLockSurfaceKHR
curr=ac708ae8,it's address is acc93091
*api=eglUnlockSurfaceKHR
curr=ac708aec,it's address is acc93095
*api=eglCreateImageKHR
curr=ac708af0,it's address is acc94201
*api=eglDestroyImageKHR
curr=ac708af4,it's address is acc93e15
*api=eglSetSwapRectangleANDROID
curr=ac708af8,it's address is acc93c51
*api=eglGetRenderBufferANDROID
curr=ac708afc,it's address is acc94125

egl_connection_t的第二个变量是一个指针数组,类型是gl_hooks_t,从名字可以看出,它指向的是一组函数指针。跟踪一下
struct gl_hooks_t {
    struct gl_t {
        #include "entries.in"
    } gl;
    struct gl_ext_t {
        void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
    } ext;
};
这个entries.ini文件里全部是函数的一些原型。。
证明了猜想。

        cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
        cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
这里将egl_connecttion_t变量指向了全局的gHooks,这些函数指针从哪里赋值的呢?跟踪发现,是在LoadDriver时,也是从
libGLES_android.so中查找出GLESV1_CM和GLESV2两组函数来对其进行了赋值操作。

major和minor是版本号。
最后一个变量egl_t egl。这个变量非常重要。在load_driver中可以看到它的身影(通过loader::open间接调用的)。

struct egl_t {
    #include "EGL/egl_entries.in"
};
egl_t中也是一组函数指针,其中包含了OpenGL ES中底层的实现。所以如果要实现硬件加速的话,这里面的函数都要实现。


egl_t* egl = &cnx->egl;
__eglMustCastToProperFunctionPointerType* curr =
(__eglMustCastToProperFunctionPointerType*)egl;
char const * const * api = egl_names;
while (*api)
{
        char const * name = *api;
        __eglMustCastToProperFunctionPointerType f =
                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
        if (f == NULL)
        {
                // couldn't find the entry-point, use eglGetProcAddress()
                f = getProcAddress(name);
                if (f == NULL)
                {
                        f = (__eglMustCastToProperFunctionPointerType)0;
                }
        }
        *curr++ = f;
        api++;
}
上面的这些语句完成了将驱动(libGLES_android.so)中的函数地址赋值给了cnx->egl指向的egl_t结构。因此有了这些操作,下面
就可以通过egl_connection_t::egl来访问EGL中的一些底层的函数了,比如初始化等的操作。

要实现硬件加速,需要实现的是与libGLES_android.so对应的那些函数。android会自动完成对其的加载、初始化、调用。


上面的一大部分功能都是在loader:pen中进行调用的,回到egl_init_drivers_locked函数中。
其在调用了loader:pen函数完成了对libGLES_android.so中的库进行加载的操作之后,真正开始 初始化操作了,所以说上面的一大部分操作,其实都是一些预初始化,真正的初始化操作还没有开始。。。。

真正的初始化操作来自这里EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
通过刚才的分析,我们很容易知道,这个egl.eglGetDisplay函数到底要去哪里找。有bet。
我们上面打印出了
*api=eglGetDisplay
curr=ac708a60,it's address is acc931a5
这个东东在libGLES_android.so的源码里。

eglGetDisplay在内部的实现并不是通过返回值的方式进行传递的,而是用的全局变量。

eglGetDisplay完成的事情主要有,加载真正的OpenGL ES 的动态链接库文件,里面包含各种openGL的操作,这个函数库在libGLES_andorid.so中,加载动态链接库之后,会将其中的一些函数指针的值传递到全局的gEGLImpl中,通过这个全局的结构体,可以访问libGLES_android.so中的所有的函数。

下面分析应用程序中调用eglInitialize函数,会完成的操作。
eglInitialize

在这个函数中,主要调用了libGLES_android中的eglIniitalize函数,eglGetConfigs函数,获取配置信息。
3.5 使用OpenGL ES硬件加速功能的方法
使用硬件加速功能的OpenGL ES的方法。
1.修改Loader.cpp文件里的Loader::loader函数,添加gConfig.add( entry_t(0, 1, "mmoid") );或者修改egl.cfg文件。此文件位于/system/lib/egl/下,如果不存在,可以自己动手新建。格式是“dpy impl tag”比如自己添加的硬件加速库是libGLES_mmoid.so,则需要在此文件里这样编写
0 1 mmoid
修改后腰重启才可生效。
现在已经可以使用硬件加速功能了。
分享到:
评论

相关推荐

    OpenGL Programming Guide: The Official Guide to Learning OpenGL (8th Edition)

    Includes Complete Coverage of the OpenGL® Shading Language! Today’s OpenGL software interface enables programmers to produce extraordinarily high-quality computer-generated images and interactive ...

    opengl+qt实现鼠标选中模型

    opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型opengl+qt实现鼠标选中模型...

    openGL实现天空盒,使用OpenGL 立方体贴图

    1.构建天空盒的另一种方法是使用OpenGL 纹理立方体贴图。OpenGL 立方体贴图比我们 在上一节中看到的简单方法稍微复杂一点。但是,使用OpenGL 立方体贴图有自己的优点, 例如减少接缝以及支持环境贴图。 2.OpenGL ...

    OpenGL资源.zip

    OpenGL是一种强大的图形编程接口,广泛应用于游戏开发、科学可视化、工程设计等领域。它允许程序员直接控制显卡硬件,实现高效且复杂的3D图形渲染。在"OpenGL学习资源.zip"这个压缩包中,很可能是包含了帮助初学者和...

    opengl编程指南第9版、超级宝典第7版、计算机图形原则和实践第3版以及opengl领悟(OpenGL insights)

    OpenGL编程指南第9版、超级宝典第7版、计算机图形原则和实践第3版以及OpenGL领悟(OpenGL Insights)这四本书是计算机图形学领域的经典之作,尤其对于使用OpenGL进行图形编程的开发者来说,它们提供了丰富的知识和深入...

    OpenGL实例源代码

    OpenGL实例源代码是一种珍贵的学习资源,它包含了多个与OpenGL编程相关的示例,涵盖了从基础到高级的各种技术。OpenGL是一个跨语言、跨平台的图形库,用于渲染2D、3D矢量图形,广泛应用于游戏开发、科学可视化以及...

    linux安装openGL库

    在Linux系统中,OpenGL是一个广泛使用的图形库,用于创建2D和3D图形。它提供了标准接口,使得开发者能够在不同的操作系统和硬件上编写图形程序。本文将详细介绍如何在Linux环境下安装OpenGL库及其相关的开发工具。 ...

    Qt+OpenGL摄像机,移动,放大缩小

    Qt+OpenGL摄像机,移动,放大缩小,Qt+OpenGL摄像机,移动,放大缩小,Qt+OpenGL摄像机,移动,放大缩小,Qt+OpenGL摄像机,移动,放大缩小,Qt+OpenGL摄像机,移动,放大缩小,Qt+OpenGL摄像机,移动,放大缩小,Qt...

    opengl+qt实现模型旋转平移

    opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移opengl+qt实现模型旋转平移...

    OpenGL4.6着色语言精通_第三版_源码_opengl_third_GLSL4.6_GLSL_源码_

    这源码是OpenGL4.6着色语言精通_第三版的全部源代码,利用GLSL 4.6和C++ 17构建高质量实时三维图形。主要重点是OpenGL着色语言(GLSL)。因此,我们不花时间讨论用OpenGL编程的基础。在这个我认为读者对在OpenGL中...

    QtOpenGL文字显示

    在IT领域,尤其是在图形编程中,Qt和OpenGL是两个非常重要的工具。Qt是一个跨平台的C++库,广泛用于创建用户界面和桌面应用程序,而OpenGL则是一个强大的图形库,允许开发者进行高性能的2D和3D图形渲染。本文将深入...

    OpenGL库文件工具包(opengl32.lib glu32.lib glaux.lib glew32.lib)

    OpenGL库文件工具包是计算机图形学领域中用于创建2D和3D图形的重要资源,它包含了一系列库文件,包括opengl32.lib、glu32.lib、glaux.lib和glew32.lib。这些库文件在Windows操作系统上开发和运行OpenGL应用程序时不...

    C#版的OpenGL

    OpenGL是一种开放源代码的图形库,它为程序员提供了一种跨平台的方式来创建高性能的2D和3D图形。OpenGL在C++中广泛使用,但在C#编程环境中,开发者通常会利用封装库来调用OpenGL的功能。标题提到的"C#版的OpenGL...

    OpenGL学习必备,红宝书及蓝宝书

    OpenGL是计算机图形学领域广泛应用的一种编程接口,它允许开发者创建复杂的3D图形和交互式视觉效果。"红宝书"通常指的是"OpenGL编程指南",而"蓝宝书"则是"OpenGL超级宝典",这两本书是OpenGL学习者的重要参考资料。...

    opengl_shader_鱼眼校正

    OpenGL Shader是一种强大的图形编程工具,它允许程序员在GPU(图形处理器)上直接编写代码,以实现复杂的图形渲染效果。在本案例"opengl_shader_鱼眼校正"中,我们探讨的是如何使用OpenGL Shader来纠正鱼眼镜头产生...

    MFC基于对话框下的OpenGL

    OpenGL是一种强大的图形编程库,广泛应用于创建复杂的2D和3D图形。在MFC(Microsoft Foundation Classes)框架下,我们通常使用Visual C++作为开发工具,可以利用OpenGL在对话框中实现图形绘制功能。MFC对话框是...

    OpenGL编程指南.pdf

    OpenGL 编程指南 本文档为 OpenGL 编程指南,涵盖了 OpenGL 的基础知识、概念、基本程序结构、数据类型、函数名、辅助库、模型建立、变换、颜色、光照、位图和图像、纹理、复杂物体建模、特殊光处理、效果处理、...

    openGL画图板实现简单画图功能

    OpenGL画图板是一种利用计算机图形学技术来实现的交互式绘图工具,它允许用户通过鼠标或触控设备在屏幕上绘制各种图形。本项目是基于C++编程语言,利用OpenGL库来实现一个简单的画图软件。OpenGL是一个跨语言、跨...

    系统提示"找不到opengl32.dll"或"opengl32.dll缺失"

    一、如果您的系统提示"找不到opengl32.dll"或"opengl32.dll缺失" 或者"opengl32.dll错误"等等,请不用担心,请把opengl32.dll下载到本机。 二、直接拷贝该文件到系统目录里:  1、Windows 95/98/Me系统,将opengl32...

Global site tag (gtag.js) - Google Analytics