虫洞效应:用 opengl 扭曲 space
Wormhole effect: warp space with opengl
我正在寻找一种方法来实现这样的虫洞效果:
- https://www.youtube.com/watch?v=WeOBXmLeJWo&feature=youtu.be&t=43s
我已经在示例中找到了不错的隧道,但这里涉及的更多一些。实际上 space 似乎以某种方式扭曲并且运动速度很快,所以它不仅仅是进入一个简单的隧道。知道如何做 space 变形部分吗?
我决定添加更多信息,因为这太宽泛了:
我有一个星系,这个星系中的每颗恒星都有 3d 坐标、大小等。我可以乘坐 space 飞船去拜访这些星星。有非常遥远的星星,要花很多时间才能到达它们,这就是为什么我需要曲速(比光速快)的原因。根据物理学,这不一定需要虫洞,但这个应用程序不必过于逼真。我不想用纯 OpenGL 解决这个问题。我们可以使用着色器。我想在加速到扭曲速度时扭曲屏幕中间的 space。之后会出现隧道效应,因为我认为以非常高的速度更新每颗星会消耗大量资源,所以我想只更新靠近的星。这不可能是预渲染动画,因为目的地并不总是确定的,所以这有时是探索目的,有时是旅行目的。我认为仅扭曲天空盒是不够的,但我对此不确定。
我要做的是简单地计算一个从屏幕中心的纹理坐标到您要着色的像素的纹理坐标的向量。
然后以您想要的任何方式修改该矢量(例如基于时间)并将其应用于您正在着色的像素的纹理坐标,然后使用生成的坐标对您的纹理进行采样。
在伪代码中,这将是这样的:
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 标签。如果您打算在没有着色器的情况下执行此操作,这将很难 and/or 效率低下。
那里发生了两件事:
space孔周围曲率
您需要构建描述 space 孔周围曲率的方程式,孔参数由孔参数 (mass,position,orientation)
和 time
参数化,这样您就可以对其进行动画处理。然后根据这个曲率你可以计算它周围 pixel/voxel 的相对位移。我将从半径由 hole
+/- 一些动画参数(需要实验)的距离的 sin
调制的圆柱形圆锥体开始。
像这样:
例如开始于(在虫洞本地坐标 LCS):
r = R * sin(z*0.5*M_PI/wormhole_max_depth)
然后用额外的热量调节它。 wormhole_max_depth,R
应该是时间的函数,甚至是线性的或者带有一些周期性的热,所以它有点脉动。
位移可以通过简单地计算相关点到锥体表面的距离并将其推向它越接近锥体来完成(锥体内体素被认为低于表面,因此应用最大位移强度)
particle/light/matter破洞
只有当 #1 已经完成时,我才会这样做。它应该是简单的粒子效果,在 #1 的锥体表面上有一些漂亮的圆形混合 alpha 纹理动画。我认为它在位置和速度上具有伪随机位移的循环很少...
技巧
这个主题取决于你想如何做到这一点。我看到了这些可能性:
渲染期间扭曲几何体(3D 矢量)
所以你可以直接在渲染的东西上应用圆锥位移。这在 GLSL 中最适用,但渲染的几何体必须具有足够小的基元才能在顶点级别上工作......
仅扭曲 skybox/stars(3D 矢量或 2D 光栅但对象不受影响)
所以你在天空盒的纹理坐标上或直接在星星位置上应用置换。
在第二遍中扭曲整个渲染场景(2D 光栅)
这需要使用 2 遍渲染,在第二遍中只将纹理坐标包裹在孔附近。
当你在每个扇区有不同的本地星星时,我会使用从星星目录(所有星星的列表)生成的星星背景,并直接在 3D 矢量 space 中对它们应用失真(所以没有天空盒。 . 选项 #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
是我的 class 对于齐次 4x4 变换矩阵(同时记住正矩阵和逆矩阵)函数 l2g
只是从局部坐标变换到全局坐标。圆锥体参数为:
R0
- 完全长大后的内锥半径
R1
- 完全长大后的外锥半径
H
- 圆锥体完全长大后的height/depth
t
- 是动画参数值 <0.0,1.0>
是生长,上面的值 1.0
是为虫洞完全生长的动画保留的
这是它的样子:
我正在寻找一种方法来实现这样的虫洞效果:
我已经在示例中找到了不错的隧道,但这里涉及的更多一些。实际上 space 似乎以某种方式扭曲并且运动速度很快,所以它不仅仅是进入一个简单的隧道。知道如何做 space 变形部分吗?
我决定添加更多信息,因为这太宽泛了:
我有一个星系,这个星系中的每颗恒星都有 3d 坐标、大小等。我可以乘坐 space 飞船去拜访这些星星。有非常遥远的星星,要花很多时间才能到达它们,这就是为什么我需要曲速(比光速快)的原因。根据物理学,这不一定需要虫洞,但这个应用程序不必过于逼真。我不想用纯 OpenGL 解决这个问题。我们可以使用着色器。我想在加速到扭曲速度时扭曲屏幕中间的 space。之后会出现隧道效应,因为我认为以非常高的速度更新每颗星会消耗大量资源,所以我想只更新靠近的星。这不可能是预渲染动画,因为目的地并不总是确定的,所以这有时是探索目的,有时是旅行目的。我认为仅扭曲天空盒是不够的,但我对此不确定。
我要做的是简单地计算一个从屏幕中心的纹理坐标到您要着色的像素的纹理坐标的向量。
然后以您想要的任何方式修改该矢量(例如基于时间)并将其应用于您正在着色的像素的纹理坐标,然后使用生成的坐标对您的纹理进行采样。
在伪代码中,这将是这样的:
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 标签。如果您打算在没有着色器的情况下执行此操作,这将很难 and/or 效率低下。
那里发生了两件事:
space孔周围曲率
您需要构建描述 space 孔周围曲率的方程式,孔参数由孔参数
(mass,position,orientation)
和time
参数化,这样您就可以对其进行动画处理。然后根据这个曲率你可以计算它周围 pixel/voxel 的相对位移。我将从半径由hole
+/- 一些动画参数(需要实验)的距离的sin
调制的圆柱形圆锥体开始。像这样:
例如开始于(在虫洞本地坐标 LCS):
r = R * sin(z*0.5*M_PI/wormhole_max_depth)
然后用额外的热量调节它。
wormhole_max_depth,R
应该是时间的函数,甚至是线性的或者带有一些周期性的热,所以它有点脉动。位移可以通过简单地计算相关点到锥体表面的距离并将其推向它越接近锥体来完成(锥体内体素被认为低于表面,因此应用最大位移强度)
particle/light/matter破洞
只有当 #1 已经完成时,我才会这样做。它应该是简单的粒子效果,在 #1 的锥体表面上有一些漂亮的圆形混合 alpha 纹理动画。我认为它在位置和速度上具有伪随机位移的循环很少...
技巧
这个主题取决于你想如何做到这一点。我看到了这些可能性:
渲染期间扭曲几何体(3D 矢量)
所以你可以直接在渲染的东西上应用圆锥位移。这在 GLSL 中最适用,但渲染的几何体必须具有足够小的基元才能在顶点级别上工作......
仅扭曲 skybox/stars(3D 矢量或 2D 光栅但对象不受影响)
所以你在天空盒的纹理坐标上或直接在星星位置上应用置换。
在第二遍中扭曲整个渲染场景(2D 光栅)
这需要使用 2 遍渲染,在第二遍中只将纹理坐标包裹在孔附近。
当你在每个扇区有不同的本地星星时,我会使用从星星目录(所有星星的列表)生成的星星背景,并直接在 3D 矢量 space 中对它们应用失真(所以没有天空盒。 . 选项 #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
是我的 class 对于齐次 4x4 变换矩阵(同时记住正矩阵和逆矩阵)函数 l2g
只是从局部坐标变换到全局坐标。圆锥体参数为:
R0
- 完全长大后的内锥半径R1
- 完全长大后的外锥半径H
- 圆锥体完全长大后的height/deptht
- 是动画参数值<0.0,1.0>
是生长,上面的值1.0
是为虫洞完全生长的动画保留的
这是它的样子: