计算映射模型UV

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)方向来计算。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个用于重新排列模型纹理的MaxScript示例,它可以增加纹理的有效使用率,重新映射模型纹理。 ``` -- 选择要重新排列纹理的对象 obj = selection[1] -- 获取对象的所有材质 mats = getClassInstances StandardMaterial -- 计算纹理的总大小 totalSize = 0 for mat in mats do ( if mat.diffuseMap != undefined do ( -- 获取纹理文件的路径 mapPath = getFilenamePath(mat.diffuseMap.fileName) -- 计算纹理文件的大小 mapSize = getFileSize mat.diffuseMap.fileName totalSize = totalSize + mapSize ) ) -- 计算纹理排列所需的最小纹理尺寸 tileSize = ceil(sqrt(totalSize)) -- 创建新的纹理 newMap = BitmapTexture size:tileSize name:"NewMap" newMap.filename = "NewMap.bmp" newMap.filename_relative = true newMap.showInViewport = true -- 初始化纹理坐标 u = 0 v = 0 -- 重新映射所有材质的纹理 for mat in mats do ( if mat.diffuseMap != undefined do ( -- 获取纹理文件的路径 mapPath = getFilenamePath(mat.diffuseMap.fileName) -- 获取纹理文件的大小 mapSize = getFileSize mat.diffuseMap.fileName -- 计算纹理在新的纹理中的位置和大小 mapRect = [u, v, u + (mapSize / totalSize), v + (mapSize / totalSize)] -- 设置材质的新纹理 mat.diffuseMap = newMap mat.diffuseMap.coords = #uv mat.diffuseMap.sourceRect = mapRect -- 更新纹理坐标 u = u + (mapSize / totalSize) if u > 1 do ( u = 0 v = v + (mapSize / totalSize) ) ) ) -- 保存新的纹理文件 newMap.filename = mapPath + "\\NewMap.bmp" newMap.filename_relative = false newMap.update = true ``` 这个脚本会遍历所选对象的所有材质,计算每个纹理文件的大小,并将它们重新映射到一个新的纹理上。新纹理的大小为所有纹理文件大小之和的平方根,可以确保纹理排列比较紧密。最终,新纹理会保存到与第一个纹理文件相同的路径下,并且所有材质的纹理都会更新为新纹理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值