歌德之殇 2022-09-29 19:31 采纳率: 0%
浏览 383
已结题

需要用虚幻UE4.27 从现实的热成像图,转换到虚拟场景的热成像效果,ji求方案或指导

问题遇到的现象和发生背景

需要用虚幻UE4.27 从现实的热成像图,转换到虚拟场景的热成像效果,j求方案或指导
图片效果地址:
https://ibb.co/8Xq3Bdh

操作环境、软件版本等信息

windows 10 虚幻 UE4.27

尝试过的解决方法

我的思路是,现实中的图片 根据像素坐标取颜色值,然后屏幕空间发射射线,让击中的射线对模型顶点做颜色修改。
修改颜色找到2个方案代码
1、是实现顶点颜色修改,但是好像顶点颜色修改,自己创建的模型顶点在C++里面计算好像是错误的,导致无法用这个代码实现原先应该着色的地方着色。
代码:

#include "Vertex2FunctionLibrary.h"

#include "Components/SkinnedMeshComponent.h"
#include "Rendering/SkeletalMeshRenderData.h"
#include "RenderResource.h"

//通过点影响修改骨骼模型顶点色
void UVertex2FunctionLibrary::ModfiySkeletalMeshVertexColorByPointEffect(USkeletalMeshComponent* SM, FVector Point, float LimitDistance, FColor Color)
{
    for (int32 i = 0; i < SM->GetNumLODs(); ++i)
    {
        //获取顶点位置
        TArray<FVector> Position = GetSkeletalMeshVertexPositionByLODIndex(SM, i);
        TArray<FColor> VertexColor;
        VertexColor.AddUninitialized(Position.Num());
        for (int32 index = 0; index < Position.Num(); ++index)
        {
            FColor BaseColor = SM->GetVertexColor(index);
            //在点范围内修改顶点色
            if ((Point - Position[index]).Size() < LimitDistance)
            {
                BaseColor = Color;
            }

            VertexColor[index] = BaseColor;
        }

        //官方自带修改VertexColor的api
        SM->SetVertexColorOverride(i, VertexColor);
    }
}


//通过点影响修改静态模型顶点色
void UVertex2FunctionLibrary::ModfiyStaticMeshVertexColorByPointEffect(UStaticMeshComponent* SM, FVector Point, float LimitDistance, FColor Color)
{
    for (int32 i = 0; i < SM->GetStaticMesh()->GetNumLODs(); ++i)
    {
        //获取顶点位置
        TArray<FVector> Position = GetStaticMeshVertexPositionByLODIndex(SM, i);
        TArray<FColor> VertexColor;
        VertexColor.AddUninitialized(Position.Num());

        //判断是否被应用顶点色
        if (SM->GetStaticMesh()->RenderData->LODResources[i].bHasColorVertexData)
        {
            for (int32 index = 0; index < Position.Num(); ++index)
            {
                FColor BaseColor = SM->LODData[i].OverrideVertexColors->VertexColor(index);

                if ((Point - Position[index]).Size() < LimitDistance)
                {
                    BaseColor = Color;
                }
                VertexColor[index] = BaseColor;
            }
        }
        else
        {

            for (int32 index = 0; index < Position.Num(); ++index)
            {
                FColor BaseColor = FColor(255, 255, 255, 255);
                if ((Point - Position[index]).Size() < LimitDistance)
                {
                    BaseColor = Color;
                }
                VertexColor[index] = BaseColor;
            }
        }

        //StaticMesh官方没有自带api,需要自己编写
        SetStaticVertexColorOverride(SM, i, VertexColor);
    }
}

//获取骨骼顶点位置
TArray<FVector> UVertex2FunctionLibrary::GetSkeletalMeshVertexPositionByLODIndex(USkeletalMeshComponent* SM, int32 LODIndex)
{
    TArray<FVector> OutPosition;
    FSkeletalMeshLODRenderData& LODData = SM->GetSkeletalMeshRenderData()->LODRenderData[LODIndex];

    TArray<FMatrix> OutRefToLocal;
    SM->CacheRefToLocalMatrices(OutRefToLocal);

    FSkinWeightVertexBuffer& SkinWeightBuffer = *SM->GetSkinWeightBuffer(LODIndex);

    SM->ComputeSkinnedPositions(SM, OutPosition, OutRefToLocal, LODData, SkinWeightBuffer);

    VPComponentSpaceToWorldSpace(SM, OutPosition);

    return MoveTemp(OutPosition);

}

//获取静态顶点位置 
TArray<FVector> UVertex2FunctionLibrary::GetStaticMeshVertexPositionByLODIndex(UStaticMeshComponent* SM, int32 LODIndex)
{
    TArray<FVector> OutPosition;

    FPositionVertexBuffer& posBuffer = SM->GetStaticMesh()->RenderData->LODResources[LODIndex].VertexBuffers.PositionVertexBuffer;

    for (uint32 i = 0; i < posBuffer.GetNumVertices(); ++i)
    {
        OutPosition.Emplace(posBuffer.VertexPosition(i));
    }

    VPComponentSpaceToWorldSpace(SM, OutPosition);

    return MoveTemp(OutPosition);
}

//把顶点位置从Compont Space 转化到 World Space
void UVertex2FunctionLibrary::VPComponentSpaceToWorldSpace(USceneComponent* SC, TArray<FVector>& Position)
{
    FTransform RelativeTransform = SC->GetRelativeTransform();
    for (FVector& pos : Position)
    {

        pos = TransformVector(RelativeTransform, pos);
        pos += RelativeTransform.GetLocation();

        if (SC->GetOwner())
        {
            FTransform WorldTransform = SC->GetOwner()->GetTransform();
            pos = TransformVector(WorldTransform, pos);
            pos += WorldTransform.GetLocation();
        }

    }
}

//静态顶点颜色修改
bool UVertex2FunctionLibrary::SetStaticVertexColorOverride(UStaticMeshComponent* SM, int32 LODIndex, const TArray<FColor> VertexColor)
{
    FStaticMeshRenderData* RenderData = SM->GetStaticMesh()->RenderData.Get();

    if (RenderData != nullptr && RenderData->LODResources.IsValidIndex(LODIndex))
    {
        FStaticMeshLODResources& LODResource = RenderData->LODResources[LODIndex];
        FStaticMeshComponentLODInfo& InstanceMeshLODInfo = SM->LODData[LODIndex];
        if (InstanceMeshLODInfo.OverrideVertexColors != nullptr)
        {
            InstanceMeshLODInfo.PaintedVertices.Empty();
            SM->CachePaintedDataIfNecessary();
            if (InstanceMeshLODInfo.OverrideVertexColors)
            {
                InstanceMeshLODInfo.ReleaseOverrideVertexColorsAndBlock();
                SM->GetStaticMesh()->RenderData->LODResources[LODIndex].bHasColorVertexData = true;
            }
            InstanceMeshLODInfo.OverrideVertexColors = new FColorVertexBuffer;
            InstanceMeshLODInfo.OverrideVertexColors->InitFromColorArray(VertexColor);
            if (LODIndex > 0)
            {
                SM->bCustomOverrideVertexColorPerLOD = true;
            }
            BeginInitResource(InstanceMeshLODInfo.OverrideVertexColors);
            SM->MarkRenderStateDirty();
            return true;
        }
    }
    return false;
}

2、有个插件ThermodynamicChart他内部好像是UV着色,只能对平面,我实际需要对3D模型进行着色。
插件内的核心代码

//核心 暴露给蓝图的  我改如何修改或者利用 到3D模型上然后可以用射线 操控3D模型点上的颜色
void AThermodynamicChartActor::AddPointToRenderTarget(FVector2D InPos, bool bIsNormalized)
{
    FVector2D tempPos = FVector2D(InPos);

    if (bIsNormalized)
    {
        tempPos = (tempPos - MinPos) / (MaxPos - MinPos);
    }

    TCRenderTargetMID->SetVectorParameterValue(TEXT("Pos"), FVector(tempPos, 0.0f));
    TCRenderTargetMID->SetScalarParameterValue(TEXT("Strength"), Strength);
    TCRenderTargetMID->SetScalarParameterValue(TEXT("Radius"), Radius);
    UKismetRenderingLibrary::DrawMaterialToRenderTarget(GetWorld(), RenderTarget, TCRenderTargetMID);
}

/************************************************************************/
/* Author: YWT20                                                        */
/* Expected release year : 2021                                         */
/************************************************************************/


#include "ThermodynamicChartActor.h"
#include "Kismet/KismetRenderingLibrary.h"
#include "Kismet/KismetMaterialLibrary.h"
#include "Kismet/KismetMathLibrary.h"
#include "UObject/ConstructorHelpers.h"
#include "Engine/StaticMesh.h"
#include "Components/SceneComponent.h"

// Sets default values
AThermodynamicChartActor::AThermodynamicChartActor()
{
    // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    Resolution = 1024;
    Strength = 0.1f;
    Radius = 0.1f;
    MinPos = FVector2D(0.0f, 0.0f);
    MaxPos = FVector2D(Resolution, Resolution);

    Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
    RootComponent = Scene;

    TCMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("TCMesh"));
    TCMesh->SetupAttachment(RootComponent);

    TCDecal = CreateDefaultSubobject<UDecalComponent>(TEXT("TCDecal"));
    TCDecal->SetupAttachment(RootComponent);
    TCDecal->DecalSize = FVector(50.0f, 50.0f, 50.0f);
    TCDecal->SetRelativeRotation(FQuat(FRotator(-90.0f, 0.0f, 0.0f)));

    static ConstructorHelpers::FObjectFinder<UStaticMesh> PlaneStaticMesh(TEXT("StaticMesh'/Engine/BasicShapes/Plane.Plane'"));
    if (PlaneStaticMesh.Succeeded())
    {
        TCMesh->SetStaticMesh(PlaneStaticMesh.Object);
    }

    static ConstructorHelpers::FObjectFinder<UMaterialInstance> MI_ThermodynamicChart(TEXT("MaterialInstanceConstant'/ThermodynamicChart/ThermodynamicChart/Materials/M_ThermodynamicChart_Inst.M_ThermodynamicChart_Inst'"));
    if (MI_ThermodynamicChart.Succeeded())
    {
        ThermodynamicChartMI = MI_ThermodynamicChart.Object;
    }

    static ConstructorHelpers::FObjectFinder<UMaterialInstance> MI_ThermodynamicChart_Decal(TEXT("MaterialInstanceConstant'/ThermodynamicChart/ThermodynamicChart/Materials/M_ThermodynamicChart_Decal_Inst.M_ThermodynamicChart_Decal_Inst'"));
    if (MI_ThermodynamicChart_Decal.Succeeded())
    {
        ThermodynamicChart_Decal_MI = MI_ThermodynamicChart_Decal.Object;
    }

    static ConstructorHelpers::FObjectFinder<UMaterialInstance> MI_TCRenderTarget(TEXT("MaterialInstanceConstant'/ThermodynamicChart/ThermodynamicChart/Materials/M_TCRenderTarget_Inst.M_TCRenderTarget_Inst'"));
    if (MI_TCRenderTarget.Succeeded())
    {
        TCRenderTargetMI = MI_TCRenderTarget.Object;
    }

    TCMesh->SetMaterial(0, ThermodynamicChartMI);

    MatColor0 = FLinearColor(0.0f, 0.0f, 1.0f, 0.0f);
    MatColor1 = FLinearColor::Green;
    MatColor2 = FLinearColor::Yellow;
    MatColor3 = FLinearColor::Red;
}

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

    RenderTarget = UKismetRenderingLibrary::CreateRenderTarget2D(GetWorld(), Resolution, Resolution);

    if (ThermodynamicChart_Decal_MID)
    {
        ThermodynamicChart_Decal_MID->SetTextureParameterValue(TEXT("RenderTarget"), RenderTarget);
        TCDecal->SetDecalMaterial(ThermodynamicChart_Decal_MID);
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("ThermodynamicChart_Decal_MID is null"));
    }

    if (ThermodynamicChartMID)
    {
        ThermodynamicChartMID->SetTextureParameterValue(TEXT("RenderTarget"), RenderTarget);
        TCMesh->SetMaterial(0, ThermodynamicChartMID);
    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("ThermodynamicChartMID is null"));
    }

    if (!TCRenderTargetMID)
    {
        UE_LOG(LogTemp, Warning, TEXT("TCRenderTargetMID is null"));
    }
    SetMatColor(MatColor0, MatColor1, MatColor2, MatColor3);
}

// Called every frame
void AThermodynamicChartActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

void AThermodynamicChartActor::OnConstruction(const FTransform& Transform)
{
    Super::OnConstruction(Transform);
    ThermodynamicChart_Decal_MID = UKismetMaterialLibrary::CreateDynamicMaterialInstance(GetWorld(), ThermodynamicChart_Decal_MI);
    ThermodynamicChartMID = UKismetMaterialLibrary::CreateDynamicMaterialInstance(GetWorld(), ThermodynamicChartMI);
    TCRenderTargetMID = UKismetMaterialLibrary::CreateDynamicMaterialInstance(GetWorld(), TCRenderTargetMI);

    if (bIsUseDecal)
    {
        TCMesh->SetVisibility(false);
        TCDecal->SetVisibility(true);
    }
    else
    {
        TCMesh->SetVisibility(true);
        TCDecal->SetVisibility(false);
    }
}

void AThermodynamicChartActor::AddPointToRenderTarget(FVector2D InPos, bool bIsNormalized)
{
    FVector2D tempPos = FVector2D(InPos);

    if (bIsNormalized)
    {
        tempPos = (tempPos - MinPos) / (MaxPos - MinPos);
    }

    TCRenderTargetMID->SetVectorParameterValue(TEXT("Pos"), FVector(tempPos, 0.0f));
    TCRenderTargetMID->SetScalarParameterValue(TEXT("Strength"), Strength);
    TCRenderTargetMID->SetScalarParameterValue(TEXT("Radius"), Radius);
    UKismetRenderingLibrary::DrawMaterialToRenderTarget(GetWorld(), RenderTarget, TCRenderTargetMID);
}

void AThermodynamicChartActor::AddPointsToRenderTarget(TArray<FVector2D> InPosArray, bool bIsNormalized)
{
    for (auto pos : InPosArray)
    {
        AddPointToRenderTarget(pos, bIsNormalized);
    }
}

void AThermodynamicChartActor::RandomMap(int32 Num /*= 1000*/)
{
    float tempPosX = 0.0;
    float tempPosY = 0.0;
    for (int32 i = 0; i < Num; i++)
    {
        tempPosX = UKismetMathLibrary::RandomFloat();
        tempPosY = UKismetMathLibrary::RandomFloat();
        AddPointToRenderTarget(FVector2D(tempPosX, tempPosY), false);
    }
}

void AThermodynamicChartActor::SetMatColor(FLinearColor InColor0, FLinearColor InColor1, FLinearColor InColor2, FLinearColor InColor3)
{
    ThermodynamicChartMID->SetVectorParameterValue("Color_0", InColor0);
    ThermodynamicChartMID->SetVectorParameterValue("Color_1", InColor1);
    ThermodynamicChartMID->SetVectorParameterValue("Color_2", InColor2);
    ThermodynamicChartMID->SetVectorParameterValue("Color_3", InColor3);

    ThermodynamicChart_Decal_MID->SetVectorParameterValue("Color_0", InColor0);
    ThermodynamicChart_Decal_MID->SetVectorParameterValue("Color_1", InColor1);
    ThermodynamicChart_Decal_MID->SetVectorParameterValue("Color_2", InColor2);
    ThermodynamicChart_Decal_MID->SetVectorParameterValue("Color_3", InColor3);
}


3、打算根据原始的热成像 贴图信息来发送 射线 ,但是这个射线好像断点进不去for循环的代码

.h代码
```c++
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

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

UCLASS()
class RELICHENGXIANG_API APictureActor : public AActor
{
    GENERATED_BODY()
    
public:    
    // Sets default values for this actor's properties
    APictureActor();
    UPROPERTY(EditAnywhere,Category="Chunk")
    int Size = 16;
    UPROPERTY(EditAnywhere, Category = "Chunk")
    int Scale = 1;
    UPROPERTY(BlueprintReadWrite,EditAnywhere ,Category = "Spawn")
    UTexture2D *MyTexture2D;
    void ReadImage();
protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:    
    // Called every frame
    virtual void Tick(float DeltaTime) override;

};


// Fill out your copyright notice in the Description page of Project Settings.

#include "PictureActor.h"

// Sets default values
APictureActor::APictureActor()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

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

// Called every frame
void APictureActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

void APictureActor::ReadImage()
{
    //从UTexture2D对象中读取颜色信息,并标识未只读状态
    const FColor* FormatedImageData 
        = static_cast<const FColor*>(MyTexture2D->PlatformData->Mips[0].BulkData.LockReadOnly());

    int counter = 0;
    for (int32 x = 0;x<5; x++)// MyTexture2D->GetSizeX()
    {
        for (int32 y = 0; y <6; y++)// MyTexture2D->GetSizeY()
        {
            //读取指定像素点的颜色
            FColor PixelColor = FormatedImageData[y* MyTexture2D->GetSizeX() + x];
            //RGPB转灰度
            float r = PixelColor.R;
            float g = PixelColor.G;
            float b = PixelColor.B;
            //UE_LOG(Chunk, Log, TEXT("PixelColor %i:i%,i%,i%"), counter, PixelColor.R, PixelColor.G, PixelColor.B);
            counter += 1;
        }
    }

    MyTexture2D->PlatformData->Mips[0].BulkData.Unlock();
}






我想要达到的结果

图片效果地址:
https://ibb.co/8Xq3Bdh

  • 写回答

4条回答

      报告相同问题?

      相关推荐 更多相似问题

      问题事件

      • 系统已结题 10月7日
      • 赞助了问题酬金100元 9月29日
      • 创建了问题 9月29日

      悬赏问题

      • ¥15 Java的运用111111111111
      • ¥15 koa2 + ts 声明文件不生效
      • ¥15 Mac系统word显示此文档已被删除或当前无法访问.
      • ¥15 Unity用代码实现Tilemap
      • ¥15 怎么求广播地址以及网络地址?
      • ¥15 想知道unity如何实现物体贴地运动
      • ¥15 从A地到B地有多条路径可以到达,现要从A地到B地运物资问题
      • ¥30 用java设计小游戏扑克牌比大小,52张牌的图片选世界篮球明星图或其它都行
      • ¥15 ATM管理员功能代码及解释
      • ¥15 EasyExcel导出下载文件响应流为空