#include #include #include #include #include #include #include #include #include #include /** * 理论上讲,我们需要按以下顺序排序 * * for(pipeline) * for(material_instance) * for(vbo) * for(distance) */ template<> int Comparator::compare(const RenderNodePointer &obj_one,const RenderNodePointer &obj_two) const { int off; hgl::graph::Renderable *ri_one=obj_one->ri; hgl::graph::Renderable *ri_two=obj_two->ri; //比较管线 { off=ri_one->GetPipeline() -ri_two->GetPipeline(); if(off) return off; } //比较材质实例 { for(int i =(int)hgl::graph::DescriptorSetsType::BEGIN_RANGE; i<=(int)hgl::graph::DescriptorSetsType::END_RANGE; i++) { off=ri_one->GetMP((hgl::graph::DescriptorSetsType)i) -ri_two->GetMP((hgl::graph::DescriptorSetsType)i); if(off) return off; } } //比较vbo+ebo { off=ri_one->GetBufferHash() -ri_two->GetBufferHash(); if(off) return off; } //比较距离 { const double dist=obj_one->distance_to_camera_square- obj_two->distance_to_camera_square; //由于距离差距可能会小于1,但又返回int,所以需要做如此处理 if(dist>0)return 1;else if(dist<0)return -1; } return 0; } namespace hgl { namespace graph { RenderList::RenderList(GPUDevice *dev) { device =dev; cmd_buf =nullptr; hgl_zero(camera_info); mvp_array =new MVPArrayBuffer(device,VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); ubo_offset =0; ubo_align =0; last_pipeline =nullptr; hgl_zero(last_mp); last_vbo =0; } RenderList::~RenderList() { delete mvp_array; } bool RenderList::Begin() { render_node_list.ClearData(); mvp_array->Clear(); ri_list.ClearData(); material_sets.ClearData(); return(true); } void RenderList::End() { if(render_node_list.GetCount()<=0)return; //排序 Sort(render_node_list,&render_node_comparator); //产生MVP矩阵UBO数据 { const uint32_t count=render_node_list.GetCount(); { //按当前总节点数量分配UBO mvp_array->Alloc(count); mvp_array->Clear(); ri_list.ClearData(); ri_list.SetCount(count); } { ubo_align=mvp_array->GetUnitSize(); char *mp=(char *)(mvp_array->Map(0,count)); Renderable **ri=ri_list.GetData(); for(RenderNode *node:render_node_list) //未来可能要在Expend处考虑做去重 { memcpy(mp,&(node->matrix),MVPMatrixBytes); mp+=ubo_align; (*ri)=node->ri; ++ri; } mvp_array->Flush(count); } } //为所有的材质绑定 for(Material *mtl:material_sets) { MaterialParameters *mp=mtl->GetMP(DescriptorSetsType::Primitive); if(mp) { if(mp->BindUBO("r_scene_info",mvp_array->GetBuffer(),true)) mp->Update(); } } } bool RenderList::Expend(SceneNode *sn) { if(!sn)return(false); Renderable *ri=sn->GetRenderable(); if(ri) { RenderNode *rn=new RenderNode; rn->matrix.Set(sn->GetLocalToWorldMatrix(),camera_info.vp,camera_info.view); rn->WorldCenter=sn->GetWorldCenter(); rn->distance_to_camera_square=length_squared(rn->WorldCenter,camera_info.pos); // rn->distance_to_camera=sqrtf(rn->distance_to_camera_square); rn->ri=ri; render_node_list.Add(rn); material_sets.Add(ri->GetMaterial()); } for(SceneNode *sub:sn->SubNode) Expend(sub); return(true); } bool RenderList::Expend(const CameraInfo &ci,SceneNode *sn) { if(!device|!sn)return(false); camera_info=ci; Begin(); Expend(sn); End(); return(true); } void RenderList::Render(Renderable *ri) { if(last_pipeline!=ri->GetPipeline()) { last_pipeline=ri->GetPipeline(); cmd_buf->BindPipeline(last_pipeline); } { uint32_t ds_count=0; uint32_t first_set=0; MaterialParameters *mp; for(int i=(int)DescriptorSetsType::BEGIN_RANGE; i<(int)DescriptorSetsType::Primitive; i++) { mp=ri->GetMP((DescriptorSetsType)i); if(last_mp[i]!=mp) { last_mp[i]=mp; if(mp) { ds_list[ds_count]=mp->GetVkDescriptorSet(); ++ds_count; } } else { if(mp) ++first_set; } } { mp=ri->GetMP(DescriptorSetsType::Primitive); if(mp) { ds_list[ds_count]=mp->GetVkDescriptorSet(); ++ds_count; cmd_buf->BindDescriptorSets(ri->GetPipelineLayout(),first_set,ds_list,ds_count,&ubo_offset,1); } else { cmd_buf->BindDescriptorSets(ri->GetPipelineLayout(),first_set,ds_list,ds_count,nullptr,0); } ubo_offset+=ubo_align; } } if(last_vbo!=ri->GetBufferHash()) { last_vbo=ri->GetBufferHash(); cmd_buf->BindVBO(ri); } const IndexBuffer *ib=ri->GetIndexBuffer(); if(ib) { cmd_buf->DrawIndexed(ib->GetCount()); } else { cmd_buf->Draw(ri->GetDrawCount()); } } bool RenderList::Render(RenderCmdBuffer *cb) { if(!cb) return(false); if(ri_list.GetCount()<=0) return(true); cmd_buf=cb; last_pipeline=nullptr; hgl_zero(last_mp); last_vbo=0; ubo_offset=0; for(Renderable *ri:ri_list) Render(ri); return(true); } }//namespace graph }//namespace hgl