Tangent算法的缺陷及修正办法

Tangent算法缺陷及修正办法
部署运行你感兴趣的模型镜像

来源:http://www.sunnycrystal.net/showdocs.aspx?id=23

一、Tangent算法缺陷

    笔者前几日翻出以前做的坦克模型想在D3D中进行NormalMap方式的渲染,结果发现坦克车体上几个面的高光、NormalMap的凹凸方向不对,后来经过多方跟踪调试,发现问题出在模型身上。共有两个问题:

    1、原来模型在3DSMax里应用了UVW Map的修改器,而在该修改器里,U Tile的方向被Flip过,所以,贴图的U坐标轴实际是反的,而V轴不变。则按照ComputeTangent的算法,先把指向+V的Tangent单位向量求出来,然后最后再用Normal 叉乘 Tangent 求 Binormal,则此时叉乘出的Binormal和实际Binormal是方向正好是反的。不应该是Normal 叉乘 Tangent,而应该是Tangent 叉乘 Normal 才对。
    所以微软等某些Tangent的算法是有缺陷的,它对应的3dsmax模型应该是UV Gizmo没有Flip或者旋转过的,而一般在美术建模阶段是很有可能对UVW Gizmo进行旋转、Flip等操作的。

    2、UVW Map映射方式的问题。我的模型有些部件通过UVW Map中的Planar模式映射UV,则出现了这样的情况:构成一个面的3个顶点,其中1、2顶点的U坐标相同,1、3顶点的U坐标不同,1、2、3顶点的V坐标均相同,(U1 == U2 && U1 != U3 && V1 == V2  && V1 == V3),这样的面是无法得到正确的Tangent的,因为Tangent垂直于这个面。当然我们也可以假设在这个面中一条垂直于Binormal的向量为Tangent。但因尽量避免这种Planar模式对于一个物体映射UV的情况

    所以,如果采用常见的Tangent求法,就要求三角形的3个顶点在UV坐标空间的图形仍然为三角形,而不能是一条线或一个点,同时U轴到V轴应该满足顺时针夹角为90度。

二、缺陷的解决

    有人提出可以用NVidia 的 MenshMender 类来修正这个问题,亲手试验了一下,发现这个办法不是很理想,有些面仍然有问题,而且NVidia为了解决问题,分裂出来了过多的顶点。

    后来,我想到了一个修正办法,就是维持ComputeTangent的算法不变,而在Mesh的NormalMap层纹理坐标上进行修正,这个办法因为修改了NormalMap的贴图坐标,适用于关键要得到正确Per-Pixel光照而可以忽略NormalMap贴图方向的情况,比如NormalMap纹理表示的是一块平坦表面或者沙粒路面等没有大型可辨识凹凸图形的情况,比如通过NormalMap增加人脸肌肉凹凸细节的话就不推荐用此方法修正,因为有可能在待修正三角面上出现原本没有的细节。

    我们知道,Compute Tangent出错的原因之一,就是一个三角形所对应在UV空间中的图形是一条线或者是一个点,所以,我们修正的原理就是通过修改三角形3个顶点的UV值,使三角形在UV空间中能保证3个点不构成一条直线,或者3个点重合,仍然是一个三角形。所以,为了实现这个目标,我们可以通过一种Box的方式来进行纹理坐标映射,类似于CubeMap的纹理坐标映射。

    具体算法如下:

    首先要计算出整个Mesh的AABB包围盒,然后计算每一个三角形的面法线,假设一个坐标在原点的正方体(注意:不是AABB盒)包围了这个三角形,我们先求出面法线与正方体的哪个面相交,然后根据对应的面来映射UV。

    举个例子:如果法线与正Y面相交(Positive Y),则我们可以通过该三角形的X、Z坐标进行纹理映射,X轴为+U坐标轴,-Z轴为+V坐标轴,同时通过AABB的X轴长度、Z轴长度及AABB的X最小值、Z最大值得到该三角形三个顶点的新UV坐标(NormalMap纹理的UV坐标)。正方体另外5个面也依此原理计算。

    U1 = ( X1 - AABB.MinPt.X ) * e;
    V1 = ( AABB.MaxPt.Z - Z1 ) * e;
    e: UV Tile的比例因子

    注意:这个算法也需要分裂顶点,当计算出当前顶点的新UV的时候如果发线新UV已经计算过了,而且与这次算出来的新UV不一致,说明这个顶点被两个三角形共享,且纹理坐标不一致,需要分裂。

    最后,用常规的ComputeTangent算法和修正过后的NormalMap纹理坐标即可得到正确的Tangent、Binormal。附图如下:

您可能感兴趣的与本文相关的镜像

Kotaemon

Kotaemon

AI应用

Kotaemon 是由Cinnamon 开发的开源项目,是一个RAG UI页面,主要面向DocQA的终端用户和构建自己RAG pipeline

提供的引用内容中未提及Tangent分布优化算法相关信息,无法准确回答该算法的具体内容。不过,一般来说优化算法通常可以从以下常见的方向进行优化: ### 初始化优化 可以使用混沌初始化方法,像引用[1]中提到的21种混沌映射方法 - 混沌初始化,通过混沌映射产生的初始种群具有更好的遍历性和随机性,能使算法更快地收敛到最优解。 ### 引入局部搜索机制 在算法的迭代过程中,结合局部搜索算法,如爬山算法等,在当前解的邻域内进行精细搜索,以提高算法的局部寻优能力。 ### 参数自适应调整 算法中的一些参数(如学习率、惯性权重等)可以根据迭代的进程进行自适应调整。在算法初期,使用较大的参数值以保证算法的全局搜索能力,在后期使用较小的参数值以提高局部搜索精度。 ### 混合其他算法Tangent分布算法与其他优秀的优化算法进行混合,例如与群体智能优化算法(像引用[2]中提到的超375种群体智能优化算法)结合,利用不同算法的优势,提升整体的优化性能。 以下是一个简单的伪代码示例,展示如何将混沌初始化应用到优化算法中: ```python import numpy as np # 混沌映射函数(以Logistic映射为例) def logistic_map(x, r=4): return r * x * (1 - x) # 混沌初始化种群 def chaotic_initialization(pop_size, dim, x_min, x_max): pop = np.zeros((pop_size, dim)) x = np.random.rand() # 初始值 for i in range(pop_size): for j in range(dim): x = logistic_map(x) pop[i, j] = x_min + x * (x_max - x_min) return pop # 假设这里是Tangent分布优化算法的主函数 def tangent_distribution_optimization(): pop_size = 50 dim = 10 x_min = -10 x_max = 10 pop = chaotic_initialization(pop_size, dim, x_min, x_max) # 后续进行Tangent分布算法的迭代过程 # ... return pop # 调用优化算法 best_solution = tangent_distribution_optimization() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值