【问题标题】:Dynamically recalculating normals after vertex displacement顶点位移后动态重新计算法线
【发布时间】:2021-04-11 03:43:17
【问题描述】:

任何人都可以告诉我,如果我的方法正确:我有一个顶点着色器,它会根据传入的点动态地向外凸出(想象一只老鼠在地毯下跑)。为了使光照正确更新,我需要在修改顶点位置后重新计算法线。我可以访问每个顶点以及原点。

我目前的想法是我做一些数学来确定切线/双切线并使用叉积来确定法线。我的数学能力不是很好,我需要做什么来确定这些向量?

这是我当前的垂直着色器:

void vert(inout appdata_full v) 
{
    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    float distanceToLift = distance(worldPos, _LiftOrigin);

    v.vertex.y = smoothstep(_LiftHeight, 0, distanceToLift / _LiftRadius) * 5;
}

【问题讨论】:

  • 您找到这个问题的答案了吗?如果我的方法有帮助,请考虑accepting it 给我一些声誉积分,并帮助其他浏览搜索面板的人在这里找到有用的答案。

标签: unity3d graphics shader vertex-shader


【解决方案1】:

Ronja 在this tutorial 中介绍了一个简单的解决方案,我将在这里总结一下,并根据您的具体情况进行修改。

首先,找到从当前点偏移少量切线和双切线(可以从法线和切线计算)的两个点:

float3 posPlusTangent = v.vertex + v.tangent * 0.01;
worldPos = mul(unity_ObjectToWorld, posPlusTangent).xyz;
distanceToLift = distance(worldPos, _LiftOrigin);
posPlusTangent.y = smoothstep(_LiftHeight, 0, distanceToLift / _LiftRadius) * 5;

float3 bitangent = cross(v.normal, v.tangent);

float3 posPlusBitangent = v.vertex + bitangent * 0.01;
worldPos = mul(unity_ObjectToWorld, bitangent).xyz;
distanceToLift = distance(worldPos, _LiftOrigin);
posPlusBitangent.y = smoothstep(_LiftHeight, 0, distanceToLift / _LiftRadius) * 5;

然后,求这些偏移量与新顶点 pos 之差,求新切线和副切线,再做另一个叉积求法线:

float3 modifiedTangent = posPlusTangent - v.vertex;
float3 modifiedBitangent = posPlusBitangent - v.vertex;

float3 modifiedNormal = cross(modifiedTangent, modifiedBitangent);
v.normal = normalize(modifiedNormal);

总共:

float find_offset(float3 localV)
{
    float3 worldPos = mul(unity_ObjectToWorld, localV).xyz;
    float distanceToLift = distance(worldPos, _LiftOrigin);

    return smoothstep(_LiftHeight, 0, distanceToLift / _LiftRadius) * 5;
}

void vert(inout appdata_full v) 
{
    v.vertex.y = find_offset(v.vertex);

    float3 posPlusTangent = v.vertex + v.tangent * 0.01;
    posPlusTangent.y = find_offset(posPlusTangent);

    float3 bitangent = cross(v.normal, v.tangent);

    float3 posPlusBitangent = v.vertex + bitangent * 0.01;
    posPlusTangent.y = find_offset(posPlusBitangent);

    float3 modifiedTangent = posPlusTangent - v.vertex;
    float3 modifiedBitangent = posPlusBitangent - v.vertex;

    float3 modifiedNormal = cross(modifiedTangent, modifiedBitangent);
    v.normal = normalize(modifiedNormal);
}

这是一种近似的方法,但它可能已经足够好了!

【讨论】:

    猜你喜欢
    • 2013-02-15
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    • 2014-09-25
    • 2010-11-12
    相关资源
    最近更新 更多