块,路点按坡度以及静态物件自动生成,主要思想是参考了火炬之光的作法,看起来效果还不错,载图留念:
posted @
2014-08-20 17:03 flipcode 阅读(177) |
评论 (0) |
编辑 收藏
unigine多线程处理系统:
一。 更新系统:
主线程World::update_multiple()中:
1. 清空update_threads[]中每一个thread的所有结点
2. 处理所有node,将node.frame==engine.frame + 1的结点均衡地分配给update_threads[](即每个updatethread尽量拥有数量相同的node, 以便线程处理时间平衡), 同时设置分配后的node.frame=engine.frame(防止更新重入时再次加入此结点)
3. 接着通过update_shader->runSync(size);函数同步更新上述加入的所有结点:
遍历所有存有node的update_threads[],将它们与cpu工作线程关联(这样他们的线程run时会转调转回调用world中的update_threads[id].update(ifps);, 而update_threads[id]能遍历所有加入的node->update()函数同时重置node.frame=engine.frame + 1;
最后等待线程同步执行完所有更新再返回.
【注意】上述第3点的runSync()中对应cpu工作线程数为实际cpu-1个,当cpu为1个时就不用线程而是直接运行完所有结点更新,而如果是
有超过一个cpu的则本地和cpu线程同时进行更新工作。虽然在主线程中同步等待完成,但这样如果有多核则能并发同时处理。
另外还有异步runAsync()函数,分别在PathFind和Physics的更新函数中调用。这个runAsync()函数功能和runSync()差不多,只是它的工作线程为实际cpu个数,然后将任务均衡交给各线程处理,并且不会同步等待完成就返回了。所以是异步并发的。
二。渲染系统:
1.收集可视surfaces(scene intersection):
在RenderRenderer::render_world()中调用scene::getIntersection(bound_frustum,occluder,exclude)中:
a. render world occluders得到所有被occluders排除的nodes;
b. 判断node是否被occluder所排除(exclude),没有则add visible nodes.
c. objects_shader->runSync(RENDER_SCENE_NUM_THREADS);同步等待8线程并发处理所有没被occulude排除的
visible node将它置为visible并将它们在bound_frustum中的surface(submesh)加入surfaces中.
c. 在update_intersection()函数中遍历各线程所加入的surfaces[iThread].size, 将其按材质是否透明收集
到opacity_surfaces和transparent_surfaces中。
2. 反射渲染(render reflections):
render reflections中遍历opacity_surfaces和transparent_surfaces处理收集reflection_2d_surfaces和 reflection_cube_surfaces.并进行反射渲染.
3. update scene:
分别UpdateSurface了opacity_surfaces和transparent_surfaces两种surface,
内部好像只是针对OpctitySurfacefade state和tessellation state设置了对应的材质,并将surface链接起来遍历调用
它们的create(),而create()内部只调用了create(ObjectSurface *surface), 这个好像只有skinmesh重载进行了处理。
4. sort scene:
按照type、mask、center.x顺序分别对Lights、defferredLights、forwardLights进行排序
按照material、resource顺序对opacity_surfaces进行排序
按照order、sequence、distance、blending顺序对transparent_surfaces进行了排序。
在scene->optimize()中将opacity_surfaces和transparent_surfaces统一收集到optimized_surfaces中,然后让 opacity_surfaces和transparent_surfaces重新指向对应的optimized_surfaces中元素。(这是为了让surface更紧凑达到优化效果?)
5. deferred textures:
a. 先得到
deferred->depth_texture、
deferred->color_texture、
deferred->normal_texture、
deferred->parallax_texture、
deferred->texturerender
b. render deferred surfaces:
render_deferred_surfaces(scene->getOpacitySurfaces(),0)
render_deferred_surfaces(scene-getTransparentSurfaces(),0)
6. occlusion queries:
这个是使用dx9的硬件查询进行occulsion的culling.
http://frustum.org/
http://www.humus.name/index.php?page=3D
https://www.assembla.com/code/scavenger/subversion/nodes/692/Scavenger
http://www.hmrengine.com/blog/?cat=5
posted @
2014-03-21 16:01 flipcode 阅读(323) |
评论 (0) |
编辑 收藏
秦坦之旅的模型显示, 上个女主角祼模:
还有招唤出来的死灵:
通过pixwin分析模拟出来的对应的shader:
uniform matrix wvp;
uniform texture BaseTexture;
uniform texture BumpTexture;
sampler t = sampler_state
{
Texture = <BaseTexture>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};
sampler b = sampler_state
{
Texture = <BumpTexture>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};
static const int MAX_MATRICES = 48;
float4x4 g_boneMatrices[MAX_MATRICES] : WORLDMATRIXARRAY;
struct VS_IN
{
float4 pos : POSITION;
float2 tex : TEXCOORD0;
float3 Normal : NORMAL;
float4 BlendIndices : BLENDINDICES;
float4 BlendWeights : BLENDWEIGHT;
};
struct VS_OUT
{
float4 pos : POSITION;
float2 tex : TEXCOORD0;
};
//----------------------------------------------------------------------
VS_OUT VS( VS_IN vsIn )
{
VS_OUT vsOut;
int indices[4] = (int[4])vsIn.BlendIndices;
indices[0] = vsIn.BlendIndices.z*255;//vsIn.BlendIndices[2]*255;
indices[1] = vsIn.BlendIndices.y*255;//vsIn.BlendIndices[1]*255;
indices[2] = vsIn.BlendIndices.x*255;//vsIn.BlendIndices[0]*255;
indices[3] = vsIn.BlendIndices.w*255;//vsIn.BlendIndices[3]*255;
float weights[4] = (float[4])vsIn.BlendWeights;
float4 pos = 0.0f;
float4 bonepos = vsIn.pos;
bonepos.w = 1;
for ( int i = 0; i < 4; i++ )
{
pos += mul( bonepos, g_boneMatrices[indices[i]]) * weights[i];
}
vsOut.pos = mul( pos, wvp );
vsOut.tex = vsIn.tex;
return vsOut;
}
struct PS_OUT
{
float4 color : COLOR;
};
//----------------------------------------------------------------------
PS_OUT PS( VS_OUT psIn )
{
PS_OUT psOut;
psOut.color = tex2D(t, psIn.tex);
//psOut.color = float4(1,1,1,1);
return psOut;
}
//----------------------------------------------------------------------
technique RenderMsh
{
pass P0
{
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_2_0 PS();
}
}
posted @
2013-12-27 17:58 flipcode 阅读(355) |
评论 (0) |
编辑 收藏
支持几十公里的大地图编辑,可以随意用笔刷在周边刷出新的patch地块,不用的任意patch也可直接删除,
该地形非常适合作超大地图的arpg, 也测试了一些角色ai,包括dota原型,上图:
posted @
2013-12-27 17:51 flipcode 阅读(230) |
评论 (0) |
编辑 收藏
rts游戏warringstates的AI管理
创建时间:2013年4月7日(星期天) 上午10:37 | 分类:
AI | 字数:1834 |
发送到我的Qzone |
另存为... |
打印 | 添加到日历
warringstates的aiplayer中有几个管理器每帧更新:
1. build_mgr(工程部)
2. exploration_mgr(探索部)
3. army_mgr(军工部)
4. unit_mgr(人力部)
5. resource_mgr(资源部)
每个管理器相当于一个部门,它每帧会更新处理两个事情:a. 请求列表(request)处理; b.工作(job)列表处理;c.job的响应事件(触发式:
job提交的请求得到满足时触发回来)
每个部门更新时在job中处理自己要做的事情(这是b.步骤),发现需要其它部门的帮助时,则向其它部门发出请求, 其它部门会把请求收入队列,
然后更新时检查是否可以满足对应的请求(这是在a.步骤),是则立即给响应,否则按排工作组员(job)去完成; 完成后再给对应请求部门(这里直接是请求者(job)发出响应 (这是c.步骤)
例如:
1. aiplayer的更新中发现人口太多,房屋不够则向build_mgr发出一个增加住房的请求,build_mgr收到后找到消耗金钱少的但住人多的
户型并产生一个AIBuildJob让组员去完成.
2. AIBuildJob的更新中发现要建造这样的户型所需的资源当前不够(缺少木村),于是他向resource_mgr(资源管理器)MakeRequest申请
所需要的资源。
3. resource_mgr的更新中:
a. 从请求列表中取出该请求,产生对应的AIHarvestJob放入jobs列表中。
b. 接着遍历更新jobs取出该AIHarvestJob更新
c. AIHarvestJob的更新发现该采集job还没有对应农民,于是它向unit_mgr请求对应类型的农民。
4. unit_mgr的更新中:
从请求列表中取出该请求, 发现当前mAvailableUnits中有符合的已产生的农民,于时立即响应给对应的请求者AIHarvestJob
AIHarvestJob把对应的农民登录到mHarvesters中.(说明:如果没有的话则产生一个AITrainJob,在AITrainJob的处理中会看是否有对应unitype的工厂,
没有则向build_mgr发出请求,有则向资源请求对应的单位所需要的资源,等资源管理器更新时发现请求满足并响应回来时则开始向对应的工厂发出
eCOMMAND_TYPE_Train指令,之后就会跑到GameBuilding的Train工作流程)
5. resource_mgr的更新中:
遍历更新jobs取出该AIHarvestJob进行更新,该AIHarvestJob遍历mHarvesters取得那个农民,向他发出eCOMMAND_TYPE_Harvest
指令。
6. object_mgr的更新中:
遍历所有单位进行更新,轮到那个农民更新时,它think函数中发现当前指令是eCOMMAND_TYPE_Harvest,于是它开始了Harvest的
工作流程:判断背包中木材是否满了,是则回城(搜索路径),否则寻找木材资源(搜索路径),到达后卸载/收割资源.
这样当木材足够时在resource_mgr的更新中,发现对应的木材资源请求足够时就会移除该请求并向
对应的AIBuildJob发出响应说明木材已收集够了; AIBuildJob收到后接着会向unit_mgr请求一名建筑工人。
(插入说明: 向unit_mgr请求所得的工人都是出租方式的,时间到了会收回并按请求级别优先级重新分配给其它需要他的请求)
由于之前收割的农民租期到了,而且那个木材收割的request已被移除(因此没再请求分配农民)。
所以unit_mgr会把当前这个农民重新分配为建筑工人,向对应AIBuildJob发出响应。AIBuildJob收到后开始在主城附近有块空地
并向建筑工人发出eCOMMAND_TYPE_Build指令让其开始建造的工作流程.
其它军工部的更新会判断当前是否需要军队,并向人力部请求对应的兵,人力部又会看是否有这样的兵,没有的话则判断对应产生
这样兵种的兵工厂是否存在,不存在的话又会向工程部发出请求对应的兵工厂,工程部收到后又会判断是否有足够资源,没有的话
又会向资源部要求对应的资源,资源部又会向人力请求对应的农民来采集资源,等等,如此类似的相关循环。。。
posted @
2013-04-07 11:34 flipcode 阅读(421) |
评论 (0) |
编辑 收藏
raven的ai处理:
先据评估项(函数)进行评估选出当前最优一项,据此项产生对应的新行为处理对象(先清除之前的所有行为),调用它的process()来处理.
具体如下:
一。行为评估项:
每个bot有一个brain(即Goal_Think类),在brain中有一个评估列表m_Evaluators;
raven中主要是有4种需要评估的行为:
1.拿药包
2.探索
3.攻击
4.拿武器
具体如下:
double HealthBias = RandInRange(LowRangeOfBias, HighRangeOfBias);
double ShotgunBias = RandInRange(LowRangeOfBias, HighRangeOfBias);
double RocketLauncherBias = RandInRange(LowRangeOfBias, HighRangeOfBias);
double RailgunBias = RandInRange(LowRangeOfBias, HighRangeOfBias);
double ExploreBias = RandInRange(LowRangeOfBias, HighRangeOfBias);
double AttackBias = RandInRange(LowRangeOfBias, HighRangeOfBias);
//create the evaluator objects
m_Evaluators.push_back(new GetHealthGoal_Evaluator(HealthBias));
m_Evaluators.push_back(new ExploreGoal_Evaluator(ExploreBias));
m_Evaluators.push_back(new AttackTargetGoal_Evaluator(AttackBias));
m_Evaluators.push_back(new GetWeaponGoal_Evaluator(ShotgunBias,
type_shotgun));
m_Evaluators.push_back(new GetWeaponGoal_Evaluator(RailgunBias,
type_rail_gun));
m_Evaluators.push_back(new GetWeaponGoal_Evaluator(RocketLauncherBias,
type_rocket_launcher));
上述评估项目主要派生了一个 CalculateDesirability(), 以便bot在更新时遍历该评估表,
调用它们的CalculateDesirability()选出最优先的行为项,并调用它的SetGoal(m_pOwnerBot)方法;
对应被选中的评估项的SetGoal函数内容:
void AttackTargetGoal_Evaluator::SetGoal(Raven_Bot* pBot)
{
pBot->GetBrain()->AddGoal_AttackTarget();
}
void ExploreGoal_Evaluator::SetGoal(Raven_Bot* pBot)
{
pBot->GetBrain()->AddGoal_Explore();
}
void GetHealthGoal_Evaluator::SetGoal(Raven_Bot* pBot)
{
pBot->GetBrain()->AddGoal_GetItem(type_health);
}
void GetWeaponGoal_Evaluator::SetGoal(Raven_Bot* pBot)
{
pBot->GetBrain()->AddGoal_GetItem(m_iWeaponType);
}
二。行为处理类:
在上述SetGoal对应具体函数中所调用的brain方法具体产生的行为如下:
void Goal_Think::AddGoal_Explore()
{
if (notPresent(goal_explore))
{
RemoveAllSubgoals();
AddSubgoal( new Goal_Explore(m_pOwner));
}
}
void Goal_Think::AddGoal_GetItem(unsigned int ItemType)
{
if (notPresent(ItemTypeToGoalType(ItemType)))
{
RemoveAllSubgoals();
AddSubgoal( new Goal_GetItem(m_pOwner, ItemType));
}
}
void Goal_Think::AddGoal_AttackTarget()
{
if (notPresent(goal_attack_target))
{
RemoveAllSubgoals();
AddSubgoal( new Goal_AttackTarget(m_pOwner));
}
}
当bot更新时会调用brain的process,从而调用到对应的subgoal中的Process()函数
注意:
每个goal在处理时还可以产生它自己的子goal。因为有时候在处理一个goal时需要等完成
另一个子goal后才能处理。 即状态管理使用了树结构.
posted @
2013-04-07 11:08 flipcode 阅读(256) |
评论 (0) |
编辑 收藏
关于预测树:
同事做了个demo,演示了这个预测树。感觉复杂的ai可能评分有点难(比如说团队合作之类的游戏,当然棋类游戏的话可以很容易使用这种方式).
主要用了两个表: 评估表和评分表
每次预测时先产生一个根结点(带当前局面S(Situation)),并开始处理根结点
1.
依赖于全局评估表根据当前局面S产生可能的决策D(decision)(它有自己的局面S,在决策处理时进行刷新);
2.
遍历决策D列表模拟每一个决策的前瞻处理(并刷新当前决策下的局面S);
在每一个决定处理完后又回到第1.步产生可能的新的决策列表以及对应的局面(模拟有深度限制),
当模拟深度结束时使用全局评分表对每个决策的新局面进行评分。把评分累积到父结点。
最后选择评分最高的决策作为下一步行动。(决策翻译成命令并发送)
posted @
2012-09-24 17:29 flipcode 阅读(308) |
评论 (0) |
编辑 收藏
关于全屏
1。 假全屏(如:成吉思汗、11的EF):
用API:ChangeDisplaySettings( &dm, CDS_FULLSCREEN );来设置
2. 对话框全屏(如:起凡早期的三国争霸):
有限制,设备缓冲必须是discard交换并且是lockable的;
颜色跟gdi兼容;
设备不能开反锯齿;
3. flip独占全屏(如war3、LOL):
这种方式最快,但是显示不出输入法的选字框。
所以必须自绘输入框(使用ime处理)
理论上第2种对话框是介于1和3的一种折中的解决方案,但是2的限制也有点大,主要是不能开反锯齿,性能和3比差别不是很大。
但是目前出现一个严重问题,在一些可进行cpu和gpu切换的笔记本中(目前发现A卡的3000-5000系列),当切换到高性能时第2种
对话框全屏方式的游戏(必须开HARDWARE顶点,软件顶点不受影响)会严重地卡帧,相当地卡!原因可能是这系列卡的驱动并未能
很好地处理这种全屏模式(开启d3d debug可以看到BitBlt or StretchBlt failed in Present之类的报错)
如果你的游戏以前也用第2种方式,那么现在你得照顾下这些交火切换之类的本本了。。。
posted @
2012-09-24 15:11 flipcode 阅读(226) |
评论 (0) |
编辑 收藏
行为树的理解:
传统的AI习惯用FSM来管理状态规则,一个管理类对多个状态类进行管理。
FSM可以通过转换状态来处理(如:泰坦之旅),
也可以让状态并行处理(如:mythos). 另外为了处理某种状态下的某种子行为,派生出了
分层状态机(mythos通过栈来实现分层)。
FSM为了处理并行以及分层,在处理上让人感觉不是非常清晰。而行为树天生就是分层的,每一层又是并行的
通过条件以及控制结点可以清晰地使用图形化来控制各种分支行为。
个人觉得搞行为树就像是在搞流程图
一般的行为树都会有控制结点、条件结点、动作结点。
用控制结点根据不同的条件结点让程序按不同的控制结点分支进行运行,当某些条件结点成立触发相应的动作结点。
为了控制分支,控制结点有选择、序列、并行等方式控制。同时还有一些用于装饰的如循环、结果取反等之类的特殊结点。
光晕2、LOL等游戏用了行为树。
可以参考:
行为树
http://aigamedev.com/premium/tutorial/second-generation-behavior-trees/
行为树
http://aigamedev.com/premium/interview/league-of-legends/
posted @
2012-09-24 14:46 flipcode 阅读(940) |
评论 (0) |
编辑 收藏
著名游戏引擎公司GARAGEGAMES联合全球一流大学MIT麻省理工大学,联合推出Torque 3d engine永久免费版本.
今年9月.著名游戏引擎公司www.GarageGames.com与国际一流大学MIT(麻省理工大学)共同推出全球最具有权威的游戏开发相关技术标准及课程.
此消息发布一周内,包括EA,暴雪,微软,UBI等多家公司随即表示加盟.现在全球最大标准及技术查询教学在线中心正在建立..
.(详细:http://services.garagegames.com/)
可到此下载:
https://github.com/GarageGames/Torque3D
posted @
2012-09-24 13:36 flipcode 阅读(426) |
评论 (0) |
编辑 收藏