如何基于线形点集生成偏移顶点以通过GL_TRIANGLE_STRIP绘制多边形轮廓
问题描述
我现有一组呈线形排列的点,如下图所示:
我需要生成一组与当前点集保持指定偏移距离的新点,最终可以通过GL_TRIANGLE_STRIP绘制出多边形轮廓形态,预期效果如下图:
以下是我当前编写的代码,但运行后无法得到预期的有效结果,请问该如何正确实现需求?
// outlineVertices are existing set of points from which we would generate the offsetPoints for (int i = 0; i < outlineVertices.size() - 3 ; i += 3) { finalVertices.push_back(outlineVertices[i]); finalVertices.push_back(outlineVertices[i + 1]); finalVertices.push_back(outlineVertices[i + 2]); glm::vec3 point1 = glm::vec3(outlineVertices[i], outlineVertices[i + 1], outlineVertices[i + 2]); glm::vec3 point2 = glm::vec3(outlineVertices[i + 7], outlineVertices[i + 1 + 7], outlineVertices[i + 2 + 7]); glm::vec4 directionVector = GetPerpendicularVectorDirection(point1, point2); finalVertices.push_back(outlineVertices[i] - (directionVector.x * outlineWidth )); finalVertices.push_back(outlineVertices[i + 1] + (directionVector.y * outlineWidth)); finalVertices.push_back(outlineVertices[i + 2]); finalVertices.push_back(outlineVertices[i + 3]); } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// glm::vec4 RectangleOutline::GetPerpendicularVectorDirection(glm::vec3 point1, glm::vec3 point2) { glm::vec3 Direction = glm::normalize(point1 - point2); float x, y; x = Direction.x; Direction.x = -y; Direction.y = x; return glm::vec4(Direction, 0); }
问题排查与修复方案
原有代码核心错误
- 垂直向量计算逻辑完全错误:
GetPerpendicularVectorDirection函数中y变量未初始化就被赋值给Direction.x,得到的是内存垃圾值,方向完全不对。正确的2D向量垂直转换逻辑为:对于方向向量(dx, dy),逆时针垂直向量为(-dy, dx),顺时针垂直向量为(dy, -dx)。 - 相邻点取址错误:循环中取下一个点的偏移量写为
i+7,但每个点占3个float存储,相邻下一个点的偏移应为i+3,取点错误导致方向计算完全偏离预期。 - 顶点组装逻辑混乱:GL_TRIANGLE_STRIP绘制线轮廓需要交替插入正负偏移点,原有逻辑额外插入了无意义的
outlineVertices[i+3],且没有处理转角处的法线平均,会导致拐角出现缺口。
修复后的实现代码
1. 修复垂直向量计算函数
// 输入两个点,返回两点方向的单位逆时针垂直向量 glm::vec3 GetPerpendicular(glm::vec3 p1, glm::vec3 p2) { glm::vec3 dir = glm::normalize(p2 - p1); // 2D垂直向量转换,z值保持不变 return glm::vec3(-dir.y, dir.x, 0.0f); }
2. 修正顶点生成逻辑(带转角miter处理)
float halfWidth = outlineWidth * 0.5f; int pointCount = outlineVertices.size() / 3; finalVertices.clear(); for (int i = 0; i < pointCount; i++) { glm::vec3 cur = glm::vec3( outlineVertices[i*3], outlineVertices[i*3 + 1], outlineVertices[i*3 + 2] ); glm::vec3 normal; if (i == 0) { // 起点只取下一段的垂直向量 glm::vec3 next = glm::vec3( outlineVertices[(i+1)*3], outlineVertices[(i+1)*3 + 1], outlineVertices[(i+1)*3 + 2] ); normal = GetPerpendicular(cur, next); } else if (i == pointCount - 1) { // 终点只取上一段的垂直向量 glm::vec3 prev = glm::vec3( outlineVertices[(i-1)*3], outlineVertices[(i-1)*3 + 1], outlineVertices[(i-1)*3 + 2] ); normal = GetPerpendicular(prev, cur); } else { // 中间点取前后两段垂直向量的平均,处理转角 glm::vec3 prev = glm::vec3( outlineVertices[(i-1)*3], outlineVertices[(i-1)*3 + 1], outlineVertices[(i-1)*3 + 2] ); glm::vec3 next = glm::vec3( outlineVertices[(i+1)*3], outlineVertices[(i+1)*3 + 1], outlineVertices[(i+1)*3 + 2] ); glm::vec3 n1 = GetPerpendicular(prev, cur); glm::vec3 n2 = GetPerpendicular(cur, next); normal = glm::normalize(n1 + n2); // 调整miter长度,避免尖角过度延伸 float miterLen = halfWidth / glm::dot(normal, n1); normal *= miterLen / halfWidth; } // 按三角带要求交替插入正负偏移点 glm::vec3 pLeft = cur + normal * halfWidth; glm::vec3 pRight = cur - normal * halfWidth; finalVertices.push_back(pLeft.x); finalVertices.push_back(pLeft.y); finalVertices.push_back(pLeft.z); finalVertices.push_back(pRight.x); finalVertices.push_back(pRight.y); finalVertices.push_back(pRight.z); }
内容的提问来源于stack exchange,提问作者Summit
相关产品推荐
相关产品推荐

