Fix particle radius and rgba start, middle, finish interpolation

Bezier interpolation of 3 points doesn't intersect the middle value.
Instead, use separate Bezier interpolations for start-middle and middle-
finish, so that the interpolated values intersect the middle value as a
user would expect.
This commit is contained in:
David Rowe 2015-12-22 15:08:03 +13:00
parent fc4ece5671
commit 58f1371eba
2 changed files with 45 additions and 7 deletions

View file

@ -71,7 +71,7 @@
Entities.editEntity(particles, {
radiusSpread: 0.0,
radiusStart: 0.0,
particleRadius: 2 * PARTICLE_RADIUS, // Bezier interpolation used means that middle value isn't intersected
particleRadius: PARTICLE_RADIUS,
radiusFinish: 0.0
});
break;

View file

@ -56,13 +56,51 @@ float bezierInterpolate(float y1, float y2, float y3, float u) {
return (1.0 - u) * (1.0 - u) * y1 + 2.0 * (1.0 - u) * u * y2 + u * u * y3;
}
vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) {
return vec4(bezierInterpolate(y1.x, y2.x, y3.x, u),
bezierInterpolate(y1.y, y2.y, y3.y, u),
bezierInterpolate(y1.z, y2.z, y3.z, u),
bezierInterpolate(y1.w, y2.w, y3.w, u));
float interpolate3Points(float y1, float y2, float y3, float u) {
// Makes the interpolated values intersect the middle value.
if ((u <= 0.5f && y1 == y2) || (u >= 0.5f && y2 == y3)) {
// Flat line.
return y2;
}
if ((y2 >= y1 && y2 >= y3) || (y2 <= y1 && y2 <= y3)) {
// U or inverted-U shape.
// Make the slope at y2 = 0, which means that the control points half way between the value points have the value y2.
if (u <= 0.5f) {
return bezierInterpolate(y1, y2, y2, 2.0f * u);
} else {
return bezierInterpolate(y2, y2, y3, 2.0f * u - 1.0f);
}
} else {
// L or inverted and/or mirrored L shape.
// Make the slope at y2 be the slope between y1 and y3, up to a maximum of double the minimum of the slopes between y1
// and y2, and y2 and y3. Use this slope to calculate the control points half way between the value points.
// Note: The maximum ensures that the control points and therefore the interpolated values stay between y1 and y3.
float slope = y3 - y1;
float slope12 = y2 - y1;
float slope23 = y3 - y2;
if (abs(slope) > abs(2.0f * slope12)) {
slope = 2.0f * slope12;
} else if (abs(slope) > abs(2.0f * slope23)) {
slope = 2.0f * slope23;
}
if (u <= 0.5f) {
return bezierInterpolate(y1, y2 - slope / 2.0f, y2, 2.0f * u);
} else {
return bezierInterpolate(y2, y2 + slope / 2.0f, y3, 2.0f * u - 1.0f);
}
}
}
vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) {
return vec4(interpolate3Points(y1.x, y2.x, y3.x, u),
interpolate3Points(y1.y, y2.y, y3.y, u),
interpolate3Points(y1.z, y2.z, y3.z, u),
interpolate3Points(y1.w, y2.w, y3.w, u));
}
void main(void) {
TransformCamera cam = getTransformCamera();
@ -82,7 +120,7 @@ void main(void) {
varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age);
// anchor point in eye space
float radius = bezierInterpolate(particle.radius.start, particle.radius.middle, particle.radius.finish, age);
float radius = interpolate3Points(particle.radius.start, particle.radius.middle, particle.radius.finish, age);
vec4 quadPos = radius * UNIT_QUAD[twoTriID];
vec4 anchorPoint;