将带参数法线的2D曲线挤出为3D模型时如何获得平滑法线?
问题描述
将正弦波曲线挤出为3D模型时,渲染后发现法线没有平滑效果。
该正弦波是通过参数法线生成的,代码如下:
vector<CurvePoint> sineWave(int n, float x0, float y0, float step, float period) { vector<CurvePoint> curve; for (int i = 0; i < n; i++) { float a = TWO_PI / period; float x = x0 + i * step; float y = y0 - sinf(x * a); float c = cosf(x * a); auto normal = glm::vec2(a * c, 1) / sqrtf(a * a * c * c + 1); curve.emplace_back(glm::vec2(x, y), normal); } return curve; }
使用的挤出方法代码如下:
void extrude(IndexedVertexBatch<XYZ.N> &batch, const Matrix &matrix, const vector<CurvePoint> &curve, GLenum frontFace, float distance) { auto size = curve.size(); if (size > 1 && distance != 0) { bool cw = ((frontFace == CW) && (distance > 0)) || ((frontFace == CCW) && (distance < 0)); for (auto i = 0; i < size - 1; i++) { auto &p0 = curve[i].position; auto &p1 = curve[i + 1].position; auto normal = matrix.transformNormal(glm::vec3(curve[i].normal, 0)); batch .addVertex(matrix.transformPoint(p0), normal) .addVertex(matrix.transformPoint(p1), normal) .addVertex(matrix.transformPoint(glm::vec3(p1, distance)), normal) .addVertex(matrix.transformPoint(glm::vec3(p0, distance)), normal); if (cw) { batch.addIndices(0, 3, 2, 2, 1, 0); } else { batch.addIndices(0, 1, 2, 2, 3, 0); } batch.incrementIndices(4); } } }
渲染采用类Phong(phong-like)着色,渲染效果如下:
解决方法
当前问题的核心是挤出逻辑中顶点法线赋值错误,导致相邻面的共享顶点法向量不连续,出现硬边效果,可按以下步骤修改:
- 修正法线赋值逻辑:你当前给同一段挤出面的4个顶点统一使用了当前段起点
curve[i]的法线,导致相邻段的共享顶点(前一段终点和后一段起点)法向量不一致。需要给每个顶点匹配其所属曲线上点的对应法线,p1对应的法线为curve[i+1].normal - 调整挤出代码的顶点法线绑定:
auto normal0 = matrix.transformNormal(glm::vec3(curve[i].normal, 0)); auto normal1 = matrix.transformNormal(glm::vec3(curve[i+1].normal, 0)); batch .addVertex(matrix.transformPoint(p0), normal0) .addVertex(matrix.transformPoint(p1), normal1) .addVertex(matrix.transformPoint(glm::vec3(p1, distance)), normal1) .addVertex(matrix.transformPoint(glm::vec3(p0, distance)), normal0);
- 确保顶点复用:如果你的顶点批处理默认不共享顶点,需要调整逻辑让相邻段的共享顶点(比如前一段的p1和后一段的p0)复用同一份顶点数据,避免相同位置的顶点被重复创建、携带不同法线
- 检查渲染管线配置:确认渲染时没有开启面法线覆盖顶点法线的选项,保证光照计算使用你传入的顶点法线
修改完成后,顶点法向量会沿正弦曲线平滑过渡,Phong着色的插值计算就会生成连续的平滑光照效果。
内容的提问来源于stack exchange,提问作者Ariel Malka
相关产品推荐
相关产品推荐

