??xml version="1.0" encoding="utf-8" standalone="yes"?> 于是查D3DRS_ZENABLE,D3DRS_ZWRITEENABLE, l果都是TRUE 无奈,只有与我以前正确的DemoҎ210个渲染状? 有部分渲染不同的,使用代码强行纠?l果: 无效 怀疑顶Ҏ式破? 重新使用以前的模型格?排除q个可能? l果:p| 无奈?查设备选项, H然注意到D3DPRESENT_PARAMETERS l构体中的EnableAutoDepthStencil 讄是FALSE 因ؓq次讑֤cL重写?Ҏ以前正确代码, 有差?其改ؓ PresentParameters.EnableAutoDepthStencil = TRUE; 以前阅SDK?注意q这个选项, q是由D3D帮你理ZBuffer. 试, 问题解决. 分析: 如果EnableAutoDepthStencil = FALSE, 意味着qZBuffer都没?那更不要说渲染状?
PresentParameters.AutoDepthStencilFormat = D3DFMT_D16;
]]>
本文译整理ȝ?a >http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter05.html
如果喜欢,误买正?/p>
多流技术在渲染时能Ҏ能和结构有一定好?但是怎样模型数据分配到各顶Ҏ据流q行渲染是一个学?
对于点数据可以分ؓq么几个大类:
G: 多边形数? 包含vertex position, normal, and vertex color(s).
T: U理映射, 包含多层U理坐标及tangent vectors{?/p>
A: 动画数据, 骨骼动画中的骨骼权重及骨骼烦?/p>
I: 用于Instancel制的用h?/p>
以下是对一些常用渲染的搭?
静态模?/p>
可以? G or G + T
骨骼动画模型
可以?G + A or G + T + A
Instancel制的骨骼动L?/p>
可以?G + I or G + T + I 或者动ȝ型的G + A + I or G + T + A + I
渲染Z-Pass物g
可以?strong>G, 或者动ȝ型的G + A or G + I or G + A + I
q里参考了mybios博客中的文章,lCEGUI字符串做一个patch
然后需要找到vs2008的autoexp.dat文g
XP下位?C:\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\autoexp.dat
用记事本{工h开, 在AutoExpandD中像这h?
[AutoExpand]
; CEGUI String
CEGUI::String = str =<d_quickbuff,su> length =<d_cplength>
卛_在VC调试器中看到CEGUI字符串内? 不过中文q是暂时无法支持
首先,我们得弃用CPU蒙皮, 虽然兼容性好,但是面对C多核但ƈ不提高单栔R率的情况下,GPUq是王道.而且GPU蒙皮代码可能更简?不过也有一点小~点, 对于引擎来?Shader必须l静态模型和骨骼动画模型写两?
其次我们需要加Z个SubSkin的骨骼支持数? 骨骼动画上的每个SubSkin都是一ơDraw, 但是按照传统骨骼动画pȝ,每个骨头对应一个矩阵传?那么SM2.0保守计算只能支持50栚w? 不过在我前段旉?a href="http://www.shnenglu.com/sunicdavy/archive/2010/04/26/113578.html">文章中有提到q个技?q且已经在我的骨骼动ȝl及OGRE中实?效果很好.
术也许很反感一个h物做1个SubSkin, 他们更新好多个SubSkin,也就是说w体每个部分都是一个SubSkin, q样方便修改, 同时pȝ支持的骨骼数量还可以有一定量的上?不过我们q需要做一个烦引工? 传统的GPU骨骼动画中L在渲染SubSkin前传入所有这些SubSkin需要用到的骨骼矩阵. 但是每个SubSkinq不一定能用到所有的q些矩阵,q明显是一U浪? 因此在OGRE中做q一ơ烦引预处理,也就是将每个SubSkin用到的骨骼统计出? 在渲染这ơSubSkin时才重新传到GPU. 很明?q是用速度q空间和兼容? 如果在DX10以上,有ConstantBufferq好. DX9实在太慢?/p>
使用Marker点的换装pȝ很难处理例如贴n衣物q类物g换装. OGRE中有一U共享骨骼的技? 可以支持, 不过从代码分析看?q种技术对CPU端骨D量实在是大的惊? 因此我们军_整个SubSkin(也就是SubEntity)换掉,q样q术根据不同换装类型来衣服在MAX中直接绑定好后直接替换原始模型中的SubSkin卛_辑ֈ换装效果.可以说这是从动态计到静态预处理的{?效率提升很多.
HRESULT DrawIndexedPrimitiveUP(
D3DPRIMITIVETYPE PrimitiveType,
UINT MinVertexIndex,
UINT NumVertices,
UINT PrimitiveCount,
CONST void * pIndexData,
D3DFORMAT IndexDataFormat,
CONST void* pVertexStreamZeroData,
UINT VertexStreamZeroStride
);
q里假设我们要绘制一个由2个三角Şl成的面,那么参数q样讄
MinVertexIndex = 0;
NumVertices = 4;
PrimitiveCount = 2;
pIndexData = { 0,1, 2, 0, 2, 3}
IndexDataFormat = D3DFMT_INDEX16
pVertexStreamZeroData = { 4个角的位|?}
VertexStreamZeroStride = { l构体的跨度 }
我们注意? 没有M一个参数用于描q?b>CONST void * pIndexData的size 大小.
但其实你的图元是可以正确l制? 但是你ƈ没有在indexdata后面加上例如字符?的结։,那么D3D是怎么知道IndexCount?
我们先看下怎么ҎVertexCount?PrimitveType定 PrimitiveCount
PrimitveType | 公式 |
D3DPT_POINTLIST | PrimitiveCount = VertexCount |
D3DPT_LINELIST | PrimitiveCount = VertexCount/2 |
D3DPT_LINESTRIP | PrimitiveCount = VertexCount-1 |
D3DPT_TRIANGLELIST | PrimitiveCount = VertexCount/3 |
D3DPT_TRIANGLESTRIP | PrimitiveCount = VertexCount-2 |
? D3DPT_TRIANGLEFAN在以后的驱动中已l不再?因此不再采用
当用烦引缓冲时, VertexCount = IndexCount
因此在上例中 PrimitiveCount = IndexCount/3
也就是说 IndexCount = PrimitiveCount * 3
代入PrimitiveCount = 2,因此 IndexCount = 6
因此E_的API的函数参数设计是l不会浪费Q何一个参数的
float4x4 matBoneArray[40]; // q是传输的瓶?/span>
VS_OUTPUT vs_main( SkinnedVS_INPUT In )
{
VS_OUTPUT Out = (VS_OUTPUT)0;
float4x4 skinTransform = 0;
skinTransform += matBoneArray[In.BoneIndices.x] * In.BoneWeights.x;
skinTransform += matBoneArray[In.BoneIndices.y] * In.BoneWeights.y;
skinTransform += matBoneArray[In.BoneIndices.z] * In.BoneWeights.z;
skinTransform += matBoneArray[In.BoneIndices.w] * In.BoneWeights.w;
float4 localpos = mul(In.Position, skinTransform);
Out.Position = mul( localpos, matViewProj );
Out.TexCoord = In.TexCoord;
return Out;
}
matBoneArrayq个数组是骨骼的LocalRot和LocalTranslation 通过以下函数build出来
Matrix4& Matrix4::FromTranslationRotation( const Vector3& translation, const Quaternion& rotation )
{
float xx = rotation.x * rotation.x * 2.0f, yy = rotation.y * rotation.y * 2.0f, zz = rotation.z * rotation.z * 2.0f;
float xy = rotation.x * rotation.y * 2.0f, zw = rotation.z * rotation.w * 2.0f, xz = rotation.x * rotation.z * 2.0f;
float yw = rotation.y * rotation.w * 2.0f, yz = rotation.y * rotation.z * 2.0f, xw = rotation.x * rotation.w * 2.0f;
m[0][0] = 1.0f - yy - zz; m[0][1] = xy + zw; m[0][2] = xz - yw; m[0][3] = 0.0f;
m[1][0] = xy - zw; m[1][1] = 1.0f - xx - zz; m[1][2] = yz + xw; m[1][3] = 0.0f;
m[2][0] = xz + yw; m[2][1] = yz - xw; m[2][2] = 1.0f - xx - yy; m[2][3] = 0.0f;
m[3][0] = translation.x; m[3][1] = translation.y; m[3][2] = translation.z; m[3][3] = 1.0f;
return *this;
}
从这里你可以发现, 本来每根骨头只需?个float4 传递变换信息的,现在却需?个float4,也就是一个矩阉|传?矩阵中还有很多不使用的变量也被传输到GPU?q里是优化的点.
重新调整后的Shader代码:
float4x4 BuildFromTransRot( float4 translation, float4 rot )
{
float4 rotation = rot;
float xx = rotation.x * rotation.x * 2.0f, yy = rotation.y * rotation.y * 2.0f, zz = rotation.z * rotation.z * 2.0f;
float xy = rotation.x * rotation.y * 2.0f, zw = rotation.z * rotation.w * 2.0f, xz = rotation.x * rotation.z * 2.0f;
float yw = rotation.y * rotation.w * 2.0f, yz = rotation.y * rotation.z * 2.0f, xw = rotation.x * rotation.w * 2.0f;
float4x4 m = {
{1.0f - yy - zz, xy + zw, xz - yw, 0},
{xy - zw, 1.0f - xx - zz, yz + xw, 0},
{xz + yw, yz - xw, 1.0f - xx - yy, 0},
{translation.x, translation.y, translation.z, 1}
};
return m;
}
float4x4 GetBoneElement( float index )
{
return BuildFromTransRot( vecBoneLocalTrans[index], vecBoneLocalRot[index] );
}
VS_OUTPUT vs_main( SkinnedVS_INPUT In )
{
VS_OUTPUT Out = (VS_OUTPUT)0;
float4x4 skinTransform = 0;
skinTransform += GetBoneElement(In.BoneIndices.x) * In.BoneWeights.x;
skinTransform += GetBoneElement(In.BoneIndices.y) * In.BoneWeights.y;
skinTransform += GetBoneElement(In.BoneIndices.z) * In.BoneWeights.z;
skinTransform += GetBoneElement(In.BoneIndices.w) * In.BoneWeights.w;
float4 localpos = mul(In.Position, skinTransform);
Out.Position = mul( localpos, matViewProj );
Out.TexCoord = In.TexCoord;
return Out;
}
我们骨头的local旋{及偏UM递至GPU,然后在GPU内重l?虽然对GPU性能计算有部分损?但是骨骼数量p保守提高?00?
http://isdlibrary.intel-dispatch.com/vc/1632/Threading_OGRE3D.pdf
ATI有关多线E效率提升的游戏比较及一些tips
http://developer.amd.com/assets/ATIMThread.pdf
CORE DLL
ENGINE DLL
GAME EXE
D3DRENDER DLL
其中D3DRENDER是GAME动态蝲入的Q其需要链接CORE,ENGINE
q是一个很常见的模式,但是不好的是Q因为CORE和ENGINE均是DLLQ代码中的Symbol都被导出才可使用。Q何h使用DEPENDENCE工具可以将DLL中引用的东西查看的清楚,虽然q不至于造成技术泄漏,但从速度和DLL大小来说都是不划的?/p>
现在很多游戏主exe一般都?0M+甚至20M+的大exeQ这都是使用静态链接而成。但是对代码l构也必dZ定的调整。所有工E必都是静态库Q这h能保证像COREq样的静态库中的全局/静态变量不至于被链?份而造成内存D逻辑错误?/p>
当然Q用全静态库q需要注意一点:所有的lib都是在最后的game工程里来做链接?/p>
UDK是unrealengine develpoment kit 的羃写,单来说就是大名鼎鼎的虚Q引擎的免费商业版本Q不q虚q3毕竟q是Q年前的dx9的入门引擎Q在商业上取?br>巨大成功Q技术上也显得落后.目前Epicxq虚q3的最后一Ҏ力,于是q脆发布了这个免费版本.M人都可以用UQO开发游戏,但是如果游戏牟利的话每年q是要向
Epic交纳一定数量的技术授权费用的Q先不管q个Q还是来看看它的官方视频教程吧.
[attach]44[/attach]
链接如下Q
http://udn.epicgames.com/Three/VideoTutorials.html
一共5个教E 从引擎配|介l开始,到关卡和人物~辑器,以及最后一个完整的游戏的制作Q对于入门来说完全够了Q?br>视频说的q比较详l,听力不好的同学可以对照下开发文 http://www.udk.com/documentation 里面基本说的很详l.
最后附上UQO的下载地址Q March 2010 UDK Beta (548 MB .exe)
好了QUQO对于初学者来说还是比较适合的.对于游戏的开发h员来说引擎的整体架构q是很值得学习的.希望你学的愉快.
OGRE的Compositor其实是用于解决l制PostEffect的,单的_是一URenderTarget的流E控制脚?/p>
q是OGRE compositor文g的片D?/p>
compositor Bloom
{
technique
{
// Temporary textures
texture rt_output target_width target_height PF_R8G8B8
texture rt0 target_width_scaled 0.25 target_height_scaled 0.25 PF_R8G8B8
texture rt1 target_width_scaled 0.25 target_height_scaled 0.25 PF_R8G8B8
target rt_output
{
// Render output from previous compositor (or original scene)
input previous
}
target rt0
{
// Start with clear texture
input none
// Horizontal blur pass
pass render_quad
{
// Renders a fullscreen quad with a material
material Ogre/Compositor/BrightPass2
input 0 rt_output
}
}
target rt1
{
// Start with clear texture
input none
// Horizontal blur pass
pass render_quad
{
// Renders a fullscreen quad with a material
material Ogre/Compositor/BlurV
input 0 rt0
}
}
target rt0
{
// Start with clear texture
input none
// Horizontal blur pass
pass render_quad
{
// Renders a fullscreen quad with a material
material Ogre/Compositor/BlurH
input 0 rt1
}
}
target_output
{
// Start with clear output
input none
// Draw a fullscreen quad
pass render_quad
{
// Renders a fullscreen quad with a material
material Ogre/Compositor/BloomBlend2
input 0 rt_output
input 1 rt0
}
}
}
}
大概我们知道Q一个Compositor分ؓ资源定义与绘制步骤(target xxxQ?/p>
而一个绘制步骤又分别定义Q?/p>
1. Q输入)l制的是什么东西?
2. Q效果)l制成什么样子?
3. Q输出)往哪里l制Q?/p>
输出方式在这个例子有2U:U理QRTQ和屏幕
输入方式?中:U理及场?/p>
我们可以使用一个回调来对一个绘制步骤提供绘制输?/p>
l制效果是一大堆的ShaderQ这些shader都是Z一个quad来做的,也就是一个矩形,使用变换后的点和一个纹理坐标作为顶点定?/p>
不过q里是不需要做vertexshader的,仅仅ps矣?/p>
l制的最后,是将前面l制的RTQ纹理)混合h
当然Q如果步骤比较多和复杂时QRT之间跟寄存器一P可以反复使用
昄茶壶法线的场景加?Blur 的PostEffect
<?xml version="1.0" encoding="gb2312" ?>
<Compositor name = "bloom" >
<Resource>
<RenderTarget name ="rt_source" size="screenquad" />
<RenderTarget name ="rt0" size="screenquad" />
<RenderTarget name ="rt1" size="screenquad" />
</Resource>
<Step target="rt_source">
<Geometry type ="callback" callback = "rt_input"/>
</Step>
<Step target="rt0">
<Geometry type = "screenquad"/>
<Effect name ="material\blurH.xml">
<Texture name ="mTexture" value ="rt_source" />
</Effect>
</Step>
<Step target="rt1">
<Geometry type = "screenquad"/>
<Effect name ="material\blurV.xml">
<Texture name ="mTexture" value ="rt_source" />
</Effect>
</Step>
<Step>
<Geometry type = "screenquad"/>
<Effect name ="material\combine.xml">
<Texture name ="mTexture1" value ="rt0" />
<Texture name ="mTexture2" value ="rt1" />
</Effect>
</Step>
</Compositor>
同样适用我的文本设计图标?+为包? <为派?
RenderTexture
RenderTarget
<ScreenTarget(引擎启动Ӟ初始化屏q大的Viewport)
+RenderView (对于一个RTQ可以是屏幕Q可以是U理RTQ所以可以拥?1~n个切分视?)
+Camera
+Viewport
以下是多Viewl制的类XNA伪代?/p>
Engine.Run()
{
Device.Clear()
// 保存当前全屏Viewport
ScreenViewport = Device.CurrentViewport
Device.BeginScene()
// 遍历当前屏幕RT下的所有View
foreach RenderView in ScreenRT
{
// 未激zȝView不用l制
if RenderView not active then continue
// View对应的Viewport提交到设?
RenderView.CommitViewport()
// 渲染回调
foreach RenderEventListener in RenderEventListenerList
{
RenderEventListener.OnRenderFrame()
}
}
Device.EndScene()
Device.Present()
Device.CurrentViewport = ScreenViewport // 恢复全屏viewport
}
以下是RT间嵌套绘制的伪代码:
RenderView.SwitchRenderTarget(stage, RenderTarget)
{
// 保存l制前的RT
PreTarget = Device.GetRenderTarget()
// 讄为当前的RT
Device.SetRenderTarget( RenderTarget )
// 更新RT摄像?/span>
RenderTarget.UpdateCamera()
// 清空RT
Device.Clear()
// l制回调
RenderTarget.OnRender( )
// 恢复之前的RT
Device.SetRenderTarget( PreTarget );
}
我的矩阵定义跟OGRE的没什么区?/p>
union
{
struct
{
float m11, m12, m13, m14;
float m21, m22, m23, m24;
float m31, m32, m33, m34;
float m41, m42, m43, m44;
};
float m[4][4];
};
乘法也跟OGRE的一模一P但在view及project乘好的矩阵送给HLSLӞ却必{|下Q才能得到正的l果
mSkinnedEffect.mMatrix.mValue = (camera.mViewMatrix * camera.mProjectMatrix).Transpose();
shader:
float4 localpos = mul(In.Position, skinTransform);
OGRE中有q么一D代码及注释:
const Matrix4& AutoParamDataSource::getProjectionMatrix(void) const
{
if (mProjMatrixDirty)
{
// NB use API-independent projection matrix since GPU programs
// bypass the API-specific handedness and use right-handed coords
if (mCurrentRenderable && mCurrentRenderable->getUseIdentityProjection())
{
// Use identity projection matrix, still need to take RS depth into account.
RenderSystem* rs = Root::getSingleton().getRenderSystem();
rs->_convertProjectionMatrix(Matrix4::IDENTITY, mProjectionMatrix, true);
}
else
{
mProjectionMatrix = mCurrentCamera->getProjectionMatrixWithRSDepth();
}
if (mCurrentRenderTarget && mCurrentRenderTarget->requiresTextureFlipping())
{
// Because we're not using setProjectionMatrix, this needs to be done here
// Invert transformed y
mProjectionMatrix[1][0] = -mProjectionMatrix[1][0];
mProjectionMatrix[1][1] = -mProjectionMatrix[1][1];
mProjectionMatrix[1][2] = -mProjectionMatrix[1][2];
mProjectionMatrix[1][3] = -mProjectionMatrix[1][3];
}
mProjMatrixDirty = false;
}
return mProjectionMatrix;
}
貌似是跟左右手这个恶心的东西有关p?/p>
回看DirectXSDK中提供的BasicHLSL例子
mWorld = g_mCenterWorld * *g_Camera.GetWorldMatrix();
mProj = *g_Camera.GetProjMatrix();
mView = *g_Camera.GetViewMatrix();
mWorldViewProjection = mWorld * mView * mProj;
V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
shaderQ?/p>
Output.Position = mul(vAnimatedPos, g_mWorldViewProjection);
丝毫无需转置矩阵,Effect接口中也提供有SetMatrixTransposeq类Ҏ。所以排除内部有自动转置的嫌疑?/p>
询问q野猪这个问题,野猪{曰:"转置后传输至需要传3个vector, 最后一个是[0 0 0 1]?
有达人知道的Q可以指点下qh| :)
MAX插g导出的模型资源分QMesh/Skin, Skeleton, Animation
不同动作按照不同的动L件保?
ResourceHandle 包含基本id
>NamedResourceHandle 带有名称资源Q包含hashA, hashBQ?使用暴雪hash函数生成
>ModelHandle
>MeshHandle
>SkeletonHandle
>AnimationHandle
获取资源Q如果资源不存在Ӟ自动加蝲
ModelMaster.ManualCache( &ModelHandle )
直接资源讉KQ?br>RawSkeleton = ModelMaster.ManualCache( &SkeletonHandle("a.skl") )
RawSkeleton->GetMarker(...)
异步资源加蝲Q异步id保存于ModelHandle中,在callback中根据id认
ModelMaster.AsyncCache( &ModelHandle )
获取资源指针Q未加蝲Ӟq回I?br>ModelResource = ModelMaster.Fetch( &ModelHandle )
模型资源加蝲?br> 在模型句柄中l定对应加蝲?br> 可以自行~写带换装的ModelLoaderQ通过d自己的配|文Ӟ自行加蝲资源后生成RawModel
ModelLoader
ModelHandle ---mapping---> ModelLoader ---generate--> RawModel
MeshHandle ---mapping---> MeshLoader ---generate--> RawMesh
SkeletonHandle ---mapping---> SkeletonLoader ---generate--> RawSkeleton
AnimationHandle ---mapping---> AnimationLoader ---generate--> RawAnimation
引用计数c?nbsp;
ModelResource
>RawModel
>RawMesh
>RawSkeleton
>RawAnimation
RawModel中不保留HandleQ只保留指针
RawModel
+MeshVB 从模型文件中直接d点格式Q包?静?GPU,CPUcd点
+RawMesh
+MeshIB 一ơ性填充IB
>GPUMeshVB 一ơ性填充VB
>CPUMeshVB 每计算
+Animation q行期数据(旉/帧)
+RawAnimation 原始动画内容
+Skeleton
+RawSkeleton
1. ASM Shader是最元老的也是DX8主要使用Shader
2. fxc~译器可以同时编译ASM,HLSL和fx脚本,其中HLSL和fx可以查看~译后的GPU汇编代码
3. D3D9中,fx是HLSL的一U渲染脚本,化了HLSL讄及常量绑定,q且附带RenderStateBlock及设|?/p>
但只能用于制作简单的Shader
4. DirectXSDK中有一个概忉|淆:C++例子中的BasicHLSL使用的其实还是fxQHLSLwithoutEffects例子才是真正的纯HLSL
5.fx与HLSLE序鉴别Q?/p>
使用fxE序必定含有QD3DXCreateEffectXXX pd函数Q?ID3DXEffect对象Q渲染中能看到SetTechniqueQBeginPassQEndPass之类的字?/p>
使用UHLSLE序含有QD3DXCompileShaderQID3DXConstantTable对象QGetConstantByNameQGetConstantDesc之类的字?/p>
6. 在fx中包含有 VertexShaderQPixelShader代码及profileQentryQRenderState讄及简单的l制q程(pass)。一ơ编译后QVS,PS,Texture,Sampler及常量都是在ID3DXEffect对象中自动完成,无需手动讄?/p>
7. HLSL可以VS及PS代码写入1?hlsl文g。注意,以下q种代码可以在HLSL中编译过Q但实际没有M效果
1: sampler_state
2: {
3: Texture = <tex>;
4: MipFilter = LINEAR;
5: MinFilter = LINEAR;
6: MagFilter = LINEAR;
7: };
q点可以参考AMD RenderMonkey中只在shader中用sampler而忽略texture?/p>
8. fx中往shader讄U理使用的是ID3DXBaseEffect::SetTexture下的q个函数
1: HRESULT SetTexture(
2: D3DXHANDLE hParameter,
3: LPDIRECT3DBASETEXTURE9 pTexture
4: );
但是在HLSL中,q点变得很ȝQ需要手动设|,可以参考这?a href="http://www.shnenglu.com/liangairan/articles/57971.html">文章
Shader代码片段Q?/p>
1: sampler Samp0 = sampler_state
2: {
3: Texture = <Tex0>;
4: MipFilter = LINEAR;
5: MinFilter = LINEAR;
6: MagFilter = LINEAR;
7: };
~译HLSL代码后得到ConstantTableQ然后取出句柄:
1: ScalarHandle = pixelConstTable->GetConstantByName(0, "Scalar");
2:
3: Samp0Handle = pixelConstTable->GetConstantByName(0, "Samp0");
4:
5: Samp1Handle = pixelConstTable->GetConstantByName(0, "Samp1");
再从句柄取出symbol的描qͼ
1: UINT count;
2:
3: pixelConstTable->GetConstantDesc(Samp0Handle, & Samp0Desc, &count);
4:
5: pixelConstTable->GetConstantDesc(Samp1Handle, & Samp1Desc, &count);
通过上面的描qͼ纹理变量的寄存器偏UM为纹理的stage
8. 优化帔R讄速度的方法一般就是根据字W串取出句柄Q以后每ơ渲染时Q只通过句柄讄。但ID3DXConstantTable最后还是通过
IDirect3DDevice9::SetPixelShaderConstantX pd函数来实现的
1: HRESULT SetPixelShaderConstantF(
2: UINT StartRegister,
3: CONST float * pConstantData,
4: UINT Vector4fCount
5: );
9. HLSL一D包含VS和PS代码~译完成后,得到VS和PS两个单独的ID3DXConstantTable
最q在写D3D9模拟D3D10接口的渲染系l中到大量的渲染状态对象,不仅成员多,枚D也多的要命?/p>
struct CORE_API RasterizerState : ResourceHandle { eFillMode mFillMode; eCullMode mCullMode; bool mFrontFaceCCW; float mDepthBias; float mSlopeScaledDepthBias; bool mDepthClipEnable; bool mScissorEnable; bool mMultisampleEnable; RasterizerState(); };
而要从配|文件中d数据q填充到q个l构体,对于C++来说完全是吃力不讨好的Q写出来的代码也是极E,修改和扩展极为麻烦的?/p>
因此军_使用反射的方法来填充数据Q先ȝ一下我的C++反射pȝ
class RTTIObject // 动态类型识别对象基c,对象通过一些宏后可以很方便的通过字符串创建出cd例,q且可以查询注册时的cd和其他绑定信?/span> class NameRef // 名字表,cM于虚qM的FNameQ可以定义Const和普通NameQ比较和拯只是一个dword耗费的时?/span> value_parseQvalue_tostringQvalue_typename // 一pdcd模板函数Q提供对cd的ToStringQParse及类型名查询
首先需要处理的是枚举查询,q里枚N过宏做成一个个枚D对象Qƈ可以通过名字创徏实例
#define DECLARE_ENUMOBJECT( TEnum ) \ struct EnumObject_##TEnum : EnumObject\ {\ DECLARE_RTTIOBJECT( EnumObject_##TEnum );\ EnumObject_##TEnum( );\ }; #define IMPLEMENT_ENUMOBJECT_BEGIN( TEnum, TEnum_prefixoffset, TMember_prefixoffset ) \ IMPLEMENT_RTTIOBJECT_STRING( EnumObject_##TEnum, #TEnum + TEnum_prefixoffset, #TEnum + TEnum_prefixoffset, "EnumObject" )\ EnumObject_##TEnum::EnumObject_##TEnum(){ const int member_prefixoffset = TMember_prefixoffset; #define ENUMOBJECT_ADD( enumkey ) AddMember( #enumkey + member_prefixoffset, (dword)enumkey ); #define IMPLEMENT_ENUMOBJECT_END } #define ENUMOBJECT_STATICINIT( TEnum ) EnumObject_##TEnum::StaticInit();
EnumObject 中通过宏将枚D的名U和g存在q个对象?/p>
IMPLEMENT_ENUMOBJECT_BEGIN( eFillMode, 1, 3 ) // q里?Q?是将eFillMode及FM_Point转成字符串后L前缀 ENUMOBJECT_ADD( FM_Point ) ENUMOBJECT_ADD( FM_Line ) ENUMOBJECT_ADD( FM_Fill ) IMPLEMENT_ENUMOBJECT_END // 注册到RTTIObjectpȝ ENUMOBJECT_STATICINIT( eFillMode )
// 通过枚D对象可以查找到字W串对应的?/span> dword v; EnumObject::GetEnumValue( "FillMode", "Point", v )
下一步是结构体成员信息记录
void SettingObject::BindMember( const NameRef& objname, void* instancePtr, void* dataPtr, SettingProxy* proxy ) { proxy->mOffset = dword(dataPtr) - dword(instancePtr); MemberList& memberlist = mSettingMap[ objname ]; memberlist[ proxy->mName ] = proxy; }
q里记录的是l构体成员的内存偏移
使用大量的宏Q可以让l构体绑定变得漂?/p>
#define BIND_SETTINGOBJECT_BEGIN( TClass ) \ { const NameRef& soname = TClass::StaticGetClassInfo()->mClassName;TClass soobj; #define BIND_SO_MEMBER( TMemberType, TMember ) \ so.BindMember( soname, &soobj, &soobj.TMember, new TSettingElement<TMemberType>(#TMember + 1 ) ); #define BIND_SO_MEMBER_NAME( TMemberType, TMember, TName ) \ so.BindMember( soname, &soobj, &soobj.TMember, new TSettingElement<TMemberType>(TName) ); #define BIND_SO_ENUM( TEnumType, TMember ) \ so.BindMember( soname, &soobj, &soobj.TMember, new TSettingEnum(#TMember + 1, #TEnumType + 1) ); #define BIND_SO_ENUM_NAME( TEnumType, TMember, TName ) \ so.BindMember( soname, &soobj, &soobj.TMember, new TSettingEnum(TName, #TEnumType + 1) ); #define BIND_SETTINGOBJECT_END }
l定代码如下
BIND_SETTINGOBJECT_BEGIN( RasterizerState ) BIND_SO_ENUM ( eFillMode , mFillMode ) BIND_SO_ENUM ( eCullMode , mCullMode ) BIND_SO_MEMBER ( bool , mFrontFaceCCW ) BIND_SO_MEMBER ( float , mDepthBias ) BIND_SO_MEMBER ( float , mSlopeScaledDepthBias) BIND_SO_MEMBER ( bool , mDepthClipEnable) BIND_SO_MEMBER ( bool , mScissorEnable) BIND_SO_MEMBER ( bool , mMultisampleEnable) BIND_SETTINGOBJECT_END
所有结构体的信息被记录在SettingObject中,d配置文g填充l构体的d变得异常的单了
SettingObject settings;
// 所有的l构体信息记?/span>
InitRenderStateObjectSetting( settings );
const NameRef& rzname = DepthStencilState::StaticGetClassInfo()->mClassName;
DepthStencilState a;
// q里是配|文件的信息填充到结构体
settings.SetMember( rzname, &a, "BackFace.StencilFunc", "Equal" );
1. LEffectpȝQ改用HLSL + 渲染脚本
2. 优化渲染接口Q用材质统一shader和渲染状?/p>
随即参考了DirectX SDK的Graphics部分文QDirectX9 时代的EffectpȝUa只是一个HLSL的简单渲染脚本实玎ͼ除了DXUTQFXComposer{极程序用这套东西外Q大型的引擎很少使用q种半成品系l。到了DirectX10甚至11Q因为架构更改,L固定线Q因此Effect成ؓ较ؓ高效和便L渲染脚本Q如果不是要求较高的3d引擎Q一般的游戏使用DirectX10的Effect渲染脚本q是很不错的?/p>
DX10的fx脚本与DX9的差异在?/p>
渲染状态,采样器状态等都变为对象,q与API高度l一
在脚本与API中均可以讄
DepthStencilState EnableDepth
{
DepthEnable = TRUE;
DepthWriteMask = ALL;
DepthFunc = LESS_EQUAL;
};
BlendState NoBlending
{
AlphaToCoverageEnable = FALSE;
BlendEnable[0] = FALSE;
};
technique10 Render
{
pass P0
{
SetDepthStencilState( EnableDepth, 0 );
SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
}
}
本h觉得Q这L设计让图形API更ؓ敏捷与归cdQ另外,也便于StateManager或者自己做渲染状态{Ud差异比较时更为高?
Vista操作pȝ推出很久后,DX10的显卡也占有了大量的市场份额。但是由于DX10仍然是一个过渡APIQ类gDX8)Q因此,很多3D游戏要么仍然支持DX9Q要不然x持DX9也支持DX10Q甚至DX11.
看博客上有达人组团编写类似DX10接口和系l的软渲染,DX10的设计是优秀的。因此,在DX9 HLSL基础上,l合自己~写的渲染脚本会是非常好的选择?
渲染脚本我的设计思\是这LQ?
1. 只是一U预处理脚本Qƈ非实时运行脚本?
~译器将文本解析后,转化Z些运行指令,比如Q本pass使用一块小U理Q下一pass的target是这个纹理,q且开启哪些渲染状态?
2. 自定义格式的解析脚本?
使用luaQpython{脚本其实也是可以的。但是在出现错误Ӟ报出的错可能会让不熟悉这个脚本语a的h莫名其妙?
使用Nsq脚本语言Q可惜其在lua基础上,对table的slot初次赋值时必须使用<-而不是统一使用=Q因此会让你的脚本稀奇古?
XML脚本Q?XML可以避免复杂的语法检查,写完是归整的,但也是罗嗦的Q本来Texture[2]可以表达完毕的,非要<Texture index = 2/>来罗嗦下?
OGRE的compositor脚本和材质脚本就是自p析的Q不q出乎预料的使用了BNF范式q类较ؓ正规的方法。这是_需要先解析BNF表达式,然后再输入脚本解析,~写q程和系l复杂度会变得异常复杂?
最l选择q是使用自己解析的脚本,使用一些具体代码结构来替代BNFq类高深的东?
军_以后Q下一步需要制定渲染脚本具体各部分及制作过E?
1. 基本lexer
从文本得到各Utoken
1. 渲染状态对?
照着DX10抄就?
2. Shader导入?
shader文g来自于何处,入口怎样定义
3. 渲染脚本VM及指?
军_一个纹理怎样讄QRenderTarget怎样使用{的指o