【目标】

植被工具-刷Actor

【思路】

1 添加类型FFoliageMeshInfo.AddInstance 的函数

2 添加Instance就直接SpawnActor

3 类结构

4 修改的函数

FEdModeFoliage.AddInstancesForBrush.

FEdModeFoliage.AddFoliageMesh

【步骤】

1 添加AcheType支持,添加FEdModeFoliage.AddFoliageAcheType 

2 添加一个AActor的表,用于记录ArcheType

  1. var    const native Map_MirrorFoliageArcheTypes{TMap<classAActor*,structFFoliageMeshInfo>};
 

3 MFoliageEditWindow.OnDrop,资源拖到面板上

  1. else
    {
    AActor*ArcheTypeActor=LoadObject<AActor>(NULL,*CurInfo.ObjectPathName, NULL, LOAD_None, NULL);
    if(ArcheTypeActor&&ArchetypeActor->HasAnyFlags(RF_ArchetypeObject))
    {
    FoliageEditSystem->AddFoliageAcheType(ArcheTypeActor);
    FoliageMeshesProperty->NotifyChanged();
    }
    }
 
MFoliageEditWindow.OnDragOver 过滤不支持的类型,添加Actor类型的支持
  1. for(TArray<FSelectedAssetInfo>::TConstIteratorDroppedAssetsIter(*(DroppedAssets.Get()));DroppedAssetsIter;++DroppedAssetsIter)
    {
    constFSelectedAssetInfo&CurInfo=*DroppedAssetsIter;
    if(CurInfo.ObjectClass!=UStaticMesh::StaticClass()&&CurInfo.ObjectClass!=AActor::StaticClass())
    {
    Args->Effects=DragDropEffects::None;
    break;
    }
还是拖不上去
在MFoliageEditWindow.OnDragEnter 中有
 
 
 
需要设置这个才能调试
 
 

4 MFoliageEditWindow.OnDragOver 改成 IsChildOf 判断

  1. voidOnDragOver(Object^Owner,DragEventArgs^Args)
    {
    Args->Effects=DragDropEffects::Copy;
    if(DroppedAssets.Get()!= NULL )
    {
    for(TArray<FSelectedAssetInfo>::TConstIteratorDroppedAssetsIter(*(DroppedAssets.Get()));DroppedAssetsIter;++DroppedAssetsIter)
    {
    constFSelectedAssetInfo&CurInfo=*DroppedAssetsIter;
    if(CurInfo.ObjectClass!=UStaticMesh::StaticClass()&&!CurInfo.ObjectClass->IsChildOf(AActor::StaticClass()))
    {
    Args->Effects=DragDropEffects::None;
    break;
    }
    }
    }
    Args->Handled= TRUE;
    }
 

5 目前拖上去没有效果显示,

MFoliageMeshWrapper

列表和FEdModeFoliage.GetFoliageMeshList 绑定了,所以显示了FFoliageMeshUIInfo列表

6 添加FFoliageArcheTypeUIInfo 继承于FFoliageMeshUIInfo 

  1.  structFFoliageResourceUIInfo:publicFFoliageMeshUIInfo
    {
    AActor*ArcheTypeActor;
    FFoliageResourceUIInfo(UStaticMesh*InStaticMesh,AActor*InArcheTypeActor,FFoliageMeshInfo*InMeshInfo)
    :FFoliageMeshUIInfo(InStaticMesh,InMeshInfo)
    :ArcheTypeActor(InArcheTypeActor)
    {}
    };
 

7 FEdModeFoliage.GetFoliageMeshList 返回值

  1.  TArray<structFFoliageResourceUIInfo>&GetFoliageMeshList();
 

8 FEdModeFoliage.FoliageMeshList 

  1. // Placed level data
    TArray<structFFoliageResourceUIInfo>FoliageMeshList;
 

9

  1.  IMPLEMENT_COMPARE_CONSTREF(FFoliageResourceUIInfo,FoliageEdMode,{return A.MeshInfo->Settings->DisplayOrder- B.MeshInfo->Settings->DisplayOrder;});
 

10 FEdModeFoliage.UpdateFoliageMeshList 

  1.  voidFEdModeFoliage::UpdateFoliageMeshList()
    {
    FoliageMeshList.Empty();
    AInstancedFoliageActor* IFA =AInstancedFoliageActor::GetInstancedFoliageActor();
    for(TMap<classUStaticMesh*,structFFoliageMeshInfo>::TIteratorMeshIt(IFA->FoliageMeshes);MeshIt;++MeshIt)
    {
    new(FoliageMeshList)FFoliageResourceUIInfo(MeshIt.Key(),NULL,&MeshIt.Value());
    }
    for(TMap<classAActor*,structFFoliageMeshInfo>::TIteratorArcheTypeIt(IFA->FoliageArcheTypes);ArcheTypeIt;++ArcheTypeIt)
    {
    new(FoliageArcheTypeList)FFoliageResourceUIInfo(NULL,ArcheTypeIt.Key(),&ArcheTypeIt.Value());
    }
    Sort<USE_COMPARE_CONSTREF(FFoliageResourceUIInfo,FoliageEdMode)>(&FoliageMeshList(),FoliageMeshList.Num());
    }
 

11 MFoliageMeshWrapper 类构造需要用新类FFoliageResourceUIInfo 

  1.  ref classMFoliageMeshWrapper:publicINotifyPropertyChanged
    {
    int index;
    FFoliageResourceUIInfo& mesh;
    UInstancedFoliageSettings* settings;
    BitmapSource^ bitmap;
    public:
    virtual event PropertyChangedEventHandler^PropertyChanged;
    MFoliageMeshWrapper( INT InIndex,FFoliageResourceUIInfo&InMesh)
    : index(InIndex)
    , mesh(InMesh)
    , settings(mesh.MeshInfo->Settings)
    {
    if(mesh.StaticMesh)
    bitmap =ThumbnailToolsCLR::GetBitmapSourceForObject(mesh.StaticMesh);
    elseif(mesh.ArcheTypeActor)
    bitmap =ThumbnailToolsCLR::GetBitmapSourceForObject(mesh.ArcheTypeActor);
    }
 

12

  1. typedefMEnumerableTArrayWrapper<MFoliageMeshWrapper,FFoliageResourceUIInfo>MFoliageMeshes;
 
终于看到效果了
 

13 跟FFoliageMeshUIInfo.StaticMesh 相关的修改

MFoliageMeshWrapper.StaticMeshName.get  获取名字的

  1.  propertyString^StaticMeshName{
    String^ get()
    {
    FStringName= mesh.StaticMesh? mesh.StaticMesh->GetName()? mesh.ArcheTypeActor->GetName();
    returnCLRTools::ToString(Name);
    }
    }
 
MFoliageEditWindow.FoliageMeshRemoveButton_Click 
  1.  // Remove the current mesh
    voidFoliageMeshRemoveButton_Click(Object^Owner,ExecutedRoutedEventArgs^Args)
    {
    MFoliageMeshWrapper^Mesh= safe_cast<MFoliageMeshWrapper^>(Args->Parameter);
    if(Mesh->GetStaticMesh())
    FoliageEditSystem->RemoveFoliageMesh(Mesh->GetStaticMesh());
    else
    FoliageEditSystem->RemoveFoliageAcheType(Mesh->GetArcheTypeActor());
    FoliageMeshesProperty->NotifyChanged();
    }
 
 

添加MFoliageMeshWrapper.GetStaticMesh

  1. AActor*GetStaticMesh(){return mesh.ArcheTypeActor;}
 

MFoliageEditWindow.FoliageMeshCopySettings_Click

  1. voidFoliageMeshUseSettings_Click(Object^Owner,ExecutedRoutedEventArgs^Args)
    {
    GCallbackEvent->Send(CALLBACK_LoadSelectedAssetsIfNeeded);
    USelection*SelectedSet=GEditor->GetSelectedSet(UInstancedFoliageSettings::StaticClass());
    UInstancedFoliageSettings*SelectedSettings=Cast<UInstancedFoliageSettings>(SelectedSet->GetTop(UInstancedFoliageSettings::StaticClass()));
    if(SelectedSettings!= NULL )
    {
    MFoliageMeshWrapper^Mesh= safe_cast<MFoliageMeshWrapper^>(Args->Parameter);
    if(Mesh->GetStaticMesh())
    FoliageEditSystem->ReplaceSettingsObject(Mesh->GetStaticMesh(),SelectedSettings);
    else
    FoliageEditSystem->ReplaceSettingsObject(Mesh->GetArcheTypeActor(),SelectedSettings);
 
MFoliageEditWindow.FoliageMeshReplaceButton_Click 
  1. if(SelectedActor&&SelectedActor->HasAnyFlags(RF_ArchetypeObject))
    {
    MFoliageMeshWrapper^Mesh= safe_cast<MFoliageMeshWrapper^>(Args->Parameter);
    FoliageEditSystem->ReplaceArchtypeActor(Mesh->GetArcheTypeActor(),SelectedActor);
    FoliageMeshesProperty->NotifyChanged();
    }
 

13 FEdModeFoliage.ReplaceArchtypeActor 

  1.  voidFEdModeFoliage::ReplaceArchtypeActor(AActor*OldArcheType,AActor*NewArcheType)
    {
    AInstancedFoliageActor* IFA =AInstancedFoliageActor::GetInstancedFoliageActor();
    FFoliageMeshInfo*OldMeshInfo= IFA->FoliageArcheTypes.Find(OldArcheType);
    if(OldMeshInfo!= NULL &&OldArcheType!=NewArcheType&&NewArcheType->HasAnyFlags(RF_ArchetypeObject))
    {
    INT InstancesNum=OldMeshInfo->Instances.Num()-OldMeshInfo->FreeInstanceIndices.Num();
    // Look for the new mesh in the mesh list, and either create a new mesh or merge the instances.
    FFoliageMeshInfo*NewMeshInfo= IFA->FoliageArcheTypes.Find(NewArcheType);
    if(NewMeshInfo== NULL )
    {
    if(InstancesNum>&&
    appMsgf(AMT_YesNo,LocalizeSecure(LocalizeUnrealEd("FoliageMode_ReplaceMesh"),InstancesNum,*OldArcheType->GetName(),*NewArcheType->GetName()))!= ART_Yes )
    {
    return;
    }
    GEditor->BeginTransaction(*LocalizeUnrealEd("FoliageMode_ChangeStaticMeshTransaction"));
    IFA->Modify();
    NewMeshInfo= IFA->AddArcheType(NewArcheType);
    NewMeshInfo->Settings->DisplayOrder=OldMeshInfo->Settings->DisplayOrder;
    NewMeshInfo->Settings->ShowNothing=OldMeshInfo->Settings->ShowNothing;
    NewMeshInfo->Settings->ShowPaintSettings=OldMeshInfo->Settings->ShowPaintSettings;
    NewMeshInfo->Settings->ShowInstanceSettings=OldMeshInfo->Settings->ShowInstanceSettings;
    }
    else
    if(InstancesNum>&&
    appMsgf(AMT_YesNo,LocalizeSecure(LocalizeUnrealEd("FoliageMode_ReplaceMeshMerge"),InstancesNum,*OldArcheType->GetName(),*NewArcheType->GetName()))!= ART_Yes )
    {
    return;
    }
    else
    {
    GEditor->BeginTransaction(*LocalizeUnrealEd("FoliageMode_ChangeStaticMeshTransaction"));
    IFA->Modify();
    }
    if(InstancesNum>)
    {
    // copy instances from old to new.
    for( INT Idx=;Idx<OldMeshInfo->Instances.Num();Idx++)
    {
    if(OldMeshInfo->Instances(Idx).ClusterIndex!=-)
    {
    NewMeshInfo->AddInstanceAT( IFA,NewArcheType,OldMeshInfo->Instances(Idx));
    }
    }
    }
    // Remove the old mesh.
    IFA->RemoveArcheType(OldArcheType);
    GEditor->EndTransaction();
    // Update mesh list.
    UpdateFoliageMeshList();
    }
    }
 

14 添加FFoliageMeshInfo.AddInstanceAT

  1.  voidFFoliageMeshInfo::AddInstanceAT(classAInstancedFoliageActor*InIFA,classAActor*InActor,constFFoliageInstance&InNewInstance)
    {
    }
 

目前是刷不上Actor模型吗,主要是FEdModeFoliage.ApplyBrush 函数里没有处理

15 修改FEdModeFoliage.ApplyBrush 

  1.  // ArcheType
    for(TMap<classAActor*,structFFoliageMeshInfo>::TIteratorArcheTypeIt(IFA->FoliageArcheTypes);ArcheTypeIt;++ArcheTypeIt)
    {
    FFoliageMeshInfo&MeshInfo=ArcheTypeIt.Value();
    UInstancedFoliageSettings*MeshSettings=MeshInfo.Settings;
    if(MeshSettings->IsSelected)
    {
    // Find the instances already in the area.
    TArray<INT>Instances;
    FSphereBrushSphere(BrushLocation,UISettings.GetRadius());
    MeshInfo.GetInstancesInsideSphere(BrushSphere,Instances);
    if(UISettings.GetLassoSelectToolSelected())
    {
    // Shift unpaints
    MeshInfo.SelectInstances( IFA,!IsShiftDown(ViewportClient->Viewport),Instances);
    }
    else
    if(UISettings.GetReapplyToolSelected())
    {
    if(MeshSettings->ReapplyDensity)
    {
    // Adjust instance density
    FMeshInfoSnapshot*SnapShot=InstanceATSnapshot.Find(ArcheTypeIt.Key());
    if(SnapShot)
    {
    // Use snapshot to determine number of instances at the start of the brush stroke
    INT NewInstanceCount= appRound((FLOAT)SnapShot->CountInstancesInsideSphere(BrushSphere)*MeshSettings->ReapplyDensityAmount);
    if(MeshSettings->ReapplyDensityAmount>.f&&NewInstanceCount>Instances.Num())
    {
    AddInstancesATForBrush( IFA,ArcheTypeIt.Key(),MeshInfo,NewInstanceCount,Instances,Pressure);
    }
    else
    if(MeshSettings->ReapplyDensityAmount<.f&&NewInstanceCount<Instances.Num())
    {
    RemoveInstancesForBrush( IFA,MeshInfo,NewInstanceCount,Instances,Pressure);
    }
    }
    }
    // Reapply any settings checked by the user
    ReapplyInstancesForBrush( IFA,MeshInfo,Instances);
    }
    else
    if(UISettings.GetPaintToolSelected())
    {
    // Shift unpaints
    if(IsShiftDown(ViewportClient->Viewport))
    {
    INT DesiredInstanceCount= appRound(BrushArea*MeshSettings->Density*UISettings.GetUnpaintDensity()/(.f*.f));
    if(DesiredInstanceCount<Instances.Num())
    {
    RemoveInstancesForBrush( IFA,MeshInfo,DesiredInstanceCount,Instances,Pressure);
    }
    }
    else
    {
    // This is the total set of instances disregarding parameters like slope, height or layer.
    FLOAT DesiredInstanceCountFloat=BrushArea*MeshSettings->Density*UISettings.GetPaintDensity()/(.f*.f);
    // Allow a single instance with a random chance, if the brush is smaller than the density
    INT DesiredInstanceCount=DesiredInstanceCountFloat>.f? appRound(DesiredInstanceCountFloat): appFrand()<DesiredInstanceCountFloat?:;
    AddInstancesATForBrush( IFA,ArcheTypeIt.Key(),MeshInfo,DesiredInstanceCount,Instances,Pressure);
    }
    }
    }
    }
 

16 添加Instance的函数FEdModeFoliage.AddInstancesATForBrush 

  1.  /** Add instances inside the brush to match DesiredInstanceCount */
    voidFEdModeFoliage::AddInstancesATForBrush(AInstancedFoliageActor* IFA,AActor*AchetypeActor,FFoliageMeshInfo&MeshInfo, INT DesiredInstanceCount,TArray<INT>&ExistingInstances, FLOAT Pressure)
    {
    UInstancedFoliageSettings*MeshSettings=MeshInfo.Settings;
    if(DesiredInstanceCount>ExistingInstances.Num())
    {
    INT ExistingInstanceBuckets[NUM_INSTANCE_BUCKETS];
    appMemzero(ExistingInstanceBuckets,sizeof(ExistingInstanceBuckets));
    // Cache store mapping between component and weight data
    TMap<ULandscapeComponent*,TArray<BYTE>>*LandscapeLayerCache= NULL;
    FNameLandscapeLayerName=MeshSettings->LandscapeLayer;
    if(LandscapeLayerName!= NAME_None )
    {
    LandscapeLayerCache=&LandscapeLayerCaches.FindOrAdd(LandscapeLayerName);
    // Find the landscape weights of existing ExistingInstances
    for( INT Idx=;Idx<ExistingInstances.Num();Idx++)
    {
    FFoliageInstance&Instance=MeshInfo.Instances(ExistingInstances(Idx));
    ULandscapeHeightfieldCollisionComponent*HitLandscapeCollision=Cast<ULandscapeHeightfieldCollisionComponent>(Instance.Base);
    if(HitLandscapeCollision)
    {
    ULandscapeComponent*HitLandscape=HitLandscapeCollision->GetLandscapeComponent();
    if(HitLandscape)
    {
    TArray<BYTE>*LayerCache=&LandscapeLayerCache->FindOrAdd(HitLandscape);
    FLOAT HitWeight=HitLandscape->GetLayerWeightAtLocation(Instance.Location,LandscapeLayerName,LayerCache);
    // Add count to bucket.
    ExistingInstanceBuckets[appRound(HitWeight*(FLOAT)(NUM_INSTANCE_BUCKETS-))]++;
    }
    }
    }
    }
    else
    {
    // When not tied to a layer, put all the ExistingInstances in the last bucket.
    ExistingInstanceBuckets[NUM_INSTANCE_BUCKETS-]=ExistingInstances.Num();
    }
    // We calculate a set of potential ExistingInstances for the brush area.
    TArray<FPotentialInstance>PotentialInstanceBuckets[NUM_INSTANCE_BUCKETS];
    appMemzero(PotentialInstanceBuckets,sizeof(PotentialInstanceBuckets));
    // Quick lookup of potential instance locations, used for overlapping check.
    TArray<FVector>PotentialInstanceLocations;
    FFoliageInstanceHashPotentialInstanceHash();// use 128x128 cell size, as the brush radius is typically small.
    PotentialInstanceLocations.Empty(DesiredInstanceCount);
    // Radius where we expect to have a single instance, given the density rules
    const FLOAT DensityCheckRadius=Max<FLOAT>( appSqrt((.f*.f)/(PI *MeshSettings->Density)),MeshSettings->Radius);
    for( INT DesiredIdx=;DesiredIdx<DesiredInstanceCount;DesiredIdx++)
    {
    FVectorStart,End;
    GetRandomVectorInBrush(Start,End);
    FCheckResultHit;
    if(!GWorld->SingleLineCheck(Hit, NULL,End,Start, TRACE_World | TRACE_Level,FVector(.f,.f,.f), NULL))
    {
    // Check filters
    if((Hit.Component&&
    (Hit.Component->GetOutermost()!=GWorld->CurrentLevel->GetOutermost()||
    (!UISettings.bFilterLandscape &&Hit.Component->IsA(ULandscapeHeightfieldCollisionComponent::StaticClass()))||
    (!UISettings.bFilterStaticMesh &&Hit.Component->IsA(UStaticMeshComponent::StaticClass()))||
    (!UISettings.bFilterTerrain &&Hit.Component->IsA(UTerrainComponent::StaticClass()))))||
    (Hit.Actor&&Hit.Actor->IsA(AWorldInfo::StaticClass())&&(!UISettings.bFilterBSP ||GWorld->Levels(Hit.LevelIndex)!=GWorld->CurrentLevel)))
    {
    continue;
    }
    if(!CheckLocationForPotentialInstance(MeshInfo,MeshSettings,DensityCheckRadius,Hit.Location,Hit.Normal,PotentialInstanceLocations,PotentialInstanceHash))
    {
    continue;
    }
    // Check landscape layer
    FLOAT HitWeight=.f;
    if(LandscapeLayerName!= NAME_None )
    {
    ULandscapeHeightfieldCollisionComponent*HitLandscapeCollision=Cast<ULandscapeHeightfieldCollisionComponent>(Hit.Component);
    if(HitLandscapeCollision)
    {
    ULandscapeComponent*HitLandscape=HitLandscapeCollision->GetLandscapeComponent();
    if(HitLandscape)
    {
    TArray<BYTE>*LayerCache=&LandscapeLayerCache->FindOrAdd(HitLandscape);
    HitWeight=HitLandscape->GetLayerWeightAtLocation(Hit.Location,LandscapeLayerName,LayerCache);
    // Reject instance randomly in proportion to weight
    if(HitWeight<= appFrand())
    {
    continue;
    }
    }
    }
    }
    new(PotentialInstanceBuckets[appRound(HitWeight*(FLOAT)(NUM_INSTANCE_BUCKETS-))])FPotentialInstance(Hit.Location,Hit.Normal,Hit.Component,HitWeight);
    }
    }
    for( INT BucketIdx=;BucketIdx< NUM_INSTANCE_BUCKETS;BucketIdx++)
    {
    TArray<FPotentialInstance>&PotentialInstances=PotentialInstanceBuckets[BucketIdx];
    FLOAT BucketFraction=(FLOAT)(BucketIdx+)/(FLOAT)NUM_INSTANCE_BUCKETS;
    // We use the number that actually succeeded in placement (due to parameters) as the target
    // for the number that should be in the brush region.
    INT AdditionalInstances=Clamp<INT>( appRound(BucketFraction*(FLOAT)(PotentialInstances.Num()-ExistingInstanceBuckets[BucketIdx])*Pressure),,PotentialInstances.Num());
    for( INT Idx=;Idx<AdditionalInstances;Idx++)
    {
    FFoliageInstanceInst=PotentialInstances(Idx).PlaceInstance(MeshSettings);
    MeshInfo.AddInstanceAT( IFA,AchetypeActor,Inst);
    }
    }
    }
    }
 
17 在FFoliageInstanceCluster 上添加Actor列表成员
  1.  structFFoliageInstanceCluster
    {
    UInstancedStaticMeshComponent*ClusterComponent;
    TArray<AActor*>ActorInstances;
    FFoliageInstanceCluster.GetInstanceCount
    INT GetInstanceCount()
    {
    INT TotalCount=;
    if(ClusterComponent)
    TotalCount+=ClusterComponent->PerInstanceSMData.Num();
    TotalCount+=ActorInstances.Num();
    }
 
 

18 添加FFoliageMeshInfo.AddInstanceAT 

  1.  voidFFoliageMeshInfo::AddInstanceAT(classAInstancedFoliageActor*InIFA,classAActor*InArchetypeActor,constFFoliageInstance&InNewInstance)
    {
    InIFA->Modify();
    // Add the instance taking either a free slot or adding a new item.
    INT InstanceIndex=FreeInstanceIndices.Num()>?FreeInstanceIndices.Pop():Instances.Add();
    FFoliageInstance&AddedInstance=Instances(InstanceIndex);
    AddedInstance=InNewInstance;
    // Add the instance to the hash
    InstanceHash->InsertInstance(InNewInstance.Location,InstanceIndex);
    FFoliageComponentHashInfo&ComponentHashInfo=ComponentHash.FindOrAddKey(InNewInstance.Base);
    ComponentHashInfo.Instances.Add(InstanceIndex);
    // Find the best cluster to allocate the instance to.
    FFoliageInstanceCluster*BestCluster= NULL;
    INT BestClusterIndex= INDEX_NONE;
    FLOAT BestClusterDistSq= FLT_MAX;
    INT MaxInstancesPerCluster=Settings->MaxInstancesPerCluster;
    FLOAT MaxClusterRadiusSq=Square(Settings->MaxClusterRadius);
    for( INT ClusterIdx=;ClusterIdx<InstanceClusters.Num();ClusterIdx++)
    {
    FFoliageInstanceCluster&Cluster=InstanceClusters(ClusterIdx);
    if(Cluster.InstanceIndices.Num()<MaxInstancesPerCluster)
    {
    FLOAT DistSq=(Cluster.Bounds.Origin-InNewInstance.Location).SizeSquared();
    if(DistSq<BestClusterDistSq&&DistSq<MaxClusterRadiusSq)
    {
    BestCluster=&Cluster;
    BestClusterIndex=ClusterIdx;
    BestClusterDistSq=DistSq;
    }
    }
    }
    // Calculate transform for the instance
    FMatrixInstanceTransform=InNewInstance.GetInstanceTransform();
    if(BestCluster== NULL )
    {
    BestClusterIndex=InstanceClusters.Num();
    BestCluster=new(InstanceClusters)FFoliageInstanceCluster(
    NULL,
    FBoxSphereBounds()// LWF_TODO
    );
    //ApplyInstancedFoliageSettings( BestCluster->ClusterComponent );
    }
    else
    {
    // BestCluster->ClusterComponent->Modify();
    // BestCluster->ClusterComponent->InvalidateLightingCache();
    // BestCluster->Bounds = BestCluster->Bounds + InMesh->Bounds.TransformBy(InstanceTransform);
    }
    BestCluster->InstanceIndices.AddItem(InstanceIndex);
    // Save the cluster index
    AddedInstance.ClusterIndex=BestClusterIndex;
    // Add the instance to the ActorList
    AActor* pActor =GWorld->SpawnActor(InArchetypeActor->GetClass(), NAME_None,InNewInstance.Location,InNewInstance.Rotation,InArchetypeActor);// Spawn Actor
    BestCluster->ActorInstances.AddItem(pActor);
    // FInstancedStaticMeshInstanceData* NewInstanceData = new(BestCluster->ClusterComponent->PerInstanceSMData) FInstancedStaticMeshInstanceData();
    if(BestCluster->ClusterComponent->SelectedInstances.Num()>)
    {
    BestCluster->ClusterComponent->SelectedInstances.AddItem(FALSE);
    }
    // NewInstanceData->Transform = InstanceTransform;
    // NewInstanceData->LightmapUVBias = FVector2D( -1.0f, -1.0f );
    // NewInstanceData->ShadowmapUVBias = FVector2D( -1.0f, -1.0f );
    // BestCluster->ClusterComponent->bNeedsReattach = TRUE;
    #if _DEBUG
    CheckValid();
    #endif
    InIFA->ConditionalUpdateComponents();
    }
 

18 修改所有FFoliageInstanceCluster.ClusterComponent 的地方

太多地方了

FFoliageMeshInfo.CheckValid

终于能刷出东西来了

 

UE3植被工具-支持刷Actor)的更多相关文章

  1. WordPress让文本小工具支持简码

    WordPress 的 “文本” 小工具是非常常用的,可以添加一些自定义的文本或者 Html 代码.但很多时候,我们需要在文本小工具里使用简码来添加一些更加丰富的内容. 默认情况下,文本小工具是不支持 ...

  2. LiveBlox无需代码的开发工具--支持win macos ubuntu等开发环境--

    LiveBlox无需代码的开发工具-支持windows macos ubuntu. 强大 灵活 易于使用 视频简介:LiveBlox Develop Technology Without Coding ...

  3. 文档资源搜索小工具 - 支持PDF,DOC,PPT,XLS

    最近做了一个文档搜索小工具,当然不是网盘搜索工具,这个工具支持四种文件格式搜索(pdf,doc,ppt,xls),你只需要在搜索框中输入你想要搜索资源的关键词,点击搜索按钮即可获取相关资源,点击下载按 ...

  4. 3-WIN10系统及开发工具支持

    本篇博客对应视频讲解 回顾 上一讲说了编程的方向和技术流派以及选择入门语言的建议.当我们决定我们的选择之后呢,我们就要学习和进行实践操作了.但在实践之前,我们仍然需要做好相应的准备,这也就是今天要讲的 ...

  5. WinSetupFromUSB - 超简单制作多合一系统安装启动U盘的工具 (支持Win/PE/Linux启动盘)

    很多同学都喜欢将电脑凌乱不堪的系统彻底重装以获得一个"全新的开始",但你会发现如今很多电脑都已经没有光驱了,因此制作一个U盘版的系统安装启动盘备用是非常必要的. 我们之前推荐过 I ...

  6. 【C#附源码】数据库文档生成工具支持(Excel+Html)

    [2015] 很多时候,我们在生成数据库文档时,使用某些工具,可效果总不理想,不是内容不详细,就是表现效果一般般.很多还是word.html的.看着真是别扭.本人习惯用Excel,所以闲暇时,就简单的 ...

  7. 【C#附源码】数据库文档生成工具支持(Excel+Htm)

    数据库文档生成工具是用C#开发的基于NPOI组件的小工具.软件源码大小不到10MB.支持生成Excel 和Html 两种文档形式.了解更多,请访问:http://www.oschina.net/cod ...

  8. 全新WayOS 配置文件保存工具支持蓝色界面路由版本

    一直以来都有群里的朋友要求我弄一个支持蓝色界面路由的参数备份工具,也一直拖了大半年 昨天忙到4点多,早上又因为一些小的BUG被用户电话叫起,干脆就帮你们整一个这个工具了 功能还是一样,支持各种参数的保 ...

  9. 通过自研数据库画像工具支持“去O”评估

    “去O”,是近些年来一直很火的一个话题,随之也产生了各种疑惑,包括现有数据库评估.技术选型等.去O是项系统工程,需要做好充分的评估.本文通过自研工具,生成数据库画像,为去O评估提供一手数据,希望给大家 ...

随机推荐

  1. java经典算法40题(21-40)

    [程序21]   题目:求1+2!+3!+...+20!的和   1.程序分析:此程序只是把累加变成了累乘.   public class Ex21 { static long sum = 0;  s ...

  2. C# 窗体

    窗体的事件:删除事件:先将事件页面里面的挂好的事件删除,再删后台代码里面的事件 Panel是一个容器 1.Label -- 文本显示工具Text:显示的文字取值.赋值:lable1.Text 2.Te ...

  3. System.arraycopy

    ref : http://blog.csdn.net/jaycee110905/article/details/45228249

  4. 安卓与PC网络对接实现视频实时播放

    研究安卓网络通信一段时间了,  由于最近公司催的比较紧, 硬着头皮弄出来了. 现在手机客户端终于能够连接流媒体服务器实时播放前端的视频流了. 其实通信方面主要还是命令包的解析, 以及分包组包. 比如要 ...

  5. [4] 智能指针boost::scoped_ptr

    [1]boost::scoped_ptr简介 boost::scoped_ptr属于boost库,定义在namespace boost中,包含头文件#include <boost/scoped_ ...

  6. Dynamics AX 2012 R2 将系统用户账号连接到工作人员记录

    要使用AX中的一些特性,需要将User Account和他们的Employee Record连接在一起.最好将所有Employee的User Account,都和他们的Employee Record连 ...

  7. HTML中一些基本的标签用法

    姓名输入框:<input type="text" value="默认有值"/> 密码输入框:<input type="text&qu ...

  8. c++11中的for简化用法

    1.序列for循环 map<string,int> m{{"a",1},{"b",2},{"c",3}} for(auto p: ...

  9. 流镜像(华为S9306和S5700)

    流镜像是指将设备.端口或者VLAN内收.发的指定类型报文复制到观察端口上,监控设备只对指定类型报文进行监测. 流镜像有基于ACL和基于MQC(即复杂流分类)两种配置方式.前者配置简便,但是没有后者支持 ...

  10. Kth Largest Element in an Array - LeetCode

    examination questions Find the kth largest element in an unsorted array. Note that it is the kth lar ...