Is it possible generate normal map from heightmap

2019-04-03 02:51发布

问题:

My view is that you can not generate normal map only from height map texture? Am I right or not?

Math Arguments:

Assume that surface is given a continuous bijection from

S = [0,1]

T = [0,1]

Let's call SxT as image space.

It can be proved from differentional geometry that normal to that parametric surface is

If assume that mapping from SxT image space to geometric euclidian space is very simple then we can retrive:

Then you can calculate such partial derivatives with some difference scheme. We came to that simple formula, only with bold suggestion and this suggestion is absolutely not true.


Sample of the problem from graphics.

Let assume we have triangle in geometric eclidian space with 3 vertices. Terms are:

normalmap -- it is normal for point with (u,v,1-u-v) barycentric coordinates fetched from (u,v) from suitable 2d texture, and it is in local coord. system relative to triangle.

heihtmap -- it is geometric offset for point with (u,v,1-u-v) barycentric coordinates in normal direction relative to triangle localspace fetched from (u,v) from suitable 2d texture.

During building normalmap we absolutely ignore how heightmap is distributed near (u,v,1-u-v) eculidian point. And we retrive only some approximation of normal map.

回答1:

Ohh, looks like my comment was too brief.

It's easier to write a full answer with code to describe the method.

I'm going to use a pseudocode mix of C++ and 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 argument of GetNormal() changes how the function computes normals for edge pixels. 1 should be used for tiled textures, like sand and water. 0 should be used for nontiled textures, like items, mobs, trees.



回答2:

For me my own initial question is invalid and it has a bug!!!

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”

Final step IV includes a lot of stuff to differentiate: H(s,t) and original definition of the function...I don't perform futher analytic of that equations...But as for me you can't generate normalmap only from (heightmap)...

P.S. To perform futher analytics if you want to do it retrive *.docx file from that place https://yadi.sk/d/Qqx-jO1Ugo3uL As I know it impossible to convert formulas in ms word to latex, but in any case please use it asa draft.