UE3植被工具-支持刷Actor)

时间:2023-03-09 04:44:48
UE3植被工具-支持刷Actor)

【目标】

植被工具-刷Actor

【思路】

1 添加类型FFoliageMeshInfo.AddInstance 的函数

2 添加Instance就直接SpawnActor

3 类结构

UE3植被工具-支持刷Actor)

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 中有
UE3植被工具-支持刷Actor)
UE3植被工具-支持刷Actor)
UE3植被工具-支持刷Actor)
需要设置这个才能调试
UE3植被工具-支持刷Actor)
UE3植被工具-支持刷Actor)

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

UE3植被工具-支持刷Actor)

列表和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;
终于看到效果了
UE3植被工具-支持刷Actor)

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)