从数学的角度来看,是否可以从高度贴图纹理生成法线贴图?
Is it possible generate normal map from heightmap texture from math point of view?
我的看法是你不能只从高度贴图纹理生成法线贴图?
我说的对不对?
数学参数:
假设从
给定曲面连续双射
S = [0,1]
T = [0,1]
让我们将 SxT 称为图像 space。
从微分几何可以证明,该参数曲面的法线是
如果假设从 SxT 图像 space 到几何欧几里德 space 的映射非常简单,那么我们可以检索:
然后你可以用一些不同的方案来计算这样的偏导数。
我们得出了那个简单的公式,只有 大胆的 建议,这个建议绝对不正确。
图形中的问题示例。
让我们假设我们有一个三角形 space 具有 3 个顶点。
条件是:
法线贴图 --
对于从合适的 2d 纹理的 (u,v) 获取的具有 (u,v,1-u-v) 重心坐标的点是正常的,并且它在局部坐标中。系统相对于三角形。
heihtmap --
它是具有 (u,v,1-u-v) 重心坐标的点在法线方向上相对于从合适的 2d 纹理的 (u,v) 获取的三角形局部 space 的几何偏移量。
在构建法线贴图的过程中,我们完全忽略了高度贴图在 (u,v,1-u-v) eculidian point 附近的分布情况。而且我们只检索法线贴图的一些近似值。
哦,看来我的评论太简短了。
用代码描述方法写一个完整的答案更容易。
我将使用 C++ 和 GLSL 的伪代码组合。
constexpr int width = 32, height = 32;
constexpr float height_scale = 16.0f; // Change if necessary.
float hmap[W][H] = {...};
float normalmap[W][H];
vec3 GetPoint(ivec2 a)
{
a.x %= W;
a.y %= H;
return {a.x, a.y, hmap[a.x][a.y] * height_scale};
}
vec3 GetNormal(ivec2 a, bool loop_hmap)
{
vec3 o = GetPoint(a),
a = GetPoint({a.x + 1, a.y}),
b = GetPoint({a.x, a.y + 1}),
c = GetPoint({a.x - 1, a.y}),
d = GetPoint({a.x, a.y - 1});
vec3 n1 = normalize(cross(a-o, b-o));
vec3 n2 = normalize(cross(b-o, c-o));
vec3 n3 = normalize(cross(c-o, d-o));
vec3 n4 = normalize(cross(d-o, a-o));
if (loop_hmap)
return normalize(n1+n2+n3+n4);
else
{
vec3 sum = {0,0,0};
bool b1 = (a.x+1 >= 0 && a.y >= 0 && a.x+1 < W && a.y < H);
bool b2 = (a.x >= 0 && a.y+1 >= 0 && a.x < W && a.y+1 < H);
bool b3 = (a.x-1 >= 0 && a.y >= 0 && a.x-1 < W && a.y < H);
bool b4 = (a.x >= 0 && a.y-1 >= 0 && a.x < W && a.y-1 < H);
if (b1 && b2) sum += n1;
if (b2 && b3) sum += n2;
if (b3 && b4) sum += n3;
if (b4 && b1) sum += n4;
return normalize(sum);
}
}
int main()
{
for (int i = 0; i < H; i++)
for (int j = 0; j < W; j++)
normalmap[j][i] = GetNormal(j, i, 0);
}
loop_hmap
GetNormal()
的参数改变了函数计算边缘像素法线的方式。 1
应用于平铺纹理,如沙子和水。 0
应用于非平铺纹理,如物品、生物、树木。
对我来说,我自己的初始问题是无效的,它有一个错误!!!
I – original parametric surface with domain as cartesian product of [0,1] and range of it as euclidean space
II - normal to original surface
III - modified original surface with heightmap
IV - normal map which we want to receive with even ignoring geometric modification of the surface by “III”
最后一步 IV 包括很多要区分的东西:H(s,t) 和函数的原始定义...我不会对方程式进行进一步分析...但对我来说,您可以't 仅从(高度图)生成法线贴图...
P.S。要执行进一步的分析,如果你想从那个地方检索 *.docx 文件 https://yadi.sk/d/Qqx-jO1Ugo3uL 据我所知,不可能将 ms word 中的公式转换为乳胶,但无论如何请将其用作草稿。
我的看法是你不能只从高度贴图纹理生成法线贴图? 我说的对不对?
数学参数:
假设从
给定曲面连续双射S = [0,1]
T = [0,1]
让我们将 SxT 称为图像 space。
从微分几何可以证明,该参数曲面的法线是
如果假设从 SxT 图像 space 到几何欧几里德 space 的映射非常简单,那么我们可以检索:
然后你可以用一些不同的方案来计算这样的偏导数。 我们得出了那个简单的公式,只有 大胆的 建议,这个建议绝对不正确。
图形中的问题示例。
让我们假设我们有一个三角形 space 具有 3 个顶点。 条件是:
法线贴图 -- 对于从合适的 2d 纹理的 (u,v) 获取的具有 (u,v,1-u-v) 重心坐标的点是正常的,并且它在局部坐标中。系统相对于三角形。
heihtmap -- 它是具有 (u,v,1-u-v) 重心坐标的点在法线方向上相对于从合适的 2d 纹理的 (u,v) 获取的三角形局部 space 的几何偏移量。
在构建法线贴图的过程中,我们完全忽略了高度贴图在 (u,v,1-u-v) eculidian point 附近的分布情况。而且我们只检索法线贴图的一些近似值。
哦,看来我的评论太简短了。
用代码描述方法写一个完整的答案更容易。
我将使用 C++ 和 GLSL 的伪代码组合。
constexpr int width = 32, height = 32;
constexpr float height_scale = 16.0f; // Change if necessary.
float hmap[W][H] = {...};
float normalmap[W][H];
vec3 GetPoint(ivec2 a)
{
a.x %= W;
a.y %= H;
return {a.x, a.y, hmap[a.x][a.y] * height_scale};
}
vec3 GetNormal(ivec2 a, bool loop_hmap)
{
vec3 o = GetPoint(a),
a = GetPoint({a.x + 1, a.y}),
b = GetPoint({a.x, a.y + 1}),
c = GetPoint({a.x - 1, a.y}),
d = GetPoint({a.x, a.y - 1});
vec3 n1 = normalize(cross(a-o, b-o));
vec3 n2 = normalize(cross(b-o, c-o));
vec3 n3 = normalize(cross(c-o, d-o));
vec3 n4 = normalize(cross(d-o, a-o));
if (loop_hmap)
return normalize(n1+n2+n3+n4);
else
{
vec3 sum = {0,0,0};
bool b1 = (a.x+1 >= 0 && a.y >= 0 && a.x+1 < W && a.y < H);
bool b2 = (a.x >= 0 && a.y+1 >= 0 && a.x < W && a.y+1 < H);
bool b3 = (a.x-1 >= 0 && a.y >= 0 && a.x-1 < W && a.y < H);
bool b4 = (a.x >= 0 && a.y-1 >= 0 && a.x < W && a.y-1 < H);
if (b1 && b2) sum += n1;
if (b2 && b3) sum += n2;
if (b3 && b4) sum += n3;
if (b4 && b1) sum += n4;
return normalize(sum);
}
}
int main()
{
for (int i = 0; i < H; i++)
for (int j = 0; j < W; j++)
normalmap[j][i] = GetNormal(j, i, 0);
}
loop_hmap
GetNormal()
的参数改变了函数计算边缘像素法线的方式。 1
应用于平铺纹理,如沙子和水。 0
应用于非平铺纹理,如物品、生物、树木。
对我来说,我自己的初始问题是无效的,它有一个错误!!!
I – original parametric surface with domain as cartesian product of [0,1] and range of it as euclidean space
II - normal to original surface
III - modified original surface with heightmap
IV - normal map which we want to receive with even ignoring geometric modification of the surface by “III”
最后一步 IV 包括很多要区分的东西:H(s,t) 和函数的原始定义...我不会对方程式进行进一步分析...但对我来说,您可以't 仅从(高度图)生成法线贴图...
P.S。要执行进一步的分析,如果你想从那个地方检索 *.docx 文件 https://yadi.sk/d/Qqx-jO1Ugo3uL 据我所知,不可能将 ms word 中的公式转换为乳胶,但无论如何请将其用作草稿。