본문 바로가기

GameDevelopmentDiary/SteppingIsland : 가제

공백

  • Landscape 활용 방법 탐구
    • 머티리얼의 vector 값을 이용해서 Landscape를 왜곡하는 방식으로 층이 있는 월드맵 생성을 하고 싶었다.
    • 선택한 방식은 두 가지였다.
      • 방식 1
        • 브러시 머티리얼 선택해서 맵 모양을 그림.
        • 단점 1 : 맵이 커지면 오래 걸린다. 심하게..
        • 단점 2 : 브러시의 알파값이 겹치면서 원하는 모양이 안 나올 수 있기에 크기를 설정해야하는데, 귀찮다. 그리고 맵 크기에 따라 어긋날 확율이 많다.
      • 방식 2
        • 브러시 모양을 맵 모양으로 만들어서 한 번만 찍기.
        • 순서 : 텍스쳐 생성 -> 텍스쳐 모양으로 렌더타겟에 그림.
        • Texture 생성은 성공했는데..
        • < 5 X 5 / 5층 테스트 UTexture2D >
  • 1차 시도 - 브러시 머티리얼의 Texture 파라미터를 텍스쳐로 바꾸기 위해 시도
    • (해당 파라미터 변경은 UMaterialInstanceDynamic 타입만 가능.)
  • 2차 시도 - 브러시 머티리얼을 UMaterialInstanceDynamic 타입으로 설정 (
    • (K2_DrawMaterial 함수의 매개 변수에 '다이나믹' 머티리얼은 사용 불가.) 

  • 3차 시도 - 사용하는 UTextureRenderTarget2D 자체를 새롭게 만든 텍스쳐로 변환 시도
    • 매크로 함수 ENQUEUE_RENDER_COMMAND(UpdateTextureRegionsData) 활용하려는데, 렌더타겟의 텍스쳐 접근시 오류로 포기
  • 4차 시도 - 2차 시도 방식(K2_DrawMaterial)으로 재도전
    • 형 변환 방법을 못 찾아 어려웠었는데(UMaterialInstanceDynamic -> UMaterialInterface), 갑자기 방법이 떠올랐다.
    • UStaticMeshComponent->SetMaterial(), GetMaterial() 함수를 사용하면 다이나믹 머티리얼이 일반 머티리얼로 변환 가능하다.
  • < 8 X 8 / 16층 테스트 URenderTargetTexture2D >
  • 추가 문제를 발견했다.
    • 언리얼의 Landscape 객체의 자동 LOD(LevelOfDetail) 관련.
    • Height Deformation (텍스쳐의 Alpha값을 버텍스 높이에 반영한다.) 방법으로 Landscape 객체에 언덕을 만들었는데, 관찰자와 거리가 멀어지면 언덕이 다시 평평해진 듯 보였다.
    • < 강조 부분이 평평해져 보이는 부분 >
    • Landscape의 LOD 수치를 조정해보았으나 여기에 반영되지는 않았고, 테셀레이션(tessellation) 프로퍼티 수정시 반응을 보였다. Landscape 생성 시 자동으로 크기 감쇠 부분이 활성화 되었기에 비활성화 시켰다.
    • < 테셀레이션 감쇠 설명 >
       
  • < 이제 멀어져도 봉우리가 잘 솟아있다 >
  •  
  • Sample code
  • void AWorldCreator::BeginPlay()
    {
    	Super::BeginPlay();
    
    	UTexture2D* texture = CreateTexture();
    
    	ALandscape* targetLandscape = Cast<ALandscape>(UGameplayStatics::GetActorOfClass(GetWorld(), ALandscape::StaticClass()));
    	if (targetLandscape && RenderTarget && HeightBrushMI && texture) {
    		// Tracing으로 위치 찾기
    		FHitResult outHit;
    		FVector traceStart = GetActorLocation();
    		FVector traceEnd = traceStart + (FVector::UpVector * -9999.f);
    		FCollisionQueryParams collisionParam;
    		collisionParam.AddIgnoredActor(GetOwner());
    		GetWorld()->LineTraceSingleByChannel(outHit, traceStart, traceEnd, ECollisionChannel::ECC_Visibility, collisionParam);
    
    		// HeightBrushMI 준비
    		UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(HeightBrushMI, GetWorld());		
    		DynamicMaterial->SetTextureParameterValue(FName("TextureParam"), texture);
    		targetLandscape->UpdateAllComponentMaterialInstances();		
    		MaterialConverter->SetMaterial(0, DynamicMaterial);
    
    		// RenderTarget 위에 HeightBrushMI 마스킹
    		if (outHit.GetActor()) {
    			UCanvas* canvas;
    			FVector origin;
    			FVector boxExtent;
    			targetLandscape->GetActorBounds(false, origin, boxExtent);
    
    			FVector2D HitScreenPosition = FVector2D(
    				abs(targetLandscape->GetActorLocation().X - outHit.Location.X) / (boxExtent.X * 2),
    				abs(targetLandscape->GetActorLocation().Y - outHit.Location.Y) / (boxExtent.Y * 2)
    			);
    			FVector2D screenSize = FVector2D(RenderTarget->SizeX, RenderTarget->SizeY);
    			FDrawToRenderTargetContext targetContext;
    
    			UKismetRenderingLibrary::BeginDrawCanvasToRenderTarget(GetWorld(), RenderTarget, canvas, screenSize, targetContext);
    
    			UKismetRenderingLibrary::ClearRenderTarget2D(GetWorld(), RenderTarget);			
    			
    			FCanvasMaterialTransform CanvasMaterialTransform = GetCanvasMaterialTransform(HitScreenPosition, screenSize, 1.0f);
    			canvas->K2_DrawMaterial(MaterialConverter->GetMaterial(0), CanvasMaterialTransform.Position, CanvasMaterialTransform.Size, FVector2D(0, 0));
    
    			UKismetRenderingLibrary::EndDrawCanvasToRenderTarget(GetWorld(), targetContext);
    		}
    	}
    	else {
    		if (targetLandscape == nullptr) UE_LOG(LogTemp, Warning, TEXT("Null targetLandscape"));
    		if (RenderTarget == nullptr) UE_LOG(LogTemp, Warning, TEXT("Null RenderTarget"));
    		if (texture == nullptr) UE_LOG(LogTemp, Warning, TEXT("Null texture"));
    	}	
    }
    
    UTexture2D* AWorldCreator::CreateTexture() {
    	uint8* pixels = (uint8*)malloc(Height * Width * 4); // x4 because it's RGBA. 4 integers, one for Red, one for Green, one for Blue, one for Alpha
    	...
    	UPackage* package = CreatePackage(nullptr, *pathPackage); 
    	...
    	UTexture2D* texture = NewObject<UTexture2D>(package, textureName, RF_Public | RF_Standalone);
    	...
        free(pixels);
    	pixels = NULL;
    
    	return texture;
    }​

'GameDevelopmentDiary > SteppingIsland : 가제' 카테고리의 다른 글

1일차 (6시간)  (0) 2021.08.11