背面剔除一个icosphere

时间:2017-05-14 17:01:00

标签: opengl-3

我已经编写了一些代码来生成一个icosphere(following the method described here)。它有效,除非我打开面部剔除我end up with this。我认为这仅仅是因为我与我的上弦顺序不一致。为了解决这个问题,我在这段代码中添加了

//need to make sure each triangle has a consistent winding order
for (int i = 0; i < indices.size(); i += 3) {
    int index1 = indices[i];
    int index2 = indices[i+1];
    int index3 = indices[i+2];

    glm::vec3 vertex1 = glm::vec3(vertices[3 * index1], vertices[3 * index1 + 1], vertices[3 * index1 + 2]);
    glm::vec3 vertex2 = glm::vec3(vertices[3 * index2], vertices[3 * index2 + 1], vertices[3 * index2 + 2]);
    glm::vec3 vertex3 = glm::vec3(vertices[3 * index3], vertices[3 * index3 + 1], vertices[3 * index3 + 2]);

    //switch vertex order if necessary
    if (!IsCorrectWindingOrder(vertex1, vertex2, vertex3)) {
        indices[i] = index3;
        indices[i + 2] = index1;
    }
} 

...

bool Sphere::IsCorrectWindingOrder(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3)
{
    glm::vec3 crossVec1 = p2 - p1;
    glm::vec3 crossVec2 = p3 - p1;
    glm::vec3 normal = glm::normalize(glm::cross(crossVec1, crossVec2));

    //center of sphere is at origin, so this is the vector from center of the triangle, to center of the sphere 
    glm::vec3 centerOfTriangle = glm::normalize(glm::vec3(
        (p1[0] + p2[0] + p3[0]) / 3.0f,
        (p1[1] + p2[1] + p3[1]) / 3.0f,
        (p1[2] + p2[2] + p3[2]) / 3.0f
    ));

    //The two vectors are either going to be the same, or negatives of each other.
    //The winding is correct if the normal is opposite the vector towards the center, 
    //since that means the 'front' of the triangle is on the outside of the sphere
    return normal[2] > 0 && centerOfTriangle[2] <= 0;
}

这种作品,因为现在我至少得到1 hemisphere,这似乎有一致的缠绕顺序。但是,我认为我必须误解一些非常基本的东西,因为如果我旋转视图,剔除不会更新,所以它很无用。我以为我可以直接确定三角形的哪一边是“前面”。使用绕线顺序,然后着色器将处理给定我的模型/视图/投影矩阵的所有更新。我错了吗?

编辑: 对于更多的上下文,这就是我生成球体的方式:

Sphere::Sphere() {
    std::vector<int> icosahedronIndices = {
        0,4,1,
        0,9,4,
        9,5,4,
        4,5,8,
        4,8,1,
        8,10,1,
        8,3,10,
        5,3,8,
        5,2,3,
        2,7,3,
        7,10,3,
        7,6,10,
        7,11,6,
        11,0,6,
        0,1,6,
        6,1,10,
        9,0,11,
        9,11,2,
        9,2,5,
        7,2,11
    };

    //http://www.opengl.org.ru/docs/pg/0208.html
    //chosen so that points are all 1 from the center
    float X = .525731112119133606;
    float Z = .850650808352039932;
    std::vector<float> icosahedronVertices = {
        -X, 0.0, Z,
         X, 0.0, Z,
        -X, 0.0, -Z,
         X, 0.0, -Z,
         0.0, Z, X,
         0.0, Z, -X,
         0.0, -Z, X,
         0.0, -Z, -X,
         Z, X, 0.0,
        -Z, X, 0.0,
         Z, -X, 0.0,
        -Z, -X, 0.0
    };

    Subdivide(icosahedronVertices, icosahedronIndices, 3);
    Inflate();

    //need to make sure each triangle has a consistent winding order
    for (int i = 0; i < indices.size(); i += 3) {
        int index1 = indices[i];
        int index2 = indices[i+1];
        int index3 = indices[i+2];

        glm::vec3 vertex1 = glm::vec3(vertices[3 * index1], vertices[3 * index1 + 1], vertices[3 * index1 + 2]);
        glm::vec3 vertex2 = glm::vec3(vertices[3 * index2], vertices[3 * index2 + 1], vertices[3 * index2 + 2]);
        glm::vec3 vertex3 = glm::vec3(vertices[3 * index3], vertices[3 * index3 + 1], vertices[3 * index3 + 2]);

        //switch vertex order if necessary
        if (!IsCorrectWindingOrder(vertex1, vertex2, vertex3)) {
            indices[i] = index3;
            indices[i + 2] = index1;
        }
    }

    for (int i = 0; i < vertices.size(); i += 3) 
    {
        float tx = std::atan2(vertices[i], vertices[i+2]) / (2. * 3.14159) + 0.5;
        float ty = std::asin(vertices[i+1]) / 3.14159 + .5;
        textureCoordinates.push_back(tx);
        textureCoordinates.push_back(ty);
    }


}
//https://stackoverflow.com/questions/7687148/drawing-sphere-in-opengl-without-using-glusphere
//http://gamedev.stackexchange.com/questions/31308/algorithm-for-creating-spheres
void Sphere::Subdivide(std::vector<float> inputVertices, std::vector<int> inputIndices, int n) {
    vertices = {};
    indices = {};

    // input index --> new index
    std::map<int, int> indexDict;
    // two input indices --> new index of the midpoint between them
    std::map<std::pair<int,int>, int> midpointDict;

    for (int i = 0; i < inputIndices.size(); i += 3) {
        int index1 = inputIndices[i];
        int index2 = inputIndices[i + 1];
        int index3 = inputIndices[i + 2];

        std::vector<float> vertex1 = { inputVertices[3 * index1], inputVertices[3 * index1 + 1], inputVertices[3 * index1 + 2], };
        std::vector<float> vertex2 = { inputVertices[3 * index2], inputVertices[3 * index2 + 1], inputVertices[3 * index2 + 2], };
        std::vector<float> vertex3 = { inputVertices[3 * index3], inputVertices[3 * index3 + 1], inputVertices[3 * index3 + 2], };

        std::vector<float> midpoint12 = {};
        std::vector<float> midpoint13 = {};
        std::vector<float> midpoint23 = {};
        for (int j = 0; j < 3; j++) {
            midpoint12.push_back(vertex2[j] + (vertex1[j] - vertex2[j]) / 2.0f);
            midpoint13.push_back(vertex3[j] + (vertex1[j] - vertex3[j]) / 2.0f);
            midpoint23.push_back(vertex3[j] + (vertex2[j] - vertex3[j]) / 2.0f);
        }

        int nextIndex = vertices.size() / 3;
        int newIndex1, newIndex2, newIndex3, newIndex12, newIndex13, newIndex23;

        newIndex12 = GetMidpointIndex(index1, index2, midpoint12, &nextIndex, &midpointDict);
        newIndex13 = GetMidpointIndex(index1, index3, midpoint13, &nextIndex, &midpointDict);
        newIndex23 = GetMidpointIndex(index2, index3, midpoint23, &nextIndex, &midpointDict);

        newIndex1 = GetUpdatedIndex(index1, vertex1, &nextIndex, &indexDict);
        newIndex2 = GetUpdatedIndex(index2, vertex2, &nextIndex, &indexDict);
        newIndex3 = GetUpdatedIndex(index3, vertex3, &nextIndex, &indexDict);

        indices.push_back(newIndex1);
        indices.push_back(newIndex13);
        indices.push_back(newIndex12);

        indices.push_back(newIndex2);
        indices.push_back(newIndex12);
        indices.push_back(newIndex23);

        indices.push_back(newIndex3);
        indices.push_back(newIndex13);
        indices.push_back(newIndex23);

        indices.push_back(newIndex12);
        indices.push_back(newIndex23);
        indices.push_back(newIndex13);
    }

    if(n > 1)
        Subdivide(vertices, indices, n-1);
}

bool Sphere::IsCorrectWindingOrder(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3)
{
    glm::vec3 crossVec1 = p2 - p1;
    glm::vec3 crossVec2 = p3 - p1;
    glm::vec3 normal = glm::normalize(glm::cross(crossVec1, crossVec2));

    //center of sphere is at origin, so this is the vector from center of the triangle, to center of the sphere 
    glm::vec3 centerOfTriangle = glm::normalize(glm::vec3(
        (p1[0] + p2[0] + p3[0]) / 3.0f,
        (p1[1] + p2[1] + p3[1]) / 3.0f,
        (p1[2] + p2[2] + p3[2]) / 3.0f
    ));

    //The two vectors are either going to be the same, or negatives of each other.
    //The winding is correct if the normal is opposite the vector towards the center, 
    //since that means the 'front' of the triangle is on the outside of the sphere
    return normal[2] > 0 && centerOfTriangle[2] <= 0;
}

int Sphere::GetMidpointIndex(int index1, int index2, std::vector<float> midpoint, int * nextIndex, std::map<std::pair<int, int>, int>* midpointDict)
{
    int newIndex;

    if (midpointDict->find(std::make_pair(index1, index2)) == midpointDict->end() &&
        midpointDict->find(std::make_pair(index2, index1)) == midpointDict->end()) {
        for (int j = 0; j < 3; j++) {
            vertices.push_back(midpoint[j]);
        }
        newIndex = *nextIndex;
        midpointDict->insert(std::pair<std::pair<int, int>, int>(std::make_pair(index1, index2), *nextIndex));
        (*nextIndex)++;
    }
    else {
        std::map<std::pair<int, int>, int>::iterator iter = midpointDict->find(std::make_pair(index1, index2));
        if (iter != midpointDict->end())
            newIndex = (*midpointDict)[std::make_pair(index1, index2)];
        else
            newIndex = (*midpointDict)[std::make_pair(index2, index1)];
    }

    return newIndex;
}

int Sphere::GetUpdatedIndex(int index, std::vector<float> vertex, int * nextIndex, std::map<int, int>* indexDict)
{
    int newIndex;
    if (indexDict->find(index) == indexDict->end()) {
        for (int j = 0; j < 3; j++) {
            vertices.push_back(vertex[j]);
        }

        newIndex = *nextIndex;
        indexDict->insert(std::pair<int, int>(index, *nextIndex));

        (*nextIndex)++;
    }
    else {
        newIndex = (*indexDict)[index];
    }

    return newIndex;
}

void Sphere::Inflate()
{
    for (int i = 0; i < vertices.size(); i += 3) {
        //assuming this is centered on the origin
        float dx = vertices[i]; 
        float dy = vertices[i+1];
        float dz = vertices[i+2];

        float currentDistance = std::powf(dx*dx + dy*dy + dz*dz, .5);
        //assuming radius = 1
        dx *= 1.0 / currentDistance;
        dy *= 1.0 / currentDistance;
        dz *= 1.0 / currentDistance;

        // = 0 + dx
        vertices[i] = dx;
        vertices[i+1] = dy;
        vertices[i+2] = dz;
    }
}

顶点着色器:

#version 330 core
layout (location = 0) in vec3 vertex;
layout (location = 1) in vec3 inputColor;
layout (location = 2) in vec3 position;
layout (location = 3) in vec2 textureCoordinate;
layout (location = 4) in int textureIndex;

out vec3 vertexColor;
flat out int texIndex;
out vec2 texCoord;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(vertex + position, 1.0f);
    vertexColor = inputColor;
    texCoord = textureCoordinate;
    texIndex = textureIndex;
}

片段着色器:

#version 330 core
in vec3 vertexColor;
in vec2 texCoord;
flat in int texIndex;

out vec4 color;
uniform sampler2DArray textures;

void main()
{
    color = texture(textures, vec3(texCoord, texIndex));
}

0 个答案:

没有答案