uv就是三维模型的Vertices坐标投影在平面上的坐标。所以重新计算UV就有了简单的思路。
(1)模型计算uv时都会丢弃一个轴向的数值,把他当作模型映射uv的法线方向,
(2)然后再考虑剩下的二个维度的值通过缩放和偏移重新计算生成三维模型相应的uv坐标。具体算法就是
1.将所有的vertices坐标都依次去掉一个轴向的值。
2.将vertices中的最后一个点坐标作为参考点,其他的点坐标分别依次计算剩下的点坐标与参考点的偏移作为此点的uv值。
比如参考点的坐标为O(x1 =0,y1=0),另一个点的坐标A(x2 =1,y2=2),那么A的uv点值为(x2-x1=1,y2-y1=2),u值等于x1到x2的偏移值 1;v值等于y1到y2的偏移值2。
3.因为uv的取值范围0~1,所以我们需要将计算后的uv的值进行缩放到0到1的范围内。之后再进行一个偏移。
直接上代码:
头文件
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "CalculateMeshUV.generated.h"/**
*
*/
UCLASS()
class HTTPREQUEST_API UCalculateMeshUV : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public :
UFUNCTION(BlueprintCallable,CateGory = "MyMath")
static void CalculateUV(TArray<FVector> MeshVertices,FVector normal, TArray<FVector2D>& uv);
};
#include "CalculateMeshUV.h"
//MeshVertices 为mesh上的vertices点
//normal为 映射的方向
//返回 uv
void UCalculateMeshUV::CalculateUV(TArray<FVector> MeshVertices, FVector normal , TArray<FVector2D>& uv)
{
float maxU = 0.0, minU = 0.0, maxV = 0.0 , minV = 0.0;
for (int i = 0 ;i < MeshVertices.Num()-1;i++)
{
uv.Add(FVector2D().ZeroVector);
if (normal.Equals(FVector(1,0,0)))
{
uv[i].X = MeshVertices.Last().Y - MeshVertices[i].Y;
if (uv[i].X > maxU)
{
maxU = uv[i].X;
}
else
{
if (uv[i].X < minU)
{
minU = uv[i].X;
}
}
uv[i].Y = MeshVertices.Last().Z - MeshVertices[i].Z;
if (uv[i].Y > maxV) {
maxV = uv[i].Y;
}
else {
if (uv[i].Y < minV)
{
minV = uv[i].Y;
}
}
}
else if (normal.Equals(FVector(0, 1, 0)))
{
uv[i].X = MeshVertices.Last().X - MeshVertices[i].X;
if (uv[i].X > maxU)
{
maxU = uv[i].X;
}
else
{
if (uv[i].X < minU)
{
minU = uv[i].X;
}
}
uv[i].Y = MeshVertices.Last().Z - MeshVertices[i].Z;
if (uv[i].Y > maxV) {
maxV = uv[i].Y;
}
else {
if (uv[i].Y < minV)
{
minV = uv[i].Y;
}
}
}else if (normal.Equals(FVector(0, 0, 1)))
{
uv[i].X = MeshVertices.Last().X - MeshVertices[i].X;
if (uv[i].X > maxU)
{
maxU = uv[i].X;
}
else
{
if (uv[i].X < minU)
{
minU = uv[i].X;
}
}
uv[i].Y = MeshVertices.Last().Y - MeshVertices[i].Y;
if (uv[i].Y > maxV) {
maxV = uv[i].Y;
}
else {
if (uv[i].Y < minV)
{
minV = uv[i].Y;
}
}
}
else {
uv[i].X = MeshVertices.Last().X - MeshVertices[i].X;
if (uv[i].X > maxU)
{
maxU = uv[i].X;
}
else
{
if (uv[i].X < minU)
{
minU = uv[i].X;
}
}
uv[i].Y = MeshVertices.Last().Y - MeshVertices[i].Y;
if (uv[i].Y > maxV) {
maxV = uv[i].Y;
}
else {
if (uv[i].Y < minV)
{
minV = uv[i].Y;
}
}
}
}
float lenghtU = maxU - minU;
float lenghtV = maxV - minV;
float uOffset = minU / lenghtU;
float vOffset = minV / lenghtV ;
for (int i = 0; i < MeshVertices.Num()-1; i++)
{
uv[i].X = uv[i].X / lenghtU - uOffset;
uv[i].Y = uv[i].Y / lenghtV - vOffset;
}
uv.Add(FVector2D().ZeroVector);
}
ok完成,UE4蓝图:
注意:
normal映射方向一般为x,y,z三个 轴向方向。也就是传值一般为(1,0,0) 或(0,1,0)或(0,0,1)。如果非三个轴向默认以(0,0,1)方向来计算。