在球体上从一点移动到另一点

时间:2012-10-17 12:59:19

标签: matrix glsl vector-graphics cinder

我正在使用基于GPU的粒子系统。 通过将x,y,z位置作为rgb值传递到1024 * 1024纹理来计算100万个粒子。他们的速度也在做同样的事情。

我正试图让它们从任意点移动到球体上的某个点。

我当前用于计算的着色器正在从一个点直接移动到另一个点。

我目前没有使用质量或速度纹理

// float mass   = texture2D( posArray, texCoord.st).a;
vec3 p      = texture2D( posArray, texCoord.st).rgb;
// vec3 v       = texture2D( velArray, texCoord.st).rgb;

// map into 'cinder space'
p = (p * - 1.0) + 0.5;

// vec3 acc = -0.0002*p; // Centripetal force
// vec3 ayAcc  = 0.00001*normalize(cross(vec3(0, 1 ,0),p)); // Angular force
// vec3 new_v  = v + mass*(acc+ayAcc);

vec3 new_p = p + ((moveToPos - p) / duration);

// map out of 'cinder space'
new_p = (new_p - 0.5) * -1.0;

gl_FragData[0] = vec4(new_p.x, new_p.y, new_p.z, mass);
//gl_FragData[1] = vec4(new_v.x, new_v.y, new_v.z, 1.0);

moveToPos是一个浮动鼠标指针(0.0f> 1.0f) 坐标系从(0.5,0.5> -0.5,-0.5)转换为(0.0,0.0> 1.0,1.0)

我对矢量数学完全陌生,而且计算让我感到困惑。我知道我需要使用公式:

X =Rsinφcosθ

Y =Rsinφsinθ

Z =Rcosφ

但是从moveToPos(xyz)计算角度> p(xyz)仍然存在问题

2 个答案:

答案 0 :(得分:1)

几年前我写了这个GPU粒子着色器的原始版本(现在是@:https://github.com/num3ric/Cinder-Particles)。对您的问题,一种可能的方法

我将从片段着色器开始,向粒子施加弹力,使它们或多或少地被约束到球体表面。像这样:

uniform sampler2D posArray;
uniform sampler2D velArray;
varying vec4 texCoord;

void main(void)
{   
    float mass  = texture2D( posArray, texCoord.st).a;
    vec3 p      = texture2D( posArray, texCoord.st).rgb;
    vec3 v      = texture2D( velArray, texCoord.st).rgb;

    float x0    = 0.5; //distance from center of sphere to be maintaned
    float x     = distance(p, vec3(0,0,0)); // current distance
    vec3 acc    = -0.0002*(x - x0)*p; //apply spring force (hooke's law)

    vec3 new_v  = v + mass*(acc);
    new_v = 0.999*new_v; // friction to slow down velocities over time
    vec3 new_p  = p + new_v;

    //Render to positions texture
    gl_FragData[0] = vec4(new_p.x, new_p.y, new_p.z, mass);
    //Render to velocities texture
    gl_FragData[1] = vec4(new_v.x, new_v.y, new_v.z, 1.0);
}

然后,我会传递一个新的vec3 uniform用于与相同半径的球体相交的鼠标位置(在Cinder中的着色器外部完成)。

现在,将其与之前的软弹簧约束相结合。您可以向此吸引点添加切向力。从一个简单的(mousePos - p)加速开始,然后找出一种方法,使用交叉产品使这个力完全相切。

我不确定球面坐标方法在这里是如何工作的。

  

X =Rsinφcosθ

     

Y =Rsinφsinθ

     

Z =Rcosφ

你在哪里获得φ和θ?纹理以笛卡尔坐标存储位置和速度。另外,来回转换不是一个真正的选择。

如果你对矢量感到不舒服,我的解释可能会太高级了。不幸的是,着色器和粒子动画本质上是非常数学的。

答案 1 :(得分:1)

这是我已经解决的一个解决方案 - 它可以工作,但是如果我将球体的中心点移动到他们自己的边界之外,我会失去粒子。

#define NPEOPLE 5

uniform sampler2D posArray;
uniform sampler2D velArray;

uniform vec3 centerPoint[NPEOPLE];
uniform float radius[NPEOPLE];
uniform float duration;

varying vec4 texCoord;

void main(void) {

    float personToGet   = texture2D( posArray, texCoord.st).a;
    vec3 p              = texture2D( posArray, texCoord.st).rgb;

    float mass          = texture2D( velArray, texCoord.st).a;
    vec3 v              = texture2D( velArray, texCoord.st).rgb;

    // map into 'cinder space'
    p = (p * - 1.0) + 0.5;

    vec3 vec_p = p - centerPoint[int(personToGet)];
    float len_vec_p = sqrt( ( vec_p.x * vec_p.x ) + (vec_p.y * vec_p.y) + (vec_p.z * vec_p.z) );
    vec_p = ( ( radius[int(personToGet)] /* mass */ ) / len_vec_p ) * vec_p;
    vec3 new_p = ( vec_p + centerPoint[int(personToGet)] );
    new_p = p + ( (new_p - p) / (duration) );

    // map out of 'cinder space'
    new_p = (new_p - 0.5) * -1.0;

    vec3 new_v = v;

    gl_FragData[0] = vec4(new_p.x, new_p.y, new_p.z, personToGet);
    gl_FragData[1] = vec4(new_v.x, new_v.y, new_v.z, mass);
}

我传递了5个vec3f的数组,并且浮点数被映射为5个中心点和半径。 粒子在开始时设置为随机位置,并朝向阵列中数字映射到位置数组的alpha值。

我的目标是从openCV传递blob数据并将球体映射到相机Feed上的人物。

此刻在视觉上真的无趣,所以需要使用速度纹理来增加粒子的行为。