Как сгладить поверхности сетки с помощью алгоритма усреднения нормалей? - PullRequest
0 голосов
/ 04 июля 2018

Во многих программах 3D-дизайна, таких как Blender и 3D Studio Max, вы можете выбрать, какие поверхности формы вы хотите сгладить, а не твердые и плоские. Это означает усреднение (я полагаю) нормалей вершин, которые находятся в той же позиции, что и конкретная вершина. Я пытаюсь написать что-то в этом роде, но я делаю это впервые, и способ, которым я придумал, должен быть действительно неэффективным, и я считаю, что это не ^ 2 временная сложность. Итак, если у нас есть трехмерная фигура с 99 вершинами, то цикл должен выполняться 99 x 99 раз, почти 10000 раз.

С шариком это легко, так как нормаль каждой вершины - это просто нормализованная позиция вершины (единичный вектор положения). Я могу сделать это легко, как показано ниже:

enter image description here

Мне было интересно, как эти программы делают это и есть ли более эффективный способ, чем этот. Мой метод состоит в том, чтобы пройти через i от 0 до 99 и j от 0 до 99. Я в основном прохожу и проверяю, имеет ли другая вершина такое же положение, если так, я проверяю, есть ли угол между ее нормалью и нормалью другой вершины. находится под желаемым угловым порогом. Если так, я добавляю это к сумме вектора, тогда я делю на число вершин, которые были сопоставлены. Я не уверен, что это правильно.

#include <iostream>
#include <vector>
#include <math.h>

using namespace std;

float thresholdAngle = 60 /*degrees*/ / 180 * 3.14159; // In radians

struct vec3
{
    float x, y, z;
    bool hasSamePositionAs(vec3& other)
    {
        if (other.x == this->x &&
            other.y == this->y &&
            other.z == this->z)
            return true;
        return false;
    }

    bool angleIsUnderThresholdWith(vec3& other)
    {//THIS SHOULD BE IF DOTPRODUCT > COS(THRESHOLDANGLE)
        return dotProductWith(other) < thresholdAngle ? true : false;
    }

    float dotProductWith(vec3& other)
    {
        return x * other.x + y * other.y + z * other.z;
    }

    void operator +=(vec3 other) { x += other.x; y += other.y; z + other.z; }

int main() 
{
    // 33 triangles, 99 vertices
    vector<vec3> vertices(99); // ALL UNIT VECTORS, NORMALS
    vector<vec3> newNormals(99);

    for (int i = 0; i < 99; i++)
    {
        vec3 normal = vertices[i];

        for (int j = 0; j < 99; j++)
        {
            if (j == i) continue;
            if (vertices[i].hasSamePositionAs(vertices[j]))
            {
                if (vertices[i].angleIsUnderThresholdWith(vertices[j]))
                {
                    normal += vertices[j];
                }
            }
        }

        normalise(normal);          
        newNormals[i] = normal;
        }
    }

Редактировать: ОК, поэтому, используя этот код, мне удалось получить то, что мне было нужно, но алгоритм по-прежнему n ^ 2. Вы можете заметить, что синие линии, которые являются нормалями, разделены для каждой грани в виде плоской штриховки и объединены (усреднены) при прохождении через этот код.

enter image description here

...