无限的程序星场模式
(特色:视差滚动)
基本配方是:
- 种子随机生成器(每帧相同的种子)
生成 N 个随机点 (X,Y) 和一个“Z”值(比如每个点 0.5 ... 2)
翻译每个点的位置:(X,Y) += scrollXY * Z
这是棘手的部分。每个点都有不同的 Z 值,因此它们以不同的速度滚动。这称为“视差滚动”并产生惊人的效果。
包裹点(以屏幕大小为模)。
每帧使用相同的种子会给你一个随机的星场模式,但每帧都是持久的(仅由滚动值改变)。
有趣的事实
该算法可以很容易地修改,因此您不必将所有 N 个位置实际存储在内存中。您只需要一个生成器,它可以为您提供随机的基础 (X,Y) 坐标(和深度),并由一个常数值加上一些星号作为种子。
伪代码:
for (int i=0; i<1000; ++i) {
RandomGenerator rnd;
rnd.seed(SomeConstantSeed + i*10293);
// determine i-th star's position
var basePosition = vec2(rnd.next(800), rnd.next(600));
var depth = rnd.next(0.5, 2);
// parallax scrolling and wrapping
var realPosition = basePosition + scrollXY * depth;
var wrappedPosition = realPosition modulo vec2(800, 600);
// these are our coordinates! let's draw
renderStar(wrappedPosition);
}
在这里,每颗星都是按需生成的,我们不必在帧之间将其值保存在内存中。随机生成器种子保持不变就足以在每一帧生成相同的(但动画的)星场。
您可以使用相同的技术为每颗星分配不同的随机(但持久)颜色。
如何使用OpenGL高效实现?
最简单和最有效的方法是在顶点着色器中动态生成位置。
在 VBO 中准备你的星形几何。它可以是你想要的任何东西:一个顶点(对于一个点精灵),一个带纹理的四边形,任何东西。
使用 渲染它glDrawArraysInstanced
,primcount
您想要的星数在哪里
在您的顶点着色器中,从上面的伪代码中实现循环体,替换gl_InstanceID
为i
. 然后通过滚动值(作为变量传递)改变每个顶点的输入 XY 屏幕位置(VS 中的属性变量),uniform vec2
如上所述。
一些脚注:
- 您将需要在顶点着色器中使用随机生成器。使用 1D 噪声纹理实现它或查看这里。
- 如果您的星星的几何图形多于一个点(即您使用四边形,而不是点精灵),您需要更加小心屏幕环绕以避免出现星形环绕的某些顶点而其他顶点没有环绕的情况。这有点棘手,但可行。使用点精灵更简单。