我想创建一个渲染器类,该类可以在2个或更多着色器之间切换,而无需添加越来越多的绘制调用。
我的意思是拥有2个着色器-A和B-以及需要着色器,位置,大小来创建例如四边形的方法。
,我想添加该数据(位置,大小)并将其传递到顶点A(因此它是第一次绘制调用),然后将另一个数据添加到顶点B(因此它是第二次绘制调用),然后再次将数据添加到着色器A(因此仍应进行2次绘制调用,因为我们之前已经在某处使用了着色器A)。最后,通过绘制调用并绘制场景。
我有一个RenderData类,它添加了绘图调用,顶点,元素数据等。
struct DrawCall
{
//it may have more data like texture, clip rect, camera, etc.
Shader* shader = nullptr;
};
struct Vertex
{
Vector2 position;
}
class RenderData
{
public:
RenderData();
~RenderData();
void Free() {
vertexBuffer.clear();
shader.clear();
drawCall.clear();
elementBuffer.clear();
}
void Draw(const Rect& dest);
void AddDrawCall();
inline DrawCall* getDrawCall() { return drawCall.size() > 0 ? &drawCall.back() : nullptr; }
void UpdateShader();
void PushShader(Shader* shader);
void PopShader();
inline Shader* getShader() { return shader.size() > 0 ? shader.back() : nullptr; }
uint currentVertexIndex = 0;
vector<Vertex> vertexBuffer; // Vertex data
vector<Shader*> shader;
vector<DrawCall> drawCall;
vector<uint> elementBuffer; // Index data
}
void RenderData::AddDrawCall()
{
DrawCall dc;
dc.shader = getShader();
drawCall.push_back(dc);
}
void RenderData::UpdateShader()
{
Shader* currentShader = getShader();
DrawCall* currentDraw = getDrawCall();
if (!currentDraw || currentDraw->shader != currentShader) {
AddDrawCall();
return;
}
DrawCall* prevDraw = drawCall.size() > 1 ? currentDraw - 1 : nullptr;
if (prevDraw->shader == currentShader) {
drawCall.pop_back();
} else { currentDraw->shader = currentShader; }
}
void RenderData::PushShader(Shader* shader)
{
this->shader.push_back(shader);
UpdateShader();
}
void RenderData::PopShader()
{
Custom_Assert(shader.size() > 0, "Cannot PopShader() with size < 0!\n");
shader.pop_back();
UpdateShader();
}
void RenderData::Draw(const Rect& dest)
{
//dest -> x, y, w and h
//setup vertices
vertexBuffer.push_back(...);
vertexBuffer.push_back(...);
vertexBuffer.push_back(...);
vertexBuffer.push_back(...);
//setup elements
elementBuffer.push_back(...);
elementBuffer.push_back(...);
elementBuffer.push_back(...);
elementBuffer.push_back(...);
elementBuffer.push_back(...);
elementBuffer.push_back(...);
}
和具有很少对象的Renderer2D类: vao,vbo,ebo,RenderData 和几种方法:
Create()
->它创建ebo和ebo
RenderClear()
->它Free()
RenderData,设置视口
RenderPresent
->它创建并绑定vao,绑定vbo,添加vbo属性和数据,绑定ebo和添加ebo数据,并经过DrawCall& drawCall : renderData.drawCall
,使用着色器程序并绘制元素; >
void Renderer2D::Create()
{
//gens and binds
vbo = vbo->Create(TYPE::ARRAY, USAGE::DYNAMIC_DRAW));
//gens and binds
ebo = ebo->Create(TYPE::ELEMENT, USAGE::DYNAMIC_DRAW));
}
void Renderer2D::RenderClear()
{
setRenderViewport(0, 0, 1280, 720);
renderData.Free();
}
void Renderer2D::RenderPresent()
{
vao = vao->Create();
vbo->BindBuffer();
vbo->AddAttribute(0, 2, GL_FLOAT, false, sizeof(Vertex), (const void*)offsetof(Vertex, position));
vbo->AddData(renderData.vertexBuffer.size() * sizeof(Vertex), renderData.vertexBuffer.data());
ebo->BindBuffer();
ebo->AddData(renderData.elementBuffer.size() * sizeof(uint), renderData.elementBuffer.data());
for (auto& drawCall : renderData.drawCall) {
drawCall.shader->UseProgram();
vao->DrawElements(drawCall.elemCount, GL_UNSIGNED_INT, nullptr);
}
//delete vertex array
vao->Free();
}
它如何工作:
int main()
{
Renderer2D renderer2D;
renderer2D.Create();
Shader A("shader.vtx", "shader.frag");
Shader B("shader.vtx", "shader2.frag");
while(!quit) {
renderer2D.RenderClear();
//Push A shader = add 1st draw call
renderer2D->PushShader(&A);
renderer2D->Draw({ 100.0f, 100.0f, 50.0f, 50.0f });
renderer2D->PopShader();
//Push B shader = add 2nd draw call
renderer2D->PushShader(&B);
renderer2D->Draw({ 200.0f, 200.0f, 50.0f, 50.0f });
renderer2D->PopShader();
//Push A shader = do not add 3rd draw call, use already existing one
//This version adds 3rd draw call instead of using existing one
renderer2D->PushShader(&A);
renderer2D->Draw({ 400.0f, 400.0f, 50.0f, 50.0f });
renderer2D->PopShader();
renderer2D.RenderPresent();
}
return 0;
}
我想以某种方式更改它,使其按我描述的方式工作,但我不知道(如果可能的话)如何做。