自学内容网 自学内容网

Games101学习 - 光栅化

Games101中讲解的光栅化的基础知识,本文就来梳理一下。

在UE中使用UTexture2D可以逐像素绘制纹理:
https://blog.csdn.net/grayrail/article/details/142165442

1.绘制三角形

这里可以通过101中讲解的叉积法逐像素绘制三角形:
在这里插入图片描述
绘制效果:
在这里插入图片描述
代码如下:

UTexture2D* UMyBlueprintFunctionLibrary::GenTexture(int32 Width, int32 Height)
{
    // 创建临时纹理
    UTexture2D* NewTexture = UTexture2D::CreateTransient(Width, Height);

    // 配置纹理
    NewTexture->MipGenSettings = TMGS_NoMipmaps;
    NewTexture->CompressionSettings = TC_VectorDisplacementmap;
    NewTexture->SRGB = false;

    // 锁定纹理数据进行写入
    FTexture2DMipMap& Mip = NewTexture->PlatformData->Mips[0];
    void* TextureData = Mip.BulkData.Lock(LOCK_READ_WRITE);

    // 设置默认颜色为黑色
    FColor* FormattedImageData = static_cast<FColor*>(TextureData);
    for (int32 y = 0; y < Height; ++y)
    {
        for (int32 x = 0; x < Width; ++x)
        {
            FormattedImageData[y * Width + x] = FColor::Black; // 背景颜色设置为黑色
        }
    }

    // 定义三角形顶点(A, B, C)
    FVector2D A(Width / 2, Height / 4);  // 三角形顶点A
    FVector2D B(Width / 4, 3 * Height / 4); // 三角形顶点B
    FVector2D C(3 * Width / 4, 3 * Height / 4); // 三角形顶点C

    // 深红色
    FColor TriangleColor = FColor(139, 0, 0, 255);

    // 叉乘判断点P是否在三角形ABC内
    auto IsPointInTriangle = [](const FVector2D& P, const FVector2D& A, const FVector2D& B, const FVector2D& C) -> bool
        {
            FVector2D AP = P - A;
            FVector2D BP = P - B;
            FVector2D CP = P - C;

            FVector2D AB = B - A;
            FVector2D BC = C - B;
            FVector2D CA = A - C;

            // 叉乘结果
            float Cross1 = AB.X * AP.Y - AB.Y * AP.X; // AB 和 AP 的叉乘
            float Cross2 = BC.X * BP.Y - BC.Y * BP.X; // BC 和 BP 的叉乘
            float Cross3 = CA.X * CP.Y - CA.Y * CP.X; // CA 和 CP 的叉乘

            // 如果三个叉乘结果符号相同,则点在三角形内
            return (Cross1 >= 0 && Cross2 >= 0 && Cross3 >= 0) || (Cross1 <= 0 && Cross2 <= 0 && Cross3 <= 0);
        };

    // 超采样抗锯齿:每个像素划分为2x2子像素
    int32 SubPixelCount = 4; // 超采样为2x2子像素
    float InvSubPixelCount = 1.0f / SubPixelCount;

    // 遍历每个像素并应用抗锯齿逻辑
    for (int32 y = 0; y < Height; ++y)
    {
        for (int32 x = 0; x < Width; ++x)
        {
            int32 CoveredSubPixels = 0;

            // 遍历2x2子像素
            for (int32 subY = 0; subY < 2; ++subY)
            {
                for (int32 subX = 0; subX < 2; ++subX)
                {
                    FVector2D SubPixelPos = FVector2D(x + subX / 2, y + (subY + 0.5f) * 0.5f); // 子像素位置
                    if (IsPointInTriangle(SubPixelPos, A, B, C))
                    {
                        CoveredSubPixels++;
                    }
                }
            }

            // 计算覆盖率并设置像素颜色
            float Coverage = CoveredSubPixels * InvSubPixelCount; // 覆盖率(0 到 1)
            if (Coverage > 0)
            {
                // 根据覆盖率设置颜色,颜色的Alpha通道根据Coverage调整
                FColor FinalColor = TriangleColor;
                FinalColor.A = FMath::RoundToInt(255 * Coverage); // 根据覆盖率设置透明度
                FormattedImageData[y * Width + x] = FinalColor;
            }
        }
    }

    // 解锁纹理数据
    Mip.BulkData.Unlock();
    NewTexture->UpdateResource();

    return NewTexture;
}

注意:如需了解具体的头文件、Build.cs引用等请看上一篇:https://blog.csdn.net/grayrail/article/details/142165442

2.抗锯齿

绘制好的三角形放大看会有锯齿:
在这里插入图片描述
Games101中提到了SSAA(超分辨率抗锯齿/反走样)的方法,来消除锯齿:

在这里插入图片描述
大致思路是将一个像素点划分为多个子像素,例如1个像素点细分为4个子像素,然后做叉积包含判断,如果4个像素点有1个包含,覆盖率结果就是0.25,有2个包含结果就是0.5,根据覆盖率的百分比作为插值系数进行绘制,从而得到更好的效果。

UE中绘制效果:
在这里插入图片描述
代码如下:

UTexture2D* UMyBlueprintFunctionLibrary::GenTexture(int32 Width, int32 Height)
{
    // 创建临时纹理
    UTexture2D* NewTexture = UTexture2D::CreateTransient(Width, Height);

    // 配置纹理
    NewTexture->MipGenSettings = TMGS_NoMipmaps;
    NewTexture->CompressionSettings = TC_VectorDisplacementmap;
    NewTexture->SRGB = false;

    // 锁定纹理数据进行写入
    FTexture2DMipMap& Mip = NewTexture->PlatformData->Mips[0];
    void* TextureData = Mip.BulkData.Lock(LOCK_READ_WRITE);

    // 设置默认颜色为黑色
    FColor* FormattedImageData = static_cast<FColor*>(TextureData);
    for (int32 y = 0; y < Height; ++y)
    {
        for (int32 x = 0; x < Width; ++x)
        {
            FormattedImageData[y * Width + x] = FColor::Black; // 背景颜色设置为黑色
        }
    }

    // 定义三角形顶点(A, B, C)
    FVector2D A(Width / 2, Height / 4);  // 三角形顶点A
    FVector2D B(Width / 4, 3 * Height / 4); // 三角形顶点B
    FVector2D C(3 * Width / 4, 3 * Height / 4); // 三角形顶点C

    // 深红色
    FColor TriangleColor = FColor(139, 0, 0, 255);

    // 叉乘判断点P是否在三角形ABC内
    auto IsPointInTriangle = [](const FVector2D& P, const FVector2D& A, const FVector2D& B, const FVector2D& C) -> bool
        {
            FVector2D AP = P - A;
            FVector2D BP = P - B;
            FVector2D CP = P - C;

            FVector2D AB = B - A;
            FVector2D BC = C - B;
            FVector2D CA = A - C;

            // 叉乘结果
            float Cross1 = AB.X * AP.Y - AB.Y * AP.X; // AB 和 AP 的叉乘
            float Cross2 = BC.X * BP.Y - BC.Y * BP.X; // BC 和 BP 的叉乘
            float Cross3 = CA.X * CP.Y - CA.Y * CP.X; // CA 和 CP 的叉乘

            // 如果三个叉乘结果符号相同,则点在三角形内
            return (Cross1 >= 0 && Cross2 >= 0 && Cross3 >= 0) || (Cross1 <= 0 && Cross2 <= 0 && Cross3 <= 0);
        };

    int SubPixelCount = 8;

    // 超采样抗锯齿:子像素划分
    float SubPixelStep = 1.0f / SubPixelCount; // 子像素的步长
    int32 TotalSubPixels = SubPixelCount * SubPixelCount; // 子像素的总数

    // 遍历每个像素并应用抗锯齿逻辑
    for (int32 y = 0; y < Height; ++y)
    {
        for (int32 x = 0; x < Width; ++x)
        {
            int32 CoveredSubPixels = 0;

            // 遍历 SubPixelCount x SubPixelCount 子像素
            for (int32 subY = 0; subY < SubPixelCount; ++subY)
            {
                for (int32 subX = 0; subX < SubPixelCount; ++subX)
                {
                    FVector2D SubPixelPos = FVector2D(x + (subX + 0.5f) * SubPixelStep, y + (subY + 0.5f) * SubPixelStep); // 子像素位置
                    if (IsPointInTriangle(SubPixelPos, A, B, C))
                    {
                        CoveredSubPixels++;
                    }
                }
            }

            // 计算覆盖率并设置像素颜色
            float Coverage = static_cast<float>(CoveredSubPixels) / TotalSubPixels; // 覆盖率(0 到 1)
            if (Coverage > 0)
            {
                FColor FinalColor = TriangleColor;
                FinalColor.R = FMath::RoundToInt(255 * Coverage);
                FormattedImageData[y * Width + x] = FinalColor;
            }
        }
    }

    // 解锁纹理数据
    Mip.BulkData.Unlock();
    NewTexture->UpdateResource();

    return NewTexture;
}

原文地址:https://blog.csdn.net/grayrail/article/details/142211284

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!