【目标】
镜头粒子的实现
【思路】
1 之前的实验
\ue3\Development\Src\ExampleGame\Classes\ExamplePlayerCamera.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)
看不到
放到\ue3\Development\Src\ExampleGame\Classes\ExampleSkeletalMeshActor.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中 资源新建出来是空的
修改\Development\Src\Engine\Classes\AnimNotify_CameraEffect.uc试下
defaultproperties
{
CameraLensEffect=class‘Engine.EmitterCameraLensEffectBase‘
}
编译uc‘通过
测试无效果
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
添加这个派生类之后就看到了
在\Development\Src\Engine\Classes\EmitterCameraLensEffectBase.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
\Development\Src\ExampleGame\Classes\ExamplePlayerCamera.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 修改\Development\Src\Engine\Classes\AnimNotify_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;
\Development\Src\ExampleGame\Classes\ExamplePlayerController.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