首页 > 代码库 > 16092001(镜头粒子)

16092001(镜头粒子)

【目标】

镜头粒子的实现

【思路】

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

可以看到

技术分享



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);
    }
}



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




来自为知笔记(Wiz)


16092001(镜头粒子)