為了不變更原本程式的運作,首先定義另一個Trace函式:
class Actor extends Object ... native noexport function Actor TraceEx ( out vector HitLocation, out vector HitNormal, vector TraceEnd, optional vector TraceStart, optional bool bTraceActors, optional vector Extent, optional out TraceHitInfo HitInfo, optional int ExtraTraceFlags );為了呼叫原本的execTrace,將此函式宣告為noexport並且自行實作:
void AActor::execTraceEx(FFrame& Stack, RESULT_DECL) { // Keep program counter. BYTE* CodePtr = Stack.Code; // Extract parameters. P_GET_VECTOR_REF(HitLocation); P_GET_VECTOR_REF(HitNormal); P_GET_VECTOR(TraceEnd); P_GET_VECTOR_OPTX(TraceStart,Location); P_GET_UBOOL_OPTX(bTraceActors,bCollideActors); P_GET_VECTOR_OPTX(TraceExtent,FVector(0.f)); P_GET_STRUCT_OPTX_REF(FTraceHitInfo,HitInfo,FTraceHitInfo()); // Restore program counter. Stack.Code = CodePtr; // Invoke the original function. this->execTrace(Stack, Result); // If terrain hit, find the material with the highest weight at the hit location. if( pHitInfo ) { ATerrain* Terrain = Cast<ATerrain>(*(AActor**)Result); if( Terrain && Terrain->WeightedMaterials.Num() > 0 ) { FVector LocalPos = Terrain->WorldToLocal().TransformFVector(*pHitLocation); INT XI = appFloor(LocalPos.X); FLOAT XF = LocalPos.X - XI; INT YI = appFloor(LocalPos.Y); FLOAT YF = LocalPos.Y - YI; INT MajorMaterial = 0; INT MajorWeight = Terrain->WeightedMaterials(0).FilteredWeight(XI, XF, YI, YF); for(INT i = 1; i < Terrain->WeightedMaterials.Num(); i++) { INT Weight = Terrain->WeightedMaterials(i).FilteredWeight(XI, XF, YI, YF); if(Weight > MajorWeight) { MajorMaterial = i; MajorWeight = Weight; } } UMaterialInterface* Material = Terrain->WeightedMaterials(MajorMaterial).Material->Material; if( Material ) { pHitInfo->PhysMaterial = Material->GetPhysicalMaterial(); pHitInfo->Material = Material->GetMaterial(); } } } }一開始先記錄目前的指令位置,取得參數後再回復指令位置,然後呼叫execTrace進行原本的射線追蹤。如果打到地形的話,才去找出是哪一層在擊中點的權重最大,再修改傳回的材質。
沒有留言:
張貼留言