实现图形算法API[软光栅渲染器,C++]

news/2024/11/15 4:13:56/

最近有点烦,发烧感冒了三天[事实上是俩天,第三天是因为摆得太舒服了索性多玩一天],啥都没学,打守望先锋也把把被虐...,想着今天来提起键盘把之前的东西都总结一下。

那么话归真题,首先我是仿造opengl来写的图形api,因为是在cpu端运行,所以要比opengl优雅很多。

首先肯定要预先计划好写哪些功能,我想的第一个是vertexbuffer,因为这个是最经常接触的,而且实现思路也非常清晰明了。

class VertexBuffer
{struct DataWarp {ITypeTag* info = nullptr;size_t InfoSize = 0;void* data = nullptr;size_t dataElemSize = 0;~DataWarp() {memory::dealloc(data, info->tSize);memory::dealloc(info, InfoSize);}};
public:/** T			  数据的类型* bufferindex 所在的缓冲下标* dataIndex   缓冲中对应的数据下标*/template<class T>T* Sample(size_t bufferIndex, size_t dataIndex);/** index 布局的下标* size  数据的字节数* data  数据指针* T	    数据的类型*/template<class T>void SetData(size_t index, size_t size, void* data);
private:std::vector<DataWarp*> buffers;friend class IInvoker;
};

这个是我设计的类;

只暴露了两个方法,一个push数据,一个采样数据,push数据的方法模仿了opengl,给定对应的布局下标以及数据内存的大小和数据指针,然后将数据拷贝;

当然,我这边有一个问题,buffers里面的指针应该用智能指针代替;

SetData的方法:

template<class T>
inline void VertexBuffer::SetData(size_t index, size_t size, void* data)
{if (!data) return;if (index >= buffers.size())buffers.resize(index + 1);buffers[index] = new DataWarp;buffers[index]->data = memory::alloc<void>(size);memcpy(buffers[index]->data, data, size);buffers[index]->info = new TypeTag<T>();//注意memory::alloc不会调用构造函数buffers[index]->InfoSize = sizeof(TypeTag<T>);buffers[index]->dataElemSize = size / sizeof(T);
}

这边要提及一下TypeTag这个类了,这个是本人的一个小发明,主要是将数据类型抹除,然后用数据去封装,以达到运行时数据类型检测的效果,这个在整个框架设计中都非常重要;

这边我们将采样步长[T的字节数]等信息都封存到TypeTag中,这些信息在我们采样数据的时候是必须要有的;

这样我们就有了最基础的push数据和采样数据的功能了;

另外一个类的设计是uniformbuffer

class UniformBuffer
{struct DataWarp {ITypeTag* info;size_t InfoSize;void* data;~DataWarp() { memory::dealloc(data, info->tSize);memory::dealloc(info, InfoSize);}};
public:template<class T>void PushBufferData(std::string name,void* data);template<class T>T* GetBufferData(std::string name);template<class T>void SetBufferData(const std::string& name,const T& data);void SetCallBack(std::function<void(const std::string&, void*)>);
private:std::unordered_map<std::string, DataWarp*> buffers;std::function<void(const std::string&, void*)> callback;friend class IInvoker;
};

我们这边和opengl一样,是通过变量名表意字符串进行索引的,大概思路和vertexbuffer差不多,一个push数据的方法,一个采样数据的方法,其外有两个不同的方法,一个是修改数据的方法,因为vertexbuffer中的数据一般都不会被修改,所以就没提供这个方法,但是uniform不一样,里面的数据是会被经常修改的所以提供了一个修改数据的方法;

uniformbuffer中的数据会被渲染器分配到shader中,所以uniformbuffer中的数据修改时,shader中的数据也必须被修改,这个时候有两个方向两个思路的解决方向;

先说思路,一个是主动思路,一个是被动思路,其中主动思路的意思是,每帧的渲染中渲染器都将uniformbuffer中的数据重新分配给shader,还有一种思路是被动思路,意思是只有当uniformbuffer中的数据被修改的时候才会去重新分配,这样的好处是降低性能开销,我选择了后者;

所以我增加了一个setCallback的方法,当数据被修改的时候会回call,以达到重新分配的目的;

另外一个类是indexbuffer这个buffer就没什么说头了和vertexbuffer差不多,只不过相比上两个buffer,indexbuffer的数据是提供给渲染器的,而那两个是提供给shader的;

另外一个类的话,是invoker;

class IInvoker
{
protected:std::shared_ptr<UniformBuffer> uniformBuffer;// shader have uniformBuffer;std::shared_ptr<VertexBuffer> vertexBuffer;std::shared_ptr<IndexBuffer> indexBuffer;std::shared_ptr<IShader> shader;std::shared_ptr<ITexture> zBuffer;OutBufferManger* outBufferManger;Interpolator* intpor;//intpor是由vertexShader收集信息创建的,但由IInvoke持有,其不是一个指针对象,所以不用shared管理glm::mat4 viewport;glm::vec2 sampleSpace;glm::vec2 zbufferSS;std::function<bool(const float&, float&)> depthTest;void CheckUniformBuffer();void CheckVertexBufferLayout();void CheckIntpor();void UniformCallback(const std::string&, void*);//这个是vertexbuffer与vertexShader数据连接的桥梁,将数据按照layout进行匹配void SetLayoutDataForVertexShader(size_t);void SetUniformForShader();void fill_triangle_optimized(glm::ivec2 v1, glm::ivec2 v2, glm::ivec2 v3, const glm::vec3* vn, const glm::vec4* vPos);void SettleFragmentShaderRes(float x, float y);void TreatPixel(const int& x, const int& y,const glm::vec3* vn,const glm::vec4* vPos);glm::vec3 barycentric(glm::vec2 v1, glm::vec2 v2, glm::vec2 v3, glm::vec2 p);void Interplator(glm::vec3 Bar);
public:enum class Status {COMPELETED,FAILED};void Link();virtual void lnvokeForTriangle();Status vertexBufferStatus = Status::FAILED;Status uniformBufferStatus = Status::FAILED;Status InterpolatorStatus = Status::FAILED;friend int main();friend struct LiRenderer;
};

这个invoker是一个算法模板,我是为了将算法模板和渲染器解耦才设计这个类的,这个类中包括但不限于三角形填充算法、线性插值、重心插值、深度测试等等算法,而且为了可装配性,我将大部分算法模块都抽象成了一个std::function<>的接口,这样就可以在渲染器具中开放接口,让客户端程序员进行装配;

另外这个类我有一个做的不够好的地方,那就是校验数据的工作我给分配到其中了,但它只是一个算法模板,后面我们给修改的;

另外还有一个类,OutBufferManger,这个类的话的作用就相当于OpenGL中的多渲染目标了,一次渲染可以渲染出多张纹理;

class OutBufferManger
{struct TexAndNVar {void* var;//链接到framebuffer中的值的指针std::shared_ptr<ITexture> tex;};
public:OutBufferManger() {}void PushTexure(size_t index, std::shared_ptr<ITexture> texture);void SetData(size_t index, float x, float y, void* data);void SetData(size_t index, size_t x, size_t y, void* data);void TakeData(size_t index, float x, float y);void TakeData(size_t index, size_t x, size_t y);std::shared_ptr<ITexture>& GetTex(size_t index) { return ts.at(index).tex; }
private:std::vector<TexAndNVar> ts;friend struct LiRenderer;friend struct IInvoker;
};

这个类最终是要与fragmentshader进行对接的,将fragmentshader中数据与其中的Texture类进行绑定,渲染出的数据push到其中;

至于shader类就比较复杂了,因为涉及到很多种数据的准备工作,比如vertexshader要准备布局数据和传递到fragmentshader中的数据还有uniform数据,fragment也要准备很多数据;

这些数据的准备都是在构造函数中完成的,在基类中会完成必要的数据准备,子类中就是各种客户端程序员的自定义数据准备了;

另外还有很多有意思的问题,比如插值,怎么对一个三角形进行插值?用重心坐标,但是可能被插值的数据类型有那么多种,int、float、vec2、vec3...怎么能抹除数据的差别,用一种方法插值呢?

等等等等等都是问题,但好在我解决了;

下面奉上效果图:

 

 


http://www.ppmy.cn/news/75705.html

相关文章

图片转字符图片工具类

├── cn.xsshome.imagetool //包名├── convert │ └── ImageToChar //图片转字符图片、文本方法 ├── slideverifycode │ └── SlideVerifyCodeGenerateUtil //滑块验证码工具类代…

GWAS分析中的GO和KEGG富集分析

上一次&#xff0c;我们介绍如何根据显著性snp&#xff0c;使用bedtools根据上下游距离&#xff0c;根据gff文件注释基因。 这一次&#xff0c;介绍一下如何根据注释的基因&#xff0c;进行富集分析&#xff0c;主要是看一下GWAS定位的基因有没有某一个趋势&#xff0c;也算是…

【JavaSE】Java基础语法(五):数组详解

文章目录 &#x1f378;1.1 数组介绍&#x1f378;1.2 数组的动态初始化1.2.1 什么是动态初始化1.2.2 动态初始化格式&#x1f378;1.3 数组元素访问1.3.1 什么是索引1.3.2 访问数组元素格式1.3.3 示例代码 &#x1f378;1.4 内存分配1.4.1 内存概述1.4.2 java中的内存分配 &am…

【数据库】事务与并发控制

文章目录 事务什么是事务事务的主要特征事务分类隐式事务显示事务事务与并发控制锁死锁事务 什么是事务 宏观上看,事务就是一次完整的操作过程;程序角度看,事务是用户自定义的数据操作系统,由多条命令组成,内部所有命令语句要被当成一个整体,要么全部被执行,要么全部不…

HACKABLE: III

文章目录 HACKABLE: III实战演练一、前期准备1、相关信息 二、信息收集1、端口扫描2、访问网站3、查看网站源码4、扫描目录5、访问网址6、查看并下载7、访问网站8、查看文件9、解密10、访问网站11、访问网站12、查看文件13、解密14、访问网站15、访问网站16、下载图片17、隐写1…

MySQL数据库基础4-内置函数

文章目录 日期函数字符串函数数学函数其他函数 日期函数 函数名称描述current date()当前日期current time()当前时间current timestamp()当前时间戳date(datetime)返回datetime参数的日期部分date add(date, interval d_value type)在date中添加日期或时间&#xff0c;interv…

新手如何学习挖漏洞?看这篇就够了【网络安全】

前言 有不少阅读过我文章的伙伴都知道&#xff0c;我从事网络安全行业已经好几年&#xff0c;积累了丰富的经验和技能。在这段时间里&#xff0c;我参与了多个实际项目的规划和实施&#xff0c;成功防范了各种网络攻击和漏洞利用&#xff0c;提高了安全防护水平。 也有很多小伙…

【react 全家桶】react-Hook(上)

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 14【react-Hook &#xff08;上&#x…