计算单独面上的平滑法线
Calculating smooth normals on seperate faces
我一直在尝试在生成的地形网格(平铺网格样式)上实现平滑的法线以发出平滑的照明,但是我只能实现平坦的阴影照明,我相信这可能与事实上所有的面都是分开的(虽然一些顶点可能有相同的位置)。
我四处寻找类似的问题,最接近的是:this question 但是我不确定如何实施他的百分比解决方案。
目前我有这段代码,它基于计算平滑法线的典型方法 - 但在我的例子中只能实现平面着色。
// Reset Normals
for (int i = 0; i < this->vertexCount; i++) {
this->vertices[i].normal = glm::vec3(0.0f);
}
// For each face
for (int i = 0; i < totalVerts; i += 3) {
auto index0 = indices ? this->indices[i] : i;
auto index1 = indices ? this->indices[i + 1] : i + 1;
auto index2 = indices ? this->indices[i + 2] : i + 2;
auto vertex0 = this->vertices[index0].position;
auto vertex1 = this->vertices[index1].position;
auto vertex2 = this->vertices[index2].position;
auto normal = glm::cross(vertex1 - vertex0, vertex2 - vertex0);
this->vertices[index0].normal += normal;
this->vertices[index1].normal += normal;
this->vertices[index2].normal += normal;
}
// Normalize
for (int i = 0; i < this->vertexCount; i++) {
this->vertices[i].normal = glm::normalize(this->vertices[i].normal);
}
我将如何改变它以在周围的面孔之间平滑? (至于为什么每个面都是分开的,是因为有些顶点可能具有特定属性,不能与其他面共享)
供您参考,获取面法线、顶点和顶点法线的工作代码是:
void get_vertices_and_normals_from_triangles(vector<triangle> &t, vector<vec3> &fn, vector<vec3> &v, vector<vec3> &vn)
{
// Face normals
fn.clear();
// Vertices
v.clear();
// Vertex normals
vn.clear();
if(0 == t.size())
return;
cout << "Triangles: " << t.size() << endl;
cout << "Welding vertices" << endl;
// Insert unique vertices into set.
set<indexed_vertex_3> vertex_set;
for(vector<triangle>::const_iterator i = t.begin(); i != t.end(); i++)
{
vertex_set.insert(i->vertex[0]);
vertex_set.insert(i->vertex[1]);
vertex_set.insert(i->vertex[2]);
}
cout << "Vertices: " << vertex_set.size() << endl;
cout << "Generating vertex indices" << endl;
vector<indexed_vertex_3> vv;
// Add indices to the vertices.
for(set<indexed_vertex_3>::const_iterator i = vertex_set.begin(); i != vertex_set.end(); i++)
{
size_t index = vv.size();
vv.push_back(*i);
vv[index].index = index;
}
for (size_t i = 0; i < vv.size(); i++)
{
vec3 vv_element(vv[i].x, vv[i].y, vv[i].z);
v.push_back(vv_element);
}
vertex_set.clear();
// Re-insert modifies vertices into set.
for(vector<indexed_vertex_3>::const_iterator i = vv.begin(); i != vv.end(); i++)
vertex_set.insert(*i);
cout << "Assigning vertex indices to triangles" << endl;
// Find the three vertices for each triangle, by index.
set<indexed_vertex_3>::iterator find_iter;
for(vector<triangle>::iterator i = t.begin(); i != t.end(); i++)
{
find_iter = vertex_set.find(i->vertex[0]);
i->vertex[0].index = find_iter->index;
find_iter = vertex_set.find(i->vertex[1]);
i->vertex[1].index = find_iter->index;
find_iter = vertex_set.find(i->vertex[2]);
i->vertex[2].index = find_iter->index;
}
vertex_set.clear();
cout << "Calculating normals" << endl;
fn.resize(t.size());
vn.resize(v.size());
for(size_t i = 0; i < t.size(); i++)
{
vec3 v0;// = t[i].vertex[1] - t[i].vertex[0];
v0.x = t[i].vertex[1].x - t[i].vertex[0].x;
v0.y = t[i].vertex[1].y - t[i].vertex[0].y;
v0.z = t[i].vertex[1].z - t[i].vertex[0].z;
vec3 v1;// = t[i].vertex[2] - t[i].vertex[0];
v1.x = t[i].vertex[2].x - t[i].vertex[0].x;
v1.y = t[i].vertex[2].y - t[i].vertex[0].y;
v1.z = t[i].vertex[2].z - t[i].vertex[0].z;
fn[i] = cross(v0, v1);
fn[i] = normalize(fn[i]);
vn[t[i].vertex[0].index] = vn[t[i].vertex[0].index] + fn[i];
vn[t[i].vertex[1].index] = vn[t[i].vertex[1].index] + fn[i];
vn[t[i].vertex[2].index] = vn[t[i].vertex[2].index] + fn[i];
}
for (size_t i = 0; i < vn.size(); i++)
vn[i] = normalize(vn[i]);
}
将顶点数据填充到向量中的代码如下。请注意,三角形的未焊接顶点在以下对 vertex_data.push_back(v0.x); 等的调用中重建
void draw_mesh(void)
{
glUseProgram(render.get_program());
glUniformMatrix4fv(uniforms.render.proj_matrix, 1, GL_FALSE, &main_camera.projection_mat[0][0]);
glUniformMatrix4fv(uniforms.render.mv_matrix, 1, GL_FALSE, &main_camera.view_mat[0][0]);
glUniform1f(uniforms.render.shading_level, 1.0f);
vector<float> vertex_data;
for (size_t i = 0; i < triangles.size(); i++)
{
vec3 colour(0.0f, 0.8f, 1.0f);
size_t v0_index = triangles[i].vertex[0].index;
size_t v1_index = triangles[i].vertex[1].index;
size_t v2_index = triangles[i].vertex[2].index;
vec3 v0_fn(vertex_normals[v0_index].x, vertex_normals[v0_index].y, vertex_normals[v0_index].z);
vec3 v1_fn(vertex_normals[v1_index].x, vertex_normals[v1_index].y, vertex_normals[v1_index].z);
vec3 v2_fn(vertex_normals[v2_index].x, vertex_normals[v2_index].y, vertex_normals[v2_index].z);
vec3 v0(triangles[i].vertex[0].x, triangles[i].vertex[0].y, triangles[i].vertex[0].z);
vec3 v1(triangles[i].vertex[1].x, triangles[i].vertex[1].y, triangles[i].vertex[1].z);
vec3 v2(triangles[i].vertex[2].x, triangles[i].vertex[2].y, triangles[i].vertex[2].z);
vertex_data.push_back(v0.x);
vertex_data.push_back(v0.y);
vertex_data.push_back(v0.z);
vertex_data.push_back(v0_fn.x);
vertex_data.push_back(v0_fn.y);
vertex_data.push_back(v0_fn.z);
vertex_data.push_back(colour.x);
vertex_data.push_back(colour.y);
vertex_data.push_back(colour.z);
vertex_data.push_back(v1.x);
vertex_data.push_back(v1.y);
vertex_data.push_back(v1.z);
vertex_data.push_back(v1_fn.x);
vertex_data.push_back(v1_fn.y);
vertex_data.push_back(v1_fn.z);
vertex_data.push_back(colour.x);
vertex_data.push_back(colour.y);
vertex_data.push_back(colour.z);
vertex_data.push_back(v2.x);
vertex_data.push_back(v2.y);
vertex_data.push_back(v2.z);
vertex_data.push_back(v2_fn.x);
vertex_data.push_back(v2_fn.y);
vertex_data.push_back(v2_fn.z);
vertex_data.push_back(colour.x);
vertex_data.push_back(colour.y);
vertex_data.push_back(colour.z);
}
GLuint components_per_vertex = 9;
const GLuint components_per_normal = 3;
GLuint components_per_position = 3;
const GLuint components_per_colour = 3;
GLuint triangle_buffer;
glGenBuffers(1, &triangle_buffer);
GLuint num_vertices = static_cast<GLuint>(vertex_data.size()) / components_per_vertex;
glBindBuffer(GL_ARRAY_BUFFER, triangle_buffer);
glBufferData(GL_ARRAY_BUFFER, vertex_data.size() * sizeof(GLfloat), &vertex_data[0], GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "position"));
glVertexAttribPointer(glGetAttribLocation(render.get_program(), "position"),
components_per_position,
GL_FLOAT,
GL_FALSE,
components_per_vertex * sizeof(GLfloat),
NULL);
glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "normal"));
glVertexAttribPointer(glGetAttribLocation(render.get_program(), "normal"),
components_per_normal,
GL_FLOAT,
GL_TRUE,
components_per_vertex * sizeof(GLfloat),
(const GLvoid*)(components_per_position * sizeof(GLfloat)));
glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "colour"));
glVertexAttribPointer(glGetAttribLocation(render.get_program(), "colour"),
components_per_colour,
GL_FLOAT,
GL_TRUE,
components_per_vertex * sizeof(GLfloat),
(const GLvoid*)(components_per_normal * sizeof(GLfloat) + components_per_position * sizeof(GLfloat)));
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
glDeleteBuffers(1, &triangle_buffer);
}
我不确定你是否收到我的编辑通知。
我一直在尝试在生成的地形网格(平铺网格样式)上实现平滑的法线以发出平滑的照明,但是我只能实现平坦的阴影照明,我相信这可能与事实上所有的面都是分开的(虽然一些顶点可能有相同的位置)。
我四处寻找类似的问题,最接近的是:this question 但是我不确定如何实施他的百分比解决方案。
目前我有这段代码,它基于计算平滑法线的典型方法 - 但在我的例子中只能实现平面着色。
// Reset Normals
for (int i = 0; i < this->vertexCount; i++) {
this->vertices[i].normal = glm::vec3(0.0f);
}
// For each face
for (int i = 0; i < totalVerts; i += 3) {
auto index0 = indices ? this->indices[i] : i;
auto index1 = indices ? this->indices[i + 1] : i + 1;
auto index2 = indices ? this->indices[i + 2] : i + 2;
auto vertex0 = this->vertices[index0].position;
auto vertex1 = this->vertices[index1].position;
auto vertex2 = this->vertices[index2].position;
auto normal = glm::cross(vertex1 - vertex0, vertex2 - vertex0);
this->vertices[index0].normal += normal;
this->vertices[index1].normal += normal;
this->vertices[index2].normal += normal;
}
// Normalize
for (int i = 0; i < this->vertexCount; i++) {
this->vertices[i].normal = glm::normalize(this->vertices[i].normal);
}
我将如何改变它以在周围的面孔之间平滑? (至于为什么每个面都是分开的,是因为有些顶点可能具有特定属性,不能与其他面共享)
供您参考,获取面法线、顶点和顶点法线的工作代码是:
void get_vertices_and_normals_from_triangles(vector<triangle> &t, vector<vec3> &fn, vector<vec3> &v, vector<vec3> &vn)
{
// Face normals
fn.clear();
// Vertices
v.clear();
// Vertex normals
vn.clear();
if(0 == t.size())
return;
cout << "Triangles: " << t.size() << endl;
cout << "Welding vertices" << endl;
// Insert unique vertices into set.
set<indexed_vertex_3> vertex_set;
for(vector<triangle>::const_iterator i = t.begin(); i != t.end(); i++)
{
vertex_set.insert(i->vertex[0]);
vertex_set.insert(i->vertex[1]);
vertex_set.insert(i->vertex[2]);
}
cout << "Vertices: " << vertex_set.size() << endl;
cout << "Generating vertex indices" << endl;
vector<indexed_vertex_3> vv;
// Add indices to the vertices.
for(set<indexed_vertex_3>::const_iterator i = vertex_set.begin(); i != vertex_set.end(); i++)
{
size_t index = vv.size();
vv.push_back(*i);
vv[index].index = index;
}
for (size_t i = 0; i < vv.size(); i++)
{
vec3 vv_element(vv[i].x, vv[i].y, vv[i].z);
v.push_back(vv_element);
}
vertex_set.clear();
// Re-insert modifies vertices into set.
for(vector<indexed_vertex_3>::const_iterator i = vv.begin(); i != vv.end(); i++)
vertex_set.insert(*i);
cout << "Assigning vertex indices to triangles" << endl;
// Find the three vertices for each triangle, by index.
set<indexed_vertex_3>::iterator find_iter;
for(vector<triangle>::iterator i = t.begin(); i != t.end(); i++)
{
find_iter = vertex_set.find(i->vertex[0]);
i->vertex[0].index = find_iter->index;
find_iter = vertex_set.find(i->vertex[1]);
i->vertex[1].index = find_iter->index;
find_iter = vertex_set.find(i->vertex[2]);
i->vertex[2].index = find_iter->index;
}
vertex_set.clear();
cout << "Calculating normals" << endl;
fn.resize(t.size());
vn.resize(v.size());
for(size_t i = 0; i < t.size(); i++)
{
vec3 v0;// = t[i].vertex[1] - t[i].vertex[0];
v0.x = t[i].vertex[1].x - t[i].vertex[0].x;
v0.y = t[i].vertex[1].y - t[i].vertex[0].y;
v0.z = t[i].vertex[1].z - t[i].vertex[0].z;
vec3 v1;// = t[i].vertex[2] - t[i].vertex[0];
v1.x = t[i].vertex[2].x - t[i].vertex[0].x;
v1.y = t[i].vertex[2].y - t[i].vertex[0].y;
v1.z = t[i].vertex[2].z - t[i].vertex[0].z;
fn[i] = cross(v0, v1);
fn[i] = normalize(fn[i]);
vn[t[i].vertex[0].index] = vn[t[i].vertex[0].index] + fn[i];
vn[t[i].vertex[1].index] = vn[t[i].vertex[1].index] + fn[i];
vn[t[i].vertex[2].index] = vn[t[i].vertex[2].index] + fn[i];
}
for (size_t i = 0; i < vn.size(); i++)
vn[i] = normalize(vn[i]);
}
将顶点数据填充到向量中的代码如下。请注意,三角形的未焊接顶点在以下对 vertex_data.push_back(v0.x); 等的调用中重建
void draw_mesh(void)
{
glUseProgram(render.get_program());
glUniformMatrix4fv(uniforms.render.proj_matrix, 1, GL_FALSE, &main_camera.projection_mat[0][0]);
glUniformMatrix4fv(uniforms.render.mv_matrix, 1, GL_FALSE, &main_camera.view_mat[0][0]);
glUniform1f(uniforms.render.shading_level, 1.0f);
vector<float> vertex_data;
for (size_t i = 0; i < triangles.size(); i++)
{
vec3 colour(0.0f, 0.8f, 1.0f);
size_t v0_index = triangles[i].vertex[0].index;
size_t v1_index = triangles[i].vertex[1].index;
size_t v2_index = triangles[i].vertex[2].index;
vec3 v0_fn(vertex_normals[v0_index].x, vertex_normals[v0_index].y, vertex_normals[v0_index].z);
vec3 v1_fn(vertex_normals[v1_index].x, vertex_normals[v1_index].y, vertex_normals[v1_index].z);
vec3 v2_fn(vertex_normals[v2_index].x, vertex_normals[v2_index].y, vertex_normals[v2_index].z);
vec3 v0(triangles[i].vertex[0].x, triangles[i].vertex[0].y, triangles[i].vertex[0].z);
vec3 v1(triangles[i].vertex[1].x, triangles[i].vertex[1].y, triangles[i].vertex[1].z);
vec3 v2(triangles[i].vertex[2].x, triangles[i].vertex[2].y, triangles[i].vertex[2].z);
vertex_data.push_back(v0.x);
vertex_data.push_back(v0.y);
vertex_data.push_back(v0.z);
vertex_data.push_back(v0_fn.x);
vertex_data.push_back(v0_fn.y);
vertex_data.push_back(v0_fn.z);
vertex_data.push_back(colour.x);
vertex_data.push_back(colour.y);
vertex_data.push_back(colour.z);
vertex_data.push_back(v1.x);
vertex_data.push_back(v1.y);
vertex_data.push_back(v1.z);
vertex_data.push_back(v1_fn.x);
vertex_data.push_back(v1_fn.y);
vertex_data.push_back(v1_fn.z);
vertex_data.push_back(colour.x);
vertex_data.push_back(colour.y);
vertex_data.push_back(colour.z);
vertex_data.push_back(v2.x);
vertex_data.push_back(v2.y);
vertex_data.push_back(v2.z);
vertex_data.push_back(v2_fn.x);
vertex_data.push_back(v2_fn.y);
vertex_data.push_back(v2_fn.z);
vertex_data.push_back(colour.x);
vertex_data.push_back(colour.y);
vertex_data.push_back(colour.z);
}
GLuint components_per_vertex = 9;
const GLuint components_per_normal = 3;
GLuint components_per_position = 3;
const GLuint components_per_colour = 3;
GLuint triangle_buffer;
glGenBuffers(1, &triangle_buffer);
GLuint num_vertices = static_cast<GLuint>(vertex_data.size()) / components_per_vertex;
glBindBuffer(GL_ARRAY_BUFFER, triangle_buffer);
glBufferData(GL_ARRAY_BUFFER, vertex_data.size() * sizeof(GLfloat), &vertex_data[0], GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "position"));
glVertexAttribPointer(glGetAttribLocation(render.get_program(), "position"),
components_per_position,
GL_FLOAT,
GL_FALSE,
components_per_vertex * sizeof(GLfloat),
NULL);
glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "normal"));
glVertexAttribPointer(glGetAttribLocation(render.get_program(), "normal"),
components_per_normal,
GL_FLOAT,
GL_TRUE,
components_per_vertex * sizeof(GLfloat),
(const GLvoid*)(components_per_position * sizeof(GLfloat)));
glEnableVertexAttribArray(glGetAttribLocation(render.get_program(), "colour"));
glVertexAttribPointer(glGetAttribLocation(render.get_program(), "colour"),
components_per_colour,
GL_FLOAT,
GL_TRUE,
components_per_vertex * sizeof(GLfloat),
(const GLvoid*)(components_per_normal * sizeof(GLfloat) + components_per_position * sizeof(GLfloat)));
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
glDeleteBuffers(1, &triangle_buffer);
}
我不确定你是否收到我的编辑通知。