7_DoubleBuffer 游戏编程中的双缓存模式
### double buffer 双缓存 简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替 #### the pattern
有两个缓存实例,一个是 current buffer, 一个是next buffer 从current buffer读取信息, 往next buffer里写入信息.
swap操作,进行两种buff的身份切换 #### 何时使用
需要增量修改的状态
在修改的过程中需要进行访问
当访问数据的时候,不会发现数据正在被写入
读操作不用等待写的操作完成 #### 注意事项 swap操作比较耗时
必须有两个buffer, 内存消耗变大 #### Sample Code ####一个帧缓存的例子 ```
class Framebuffer
{
public:
Framebuffer() { clear(); } void clear()
{
for (int i = ; i < WIDTH * HEIGHT; i++)
{
pixels_[i] = WHITE;
}
} void draw(int x, int y)
{
pixels_[(WIDTH * y) + x] = BLACK;
} const char* getPixels()
{
return pixels_;
} private:
static const int WIDTH = ;
static const int HEIGHT = ; char pixels_[WIDTH * HEIGHT];
}; // 问题版本
class Scene
{
public: // 每一帧执行 void draw()
{
buffer_.clear(); buffer_.draw(, );
buffer_.draw(, );
// 问题! video driver 可以在任何时候读取pixels, 可能会读到非法值
buffer_.draw(, );
buffer_.draw(, );
buffer_.draw(, );
buffer_.draw(, );
} Framebuffer& getBuffer() { return buffer_; } private:
Framebuffer buffer_; void swap()
{
// Just switch the pointers.
Framebuffer* temp = current_; current_ = next_;
next_ = temp;
} }; // 使用double buffer
class Scene
{
public:
Scene()
: current_(&buffers_[]),
next_(&buffers_[])
{} // video driver 只会从 current里获取pixel
void draw()
{
next_->clear(); next_->draw(, );
// ...
next_->draw(, ); swap();
} Framebuffer& getBuffer() { return *current_; } private:
void swap()
{
// Just switch the pointers.
Framebuffer* temp = current_;
current_ = next_;
next_ = temp;
} Framebuffer buffers_[];
Framebuffer* current_;
Framebuffer* next_;
}; ``` ##### Artificial unintelligence ```
class Actor
{
public:
Actor() : slapped_(false) {} virtual ~Actor() {}
virtual void update() = ; void reset() { slapped_ = false; }
void slap() { slapped_ = true; }
bool wasSlapped() { return slapped_; } private:
bool slapped_;
}; // 每一帧都会调用actor的update, ,所有的actor需要同时进行更新
// actor之间可以交互, 例如击打 class Stage
{
public:
void add(Actor* actor, int index)
{
actors_[index] = actor;
} void update()
{
for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->update();
actors_[i]->reset();
}
} private:
static const int NUM_ACTORS = ; Actor* actors_[NUM_ACTORS];
}; // 同一时间, 只会有一个actor执行update class Comedian : public Actor
{
public:
void face(Actor* actor) { facing_ = actor; } virtual void update()
{
if (wasSlapped()) facing_->slap();
} private:
Actor* facing_;
}; // 面对某人
harry ------> balay ------> chump
^ |
|
-------------------------------v Stage stage; Comedian* harry = new Comedian();
Comedian* baldy = new Comedian();
Comedian* chump = new Comedian(); harry->face(baldy);
baldy->face(chump);
chump->face(harry); stage.add(harry, );
stage.add(baldy, );
stage.add(chump, ); harry->slap(); stage.update(); // slap
harry ---slap---> balay --slap----> chump
^ |
|
----------------slap---------------v
正确的结果 #如果把三人的执行顺序换一下, 结果将不正确#
stage.add(harry, );
stage.add(baldy, );
stage.add(chump, ); 只有harry slap 了baldy buffered slaps // 把slap用buffer记录下来 class Actor
{
public:
Actor() : currentSlapped_(false) {} virtual ~Actor() {}
virtual void update() = ; void swap()
{
// Swap the buffer.
currentSlapped_ = nextSlapped_; // Clear the new "next" buffer.
nextSlapped_ = false;
} void slap() { nextSlapped_ = true; }
bool wasSlapped() { return currentSlapped_; } private:
bool currentSlapped_;
bool nextSlapped_;
}; void Stage::update()
{
for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->update();
} for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->swap();
}
} ``` #### buffer swap
swap需要锁住两个buffer, 所需需要尽量的轻量快速
交换指针 引用
.快速
.外部代码不能保存buffer指针
当前的数据,是两帧之前的数据(读current的同时,数据写入了next) buffer之间拷贝数据
如果无法进行swap,可以把next的数据copy到current
如果数量小则没什么问题,如果大则会耗时 ```
当很多对象都有需要swap操作时, 会很慢
下面这个例子,不用swap,而是slap的时候修改了next的值 class Actor
{
public:
static void init() { current_ = ; }
static void swap() { current_ = next(); } void slap() { slapped_[next()] = true; }
bool wasSlapped() { return slapped_[current_]; } private:
static int current_;
static int next() { return - current_; } bool slapped_[];
};
``` #### See also
double buffer 模式在图形编程上应用广泛 You can find the Double Buffer pattern in use in almost every graphics API out there. For example, OpenGL has swapBuffers(), Direct3D has “swap chains”, and Microsoft’s XNA framework swaps the framebuffers within its endDraw() method.
7_DoubleBuffer 游戏编程中的双缓存模式的更多相关文章
- 第28月第21天 记事本Unicode 游戏编程中的人工智能技术
1. Windows平台,有一个最简单的转化方法,就是使用内置的记事本小程序notepad.exe.打开文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条. 里面有四个选 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用
RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在 ...
- windows游戏编程X86 32位保护模式下的内存管理概述(二)
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22448323 作者:jadeshu 邮箱: jades ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验
运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...
- 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序
在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[2]--Aop PostSharp篇
上一篇我们使用了一个通用JSON协议约定来进行达到远程调用的目的.但是从实现上,我们需要不断的在所有的方法上添加拦截,并且判断拦截,然后执行,这就达到了一个比较繁琐的目的. 之前我们尝试过使用代码生成 ...
- windows游戏编程X86 32位保护模式下的内存管理概述(一)
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22445945 作者:jadeshu 邮箱: jades ...
- 如何系统掌握游戏编程中3D图形学相关的基础?
https://www.zhihu.com/question/27544895 三维几何学基础:三维坐标系统点与矢量矩阵与几何变换四元数与三维旋转
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存
第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...
随机推荐
- Centos date 设置自定义时间
[1]手动修改 (1)设置日期 # date -s 20190315 (2)设置时间 # date -s 15:23:34 (3)设置日期和时间 # date -s "20190315 15 ...
- 浅析js绑定同一个事件依次触发问题系列(一)
算了 还是上代码吧 记得写过这篇文章,但是找不到了(对,就是找不到了,算了再写一遍吧) 也是在群中有人问这个绑定不同事件 或者同一个事件的依次触发问题 个人建议如果是一个事件的话那么最好写成函数, ...
- 创建有提示的ui组件
using UnityEditor; using UnityEngine; using System.Collections; using Edelweiss.CloudSystem; namespa ...
- hihoCoder #1321 : 搜索五•数独 (Dancing Links ,精确覆盖)
hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. ...
- Android Studio报Error:Execution failed for task ':Companion:preDexDebug'.
错误例如以下: Error:Execution failed for task ':Companion:preDexDebug'. > com.android.ide.common.proces ...
- C++中面向对象的理解
1.对于OO(面向对象)的含义,并非每一个人的看法都是同样的. 即使在如今.假设问十个人,可能会得到15种不同的答案.差点儿全部的人都会允许继承和多态是OO中的概念.大多数人还会再加上封装. 另 ...
- [DBNETLIB][ConnectionOpen(Connect()).]SQL Server 不存在或拒绝访问 数据库错误 解决办法总结
连接数据库报错:“数据库异常:[DBNETLIB] [ConnectionOpen(Connenct()).] Sqlserver 不存在或拒绝访问” 原因: 1.查看是不是没有在数据库中添加数据库服 ...
- Linux安装python3.7.2详细操作步骤
1.下载Python依赖环境 yum install gcc patch libffi-devel python-devel zlib-devel bzip2-devel openssl-devel ...
- 程序运行之ELF 符号表
当一个工程中有多个文件的时候,链接的本质就是要把多个不同的目标文件相互粘到一起.就想玩具积木一样整合成一个整体.为了使不同的目标文件之间能够相互粘合,这些目标文件之间必须要有固定的规则才行.比如目标文 ...
- statu 设置
DATA: itab TYPE TABLE OF sy-ucomm. APPEND 'DELE' TO itab. APPEND 'PICK' TO itab. SET PF-STATUS 'STA3 ...