2

对于我正在开发的游戏,我想实现一个滚动星空。到目前为止,所有游戏都是从 OpenGL 原语中绘制的,我想继续这个,gl_points 似乎很合适。

我正在使用 pyglet (python) 并且知道我可以存储一大堆的位置或点更新它们并手动移动它们,但我希望有一个更整洁的选择。

编辑: 在回答 Ian Mallett 时,我想我想问的是,如果我生成一堆点,有没有办法可以将这些点粘贴到某种表面或缓冲区上,并在后台滚动它。

此外,至于我在这个阶段想要生成什么样的星空,我正在尝试为自上而下的游戏创建一个简单的单层,几乎就像你在小行星中所拥有的那样

4

2 回答 2

3

无限的程序星场模式

特色:视差滚动

基本配方是:

  • 种子随机生成器(每帧相同的种子)
  • 生成 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 中准备你的星形几何。它可以是你想要的任何东西:一个顶点(对于一个点精灵),一个带纹理的四边形,任何东西。

  • 使用 渲染它glDrawArraysInstancedprimcount您想要的星数在哪里

  • 在您的顶点着色器中,从上面的伪代码中实现循环体,替换gl_InstanceIDi. 然后通过滚动值(作为变量传递)改变每个顶点的输入 XY 屏幕位置(VS 中的属性变量),uniform vec2如上所述。

一些脚注:

  • 您将需要在顶点着色器中使用随机生成器。使用 1D 噪声纹理实现它或查看这里
  • 如果您的星星的几何图形多于一个点(即您使用四边形,而不是点精灵),您需要更加小心屏幕环绕以避免出现星形环绕的某些顶点而其他顶点没有环绕的情况。这有点棘手,但可行。使用点精灵更简单。
于 2012-09-18T16:15:20.570 回答
1

你能澄清一下是什么样的星空吗?2D 滚动(对于侧面或顶部滚动游戏,可能有不同的层)或 3D(就像在难以置信的快速宇宙飞船中真正飞过星空)?

在前者中,纹理(或叠加混合的纹理层)可能是最干净和最快的方法。[编辑:纹理是迄今为止最好的方法,但如果你真的不想使用纹理,你可以执行以下操作,这是下一个最好的方法:

  • 制作一个静态 VBO 或显示点列表,其大小可能是滚动方向所需的六倍(例如,如果您正在运行 800x600 屏幕并且您正在水平滚动,则在 4800x600 网格上生成点)。
  • 绘制这些点两次,偏移宽度和滚动变量。例如,让 x 成为您的滚动变量(它从 0 开始,然后递增直到达到 4800(点的宽度),然后回绕并从 0 重新开始)。每一帧,用 glTranslatef(x,0,0) 绘制你的点。然后用 glTranslatef(x+4800,0,0) 再次绘制它们。
  • 通过这种方式,您的积分将看似连续滚动过去。常数(我在上面选择了六个)对算法并不重要。值越大,重复次数越少,但性能越慢。
  • 您也可以尝试使用不同的滚动常数多次执行上述所有操作,以产生深度错觉(具有多层)。

]

在后者中,我能想到很多聪明的算法,但我建议只使用原始点(如果你喜欢的话,点精灵);如果将 GPU 放在静态 VBO 或显示列表中,GPU 可以处理此问题。如果您的积分很小,您可能一次可以抛出几千个,而不会对性能造成任何明显影响。

于 2012-09-18T05:55:17.447 回答