精华内容
下载资源
问答
  • OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13 文章目录OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.131 帧缓存运算6 总结 1 帧缓存运算 6 总结 这一篇我们介绍了片段着色器的...

    OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13


    上一篇介绍了一下有关片段着色器的相关内容(虽然还有未解决的问题),这一篇我们将介绍图形管线的最后一部分,帧缓存运算,还介绍一下一个单独形成管线的着色器:计算着色器。

    1 帧缓存运算

    帧缓存是OpenGL管线的最后一个阶段,我们可以把渲染的图像传输给窗口的帧缓存中去,这样我们就能看到绘制的图形了,如果我们需要渲染到屏幕以外的地方(以后的有些计算需要我们这样做),那我们就要提供自己的缓存。

    当然在这个环节中,即在写入窗口前我们还要进行很多的筛选和计算,主要是分为4步:裁剪测试,模板测试,深度测试,混合和逻辑运算阶段。

    1.1 裁剪测试

    我们可以通过设置一个矩形,当像素在矩形外的话,我们就把这些像素丢弃,如果像素在矩形内,那么它的值将会继续进行之后的运算。

    1.2 模板测试

    这一步的时候我们将比较我们设置的参照值和模板缓存之间的大小。

    1.3 深度测试

    这是一个非常重要的环节,还记得之前我们在剔除中进行的计算吗,通过计算三角形的正反(向量叉积)来剔除一些不用绘制的三角形。但是我们无法解决前面的三角形挡住了后面三角形的正面这种情况,当时我们提到要用深度测试,而这里就要进行深度测试。

    深度测试就是在绘制三角形的像素时判断一下,该三角形在该像素上的深度(Z值)是多少,如果比缓存中的小,那么将该像素的信息覆盖在上面。

    比如说我先画一个三角形:
    这里标出了每个像素对应的深度图
    在这里插入图片描述
    观察到第一个绘制的三角形是位于Z=0.5平面上的,所以每个像素的深度值现在是0.5(在三角形区域中的像素)。
    在这里插入图片描述
    在绘制第二个三角形时,运行到深度测试的时候,在重叠部分,蓝色的三角形的深度是小于红色的,所以在重叠的区域红色的三角形被蓝色三角形覆盖。虽然显示的是蓝色完全盖住了重叠的区域,但深度测试是逐像素进行的,因为重叠区域蓝色三角形的深度都小于红色,所以蓝色在重叠区域才能全部挡住红色。

    因为是逐像素的运行深度测试,所以可以处理两个三角形交叉的复杂情况:
    在这里插入图片描述
    比如在这里的红蓝三角形,因为两个三角形有交叉,这会导致重叠区域(1和2)中,有的区域是蓝色在前(2),而有的区域是红色在前(1),也有非重叠区域(3、4、5、6)。在1、2的区分上逐像素的深度测试就体现出了优势。

    假设先绘制的是红色三角形,那么1、2、3、6都会记录为红色三角形在该像素处的深度(这个深度一定是左浅右深的)。当绘制蓝色三角形时,对于5、4区域没什么问题,因为没有重合,但是在运算1区域的像素时,会发现蓝色三角形在该区域的像素深度比当前的像素的深度大(当前像素的深度就是红色三角形在该处的深度,因为红色先绘制),所以蓝色在1区域不会覆盖红色,而2区域相反,蓝色的深度是低于当前像素的深度的(当前像素的深度就是红三角形在该处的深度),所以蓝色会覆盖上去。最终得到了效果图像。

    深度测试是对每个像素进行的,虽然有很多的三角形在该像素处重叠,但是我们通过深度测试找到在该像素处深度最低的那一个,最终绘制的结果就是前面的三角形遮挡后面的三角形。

    就有点像找一群人中的最矮的那个,先来了一个人(该像素处有一个三角形要进行绘制),看看当前本上记录的最矮的人是谁、比一比看谁更矮(那三角形在该处的深度和缓存中比较),假如新来的人更矮,那就把他当做最矮的人记到本上(进行缓存的覆盖),如果新人高一些,那就不变(不进行覆盖)。在试过所有的人之后(在完成所有的三角形绘制之后),本子上记录的就是最矮的人(缓存中的就是离我们最近的那个图案)。

    不知道解没解释清楚O(∩_∩)O

    1.4 混合和逻辑运算阶段。

    在写入缓存之前还要可以进行混合和逻辑运算,就是把这一帧的内容(还未显示)与之前的内容进行与、或、异或等计算,这部分是OpenGL的一个高度可配置的阶段,之后的章节具体介绍。(应该是第9章了)

    2 计算着色器

    上面提到,其实结束了混合逻辑运算最终的缓冲已经形成,那么整个图形管线就结束了,那这个计算着色器又是什么呢?
    其实计算着色器是单独作为一个管线存在的,这个管线并不直接计算我们要绘制的图形,而是通过帮助计算数据来辅助我们完成渲染,当然你也可以通过它来计算一些其他东西。(也许可以挖矿、进行人工智能的计算等等)。我们把它从渲染管线中抽离出来的原因是为了减轻CPU的负担,因为显卡有大量的核心,可以同时处理很多的数据,由于并行计算的速度很快,所以用显卡计算大量的数据更为快速(这就是为什么挖矿导致显卡涨价而不是CPU涨价…)

    我们在建立计算着色器的时候要注意:计算着色器虽然和其他着色器一样需要创建对象,编辑拷贝着色器内容,编译,连接着色器程序,但是不同的是计算着色器不能和其他的着色器放在同一个着色器程序中,也就是说如果一个程序有了计算着色器就不能连接顶点着色器、片段着色器、、、、。

    我们看书上的例子吧
    清单3.13 一个什么也不干的计算着色器

    #version 450 core
    layout (local_size_x = 32,local_size_y = 32) in;
    //指示全局工作组的大小是32*32个工作项
    void main(void){
    	//什么都不做
    }
    

    这个计算着色器的确什么也没做,我们在第十章的时候会在进行深入的讨论吧(现在还不会o(╥﹏╥)o)

    相关的参考博客:
    计算着色器(Compute Shader)

    3 总结

    这一篇我们介绍了图形管线的最后一个阶段帧缓存运算,包括4部分:裁剪测试,模板测试,深度测试,混合和逻辑运算阶段。其中我们重点介绍了深度测试的基本原理。最后我们对计算着色器做了一个超级简单的介绍(跟只介绍了计算着色器这个名字,没什么区别0v0),其中我们值得注意的是计算着色器在链接着色器程序时,该着色器程序不能链接顶点着色器、片段着色器等图形管线着色器,因为计算着色器是单独运行的一个管线。

    下一篇我们将对整个前三章做一个整体的回顾,并且稍微说说OpenGL的扩展(仅提一提,我暂时没有试验过OpenGL的扩展,毕竟读到此处还是初学者,还是先学习OpenGL的核心内容要紧~)

    我们下篇见~~

    关于书籍的问题
    如果你手中没有该书,我还是建议你购买一本,毕竟书本毕竟更加严谨专业,我这里难免遗漏一些细节,主要是提供实例,并做一个消化,将很混乱的流程为大家理清,但这笔记一定是通俗的,是对新手友好的(当然有时候你需要在某些方面自己努努力,比如后面出现的基本线性代数的内容,还有C语言或是c++的基础知识,虽然我可能也不太懂O(∩_∩)O,慢慢来吧)。

    别被吓住
    刚开始的时候很容易被OpenGL的巨长的函数和超级复杂的流程吓到,其实并没有那么可怕,只要对这样或那样的流程熟悉之后,一切都变得相当简单(当然如果你能提出一个更好的流程那就更好了,当我们把很多基础的工作做完,我们会不断的提出新问题新点子,用新的技术来实现它,最终完成OpenGL的学习)

    虽然我也不知道后面将是怎样的道路,但至少努力学习是没错的。

    我看过的相关内容
    以下并不是全看完了,大部分看了15%就看不下去了,实在是没看懂。(本人没什么计算机编程基础,算是野生程序员吧,很多内容都不能标准表述,望见谅)
    如果你对opengl的工作有了一定的了解,我一开始也是从这里开始的,但是仍然有很多的不懂的,最后至今为止,我杂糅了很多的网站内容包括LearnOpenGL极客学院哔哩哔哩的闫令琪计算机图形学哔哩哔哩的傅老师的OpenGL课程、OpenGL编程指南"也称为红宝书"、OpenGL超级宝典"也称为蓝宝书"、当然还有很多的csdn文章O(∩_∩)O这就不介绍了,等用到是时候我在放链接吧O(∩_∩)O

    这里面图形学比较易懂也很基础推荐可以作为开始(如果你是学OpenGL需要马上用,应该可以跳过,但是其中的内容很是很重要,这会让后面涉及变换透视的章节更加易懂,推荐大家看看),之后是蓝宝书或是极客学院翻译的教程比较推荐,这两个还是比较适合你我这样的新手的。
    这里不推荐看的是红宝书,这本书我看了有点类似于字典那样的工具书,不太适合新手上手学,而且讲的也并不是很通俗易懂(可能是我的书版本比较老吧…)

    加油
    当然如果你对我有信心,我也会持续更新(虽然前路漫漫),跟大家一同进步(虽然很可能没人看(╥╯^╰╥),无所谓了,当然如有错误还请大家指正∠(°ゝ°),哪里不懂我会尽力解决,哪里说的不好也可以指出我会及时修改~)

    我们下篇见~~

    展开全文
  • 一、纹理缓存、帧缓存、动画缓存 缓存机制:存储设施有快慢之分,PC机上有硬盘与内存之分,计算机软件运行时候把资源加载到内存中运行;手机与PC也是类似的。当手机软件运行时候,把经常需要用到的资源预先加载到...

    一、纹理缓存帧缓存动画缓存

    缓存机制:存储设施有快慢之分,PC机上有硬盘与内存之分,计算机软件运行时候把资源加载到内存中运行;手机与PC也是类似的。当手机软件运行时候,把经常需要用到的资源预先加载到存取速度快的内存中,之后访问该资源将会节省大量时间。

    Cocos2d-x为我们提供了三个实现缓存的接口,有纹理缓存帧缓存动画缓存,都是全局单例

    纹理缓存(CCTextureCache):

        纹理缓存缓存加载到内存中的纹理资源,纹理是OpenGL中对图片的叫法,将纹理缓存起来方便之后的绘制工作。

        每一个缓存的图像的大小,颜色和区域范围都是可以被修改的。这些信息都是存储在内存中的,不用在每一次绘制的时候都发送给GPU。

        原理:对加入缓存的纹理资源进行一次引用,使其引用计数加一,保持不被清楚,从而使Cocos2d-x的渲染机制可以重复使用同一纹理多次渲染。

       CCTextureCache的继承关系:class CC_DLL CCTextureCache : public CCObject。

        CCTextureCache.h中部分代码如下:

     

    [cpp] view plaincopyprint?

    1. class CC_DLL CCTextureCache : public CCObject  
    2. {  
    3. protected:  
    4.     CCDictionary* m_pTextures;  
    5. public:  
    6.     /** Returns the shared instance of the cache*/  
    7.     static CCTextureCache * sharedTextureCache();  
    8.     /** purges the cache. It releases the retained instance.*/  
    9.     static void purgeSharedTextureCache();  
    10.     /** Returns a Texture2D object given an file image 
    11.     * If the file image was not previously loaded, it will create a new CCTexture2D 
    12.     *  object and it will return it. It will use the filename as a key. 
    13.     * Otherwise it will return a reference of a previously loaded image. 
    14.     * Supported image extensions: .png, .bmp, .tiff, .jpeg, .pvr, .gif 
    15.     */  
    16.     CCTexture2D* addImage(const char* fileimage);  
    17.     /** Reload texture from the image file 
    18.     * If the file image hasn't loaded before, load it. 
    19.     * Otherwise the texture will be reloaded from the file image. 
    20.     * The "filenName" parameter is the related/absolute path of the file image. 
    21.     * Return true if the reloading is succeed, otherwise return false.*/  
    22.     bool reloadTexture(const char* fileName);  
    23.     /** Purges the dictionary of loaded textures. 
    24.     * Call this method if you receive the "Memory Warning" 
    25.     * In the short term: it will free some resources preventing your app from being killed 
    26.     * In the medium term: it will allocate more resources 
    27.     * In the long term: it will be the same*/  
    28.     void removeAllTextures();  
    29.     /** Removes unused textures 
    30.     * Textures that have a retain count of 1 will be deleted 
    31.     * It is convenient to call this method after when starting a new Scene*/  
    32.     void removeUnusedTextures();  
    33.     /** Deletes a texture from the cache given a texture*/  
    34.     void removeTexture(CCTexture2D* texture);  
    35.     /** Deletes a texture from the cache given a its key name*/  
    36.     void removeTextureForKey(const char *textureKeyName);  
    37.     /** Reload all textures 
    38.     It's only useful when the value of CC_ENABLE_CACHE_TEXTURE_DATA is 1 
    39.     */  
    40.     static void reloadAllTextures();  
    41. };  

     

    上面代码都有英文注释,简单易懂,下面解释一些常用的。

    sharedTextureCache:得到CCTextureCache的单例对象。

    purgeSharedTextureCache:清空缓存,销毁CCTextureCache单例对象。

    addImage:加载一个图片生成纹理,返回生成的纹理指针。

    removeAllTextures:释放所有纹理。

    removeUnusedTextures:清除未被外部使用的纹理。怎么知道未使用呢?这里只需要遍历下计数器值为1的纹理即未被外部使用的纹理进行释放即可。 新场景创建好后,使用此方法释放没有使用的纹理非常方便。

    removeTexture:移除指定的纹理。

    再来看看下面代码:

     

    [cpp] view plaincopyprint?

    1. bool CCSprite::initWithFile(const char *pszFilename)  
    2. {  
    3.     CCAssert(pszFilename != NULL, "Invalid filename for sprite");  
    4.   
    5.     CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFilename);  
    6.     if (pTexture)  
    7.     {  
    8.         CCRect rect = CCRectZero;  
    9.         rect.size = pTexture->getContentSize();  
    10.         return initWithTexture(pTexture, rect);  
    11.     }  
    12.   
    13.     // don't release here.  
    14.     // when load texture failed, it's better to get a "transparent" sprite than a crashed program  
    15.     // this->release();   
    16.     return false;  
    17. }  

    由此可知,当创建一个精灵时候,实际上是通过纹理缓存创建的。

     

    精灵帧缓存(CCSpriteFrameCache)

        CCSpriteFrameCache也是一个单例对象,使用xml格式文件(plist文件)。

        我们可以加载很多的精灵帧到缓存中,之后就可以从这个缓存中创建精灵对象了。

        精灵帧缓存主要用来缓存多张小图合并后的图片,一张图中包含多张小图,通过CCSpriteFrameCache缓存后通过CCSpriteFrame引用其中一个小图片。

        继承关系:class CC_DLL CCSpriteFrameCache : public CCObject。

        CCSpriteFrameCache.h部分代码如下:

    [cpp] view plaincopyprint?

    1. class CC_DLL CCSpriteFrameCache : public CCObject  
    2. {  
    3. public:  
    4.     void addSpriteFramesWithFile(const char *pszPlist);  
    5.     void addSpriteFramesWithFile(const char* plist, const char* textureFileName);  
    6.     void addSpriteFramesWithFile(const char *pszPlist, CCTexture2D *pobTexture);  
    7.     void addSpriteFrame(CCSpriteFrame *pobFrame, const char *pszFrameName);  
    8.     void removeSpriteFrames(void);  
    9.     void removeUnusedSpriteFrames(void);  
    10.     void removeSpriteFrameByName(const char *pszName);  
    11.     void removeSpriteFramesFromFile(const char* plist);  
    12. }  

     

    void addSpriteFramesWithFile(const char *pszPlist):从一个.plist文件添加多个精灵帧。 一个纹理将被自动加载。纹理名称将把.plist后缀名替换为.png来组成。

    void addSpriteFramesWithFile(const char* plist, const char* textureFileName):通过一个.plist文件添加多个精灵帧。纹理将与被创建的精灵帧结合。

    void addSpriteFramesWithFile(const char *pszPlist, CCTexture2D *pobTexture):通过一个.plist文件添加多个精灵帧。纹理将与被创建的精灵帧结合。

    void addSpriteFrame(CCSpriteFrame *pobFrame, const char *pszFrameName):通过给定的名称添加一个精灵帧。 如果名称已经存在,那么原来名称的内容将被新的所替代。

    二、精灵的创建

    精灵的创建:

        精灵是游戏中主要的元素,创建的方式有很多种,通过纹理创建,通过精灵帧创建等。

        精灵的继承关系:class CC_DLL CCSprite : public CCNodeRGBA, public CCTextureProtocol

        精灵的部分代码如下:

     

    [cpp] view plaincopyprint?

    1. class CC_DLL CCSprite : public CCNodeRGBA, public CCTextureProtocol  
    2. {  
    3. public:  
    4.     static CCSprite* create();  
    5.     static CCSprite* create(const char *pszFileName);  
    6.     static CCSprite* create(const char *pszFileName, const CCRect& rect);  
    7.     static CCSprite* createWithTexture(CCTexture2D *pTexture);  
    8.     static CCSprite* createWithTexture(CCTexture2D *pTexture, const CCRect& rect);  
    9.     static CCSprite* createWithSpriteFrame(CCSpriteFrame *pSpriteFrame);  
    10.     static CCSprite* createWithSpriteFrameName(const char *pszSpriteFrameName);  
    11.     virtual bool initWithTexture(CCTexture2D *pTexture);  
    12.     virtual bool initWithTexture(CCTexture2D *pTexture, const CCRect& rect);  
    13.     virtual bool initWithTexture(CCTexture2D *pTexture, const CCRect& rect, bool rotated);  
    14.     virtual bool initWithSpriteFrame(CCSpriteFrame *pSpriteFrame);  
    15.     virtual bool initWithSpriteFrameName(const char *pszSpriteFrameName);  
    16.     virtual bool initWithFile(const char *pszFilename);  
    17.     virtual bool initWithFile(const char *pszFilename, const CCRect& rect);  
    18. }  

    光看上面代码就知道它们是创建和初始化精灵的函数。有许多种方法可以创建一个精灵。

     

    创建精灵方式如下图所示:

    提示:系统默认的图片路径是工程下面Resources,如果是其下有更深层次的目录。需要手动添加。

    第一种:利用图片直接创建精灵

    [cpp] view plaincopyprint?

    1. static CCSprite* create(const char *pszFileName);  
    2. static CCSprite* create(const char *pszFileName, const CCRect& rect);  

    通过这两个create函数可以从图片直接创建一个精灵出来,pszFileName为图片的名字,第二个参数可以指定图片截取大小,方向为从左上放到右下方截取。

     

     

    [cpp] view plaincopyprint?

    1. 1:  CCSprite* sprite1 = CCSprite::create("HelloWorld.png");  
    2.     addChild(sprite1);  

    上面实例仅使用一张图片创建精灵,精灵的默认锚点为(0.5,0.5),加到父节点上默认位置为(0,0)。

     

    利用第二个函数创建精灵先来看看相关的宏:

     

    [cpp] view plaincopyprint?

    1. #define CCPointMake(x, y) CCPoint((float)(x), (float)(y))  
    2. #define CCSizeMake(width, height) CCSize((float)(width), (float)(height))  
    3. #define CCRectMake(x, y, width, height) CCRect((float)(x), (float)(y), (float)(width), (float)(height))  
    4. CCRect::CCRect(void)  
    5. {  
    6.     setRect(0.0f, 0.0f, 0.0f, 0.0f);  
    7. }  
    8.   
    9. CCRect::CCRect(float x, float y, float width, float height)  
    10. {  
    11.     setRect(x, y, width, height);  
    12. }  

    由上面代码可以知道我们可以用CCRectMake创建一个CCRect。

     

    下面实例:

    [cpp] view plaincopyprint?

    1. CCSize winSize = CCDirector::sharedDirector()->getWinSize();  
    2. CCSprite* sprite2 = CCSprite::create("HelloWorld.png",CCRect(0,0,240,100));  
    3. sprite2->setPosition(ccp(winSize.width/2, winSize.height/2));  
    4. addChild(sprite2);  

    实际上显示出HelloWorld.png图片,左上角截取的一部分图片。方向为从左上放到右下方截取。

     

     

    第二种:利用纹理来创建精灵

     

    [cpp] view plaincopyprint?

    1. static CCSprite* createWithTexture(CCTexture2D *pTexture);  
    2. static CCSprite* createWithTexture(CCTexture2D *pTexture, const CCRect& rect);  

    这两个函数参数pTexture是一个纹理对象指针,那么首先就要先创建这个纹理;第二个参数同样是截取大小所用,从左上到右下截取。

     

    CCTexture2D类中没有create函数,只能用new创建一个CCTexture2D对象,之后通过initWithImage来添加纹理内容。 

    CCTexture2D中关于initWithImage函数的代码如下:

     

    [cpp] view plaincopyprint?

    1. class CC_DLL CCTexture2D : public CCObject  
    2. {  
    3. public:  
    4.     bool initWithImage(CCImage * uiImage);  
    5. }  

    由此可知道想要创建一个CCTexture2D对象需要CCImage对象指针。

     

    CCImage类:支持从JPG, PNG, TIFF以及数据流,字符串中创建供Cocos2d - x进行访问的图片数据对象。

    看看CCImage中,只列出我们目前关心的内容:

     

    [cpp] view plaincopyprint?

    1. class CC_DLL CCImage : public CCObject  
    2. {  
    3. public:  
    4.     bool initWithImageFile(const char * strPath, EImageFormat imageType = kFmtPng);  
    5. }  

    第一个参数为图片文件路径与名字,第二个参数为类型,指明是从那种数据创建CCImage,使用时使用其默认值就好。

     

    实例一,通过直接创建纹理来创建精灵:

     

    [cpp] view plaincopyprint?

    1. CCSize winSize = CCDirector::sharedDirector()->getWinSize();  
    2. CCImage* image = new CCImage();  
    3. image->initWithImageFile("HelloWorld.png");  
    4.   
    5. CCTexture2D* texture = new CCTexture2D;  
    6. texture->autorelease();  
    7. texture->initWithImage(image);  
    8. CCSprite* sprite = CCSprite::createWithTexture(texture);  
    9. sprite->setPosition(ccp(winSize.width/2,winSize.height/2));  
    10. addChild(sprite);  


    首先创建一个CCImage对象,用来创建CCTexture2D;

     

    因为CCTexture2D没有添加到渲染树中,不会自动释放,所以用autorelease来延迟释放;

    之后利用CCTexture2D来创建CCSprite。

    CCTexture2D还有另一种获取的方法,就是之前介绍的从纹理缓存中获取,利用这种方法需要现在纹理缓存中添加图片。

    实例二,通过纹理缓存获取纹理创建精灵:

     

    [cpp] view plaincopyprint?

    1. CCSize winSize = CCDirector::sharedDirector()->getWinSize();  
    2. CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png");  
    3. CCSprite* sprite = CCSprite::createWithTexture(texture);  
    4. sprite->setPosition(ccp(winSize.width/2,winSize.height/2));  
    5. addChild(sprite);  


    首先创建一个纹理缓存,然后把图片加载到纹理缓存中;

     

    从纹理缓存中获取纹理;

    之后利用纹理创建精灵。

    第三种:利用精灵帧创建精灵

     

    [cpp] view plaincopyprint?

    1. static CCSprite* createWithSpriteFrame(CCSpriteFrame *pSpriteFrame);  
    2. static CCSprite* createWithSpriteFrameName(const char *pszSpriteFrameName);  

     

    上面两行代码虽然相似,但是也有些区别,第一个函数需要精灵帧对象指针作为参数,第二个函数则需要精灵帧的名字做参数。

    之前介绍了精灵帧缓存,现在再来看看精灵帧,部分代码如下:

     

    [cpp] view plaincopyprint?

    1. class CC_DLL CCSpriteFrame : public CCObject  
    2. {  
    3. public:  
    4.     static CCSpriteFrame* create(const char* filename, const CCRect& rect);  
    5.     static CCSpriteFrame* create(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize);  
    6.     static CCSpriteFrame* createWithTexture(CCTexture2D* pobTexture, const CCRect& rect);  
    7.     static CCSpriteFrame* createWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize);  
    8. }  

    由上面代码可以看出,创建精灵帧可以通过图片文件直接创建,也可以通过纹理创建精灵帧。精灵帧也可以有精灵帧缓存获得。

     

    实例一,通过图片直接创建精灵帧创建精灵:

     

    [cpp] view plaincopyprint?

    1. CCSize winSize = CCDirector::sharedDirector()->getWinSize();  
    2. CCSpriteFrame* spriteFrame = CCSpriteFrame::create("HelloWorld.png", CCRectMake(0, 0, 200, 200));  
    3. CCSprite* sprite = CCSprite::createWithSpriteFrame(spriteFrame);  
    4. sprite->setPosition(ccp(winSize.width/2, winSize.height/2));  
    5. addChild(sprite);  

    这里首先通过图片创建了一个精灵帧;

     

    利用这个精灵帧创建了一个精灵。

    实例二,通过精灵帧缓冲取出精灵帧创建精灵:

     

    [cpp] view plaincopyprint?

    1. CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sprite/zombie.plist");  
    2. CCSpriteFrame* spriteFrame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("z_1_attack_01.png");  
    3. CCSprite* sprite = CCSprite::createWithSpriteFrame(spriteFrame);  
    4. sprite->setPosition(ccp(100, 100));  
    5. addChild(sprite);  

    首先,把plist文件添加到精灵帧缓冲当中,精灵帧缓冲添加精灵帧的方法在之前介绍精灵帧缓冲时候介绍过;

     

    然后,通过精灵帧缓冲取得我们需要用到的精灵帧,用到了CCSpriteFrameCache中spriteFrameByName函数,

    此函数通过小图片的名字从小图片集合成的大图片创建的精灵帧缓冲中取出对应的精灵帧;

    最后通过精灵帧创建精灵。

    实例三,通过精灵帧缓冲中精灵帧的名字直接创建精灵:

     

    [cpp] view plaincopyprint?

    1. CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sprite/zombie.plist");  
    2. CCSprite* sprite = CCSprite::createWithSpriteFrameName("z_1_attack_01.png");  
    3. sprite->setPosition(ccp(100,100));  
    4. addChild(sprite);  

    首先创建了一个精灵帧缓冲;

     

    创建精灵时候直接通过精灵帧缓冲中精灵帧名字创建。

     

    三、zOrder

    zOrder在Cocos2d-x中用来描述节点渲染的顺序,CCNode派生的类都有zOrder,默认值是0。

    zOrder的值越大,绘制越靠后,以精灵为例子zOrder值大的精灵呈现在zOrder值小的精灵上面。

    zOrder在CCNode中相关内容代码精简后如下:

     

    [cpp] view plaincopyprint?

    1. class CC_DLL CCNode : public CCObject  
    2. {  
    3. protected:  
    4.     int m_nZOrder;  //< z-order value that affects the draw order  
    5.     CCNode *m_pParent;  
    6. public:  
    7.     CCNode::CCNode(void) :..., m_nZOrder(0)...  
    8.     {  
    9.     }  
    10.     void setZOrder(int z)  
    11.     {  
    12.         _setZOrder(z);  
    13.         if (m_pParent)  
    14.         {  
    15.             m_pParent->reorderChild(this, z);  
    16.         }  
    17.     }  
    18.     void reorderChild(CCNode *child, int zOrder)  
    19.     {  
    20.         child->_setZOrder(zOrder);  
    21.     }  
    22.     void _setZOrder(int z)  
    23.     {  
    24.         m_nZOrder = z;  
    25.     }  
    26. }  

    由上诉代码可以知道,如果zOrder没有人为指定,在构造函数中初始化为0;

     

    我们可以通过setZOrder来修改zOrder的值。

    展开全文
  • //申请帧缓存对象的内存 glGenFramebuffers(1,FBOs);//产生帧缓存对象 glBindFramebuffer(GL_FRAMEBUFFER, FBOs[0]);//绑定帧缓存对象 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_...
  • OPENGL帧缓存和动画

    千次阅读 2017-01-10 23:06:37
    一般正规的动画制作在实现上都是通过双缓存实现的(硬件也好,软件也好)大家可以参考《家用...当前台显示缓存用于显示时,后台缓存已经进行计算计算完毕把所有内容通过缓存拷贝一次性完成,防止闪烁的出现。 

    首先感谢转载原链接:http://blog.163.com/cp7618@yeah/blog/static/7023477720106156557104/


    一般正规的动画制作在实现上都是通过双缓存实现的(硬件也好,软件也好)大家可以参考《家用电脑与游戏机》的98-2中的一篇文章。当前台显示缓存用于显示时,后台缓存已经进行计算,计算完毕把所有内容通过缓存拷贝一次性完成,防止闪烁的出现。 

    一 OPENGL帧缓存的实现 

    1 颜色缓存(Color Buffer)其中内容可以是颜色索引或者RGBA数据,如果用的OPENGL系统支持立体图,则有左右两个缓存。 

    2 深度缓存(Depth Buffer) 就是Z-BUFFER,用于保存象素Z方向的数值,深度大的被深度小的代替,用以实现消隐 

    3 模板缓存(Stencil Buffer) 用以保持屏幕上某些位置图形不变,而其他部分重绘。例如大家熟悉的开飞机和赛车的游戏的驾驶舱视角,只有挡风外面的景物变化,舱内仪表等等并不变化。 

    4 累计缓存(Accumulation Buffer) 只保存RGBA数据,用于合成图象,例如有某缓存中的位图调入这里合成一幅新图。 

    二 帧缓存的清除 
    对高分辨率模式清除缓存是工作量巨大的任务,OPENGL一般先寻求硬件同时完成,否则软件依次解决。我们前面每次必用的glClearColor()大家已经不陌生吧。 

    首先设置清除值 
    void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf
    alpha); 
    void glClearIndex(GLfloat index); 
    void glClearDepth(GLclampd depth); 
    void glClearStencil(GLint s); 
    void glClerAccum(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha); 

    然后进行清除 
    void glClear(GLbitfield mask); 
    mask: GL_COLOR_BUFFER_BIT| 
    GL_DEPTH_BUFFER_BIT| 
    GL_STENCIL_BUFFER_BIT| 
    GL_ACCUM_BUFFER_BIT 

    三 双缓存动画 
    你可以把所有的变换工作看成后台缓存的计算,然后把所有结果拷贝到前台即可。 因此我们只需两个新内容: 

    首先初始化时调用 
    auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA); 
    用AUX_DOUBLE代替AUX_SINGLE设置成双缓存模式 

    然后在绘制完毕(glFlush();后)调用 
    auxSwapBuffers(); 
    进行缓存拷贝。Easy like sunday morning!! 
    当然不同系统下,这个函数也许不同(毕竟是辅助库函数么),例如X-WINDOWS 
    下可以使用glxSwapBuffers(),意思完全一样。 

    先说说下面这个例子的功能: 
    有一个兰色的环作为主体,有一个黄色高亮的球表示光源的位置。小球不断从屏幕左方运动到右方,可以看出环状物上光影的变化。 
    操作: 
    鼠标左键/右键:开始/停止光源的运动 
    键盘 上/下/左/右:控制环状物的 前进/后退/旋转 

    // 
    //sample.cpp 
    #include "glos.h" 
    #include 
    #include 
    #include "windows.h" 

    void myinit(void); 
    void CALLBACK display(void); 
    void CALLBACK reshape(GLsizei w,GLsizei h); 
    void CALLBACK stepDisplay(void); 
    void CALLBACK startIdleFunc(AUX_EVENTREC *event); 
    void CALLBACK stopIdleFunc(AUX_EVENTREC *event); 

    //step是表示环状物旋转的参数;z是控制其前后坐标的参数 
    static GLfloat step=0.0,z=0.0; 
    //position是控制光源的位置的参数 
    static GLfloat position[]={-20.0,0.0,-5.0,1.0}; 

    void myinit(void) 

    //初始化注意是双缓存模式 
    auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA); 

    auxInitPosition(0,0,500,500); 
    auxInitWindow("sample1"); 
    glClearColor(0.0,0.0,0.0,0.0); 
    glClear(GL_COLOR_BUFFER_BIT); 


    glFrontFace(GL_CW); 

    glEnable(GL_LIGHTING); 
    glFrontFace(GL_CW); 
    // glEnable(GL_POLYGON_SMOOTH); 
    // glEnable(GL_BLEND); 
    // glBlendFunc(GL_SRC_ALPHA,GL_ONE); 

    glDepthFunc(GL_LESS); 
    glEnable(GL_DEPTH_TEST); 
    // glShadeModel(GL_FLAT); 

    void CALLBACK reshape(GLsizei w,GLsizei h) 


    glViewport(0,0,w,h); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    /*if(w<=h*3) 
    glOrtho(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w, 
    2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0); 
    else 
    glOrtho(-2.0*(GLfloat)h/(GLfloat)w, 
    2.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,-10.0,10.0); 
    */ 

    //启用立体的视景,具有近大远小的效果 
    glFrustum(-6.0,6.0,-6.0,6.0,3.0,20.0); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 




    void CALLBACK display(void) 


    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 

    //首先在当前位置设置光源 
    glPushMatrix(); 
    GLfloat light_ambient[]={0.3,0.5,0.3}; 
    GLfloat light_diffuse[]={1.0,1.0,1.0}; 
    GLfloat light_specular[]={0.8,0.8,0.0}; 
    glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); 
    glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); 
    glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); 
    glLightfv(GL_LIGHT0,GL_POSITION,position); 
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    //在光源旁边绘制黄色高亮的小球,标志光源位置 
    //小球和光源位置由position[]决定 
    glTranslatef(position[0],position[1],position[2]-1.0); 
    GLfloat mat_ambient[]={1.0,0.0,0.0,1.0}; 
    GLfloat mat_diffuse[]={1.0,1.0,0.0,1.0}; 
    GLfloat mat_specular[]={1.0,1.0,0.0,1.0}; 
    GLfloat mat_shininess[]={50.0}; 
    glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); 
    glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); 
    glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); 
    glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); 
    auxSolidSphere(0.5); 
    glPopMatrix(); 

    //在当前位置绘制兰色环状物,其位置由step z共同决定 
    glPushMatrix(); 
    glTranslatef(0.0,0.0,-8.0+z); 
    glRotatef(135.0+step,0.0,1.0,0.0); 
    GLfloat mat2_ambient[]={0.0,0.0,1.0,1.0}; 
    GLfloat mat2_diffuse[]={0.2,0.0,0.99,1.0}; 
    GLfloat mat2_specular[]={1.0,1.0,0.0,1.0}; 
    GLfloat mat2_shininess[]={50.0}; 
    glMaterialfv(GL_FRONT,GL_AMBIENT,mat2_ambient); 
    glMaterialfv(GL_FRONT,GL_DIFFUSE,mat2_diffuse); 
    glMaterialfv(GL_FRONT,GL_SPECULAR,mat2_specular); 
    glMaterialfv(GL_FRONT,GL_SHININESS,mat2_shininess); 
    auxSolidTorus(2.0,3.5); 
    glPopMatrix(); 

    glFlush(); 
    //绘制完毕,缓存交换 
    auxSwapBuffers(); 


    void CALLBACK Up(void) 

    //键盘“上”的处理 
    z=z+0.05; 

    void CALLBACK Down(void) 

    //键盘“下”的处理 
    z=z-0.05; 

    void CALLBACK Left(void) 

    //键盘“左”的处理 
    step=step+2.0; 

    void CALLBACK Right(void) 

    //键盘“右”的处理 
    step=step-2.0; 


    void CALLBACK stepDisplay(void) 

    //系统闲时的调用过程 
    position[0]=position[0]+0.5; 
    if(position[0]>20.0) position[0]=-20.0; 
    display(); 


    void CALLBACK startFunc(AUX_EVENTREC *event) 

    //鼠标左键的处理 
    auxIdleFunc(stepDisplay); 


    void CALLBACK stopIdleFunc(AUX_EVENTREC *event) 

    //鼠标右键的处理 
    auxIdleFunc(0); 


    void main(void) 

    myinit(); 

    auxReshapeFunc(reshape); 
    auxIdleFunc(stepDisplay); 
    auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,startFunc); 
    auxMouseFunc(AUX_RIGHTBUTTON,AUX_MOUSEDOWN,stopIdleFunc); 
    auxKeyFunc(AUX_UP,Up); 
    auxKeyFunc(AUX_DOWN,Down); 
    auxKeyFunc(AUX_LEFT,Left); 
    auxKeyFunc(AUX_RIGHT,Right); 
    auxMainLoop(display); 

    //end of sample 
     
    其中用到大量CALLBACK函数,分别处理不同消息比较前面演示的动画效果,闪烁的现象明显改善乐(你可以把这个程序两个关于双缓存的地方改成单缓存:设置AUX_SINGLE和去掉auxSwapBuffers(),看看闪烁的多么厉害),至于本身的绘图可能的拖尾现象,只能怪自己机器不好乐。


    展开全文
  • OPENGL帧缓存和动画

    2008-09-26 21:14:00
    OPENGL帧缓存和动画 作为最后一关,我们将架设自己即时光影的动画,让没有VOODOO的玩家看看OPENGL 这震撼(至少我是这么认为的吧)的效果,完成所有这将近20次灌水最终目标。 我们前面(好象是第三还是第四次)讲...
    OPENGL帧缓存和动画 
    作为最后一关,我们将架设自己即时光影的动画,让没有VOODOO的玩家看看OPENGL 
    这震撼(至少我是这么认为的吧)的效果,完成所有这将近20次灌水最终目标。 
     
    我们前面(好象是第三还是第四次)讲过如何用几何变换实现动画。那时的效果 
    现在看肯定不尽人意,因为频繁的闪烁不是我们需要的。因为那时(到这之前也 
    是)采用的是单缓存模式。对正在显示的部分边计算边修改必然造成速度瓶颈, 
    出现闪烁。一般正规的动画制作在实现上都是通过双缓存实现的(硬件也好,软 
    件也好)大家可以参考《家用电脑与游戏机》的98-2中的一篇文章。当前台显示 
    缓存用于显示时,后台缓存已经进行计算,计算完毕把所有内容通过缓存拷贝一 
    次性完成,防止闪烁的出现。 
     
    一 OPENGL帧缓存的实现 
     
    1 颜色缓存(Color Buffer)其中内容可以是颜色索引或者RGBA数据,如果用的 
    OPENGL系统支持立体图,则有左右两个缓存。 
     
    2 深度缓存(Depth Buffer) 就是Z-BUFFER,用于保存象素Z方向的数值,深度 
    大的被深度小的代替,用以实现消隐 
     
    3 模板缓存(Stencil Buffer) 用以保持屏幕上某些位置图形不变,而其他部分 
    重绘。例如大家熟悉的开飞机和赛车的游戏的驾驶舱视角,只有挡风外面的景物 
    变化,舱内仪表等等并不变化。 
     
    4 累计缓存(Accumulation Buffer) 只保存RGBA数据,用于合成图象,例如有某 
    缓存中的位图调入这里合成一幅新图。 
     
    二 帧缓存的清除 
    对高分辨率模式清除缓存是工作量巨大的任务,OPENGL一般先寻求硬件同时完成, 
    否则软件依次解决。我们前面每次必用的glClearColor()大家已经不陌生吧。 
     
    首先设置清除值 
    void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha); 
    void glClearIndex(GLfloat index); 
    void glClearDepth(GLclampd depth); 
    void glClearStencil(GLint s); 
    void glClerAccum(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha); 
     
    然后进行清除 
    void glClear(GLbitfield mask); 
    mask: GL_COLOR_BUFFER_BIT| 
          GL_DEPTH_BUFFER_BIT| 
          GL_STENCIL_BUFFER_BIT| 
          GL_ACCUM_BUFFER_BIT 
     
    三 双缓存动画 
    你可以把所有的变换工作看成后台缓存的计算,然后把所有结果拷贝到前台即可。 
    因此我们只需两个新内容: 
     
    首先初始化时调用 
    auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA); 
    用AUX_DOUBLE代替AUX_SINGLE设置成双缓存模式 
     
    然后在绘制完毕(glFlush();后)调用 
    auxSwapBuffers(); 
    进行缓存拷贝。Easy like sunday morning!! 
    当然不同系统下,这个函数也许不同(毕竟是辅助库函数么),例如X-WINDOWS 
    下可以使用glxSwapBuffers(),意思完全一样。 
     
    先说说下面这个例子的功能: 
    有一个兰色的环作为主体,有一个黄色高亮的球表示光源的位置。 
    小球不断从屏幕左方运动到右方,可以看出环状物上光影的变化。 
    操作: 
         鼠标左键/右键:开始/停止光源的运动 
         键盘 上/下/左/右:控制环状物的 前进/后退/旋转 
     
    // 
    //sample.cpp 
    #include "glos.h" 
    #include <GL/gl.h> 
    #include <GL/glaux.h> 
    #include "windows.h" 
     
    void myinit(void); 
    void CALLBACK  display(void); 
    void CALLBACK  reshape(GLsizei w,GLsizei h); 
    void CALLBACK  stepDisplay(void); 
    void CALLBACK  startIdleFunc(AUX_EVENTREC *event); 
    void CALLBACK  stopIdleFunc(AUX_EVENTREC *event); 
     
    //step是表示环状物旋转的参数;z是控制其前后坐标的参数 
    static GLfloat step=0.0,z=0.0; 
    //position是控制光源的位置的参数 
    static GLfloat position[]={-20.0,0.0,-5.0,1.0}; 
     
    void myinit(void) 

    //初始化注意是双缓存模式 
            auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA); 
     
            auxInitPosition(0,0,500,500); 
            auxInitWindow("sample1"); 
            glClearColor(0.0,0.0,0.0,0.0); 
            glClear(GL_COLOR_BUFFER_BIT); 
     
     
            glFrontFace(GL_CW); 
     
            glEnable(GL_LIGHTING); 
            glFrontFace(GL_CW); 
    //      glEnable(GL_POLYGON_SMOOTH); 
    //      glEnable(GL_BLEND); 
    //      glBlendFunc(GL_SRC_ALPHA,GL_ONE); 
     
            glDepthFunc(GL_LESS); 
            glEnable(GL_DEPTH_TEST); 
    //      glShadeModel(GL_FLAT); 

     
    void CALLBACK reshape(GLsizei w,GLsizei h) 

     
    glViewport(0,0,w,h); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    /*if(w<=h*3) 
     glOrtho(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w, 
             2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0); 
    else 
      glOrtho(-2.0*(GLfloat)h/(GLfloat)w, 
             2.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,-10.0,10.0); 
    */ 
     
    //启用立体的视景,具有近大远小的效果 
    glFrustum(-6.0,6.0,-6.0,6.0,3.0,20.0);   
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
     

     
     
    void CALLBACK display(void) 

     
      glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 
     
    //首先在当前位置设置光源   
        glPushMatrix(); 
            GLfloat light_ambient[]={0.3,0.5,0.3}; 
            GLfloat light_diffuse[]={1.0,1.0,1.0}; 
            GLfloat light_specular[]={0.8,0.8,0.0}; 
            glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient); 
            glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse); 
            glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular); 
            glLightfv(GL_LIGHT0,GL_POSITION,position); 
            glEnable(GL_LIGHTING); 
            glEnable(GL_LIGHT0); 
    //在光源旁边绘制黄色高亮的小球,标志光源位置 
    //小球和光源位置由position[]决定 
            glTranslatef(position[0],position[1],position[2]-1.0); 
            GLfloat mat_ambient[]={1.0,0.0,0.0,1.0}; 
            GLfloat mat_diffuse[]={1.0,1.0,0.0,1.0}; 
            GLfloat mat_specular[]={1.0,1.0,0.0,1.0}; 
            GLfloat mat_shininess[]={50.0}; 
            glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); 
            glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); 
            glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); 
            glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); 
            auxSolidSphere(0.5); 
        glPopMatrix(); 
     
    //在当前位置绘制兰色环状物,其位置由step z共同决定   
        glPushMatrix(); 
            glTranslatef(0.0,0.0,-8.0+z); 
            glRotatef(135.0+step,0.0,1.0,0.0); 
            GLfloat mat2_ambient[]={0.0,0.0,1.0,1.0}; 
            GLfloat mat2_diffuse[]={0.2,0.0,0.99,1.0}; 
            GLfloat mat2_specular[]={1.0,1.0,0.0,1.0}; 
            GLfloat mat2_shininess[]={50.0}; 
            glMaterialfv(GL_FRONT,GL_AMBIENT,mat2_ambient); 
            glMaterialfv(GL_FRONT,GL_DIFFUSE,mat2_diffuse); 
            glMaterialfv(GL_FRONT,GL_SPECULAR,mat2_specular); 
            glMaterialfv(GL_FRONT,GL_SHININESS,mat2_shininess); 
            auxSolidTorus(2.0,3.5); 
        glPopMatrix(); 
             
      glFlush(); 
    //绘制完毕,缓存交换 
      auxSwapBuffers(); 
     

    void CALLBACK Up(void) 

    //键盘“上”的处理 
    z=z+0.05; 

    void CALLBACK Down(void) 

    //键盘“下”的处理 
    z=z-0.05; 

    void CALLBACK Left(void) 

    //键盘“左”的处理 
    step=step+2.0; 

    void CALLBACK Right(void) 

    //键盘“右”的处理 
    step=step-2.0; 

     
    void CALLBACK stepDisplay(void) 

    //系统闲时的调用过程 
      position[0]=position[0]+0.5; 
      if(position[0]>20.0) position[0]=-20.0; 
      display(); 

     
    void CALLBACK startFunc(AUX_EVENTREC *event) 

    //鼠标左键的处理 
            auxIdleFunc(stepDisplay); 

     
    void CALLBACK stopIdleFunc(AUX_EVENTREC *event) 

    //鼠标右键的处理 
      auxIdleFunc(0); 

     
    void main(void) 

            myinit(); 
         
            auxReshapeFunc(reshape); 
            auxIdleFunc(stepDisplay); 
            auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,startFunc); 
            auxMouseFunc(AUX_RIGHTBUTTON,AUX_MOUSEDOWN,stopIdleFunc); 
            auxKeyFunc(AUX_UP,Up); 
            auxKeyFunc(AUX_DOWN,Down); 
            auxKeyFunc(AUX_LEFT,Left); 
            auxKeyFunc(AUX_RIGHT,Right); 
            auxMainLoop(display); 

    //end of sample 
     
    其中用到大量CALLBACK函数,分别处理不同消息 
    比较前面演示的动画效果,闪烁的现象明显改善乐(你可以把这个程序两个关于 
    双缓存的地方改成单缓存:设置AUX_SINGLE和去掉auxSwapBuffers(),看看闪烁 
    的多么厉害),至于本身的绘图可能的拖尾现象,只能怪自己机器不好乐。 
    写到这里,终于打穿乐OPENGL!!!实现当初提出的“长长见识”的设想。 
    今后有什么新内容我还会尽量补充,大家也可以自由补充。 
    展开全文
  • react 双缓存计算

    2021-02-09 16:57:48
    举个例子,使用 canvas 绘制动画时,在绘制每一前都会清除上一的画面,清除上一需要花费时间,如果当前画面计算量又比较大,又需要花费比较长的时间,这就导致上一清除到下一显示中间会有较长的间隙,就...
  • 一、纹理缓存、帧缓存、动画缓存 缓存机制:存储设施有快慢之分,PC机上有硬盘与内存之分,计算机软件运行时候把资源加载到内存中运行;手机与PC也是类似的。当手机软件运行时候,把经常需要用到的资源预先加载到...
  • 灰度等级为256级,分辨率为1024*1024的显示器,至少需要的帧缓存容量为() A 512KB B 1MB C 2MB D 4MB 正确答案:B **科普:** 灰度是用来衡量像素颜色的指标,黑白色,非0即1,灰度等级为256级,即2^8是256,...
  • OpenGL帧缓存(转)

    千次阅读 2007-10-08 11:39:00
    作为最后一关,我们将架设自己即时光影的动画,让没有VOODOO的玩家看看OPENGL 这震撼(至少我是这么...对正在显示的部分边计算边修改必然造成速度瓶颈,出现闪烁。一般正规的动画制作在实现上都是通过双缓存实现的(硬
  • 今天在抖音上有位网友朋友,给我留言,他在使用Vray5渲染器当中,遇到了帧缓存界面渲染的时候并不会自动弹出来,但可以在渲染过程结束后,在F10渲染器设置面板中,通过手动的方式打开,非常妨碍正常的工作,影响工作...
  • 但是如果需要实现计算较为复杂的图像处理例如高斯滤波或者双边滤波,则效果则差很多。例如以1920X1080为PrevewSize的预览数据进行高斯滤波处理,每次加权处理过程都需要从对应2D纹理中找到自身所在点的数据和周围...
  • [UWP]缓存Lottie动画

    2018-12-29 16:39:00
    在上一篇博文《[UWP]在UWP平台中使用Lottie动画》中我简单介绍了一下LottieUWP项目以及如何使用它呈现Lottie动画,这篇文章里我们来讲点进阶的东西——缓存Lottie动画。 为什么会有这样的需求呢? 有两方面原因: ...
  • 聊聊vue的计算属性和听器vue的计算属性computed和侦听器watch都是监听数据变化。computed顾名思义,computed 中文为计算;所以其在vue单文件组件中做的就是对数据进行简单的一些逻辑计算,这在项目开发中很方便...
  • 最近在想着怎么提高自己的iOS技能,不断的阅读别人的blog。发现读完了不练手很快又忘掉了,练手吧又不知道从何处下手。...不恰当的使用往往会造成掉引起界面卡顿。关于界面上图像的显示原理,卡顿造成的原...
  • 但是在做数值计算的时候,一般是不需要输出到屏幕上的,这就是今天我们要用到的帧缓存。有了帧缓存,我们的输出不需要是屏幕了,而是直接输出到帧缓存中去。而且帧缓冲区对象的使用还会对程序的性能有一定提升 ...
  • 举个例子,使用 canvas 绘制动画时,在绘制每一前都会清除上一的画面,清除上一需要花费时间,如果当前画面计算量又比较大,又需要花费比较长的时间,这就导致上一清除到下一显示中间会有较长的间隙,就...
  • 帧调试器可以查看每一个渲染事件使用的shader、pass、keywords等属性,以及当前渲染的目标(如阴影映射纹理、深度纹理、帧缓存等),还可以查看shader中一些计算变量(纹理、坐标、矩阵等),配合Game窗口可以很好的...
  • 计算机图形学习题.pdf

    2020-07-20 00:17:54
    计算机图形学部分习题答案 王飞 1.... 视帧缓存的深度而定以帧缓存为深度为 1 为例速度为 1024*1280*1*72b=11.25MB/s,即读取一个像素用时倒数分之 1 每秒隔行扫描72 变 30. 3. 每帧 480*640 像素的视频显示仅含有 300
  • 而我们的GPU则是负责对位图进行渲染,最后将渲染好的位图放到帧缓存区。由视频控制器在指定时间之前去帧缓冲区提取显示内容,通过显示屏显示出来。 举例说明 当我们创建一个UIView控件之后,它的显示部分由CALayer...
  • 从逻辑上讲,网卡包括7个功能模块,分别是CU(控制单元)、OB(输出缓存)、IB(输入缓存)、LC(线路编码器)、LD(线路解码器)、TX(发射器)、RX(接收器)。 计算机通过网卡发送信息的过程: 计算机上的应用...
  • 帧缓存的深度决定可以表示多少种颜色; 分辨率 帧缓存中的像素个数,决定你在图像中可以看到的细节; 扫描转换或光栅化 将几何实体转化为帧缓存中的像素。 特点 使用 可移植性强 内容 指令丰富 程序组成...
  • 1.图形定义保存在刷新缓存或者帧缓存的存储器中,这里的贞是指整个屏幕范围 2.每个可由电子束点亮的屏幕点成为像素, pixel 或pel 3.由于刷新缓存用来存储屏幕颜色值,因此它也被称为颜色缓存。 4.每像素的位数...
  • 帧缓存存储器——简称帧缓存 流水线的概念 应用阶段 几何阶段 光栅化阶段 GPU渲染管线 几何阶段 1.顶点着色器 2. 几何曲面着色器 3.剪裁 4.屏幕映射 ...
  • 交换机的自学习:交换机在二层转发,通过学习的源mac地址,会在内部建立一张MAC地址表,也可以称为FDB(转发数据库),当交换机的一个端口收到一个,如果的源MAC地址,不在表中,会新增一条表项(vlan—mac—...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 384
精华内容 153
关键字:

帧缓存计算