在pyglet中使用gl_points滚动starfield

时间:2012-09-18 04:33:30

标签: python opengl pyglet

对于我正在制作的游戏,我想实现一个滚动的星空。到目前为止,所有游戏都是从OpenGL原语中提取出来的,我想继续这个并且gl_points似乎是合适的。

我正在使用pyglet(python)并知道我可以实现这一点存储一大堆的位置或点更新它们并手动移动它们但我希望有一个更整洁的替代方案。

修改 回答伊恩马利特 我想我想问的是,如果我生成一堆点,是否有某种方法可以将它们放在某种表面或缓冲区上并在后台滚动它。

另外至于我在这个阶段想要产生什么样的星场所有我想要一个简单的单层进行自上而下的游戏,几乎就像你在小行星中所拥有的那样

2 个答案:

答案 0 :(得分:4)


无限程序星空模式

特色:视差滚动

基本配方是:

  • 种子随机发生器(每帧相同种子)
  • 生成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。然后通过滚动值(作为uniform vec2变量传递)更改每个顶点的输入XY屏幕位置(VS中的属性变量),如上所述。

一些脚注:

  • 您的顶点着色器中需要一个随机生成器。使用1D噪声纹理或have a look here实现它。
  • 如果你的星星的几何形状多于一个点(即你使用四边形,而不是点精灵),你需要更加小心屏幕包裹,以避免一些星形顶点包裹而其余部分没有的情况。这有点棘手,但可行。使用点精灵更简单。

答案 1 :(得分:1)

你能澄清什么样的星空吗? 2D滚动(用于侧面或顶部滚动游戏,可能有不同的图层)或3D(就像在一个不可思议的快速飞船中真正飞过星空一样)?

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

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

在后者中,我可以想到一些聪明的算法,但我建议只使用原始点(如果你感觉很奇怪,那就是点精灵);如果将GPU放在静态VBO或显示列表中,GPU可以处理此问题。如果你的积分很小,你可以一次扔掉几千,但没有任何明显的性能损失。