Пересчитать нормали регулярной поверхности сетки (C ++ / OpenGL) - PullRequest
0 голосов
/ 01 октября 2019

Я пытаюсь вычислить нормали моей поверхности сетки. Карта имеет размер 29952px x 19968px, а каждая ячейка имеет размер 128px x 128px . Итак, у меня 36895 вершин.

Сетка:
Grid

Мой массив плоских карт отправляется шейдерам со следующей структурой:

float vertices[368950] = {

  //  x     y     z    znoise   xTex  yTex  xNorm yNorm zNorm Type
    16384,16256,-16256,   0,    0.54, 0.45,   0,    0,   1,    1,
    16256,16384,-16384,   0,    0.54, 0.45,   0,    0,   1,    1,
    ......
} 

Я вычисляюzNoise с функцией

float noise(float x, float y){};

И это работает (я добавляю его к y и z в вершинном шейдере) .

Метод 1

Если я вычислю нормали, используя метод конечных разностей , я получу хороший результат. Псевдокод:

  vec3 off = vec3(1.0, 1.0, 0.0);
  float hL = noise(P.xy - off.xz);
  float hR = noise(P.xy + off.xz);
  float hD = noise(P.xy - off.zy);
  float hU = noise(P.xy + off.zy);
  N.x = hL - hR;
  N.y = hD - hU;
  N.z = 2.0;
  N = normalize(N);

Но, в случае, если мне нужно отредактировать карту вручную, например, в контексте редактора, где вы устанавливаете zNoise с помощью инструмента для создания гор, как вы хотите, этот метод не поможет .

Я получаю этот замечательный результат (видно из миникарты) (Нормальные значения довольно темные):
nice result

Метод 2

  |    |    |
--6----1----+-
  |\   |\   |      Y
  | \  | \  |      ^
  |  \ |  \ |      |
  |   \|   \|      |
--5----+----2--    +-----> X
  |\   |\   |
  | \  | \  |
  |  \ |  \ |
  |   \|   \|
--+----4----3--
  |    |    |

Итак, я пытаюсь вычислить нормаль, используя соседние треугольники, но результат сильно отличается (кажется, что где-то есть ошибка):

Код.

getVertex() - это функция, которая принимает x, а y возвращает информацию о вершине, связанную с этой вершиной. VerticesPos - это массив 1d, который содержит позицию каждой вершины , чтобы иметь возможность получить информацию из vertices (той, которую я описал выше, с 10 значениями на вершину). я решил отредактировать y и z в вершинном шейдере, чтобы не трогать x и y и использовать их для индексации вершин до VerticesPos. (Надеюсь, это вполне понятно).

glm::vec3 getVertex(int x, int y) {

    int j = VerticesPos[(int)(y/128 * 29952 / 128 + x/128)];

    float zNoise = vertices[j * 10 + 3] * 2;
    float x1 = vertices[j * 10];
    float y1 = vertices[j * 10 + 1] + zNoise;
    float z1 = vertices[j * 10 + 2] + zNoise;

    return glm::vec3(x1, y1, z1);
}

getAdjacentVertices() - это функция, которая принимает vec2d (координаты x и y) и возвращает 6 соседних вершин , упорядоченных по часовой стрелке

std::array<glm::vec3, 6> getAdjacentVertices(glm::vec2 pos) {
    std::array<glm::vec3, 6> output;
    output = {
        getVertex(pos.x, pos.y + 128), // up
        getVertex(pos.x + 128, pos.y), // right 
        getVertex(pos.x + 128, pos.y - 128), // down-right
        getVertex(pos.x, pos.y - 128), // down
        getVertex(pos.x - 128, pos.y), // left
        getVertex(pos.x - 128, pos.y + 128), // up-left

    };
    return output;
}

И последняя функция, которая выполняет эту работу:

glm::vec3 mapgen::updatedNormals(glm::vec2 pos) {

    bool notBorderLineX = pos.x > 128 && pos.x < 29952 - 128;
    bool notBorderLineY = pos.y > 128 && pos.y < 19968 - 128;

    if (notBorderLineX && notBorderLineY) {

        glm::vec3 a = getVertex(pos.x, pos.y);

        std::array<glm::vec3, 6> adjVertices = getAdjacentVertices(pos);
        glm::vec3 sum(0.f);

        for (int i = 0; i < 6; i++) {
            int j;
            (i == 0) ? j = 5 : j = i - 1;

            glm::vec3 side1 = adjVertices[i] - a;
            glm::vec3 side2 = adjVertices[j] - a;

            sum += glm::cross(side1, side2);
        }
        return glm::normalize(sum);
    }

    else {
        return glm::vec3(0.3333f);
    }
}

Я получаю плохой результат (видно из миникарты), к сожалению:
bad result

Примечание. Здания находятся в разных положениях, но поверхность имеет одинаковое начальное число с использованием двух методов.

Возможнокто-нибудь поможет? : -)


РЕДАКТИРОВАТЬ:

Я добавляю больше изображений, чтобы помочь понять проблему. Метод 1: image

Метод 2: Image2

1 Ответ

0 голосов
/ 06 октября 2019

решено!

Я вычислял нормали в то же время, когда вычислял zNoise. Таким образом, возможно, что некоторые вершины были не в правильном Z.

Я решил вычислить раньше всех Z, а затем и всех нормалей. Я просто хочу поставить код:

struct Triangle {
    glm::vec3 a, b, c;
};
std::array<Triangle, 6> getAdjacentTriangles(glm::ivec2 pos) {
    int gap = 128;
    std::array<Triangle, 6> triangles;  
    triangles[0] = {
        getVertex(pos.x, pos.y), getVertex(pos.x - gap, pos.y),getVertex(pos.x - gap, pos.y + gap),
    };
    triangles[1] = {
        getVertex(pos.x, pos.y), getVertex(pos.x - gap, pos.y + gap), getVertex(pos.x, pos.y + gap)
    };
    triangles[2] = {
        getVertex(pos.x, pos.y), getVertex(pos.x, pos.y + gap), getVertex(pos.x + gap, pos.y)
    };
    triangles[3] = {
        getVertex(pos.x, pos.y), getVertex(pos.x + gap, pos.y), getVertex(pos.x + gap, pos.y - gap)
    };
    triangles[4] = {
        getVertex(pos.x, pos.y), getVertex(pos.x + gap, pos.y - gap),getVertex(pos.x, pos.y - gap),
    };
    triangles[5] = {
        getVertex(pos.x, pos.y), getVertex(pos.x, pos.y - gap), getVertex(pos.x - gap, pos.y)
    };
    return triangles;
}
glm::vec3 calculateTriangleNormal(Triangle T) {
    glm::vec3 N = glm::cross(T.c - T.a, T.b - T.a);
    return N;
}
void mapgen::updateNormals() {
    for (int i = 0; i < nVertices * 10; i += 10) {
        float xCoord = mapgen::MapVertices()[i];
        float yCoord = mapgen::MapVertices()[i + 1];
        glm::ivec2 pos = glm::ivec2(int(xCoord), int(yCoord));  
        if (pos.x > 128 && pos.x < 29952 - 128 && pos.y > 128 && pos.y < 19968 - 128) {

            std::array<Triangle, 6> adjacentTriangles = getAdjacentTriangles(pos);
            glm::vec3 sum(0.f);

            for (int i = 0; i < 6; i++) {
                glm::vec3 normal = calculateTriangleNormal(adjacentTriangles[i]);
                sum += normal;
            }
            glm::vec3 N = glm::normalize(sum);

            mapgen::MapVertices()[i + 6] = N.x;
            mapgen::MapVertices()[i + 7] = N.y;
            mapgen::MapVertices()[i + 8] = N.z;
        }
        else {
            mapgen::MapVertices()[i + 6] = 0.f;
            mapgen::MapVertices()[i + 7] = 0.f;
            mapgen::MapVertices()[i + 8] = 1.f;
        }
    }
}

Даааааа!

...