虫洞效应:用opengl扭曲空间

时间:2016-09-07 04:19:17

标签: opengl glsl webgl

我正在寻找一种方法来做这样的虫洞效果:

animation   - https://www.youtube.com/watch?v=WeOBXmLeJWo&feature=youtu.be&t=43s

我已经在示例中找到了很好的隧道,但这里涉及的内容更多一些。实际上,空间似乎以某种方式翘曲并且运动速度很快,所以它不仅仅是进入一个简单的隧道。任何想法如何做空间扭曲部分?

我决定添加更多信息,因为这太宽泛了:

我有一个星系,每个恒星在这个星系中都有一个三维坐标,大小等。我可以乘坐太空船参观这些星星。有非常遥远的恒星,它需要花费很多时间才能到达它们,这就是为什么我需要翘曲(比光速更快)的速度。根据物理学,这并不一定需要虫洞,但这个应用程序不一定过于现实。我不想用纯OpenGL来解决这个问题。我们可以使用着色器。当加速到翘曲速度时,我想扭曲屏幕中间的空间。之后会出现隧道效应,因为我认为它会消耗大量资源来以非常高的速度更新每颗星,因此我只想更新近星。这不是预呈现的动画,因为目的地并不总是确定的,因此这有时是探索目的,有时也是旅行目的。我不认为只有天空箱翘曲就足够了,但我不确定这一点。

2 个答案:

答案 0 :(得分:2)

那里有两件事:

  1. 洞周围的空间曲率

    您需要构建方程式来描述由孔参数(mass,position,orientation)time参数化的孔周围的空间曲率,以便您可以对其进行动画处理。然后,从这个曲率,您可以计算它周围的像素/体素的相对位移。我将从圆柱形锥体开始,其半径由sin +/-一些动画参数(需要实验)的hole调制。

    这样的事情:

    wormhole cone

    例如以(在虫洞局部坐标 LCS 中)开始:

    r = R * sin(z*0.5*M_PI/wormhole_max_depth)
    

    然后通过额外的温度调节它。 wormhole_max_depth,R应该是时间函数,甚至是线性的,或者是一些周期性的热,所以它会有点脉动。

    可以通过简单地计算相关点到锥面的距离并将其推向它而越靠近它的锥体(锥体体内被认为低于表面,因此应用最大位移强度)来完成位移

  2. 粒子/光线/物质从洞中爆裂

    只有当#1 完成时,我才会这样做。它应该是简单的粒子效果,在#1 的锥体表面上有一些漂亮的圆形混合alpha纹理。我认为在位置和速度上具有伪随机位移的循环很少......

  3. <强>技术

    此主题取决于您希望如何执行此操作。我看到了这些可能性:

    1. 渲染过程中扭曲几何体(3D矢量)

      因此,您可以直接在渲染的东西上应用锥体位移。这最适用于GLSL,但渲染的几何体必须具有足够小的基元,以使其在顶点级别上工作...

    2. 仅扭曲天空盒/星星(3D矢量或2D光栅,但物体不受影响)

      因此,您可以在天空盒的纹理坐标上或直接在星位上应用位移。

    3. 在第二遍(2D光栅)中扭曲整个渲染场景

      这需要使用2遍渲染,在第二遍中只需将纹理坐标包裹在孔附近。

    4. 当你在每个扇区中获得不同的局部星星时,我会使用星星目录中生成的星形背景(所有星星的列表)并直接在3D矢量空间中应用它们(因此没有天空盒..选项# 2 )。而且因为我的引擎已经出于同样的原因使用了这种表示和渲染。

      [Edit1]圆锥几何

      直到今天我没有太多时间这样做,所以我没有取得多大进展。我决定从锥形几何开始,所以这里是:

      class wormhole
          {
      public:
          reper rep;          // coordinate system transform matrix
          double R0,R1,H,t;   // radiuses,depth
      
          wormhole(){ R0=10.0; R1=100.0; H=50.0; t=0.0; };
          wormhole(wormhole& a){ *this=a; };
          ~wormhole(){};
          wormhole* operator = (const wormhole *a) { *this=*a; return this; };
          /*wormhole* operator = (const wormhole &a) { ...copy... return this; };*/
      
          void ah2xyz(double *xyz,double a,double h) // compute cone position from parameters a=<0,2pi>, h=<0,1>
              {
              double r,tt;
              tt=t; if (t>0.5) tt=0.5; r=2.0*R0*tt;           // inner radius R0
              tt=t; if (t>1.0) tt=1.0; r+=(R1-r)*h*h*tt;      // outer radius R1
              xyz[0]=r*cos(a);
              xyz[1]=r*sin(a);
              xyz[2]=H*h*tt;
              rep.l2g(xyz,xyz);
              }
          void draw_cone()
              {
              int e;
              double a,h,da=pi2*0.04,p[3];
              glColor3f(0.2,0.2,0.2);
              for (h=0.0;h<=1.0;h+=0.1){ glBegin(GL_LINE_STRIP); for (e=1,a=0.0;e;a+=da) { if (a>=pi2) { e=0; a=0.0; } ah2xyz(p,a,h); glVertex3dv(p); } glEnd(); }
              for (e=1,a=0.0;e;a+=da){ glBegin(GL_LINE_STRIP); for (h=0.0;h<=1.0;h+=0.1) { if (a>=pi2) { e=0; a=0.0; } ah2xyz(p,a,h); glVertex3dv(p); } glEnd(); }
              }
          } hole;
      

      其中rep是同类4x4变换矩阵(同时记住直接矩阵和逆矩阵)的类,函数l2g只是从局部坐标转换为全局。锥形参数为:

      • R0 - 完全成长时的内锥半径
      • R1 - 完全成长时的外锥半径
      • H - 完全成长时锥体的高度/深度
      • t - 动画参数值<0.0,1.0>是增长,1.0以上的值是为虫洞完全成长的动画保留的

      这是它的样子:

      cone geometry

答案 1 :(得分:1)

我要做的只是计算从屏幕中心的纹理坐标到您要着色的像素的纹理坐标的矢量。
然后以您想要的任何方式修改该向量(例如,基于时间)并将其应用于您要着色的像素的纹理坐标,然后使用生成的坐标对纹理进行采样。

在伪代码中,这将是这样的:

vec2 vector_to_screen_center = vec2(0.5) - texture_coordinate;
texture_coordinate += vector_to_screen_center * sin(time) * 0.1; // Time based modulation of the vector.
gl_FragColor = texture2D(screen_texture, texture_coordinate);

您的问题没有GLSL标记。如果您计划在没有着色器的情况下执行此操作,则这将很难和/或效率低下。