UE中:运行时(伪)无限细分网格

先看效果:

UE:运行时(伪)无限细分网格

实际代码如下:

InfiniteGrid.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "InfiniteGrid.generated.h"

USTRUCT()
struct FGridLayer
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, Category = "Grid")
	float CellSize = 100.0f;

	UPROPERTY(EditAnywhere, Category = "Grid")
	float MaxVisibleDistance = 1000.0f;

	UPROPERTY(EditAnywhere, Category = "Grid")
	float FadeStartRatio = 0.8f;        // 开始淡出的距离比例(例如0.8表示在80%最大距离时开始淡出)
};

UCLASS()
class FALCONV_API AInfiniteGrid : public AActor
{
	GENERATED_BODY()

public:
	// Sets default values for this actor's properties
	AInfiniteGrid();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;
	void GenerateGridLayer(const FGridLayer& Layer, const FVector& WorldPos, float Thickness, int32 ActiveLayerIndex);

	UPROPERTY(VisibleAnywhere)
	ULineBatchComponent* LineBatch;

	float gGridSize = 1000.0f;
	float gGridMinPixelsBetweenCells = 2.0f;
	float gGridCellSize = 0.025f;
	FLinearColor gGridColorThick = FLinearColor(0.0f, 0.0f, 0.0f, 1.0f);

	UPROPERTY(EditAnywhere, Category = "Grid")
	TArray<FGridLayer> GridLayers;
	UPROPERTY(EditAnywhere, Category = "Grid")
	FLinearColor gGridColorThin = FLinearColor(0.5f, 0.5f, 0.5f, 1.0f); // 基础颜色
};

InfiniteGrid.cpp

#include "Util/InfiniteGrid.h"

#include "Camera/CameraComponent.h"
#include "Engine/World.h"
#include "Camera/CameraTypes.h"
#include "Components/LineBatchComponent.h"
#include "Camera/PlayerCameraManager.h"
#include "Kismet/GameplayStatics.h"

// Sets default values
AInfiniteGrid::AInfiniteGrid()
{
    PrimaryActorTick.bCanEverTick = true;

    LineBatch = CreateDefaultSubobject<ULineBatchComponent>(TEXT("LineBatch"));
    RootComponent = LineBatch;

	float BaseCellSize = 10.0f;
	GridLayers.Add({BaseCellSize, 400.0f, 0.8f});

	// 每级CellSize和MaxVisibleDistance放大10倍
	for (int32 i = 1; i < 10; i++)
	{
		FGridLayer Layer;
		Layer.CellSize = GridLayers[i - 1].CellSize * 5.0f;
		Layer.MaxVisibleDistance = GridLayers[i - 1].MaxVisibleDistance * 5.0f;
		Layer.FadeStartRatio = 0.8f;
		GridLayers.Add(Layer);
	}
	// for (int32 i = 0; i < 10; i++)
	// {
	//     GridLayers[i].MaxVisibleDistance +=50;
	// }
}

// Called when the game starts or when spawned
void AInfiniteGrid::BeginPlay()
{
    Super::BeginPlay();
}

// Called every frame
void AInfiniteGrid::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
    auto WorldRef = GetWorld();
    if (!WorldRef) return;

    // 获取相机信息
    APlayerCameraManager* PCM = UGameplayStatics::GetPlayerCameraManager(WorldRef, 0);
    APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
    if (!PCM || !PC) return;

    // 获取视口大小
    FVector2D ViewportSize;
    GEngine->GameViewport->GetViewportSize(ViewportSize);

    // 获取视口中心射线
    FVector RayStart;
    FVector RayDirection;
    PC->DeprojectScreenPositionToWorld(
        ViewportSize.X * 0.5f,
        ViewportSize.Y * 0.5f,
        RayStart,
        RayDirection
    );

    // 计算射线与网格平面的交点
    FVector CurrentWorldPos = GetActorLocation();
    float PlaneZ = CurrentWorldPos.Z;
    float t = (PlaneZ - RayStart.Z) / RayDirection.Z;

    FVector IntersectionPoint;
    if (!FMath::IsNearlyZero(RayDirection.Z) && t >= 0)
    {
        IntersectionPoint = RayStart + t * RayDirection;
    }
    else
    {
        // 备用方案:使用相机水平投影
        IntersectionPoint = FVector(RayStart.X, RayStart.Y, PlaneZ);
    }

    // 更新Actor位置(保持Z不变)
    SetActorLocation(FVector(IntersectionPoint.X, IntersectionPoint.Y, PlaneZ));
    // 更新Actor位置到射线交点(省略射线计算部分,同之前代码)
    FVector WorldPos = GetActorLocation();

	// 计算相机水平距离
	// FVector Camera2DPos(PCM->GetCameraLocation().X, PCM->GetCameraLocation().Y);
	// FVector Grid2DPos(WorldPos.X, WorldPos.Y);
	float HorizontalDistance = FVector::Distance(PCM->GetCameraLocation(), WorldPos);

    // 筛选当前主层级和次层级
    int32 ActiveLayerIndex = 0;
    for (int32 i = 0; i < GridLayers.Num(); i++)
    {
        if (HorizontalDistance < GridLayers[i].MaxVisibleDistance)
        {
            ActiveLayerIndex = i;
            break;
        }
    }
    ActiveLayerIndex = FMath::Clamp(ActiveLayerIndex, 0, GridLayers.Num() - 2);
    FGridLayer& PrimaryLayer = GridLayers[ActiveLayerIndex];
    FGridLayer& SecondaryLayer = GridLayers[ActiveLayerIndex + 1];

    // 清除旧线条
    LineBatch->Flush();
    float BaseCellSize = GridLayers[0].CellSize;
    float PrimaryLineThickness = 0.1f * PrimaryLayer.CellSize / BaseCellSize;
    float SecondaryLineThickness = 0.05f * SecondaryLayer.CellSize / BaseCellSize;
    // 生成主层级(小网格)
    GenerateGridLayer(PrimaryLayer, WorldPos, PrimaryLineThickness,ActiveLayerIndex+1); // 线宽5.0f

    // 生成次层级(大网格)
    GenerateGridLayer(SecondaryLayer, WorldPos, SecondaryLineThickness,ActiveLayerIndex+1); // 线宽2.5f
}

// 辅助函数:生成单个层级的网格
void AInfiniteGrid::GenerateGridLayer(const FGridLayer& Layer, const FVector& WorldPos, float Thickness,int32 ActiveLayerIndex)
{
    // 对齐到当前层级的网格单元
    float GridCenterX = FMath::GridSnap(WorldPos.X, Layer.CellSize);
    float GridCenterY = FMath::GridSnap(WorldPos.Y, Layer.CellSize);

    // 动态计算覆盖范围(根据层级单元大小扩展)
    int32 CellsToExtend = FMath::CeilToInt(5000.0f*ActiveLayerIndex*ActiveLayerIndex*ActiveLayerIndex*ActiveLayerIndex*ActiveLayerIndex / Layer.CellSize);
    float MinX = GridCenterX - Layer.CellSize * CellsToExtend;
    float MaxX = GridCenterX + Layer.CellSize * CellsToExtend;
    float MinY = GridCenterY - Layer.CellSize * CellsToExtend;
    float MaxY = GridCenterY + Layer.CellSize * CellsToExtend;

    // 生成水平线
    for (float y = MinY; y <= MaxY; y += Layer.CellSize)
    {
        FVector Start(MinX, y, WorldPos.Z);
        FVector End(MaxX, y, WorldPos.Z);
        LineBatch->DrawLine(Start, End, gGridColorThin, 0.0f, Thickness, 0);
    }

    // 生成垂直线
    for (float x = MinX; x <= MaxX; x += Layer.CellSize)
    {
        FVector Start(x, MinY, WorldPos.Z);
        FVector End(x, MaxY, WorldPos.Z);
        LineBatch->DrawLine(Start, End, gGridColorThin, 0.0f, Thickness, 0);
    }
}

快速部署

1.将代码编译至UE5工程
2.在场景中创建AInfiniteGrid实例

你可能感兴趣的:(android,数码相机)