本文实现一个将网格绘制成一个个球形,并有一定的立体感特效,希望对大家有帮助。
整体效果如下:
![](https://img-blog.csdnimg.cn/8270c44f1e094afc8b3b2c717e34309b.png)
正常绘制的网格
![](https://img-blog.csdnimg.cn/0a4ac2e3f73b4cfebfc4846049223835.png)
球形模式绘制
单个球形最终效果:
![](https://img-blog.csdnimg.cn/9a5ded3f03274add952b220549b2386c.png)
单个球形
这里主要用的步骤有:
1. 网格绘制成点
这一步很简单,调用drawcall的时候使用点模式GL_POINTS就可以了。如:
glDrawArrays(GL_POINTS, 0, 3);
2. 点画圆
点画圆需要借助两个OpenGL内部变量:gl_PointSize、gl_PointCoord。
- gl_PointSize:一个点占屏幕多少个像素
- gl_PointCoord:一个像素在点区域的局部坐标,范围是[0.0~1.0]。
默认一个点只有一个像素,gl_PointSize可改变一个点占几个像素,前提是需要调用启用GL_VERTEX_PROGRAM_POINT_SIZE,调用glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
启用gl_PointSize需在Vertex Shader中指定,代码类似如下:
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
gl_PointSize = 100;
}
当指定点绘制大小之后,一个点会占用长宽是gl_PointSize像素的正方形区域。gl_PointCoord就是像素在这个区域的局部坐标,左上角是(0,0), 中心点是(0.5, 0.5), 右下角是(1.0, 1.0)。要想其变成圆形,需要丢弃一部分像素。这个需要在Fragment Shader中借助gl_PointCoord实现,丢弃方式就是根据像素点到圆心的距离,距离大于半径就丢弃:
vec2 coord = gl_PointCoord * 2.0 - vec2(1.0);
if (dot(coord, coord) > 1.0)
discard;
3. 立体感
立体感是通过颜色的明暗变化实现的。可以根据当前像素与圆心的距离确定一个颜色衰减因子,实现颜色的变化。下面代码中fNDotV就是衰减因子。
float dist = distance(gl_PointCoord, vec2(0.5));
float fNDotV = sqrt(1.0 - dist * dist * 4);
FragColor = vec4(vec3(1.0f, 0.5f, 0.2f)* fNDotV, 1.0);
衰减因子可以自己根据距离等规则进行调整。
最终的Fragment Shader的代码如下:
#version 330 core
out vec4 FragColor;
void main()
{
vec2 coord = gl_PointCoord * 2.0 - vec2(1.0);
if (dot(coord, coord) > 1.0)
discard;
float dist = distance(gl_PointCoord, vec2(0.5));
float fNDotV = sqrt(1.0 - dist * dist * 4);
FragColor = vec4(vec3(1.0f, 0.5f, 0.2f)* fNDotV, 1.0);
}