我已经编写了一些代码来生成一个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));
}