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实例

<think>好的,我现在需要帮助用户解决在Unreal Engine 5.3中为材质启用细分级别的设置方法。首先,我需要确认用户的需求。用户提到“细分级别”,这可能与材质的分层混合或几何体细分有关。不过根据提供的引用内容,特别是引用[3]提到的“MakeMaterialAttributes + Layer Blender”,这更可能涉及到材质的分层混合,比如通过细节层次(Level of Detail, LOD)来优化性能或增强细节。 接下来,我需要回忆UE5中材质设置的步骤。通常在材质编辑器中,可以通过节点如“TextureCoordinate”来控制UV平铺次数,增加细节。而细分级别可能涉及到使用“Tessellation”技术,这在UE4中需要启用,但UE5可能有所不同,需要检查是否有变化。不过,引用[3]提到的Layer Blender可能是指材质层的混合,比如使用多个材质层叠加,并通过某种方式控制细节层次。 然后,考虑用户提到的UE5.3版本是否有新的设置方法。可能需要查阅官方文档(引用[2]提供的链接),但用户给的链接是UE5.0的迁移指南,可能需要搜索UE5.3的材质细分相关文档。此外,引用[1]提到的高级渲染技术集成可能与此相关,比如使用虚拟纹理或Nanite技术来优化材质细节。 现在需要整理步骤:首先检查材质编辑器中是否有细分设置,或者是否需要在材质属性中启用曲面细分(Tessellation)。如果用户指的是几何细分,可能需要调整网格体的LOD设置,但如果是材质细节层次,可能涉及纹理的多次采样或混合。例如,通过增加TextureCoordinate节点的平铺参数来增强细节,或者使用材质函数如“Detail Texturing”来混合基础纹理和细节纹理。 另外,引用[3]中的“Layer Blender”可能指通过材质层混合来增加细节层次。例如,使用Layer Blend节点将多个材质属性混合,根据距离或其他参数调整混合强度,从而实现不同细分级别的效果。需要指导用户如何创建材质层,设置混合参数,并连接到材质输出。 可能还需要注意项目设置中是否启用了相关功能,比如虚拟纹理支持或细分曲面(Tessellation),这些可能需要额外的步骤来激活。例如,在UE5中,Tessellation可能被替换为Nanite,但需要确认。如果用户的目标是优化材质在不同距离下的表现,可能需要使用纹理流送或LOD系统。 最后,确保步骤清晰,并生成相关问题,帮助用户深入理解。例如,如何优化材质性能,如何混合多层纹理,或者如何使用Nanite进行几何细分。</think>### Unreal Engine 5.3 材质细分级别设置方法 #### 1. **基础材质细分设置** 在材质编辑器中,通过**TextureCoordinate节点**控制细节层次: - 创建$TextureCoordinate$节点,调整其$UTiling$和$VTiling$参数增加纹理采样密度 - 连接至纹理节点的UV输入,实现高频细节叠加 例如: ```cpp MaterialGraph: TextureCoordinate -> Multiply(Scale) -> BaseColorTexture.UVs ``` #### 2. **高级分层混合** 使用**Material Layer系统**实现多级细节混合[^3]: 1. 创建`MaterialFunction`作为细节层 2. 添加`LayerBlend`节点混合基础材质与细节层 3. 通过`Distance`参数控制混合强度: $$ BlendFactor = 1 - saturate(\frac{Distance}{TransitionRange}) $$ #### 3. **曲面细分设置** 在材质属性面板启用几何细分: 1. 材质域选择**Surface** 2. 勾选`Tessellation`选项 3. 添加$TessellationMultiplier$节点控制细分密度 ```cpp Attributes: [Surface] Shading Model=Default [Tessellation] Enable=True ``` #### 4. **实例参数化** 创建材质实例实现动态调节: 1. 将细分参数设为`ScalarParameter` 2. 在实例编辑器中实调节: ```cpp Parameters: DetailScale (Scalar): 1.0~5.0 TessellationDensity (Scalar): 1.0~16.0 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dawn·张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值