Image Based Flow Visualization
IBFV(Image Based Flow Visualization)是利用噪点图(noise image)来模拟向量场运动的一种可视化方法。为了了解IBFV,先来看看它的原理。如下图
从上图中可以看到,在一个2D向量场(vector field)中有很多样点(sampling),这些样点都在网格(grid)上。每个样点受到向量场的影响,在Δt时刻后,产生速度和位移。由于向量场的影响,网格就要发生变形,如上图中的(warped grid)。然后,我们再用噪点图作为网格的texture,和flow texture进行混合(blending)。上图中map texture,inject nosie和flow texture是个循环的过程,这样就能产生像流动一样的效果。要注意的是,这里不能只使用一张噪点图,因为我们想到得到动画的效果。所以我们可以预先用代码随机的生成很多张。
{
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures(NOISE+1, tex);
int phase[NSIZE][NSIZE];
float noise[NSIZE][NSIZE][2];
for(int i=0; i<NSIZE;i++)
for(int j=0; j<NSIZE;j++)
phase[i][j] = rand() % 256;
for(int k=0;k<NOISE;k++)
{
int t = k*256/NOISE;
for(int i=0;i<NSIZE;i++)
for(int j=0;j<NSIZE;j++)
{
noise[i][j][0] = f((t+phase[i][j]) % 256);
noise[i][j][1] = alpha;
}
glBindTexture(GL_TEXTURE_2D, tex[k]);
glTexImage2D(GL_TEXTURE_2D, 0 , GL_LUMINANCE_ALPHA, NSIZE, NSIZE, 0,
GL_LUMINANCE_ALPHA, GL_FLOAT, noise);
}
}
上面的代码随机生成噪点图。有了噪点图我们就可以在进行对网格贴图的时候,顺序的取出噪点图。下面来看看如何计算向量场对网格的影响。假设向量场中一点p的位置为p(x,y),那么在 Δt时刻后,p’的位置为:
这里假设在很短的Δt时刻内,p做匀速直线运动。这样就可以得到2D向量场中每个样点受向量场影响在Δt时刻后的位置了。利用这个位置坐标作为噪点图的贴图坐标,然后和inject noise进行混合。然后重复这个步骤,就可以得到连续的动画效果,如下图。
如果我们在inject noise阶段,把inject noise用color map进行贴图,那么我们可以得到彩色的流动画。比如,我们用红色代表速度快的部分,蓝色代表速度慢的部分,如下图。
下面列出主要的pseudo代码
float f(int t)
{
return (t>127 ? 1: 0);
}
void advect()
{
for(int i = 0; i<N; i++)
{
glBegin(GL_POLYGON);
for(int j = 0; j<n(i); j++)
{
glTexCoord2f(xij, yij);
glVertex2f(xij+v(xij)*t , yij+v(yij)*t);
}
glEnd();
}
}
void inject()
{
glEnable(GL_BLEND);
glBindTexture(tex[frame % NOISE]);
glBegin(GL_QUADS);
glTexCoord2f(0,0); glVertex2f(0,0);
glTexCoord2f(T,0); glVertex2f(1,0);
glTexCoord2f(T,T); glVertex2f(1,1);
glTexCoord2f(0,T); glVertex2f(0,1);
glEnd();
glDisable(GL_BLEND);
}
void init(float alpha)
{
glViewport(0,0,ISIZE,ISIZE);
glMatrixMode(GL_PROJECTION);
glTranslatef(-1,-1,0);
glScalef(2,2,1);
glEnable(GL_TEXTURE_2D);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glGenTextures(NOISE+1, tex);
int phase[NSIZE][NSIZE];
float noise[NSIZE][NSIZE][2];
for(int i=0; i<NSIZE;i++)
for(int j=0; j<NSIZE;j++)
phase[i][j] = rand() % 256;
for(int k=0;k<NOISE;k++)
{
int t = k*256/NOISE;
for(int i=0;i<NSIZE;i++)
for(int j=0;j<NSIZE;j++)
{
noise[i][j][0] = f((t+phase[i][j]) % 256);
noise[i][j][1] = alpha;
}
glBindTexture(GL_TEXTURE_2D, tex[k]);
glTexImage2D(GL_TEXTURE_2D, 0 , GL_LUMINANCE_ALPHA, NSIZE, NSIZE, 0,
GL_LUMINANCE_ALPHA, GL_FLOAT, noise);
}
}
void run()
{
init(0.10);
for(;;frame++)
{
advect();
inject();
glBindTexture(GL_TEXTURE_2D, tex[NOISE]);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, SIZE, SIZE, 0)
}
}
*原创文章,转载请注明出处*