3D API中,字体绘制的Batch优化

本文介绍了一种在3D引擎中高效渲染大量字体的方法,通过使用实例化绘制技术和顶点着色器常量传递,避免了频繁的顶点缓冲锁定解锁操作,显著提高了渲染效率。
在3D引擎中绘制字符是很恶心的事情。一个个绘制吧又太慢。组成一个大mesh吧。
又太耗引擎的人品。而且还是得lock/unlock vb。
才绘制了一百多个字。 fps从600掉到80多。

经过跟别人的讨论。pos之类的数据用shader constant来传递会效率高一些。
于是做了这样个处理。
1. 做72个1x1大小的Quad。 (其实可以用一个,DrawInstance就好了)。
2. 将纹理相同的char集合起来。
3. 准备一个shader接受 72个字符的信息(pos , texture , color)。其实最多可以81个。 81x3 = 243 + 3 x 4 = 255(最多256个constant)
4. 将这些constant一次性传递过去。一次绘制72个字符。

这个好处是1 没有lock unlock vb。2. 一次绘制最多72个字符。效率更高。

这样处理后,绘制100个字符后, fps基本没有多大的变化。

BEGIN_NAMESPACE_XEVOL3D;
class xBatchFontDevice : public IFontRenderDevice
{
IRenderApi* m_pRenderApi;
eFontFilter m_filter;
IBlenderState* m_BlendState;
ISamplerState* m_pPointSampler;
ISamplerState* m_pLinearSampler;
HGpuProgram m_pDefFontShader;
HGpuProgram m_pUsrFontShader;
IDepthStencilState* m_pStencilState;


IVertexStream* m_pVertexStream;
IInputBuffer* m_pVertexBuffer;
IInputBuffer* m_pIdxBuffer ;
IInputAssembler* m_pAss ;
int m_nQuad ;


float4 m_FontColor[72];
float4 m_SrcRect [72];
float4 m_DstRect [72];
int m_iQuadIndex;
IBaseTexture* m_pTexture;
struct xBathFontVertex
{
xvec4 m_pos;
xvec2 m_uv[2];
};
public:
IMPL_REFCOUNT_OBJECT_INTERFACE(xBatchFontDevice);
xBatchFontDevice(IRenderApi* pRenderApi);
~xBatchFontDevice();
IRenderApi* renderApi(){return m_pRenderApi ; }
public:
virtual bool resetFontFilter() { return true ; }
virtual bool setUVLayer(int nUVLayer);
virtual bool setShaderProgram(HGpuProgram pProgram);
virtual bool init();
virtual bool setFontFilter(eFontFilter filter);
virtual bool beginFontRender();
virtual bool endFontRender();
virtual bool commit();
virtual bool drawRectf(IBaseTexture* pTexture, float vDestRect[4] , const xColor_4f& color);
virtual bool drawRectf(IBaseTexture* pTexture, float vDestRect[4] ,float vSrcRect[4] , const xColor_4f& color);
virtual IBaseTexture* createTexture(int w , int h , ePIXEL_FORMAT fmt , bool bReadable , eResourceUsage usage , int nMipMap = 1, int nArraySize = 1 );
virtual bool isTextureSupport(ePIXEL_FORMAT fmt , bool lockable = true);
};




bool xBatchFontDevice::setUVLayer(int nUVLayer)
{


return true;
}


bool xBatchFontDevice::setShaderProgram(HGpuProgram pProgram)
{
m_pUsrFontShader = pProgram;
return true;
}


bool xBatchFontDevice::init()
{
xInputLayoutDesc InputDesc;
InputDesc.addElement(SHADER_SEMANTIC_POSITION , SHADERVARTYPE_FLOAT4 );
InputDesc.addElement(SHADER_SEMANTIC_TEXCOORD , SHADERVARTYPE_FLOAT2 , 0);
InputDesc.addElement(SHADER_SEMANTIC_TEXCOORD , SHADERVARTYPE_FLOAT2 , 1);
InputDesc.addBufferDesc(RESOURCE_USAGE_DEFAULT , RESOURCE_ACCESS_NONE);


m_pAss = m_pRenderApi->createInputAssembler(L"BatchFont", InputDesc);
m_pVertexStream = m_pAss->createVertexStream();


m_nQuad = m_pRenderApi->intCapsValue(L"FontBatchCount" , 72 );
if(m_nQuad > 72) m_nQuad = 72;
xFaceIndex16_U indices[ 72 * 2 ];
for(int i = 0 ; i < m_nQuad ; i ++)
{
int baseIndex = i * 4;
indices[i * 2 ].v1 = 0 + baseIndex;
indices[i * 2 ].v2 = 2 + baseIndex;
indices[i * 2 ].v3 = 1 + baseIndex;


indices[i * 2 + 1].v1 = 2 + baseIndex;
indices[i * 2 + 1].v2 = 0 + baseIndex;
indices[i * 2 + 1].v3 = 3 + baseIndex;
}
xInputBufferDesc idxBufDesc;
idxBufDesc.m_usage = RESOURCE_USAGE_DEFAULT;
idxBufDesc.m_accessFlage = RESOURCE_ACCESS_NONE;
idxBufDesc.m_bindtype = BIND_AS_INDEX_BUFFER;
m_pIdxBuffer = m_pRenderApi->createInputBuffer(72 * 6 , 2 , &idxBufDesc,indices);
//////////////////////////////////////////////////////////////////////////
xInputBufferDesc vBufDesc;
vBufDesc.m_usage = RESOURCE_USAGE_DEFAULT;
vBufDesc.m_accessFlage = RESOURCE_ACCESS_NONE;
vBufDesc.m_bindtype = BIND_AS_VERTEX_BUFFER;


xBathFontVertex batchVertex[72 * 4];
float _zValue = m_pRenderApi->get2DZValue();
for(int i = 0 ; i < 72 ; i ++)
{
xBathFontVertex* Vertex = batchVertex + i * 4;
Vertex[0].m_uv[0] = Vertex[0].m_uv[1] = xvec2(0.0f , 1.0f);
Vertex[1].m_uv[0] = Vertex[1].m_uv[1] = xvec2(0.0f , 0.0f);
Vertex[2].m_uv[0] = Vertex[2].m_uv[1] = xvec2(1.0f , 0.0f);
Vertex[3].m_uv[0] = Vertex[3].m_uv[1] = xvec2(1.0f , 1.0f);

Vertex[0].m_pos = xvec4(0.0f , 1.0f , _zValue , i);
Vertex[1].m_pos = xvec4(0.0f , 0.0f , _zValue , i);
Vertex[2].m_pos = xvec4(1.0f , 0.0f , _zValue , i);
Vertex[3].m_pos = xvec4(1.0f , 1.0f , _zValue , i);
}


m_pVertexStream->createInputBuffer( 0 , 4 * m_nQuad , &batchVertex , &vBufDesc );
m_pVertexBuffer = m_pVertexStream->getInputBuffer(0);
m_pVertexBuffer->update(eLock_WriteDiscard , batchVertex , sizeof(xBathFontVertex) * 4 * 72);




m_iQuadIndex = 0;


m_filter = eFontFilter_Point;


if(m_pDefFontShader.isHandle() == false)
{
HGpuProgram hGpuProgram = m_pRenderApi->gpuProgramManager()->load(L"batchFont.vertex", L"font.pixel");
m_pDefFontShader = hGpuProgram;
}


if(m_pStencilState == NULL) { m_pStencilState = m_pRenderApi->createDepthStencilState(L"Overlay");}
if(m_pPointSampler == NULL) { m_pPointSampler = m_pRenderApi->createSamplerState(L"FontPoint"); }
if(m_pLinearSampler == NULL) { m_pLinearSampler = m_pRenderApi->createSamplerState(L"FontLinear"); }
if(m_BlendState == NULL) { m_BlendState = m_pRenderApi->createBlendState(L"Font.Blend"); }
return true;
}


bool xBatchFontDevice::setFontFilter(eFontFilter filter)
{
m_filter = filter;
if(m_filter == eFontFilter_Point)
{
return m_pRenderApi->setSamplerState(eShader_PixelShader , 0 , m_pPointSampler );
}
else if(m_filter == eFontFilter_Linear)
{
return m_pRenderApi->setSamplerState(eShader_PixelShader , 0 , m_pLinearSampler );
}
return false;
}


xBatchFontDevice::xBatchFontDevice(IRenderApi* pRenderApi)
{
m_filter = eFontFilter_Point;
m_pStencilState = NULL;
m_pDefFontShader.setNULL();
m_pRenderApi = pRenderApi;
m_pPointSampler = NULL;
m_pLinearSampler = NULL;
m_BlendState = NULL;
m_pUsrFontShader.setNULL();
m_pTexture = NULL;


m_pVertexStream= NULL;
m_pVertexBuffer= NULL;
m_pIdxBuffer = NULL;
m_pAss = NULL;
m_nQuad = 0;
m_iQuadIndex = 0;


}


xBatchFontDevice::~xBatchFontDevice()
{


}


bool xBatchFontDevice::beginFontRender()
{
if(m_pDefFontShader.isHandle() == false )
return false;
m_pRenderApi->setDepthStencilState(m_pStencilState);
m_pRenderApi->setBlendState(m_BlendState);
IGpuProgramParamTable* pShaderTable = NULL;
if(m_pUsrFontShader)
{
m_pRenderApi->setGpuProgram(m_pUsrFontShader);// pushGpuProgram(m_pUsrFontShader);
pShaderTable = m_pUsrFontShader->getParamTable();// pushGpuProgram(m_pUsrFontShader);
}
else
{
m_pRenderApi->setGpuProgram(m_pDefFontShader) ; // pushGpuProgram(m_pDefFontShader);
pShaderTable = m_pDefFontShader->getParamTable(); // pushGpuProgram(m_pDefFontShader);
}


float4x4 matWorld;
float4x4 matProject;
float4x4 matView;
m_pRenderApi->getCamera()->toMatrix(matView , matProject);
m_pRenderApi->getMatrix(matWorld.data , MATRIXMODE_World );


pShaderTable->setParamater(L"_matWorld" , matWorld , eShader_VertexShader);
pShaderTable->setParamater(L"_matView" , matView , eShader_VertexShader);
pShaderTable->setParamater(L"_matProject" , matProject , eShader_VertexShader);


m_iQuadIndex = 0;
return true;
}


bool xBatchFontDevice::endFontRender()
{
commit();
return true;
}


bool xBatchFontDevice::drawRectf(IBaseTexture* pTexture, float vDestRect[4] , const xColor_4f& color)
{
if(m_pRenderApi)
{
assert(0);
return false;
}
return false;
}


bool xBatchFontDevice::commit()
{
if(m_iQuadIndex == 0)
return true ;


IGpuProgramParamTable* pShaderTable = NULL;
if(m_pUsrFontShader)
{
pShaderTable = m_pUsrFontShader->getParamTable();// pushGpuProgram(m_pUsrFontShader);
}
else
{
pShaderTable = m_pDefFontShader->getParamTable(); // pushGpuProgram(m_pDefFontShader);
}

m_pRenderApi->setTextureByLayer(0 , m_pTexture);
pShaderTable->setParamater(L"SrcRect" , m_SrcRect , m_iQuadIndex , 0 , eShader_VertexShader);
pShaderTable->setParamater(L"DstRect" , m_DstRect , m_iQuadIndex , 0 , eShader_VertexShader);
pShaderTable->setParamater(L"RectColor" , m_FontColor , m_iQuadIndex , 0 , eShader_VertexShader);


m_pRenderApi->setVertexBuffer(m_pVertexBuffer , 0 , sizeof(xBathFontVertex) );
m_pRenderApi->setInputAssembler( m_pAss );
m_pRenderApi->draw(m_pIdxBuffer , m_iQuadIndex * 6 );


m_iQuadIndex = 0;
return true;
}


bool xBatchFontDevice::drawRectf(IBaseTexture* pTexture, float vDestRect[4] ,float vSrcRect[4] , const xColor_4f& color)
{
if(m_pRenderApi)
{
if(m_pTexture != NULL && m_pTexture != pTexture)
commit();


m_pTexture = pTexture;
const xTextureDesc& textDesc = pTexture->desc();
xvec4& dstRect = *((xvec4*)vDestRect);
xvec4 srcRect = *((xvec4*)vSrcRect);
const xTextureDesc& desc = pTexture->desc();


srcRect.rect.x /= desc.m_width;
srcRect.rect.w /= desc.m_width;


//////////////////////////////////////////////////////////////////////////
srcRect.rect.y /= desc.m_height;
srcRect.rect.h /= desc.m_height;


m_SrcRect[m_iQuadIndex] = srcRect;
m_DstRect[m_iQuadIndex] = dstRect;
m_FontColor[m_iQuadIndex] = float4(color.r, color.g,color.b,color.a);
m_iQuadIndex ++;
if(m_iQuadIndex >= m_nQuad )
{
commit();
}
}
return false;
}


IBaseTexture* xBatchFontDevice::createTexture(int w , int h , ePIXEL_FORMAT fmt , bool bReadable, eResourceUsage usage , int nMipMap, int nArraySize)
{
if(m_pRenderApi)
{
xTextureInitDesc texInitDesc(w , h , fmt);
texInitDesc.m_bReadable = bReadable;//;
texInitDesc.m_TextureDesc.m_nMipmap = nMipMap;
texInitDesc.m_TextureDesc.m_nArraySize = nArraySize;
texInitDesc.m_usage = usage;
if(texInitDesc.m_usage == RESOURCE_USAGE_DEFAULT)
{
texInitDesc.m_access = 0;
}
return m_pRenderApi->createTexture(texInitDesc , NULL , 0);
}
return false;
}


bool xBatchFontDevice::isTextureSupport(ePIXEL_FORMAT fmt , bool lockable)
{
if(m_pRenderApi)
{
return m_pRenderApi->isTextureSupport(fmt , lockable);
}
return false;
}


END_NAMESPACE_XEVOL3D;
基于遗传算法的微电网调度(风、光、蓄电池、微型燃气轮机)(Matlab代码实现)内容概要:本文档介绍了基于遗传算法的微电网调度模型,涵盖风能、太阳能、蓄电池和微型燃气轮机等多种能源形式,并通过Matlab代码实现系统优化调度。该模型旨在解决微电网中多能源协调运行的问题,优化能源分配,降低运行成本,提高可再生能源利用率,同时考虑系统稳定性与经济性。文中详细阐述了遗传算法在求解微电网多目标优化问题中的应用,包括编码方式、适应度函数设计、约束处理及算法流程,并提供了完整的仿真代码供复现与学习。此外,文档还列举了大量相关电力系统优化案例,如负荷预测、储能配置、潮流计算等,展示了广泛的应用背景和技术支撑。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事微电网、智能电网优化研究的工程技术人员。; 使用场景及目标:①学习遗传算法在微电网调度中的具体实现方法;②掌握多能源系统建模与优化调度的技术路线;③为科研项目、毕业设计或实际工程提供可复用的代码框架与算法参考; 阅读建议:建议结合Matlab代码逐段理解算法实现细节,重点关注目标函数构建与约束条件处理,同时可参考文档中提供的其他优化案例进行拓展学习,以提升综合应用能力。
此项目旨在实现一个简易而实用的RFID智能门禁控制系统。采用经典的51系列单片机——STC89C52作为核心控制器,集成MFRC522射频识别模块来读取RFID卡片信息。用户界面通过128x64像素的LCD显示屏展示相关信息,同时配备了键盘用于密码的输入、验证及修改。此设计结合了RFID技术的高效率识别与单片机的强大控制能力,适用于学习、教学或小型安防项目。 资源包含 源代码:完整C语言编写的源程序,涵盖了RFID识别、密码验证逻辑、显示控制以及用户交互等功能模块。 原理图:详细展示了整个系统的电路连接,包括单片机、MFRC522模块、LCD12864屏幕、按键等组件的电气连接方式,便于理解和自制。 技术特点 RFID技术应用:通过MFRC522模块实现非接触式身份认证,提升门禁安全性与便捷性。 人机交互界面:利用LCD12864显示屏直观展示状态信息,并通过物理按键进行操作,增加了系统的易用性。 密码安全机制:支持用户密码的设定和更改,增强系统安全性。 51单片机编程:适合初学者和专业人士学习51单片机应用开发,尤其是嵌入式系统与物联网领域的实践。 使用指南 环境搭建:确保你有合适的IDE(如Keil uVision)安装以编译51单片机的C代码。 原理图分析:详细阅读原理图,了解各部件间的连接,这对于正确搭建硬件平台至关重要。 编译与上传:将提供的源代码编译无误后,通过编程器或ISP接口烧录到STC89C52单片机中。 硬件组装:根据原理图搭建电路,确保所有组件正确连接。 测试与调试:完成后进行功能测试,可能需要对代码或硬件做适当调整以达到最佳工作状态。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值