球体生成与渲染(细分法)
单纯生成球体的mesh很简单, 但是要保证mesh和uv对应, 并且在接缝处不出现问题还是会有一些麻烦的.
1. 细分算法
细分法很简单, 本质就是对一个三角形进行细分变成四个三角形

如图(网图, 侵删), 在三角形的三条边上取中点, ab, ac, bc, 这三个点减去球心, 得到从球心指向ab, ac, bc 的向量, 在做归一化, 乘以球体半径, 得到最终的ab, ac, bc. 对这六个点, 可以得到四个三角形
- ab, ac, bc
- a, ab, ac
- b, ab, bc
- c, bc, ac
然后对这四个三角形重复上面的步骤, 直到越来越接近一个完美的曲面.
2. 球体实现
具体实现方法, 首先我们准备一个正二十面体, 从这个二十面体细分出球体
1 | const double t = 1.61803; |
第二步细分
1 | for (var i = 0; i < subdivisions; i++) { |
1 | // 获取两点的中点 |
这样我们就得到了一个可以设置任意细分次数的球体mesh.
3. 计算uv和法线
球体的uv, 我们可以理解为经纬度.

对于纬度, 也就是上到下, 我们可以用a角表示

对于经度, 也就是左到右, 图片有点问题, 点应该在曲线上, 但是没啥影响. 也可以用, a和b的tan角表示

代码:
1 | var u = Math.Atan2(vector4.x, vector4.z) / (2.0f * Math.PI) + 0.5f |
法线更简单了, 球心到顶点的连线即为法线:
1 | var normal = vec.Normalize(); |
4. 问题:
实现完发现了一个问题, 在接缝处会出现明显的纹理被压缩的画面.


可以看到, 在最左边到最右边的接缝区域, 三角形纹理采样有问题.
这是因为会出现有三角形的两个顶点的uv坐标是跨越了左右边缘的情况, 比如顶点A的uv.x是0.95, 顶点B的uv.x是0.1. 那么这个时候我们期望的uv差值应该是从0.95 -> 1.0 -> 0.1这个方向的, 但是实际情况确是0.95 -> 0.5 -> 0.1这个方向, 这个方向就几乎涵盖了整个纹理, 所以会出现在接缝区域的纹理被压缩的感觉.
这种情况话, 把顶点B的uv.x改为1.1也是没用的, 因为对于下一个三角形, 本来是0.1 ~ 0.3, 现在变成1.1 ~ 0.3, 方向还是错误的.
解决办法:
没有想到特别好的解决办法, 目前想的方法是在接缝区域的三角形多生成一个顶点, 还是上面的例子, 顶点A和顶点B, 在顶点B的位置多加一个顶点C, 顶点C的uv.x为1.1, 顶点A和顶点C位接缝处的三角形, 而顶点B为下一个三角形的顶点.
这样就可以解决接缝处uv采样错误的问题了.