【目标】
镜头粒子的实现
【思路】
1 之前的实验
ue3DevelopmentSrcExampleGameClassesExamplePlayerCamera.uc
Begin Object Class=SpriteComponent Name=Sprite
Sprite=Texture2D'EditorResources.S_Emitter'
//HiddenGame=True
AlwaysLoadOnClient=False
AlwaysLoadOnServer=False
bIsScreenSizeScaled=True
ScreenSize=0.0025
SpriteCategoryName="Effects"
End Object
Components.Add(Sprite)
看不到
放到ue3DevelopmentSrcExampleGameClassesExampleSkeletalMeshActor.uc
可以看到
2 EmitterCameraLensEffectBase
3 UDN中描述
http://udn.epicgames.com/Three/CameraTechnicalGuideCH.html
镜头特效
镜头特效是粒子特效,可以将其用于玩家的相机的镜头。这些镜头特效可以用于创建诸如相机镜头中下的雨滴、血溅、镜头上的污物或灰尘等等这一类的效果。这个 camera 类会包含可以使用这些特效类型的函数。
要了解有关粒子系统和特效的更多信息,请参阅ParticleSystemReference(粒子系统参考)。
镜头特效属性
- CameraLensEffects – 当前应用于相机的所有粒子特效的数组。
镜头特效函数
- FindCameraLensEffect [LensEffectEmitterClass] – 会搜索当前应用于相机的镜头特效并返回任何与之匹配的类型。
- LensEffectEmitterType – 要搜索的镜头特效的类。
- AddCameraLensEffect [LensEffectEmitterClass] – 会将指定类型的新镜头特效应用于相机中。
- LensEffectEmitterClass – 要应用到相机中的镜头特效的类。
- RemoveCameraLensEffect [Emitter] – 从相机中删除一个镜头特效。
- Emitter – 要从相机中删除的镜头特效。
- ClearCameraLensEffects – 删除当前应用于相机中的所有镜头特效。
4 在Notify_CameraEffect中 资源新建出来是空的
修改DevelopmentSrcEngineClassesAnimNotify_CameraEffect.uc试下
defaultproperties{ CameraLensEffect=class'Engine.EmitterCameraLensEffectBase'}
测试无效果
5 实验:UAnimNotify_CameraEffect.Notify 中
void UAnimNotify_CameraEffect::Notify( UAnimNodeSequence* NodeSeq ){ AActor* Owner = NodeSeq->SkelComponent->GetOwner(); CameraLensEffect = AEmitterCameraLensEffectBase::StaticClass();
机器人的动作上绑
跑地图测试,触发run动作,发现Spawn不了抽象类
该类的脚本
难道需要继承一个类
好吧,添加一个EmitterCameraLensEffect.uc
class EmitterCameraLensEffect extends EmitterCameraLensEffectBase native(Particle);DefaultProperties{}
编译uc
添加这个派生类之后就看到了
在DevelopmentSrcEngineClassesEmitterCameraLensEffectBase.uc中设置PSTemplate
PS_CameraEffect=ParticleSystem'FogClouds.P_TestCloud_c' PS_CameraEffectNonExtremeContent=ParticleSystem'ef_wj_016.ef_wj_016_eff01'
测试发现,没有调用UpdateCameraLensEffects函数来更新位置
打印一些GamePlayerCamera.UpdateViewTarget的log
原因是ExamplePlayerCamera.有自己的UpdateViewTarget
DevelopmentSrcExampleGameClassesExamplePlayerCamera.uc添加应用LensEffect函数
`log("ExamplePlayerCamera::UpdateViewTarget 4"); UpdateCameraLensEffects( OutVT );
还需要复制UpdateCameraLensEffects
/** Update any attached camera lens effects (e.g. blood) **/simulated function UpdateCameraLensEffects( const out TViewTarget OutVT ){ local int Idx; for (Idx=0; Idx<CameraLensEffects.length; ++Idx) { if (CameraLensEffects[Idx] != None) { CameraLensEffects[Idx].UpdateLocation(OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV); } }}
屏幕上出现了粒子,
小结:
- 这里是Notify触发一个Class去Spawn出一个Emitter
- 这样做很不方便
- 继承一个EmitterCameraLensEffectBase的派生用于Notify类型的
- Notify中可配置特效Template,和摄像机的距离等参数
- Spawn出来后,Notify再将参数传递给它
- 如果是场景相关的也是配置到WorldInfo中
- 在PlayerController的PostBeginPlay中去Spawn,不行!此时还没有Camera,添加不了特效
- 在PlayerController.SpawnPlayerCamera
问题:
- 在PlayerController无法去传递参数
- 原有机制的初衷应该是所有参数都在CameraLensEffectClass中
- 所以如果能做多个派生类,在资源管理器中去选择,
- 那每新建一个不同资源,就要都要写一个uc,而且还需要编译u,
- 为什么不能实时动态的去控制它,修改资源
- 添加另外的接口,在Spawn的是否传入PSTemplate
待解决
- 删除的时机,如果是循环粒子
- 如何切换,替换原有的,根据类型来判断?
【步骤】
1 修改DevelopmentSrcEngineClassesAnimNotify_CameraEffect.uc
/** * How far in front of the camera this emitter should live, assuming an FOV of 80 degrees. * Note that the actual distance will be automatically adjusted to account for the actual FOV. */var() float DistFromCamera;/** Particle System to use */var() ParticleSystem PS_CameraEffect;...
defaultproperties{ CameraLensEffect=class'Engine.EmitterCameraLensEffect' DistFromCamera=90}
2 添加AddEmitterCameraLensEffect 接口
/** * Initiates a camera lens effect of the given PSTemplate on this camera. */function EmitterCameraLensEffectBase AddEmitterCameraLensEffect( ParticleSystem LensEffectTemplate ){ local vector CamLoc; local rotator CamRot; local EmitterCameraLensEffectBase LensEffect; if (LensEffectTemplate != None) { LensEffect = Spawn( class'EmitterCameraLensEffect', PCOwner.GetViewTarget() ); if (LensEffect != None) { LensEffect.SetEffectTemplate(LensEffectTemplate); GetCameraViewPoint(CamLoc, CamRot); LensEffect.UpdateLocation(CamLoc, CamRot, GetFOVAngle()); LensEffect.RegisterCamera(self); CameraLensEffects.AddItem(LensEffect); } }}
3 UAnimNotify_CameraEffect.Notify
AEmitterCameraLensEffectBase* pCameraEffect = Cast<APlayerController>(Owner->GetAPawn()->Controller)->eventClientSpawnLensEffect(PS_CameraEffect); if (pCameraEffect) { pCameraEffect->DistFromCamera = DistFromCamera; }
如果不旋转呢?
4 为EmitterCameraLensEffectBase添加两个属性
var protected transient bool bAdjustRot;var protected ESceneDepthPriorityGroup DepthPriorityGroup;
event SetEffectTemplate(ESceneDepthPriorityGroup NewDepthPriorityGroup){ ParticleSystemComponent.SetDepthPriorityGroup(NewDepthPriorityGroup);}
5 场景的配置,修改worldinfo.uc
var (Player) ParticleSystem CameraEffect;
DevelopmentSrcExampleGameClassesExamplePlayerController.uc
simulated event PostBeginPlay(){ local EmitterCameraLensEffectBase LensEffect; super.PostBeginPlay(); if ( WorldInfo.CameraEffect != none ) { LensEffect = ClientSpawnLensEffect(WorldInfo.CameraEffect); if ( LensEffect != none ) LensEffect.SetDepthPriorityGroup(SDPG_World); }}
6 PlayerController.SpawnPlayerCamera
// Camera Effect if ( WorldInfo.CameraEffect != none ) { `log( "Examp PC PostBeginPlay 1" ); LensEffect = ClientSpawnLensEffect(WorldInfo.CameraEffect); if ( LensEffect != none ) LensEffect.SetDepthPriorityGroup(SDPG_World); }
跑地图看不到粒子 OMG
有tick有调用FParticleDataManager.UpdateDynamicData.
修改一下调用时机,在UWorld.Tick中调用一次,就可以看到
在UWorld.SpawnPlayActor最后面调用就行了
7 UWorld添加一个接口是 用于设置镜头特效的,用于Matinee等地方触发
8 修改Emitter.uc 添加一个镜头属性
var(LensEffect) bool bLensEffect;var(LensEffect) bool bAdjustRot;var(LensEffect) float DistFromCamera;var(LensEffect) ESceneDepthPriorityGroup DPG;
void USkelControlHitPlacement::CalculateNewBoneTransforms(INT BoneIndex, USkeletalMeshComponent* SkelComp, TArray<FBoneAtom>& OutBoneTransforms)
{
check(BoneIndex != 0);
....
}
【运行】
3