2022-06-25 11:52:00 +08:00

396 lines
16 KiB
SourcePawn

precision mediump float;
#include <particle-common>
#define MAX_KEY_NUM 8
#define CURVE_MODE_CONSTANT 0
#define CURVE_MODE_RANDOM_CONSTANT 1
#define CURVE_MODE_CURVE 2
#define CURVE_MODE_RANDOM_CURVE 3
#define GRADIENT_MODE_FIX 0
#define GRADIENT_MODE_BLEND 1
#define GRADIENT_RANGE_MODE_COLOR 0
#define GRADIENT_RANGE_MODE_TWO_COLOR 1
#define GRADIENT_RANGE_MODE_RANDOM_COLOR 2
#define GRADIENT_RANGE_MODE_GRADIENT 3
#define GRADIENT_RANGE_MODE_TWO_GRADIENT 4
#define SIMULATE_SPACE_LOCAL 0
#define SIMULATE_SPACE_WORLD 1
#define ANIMATION_MODE_WHOLE_SHEET 0
#define ANIMATION_MODE_SINGLE_ROW 1
#define COLOR_OVERTIME_RAND_OFFSET 91041.
#define FORCE_OVERTIME_RAND_OFFSET 212165.
#define ROTATION_OVERTIME_RAND_OFFSET 125292.
#define SIZE_OVERTIME_RAND_OFFSET 39825.
#define TEXTURE_ANIMATION_RAND_OFFSET 90794.
#define VELOCITY_OVERTIME_RAND_OFFSET 197866.
#define DECL_CURVE_STRUCT(name) \
uniform CurveStruct_##name## { \
int u_##name##_curveMode; \
float u_##name##_minConstant; \
float u_##name##_maxConstant; \
float u_##name##_minKeyTime[MAX_KEY_NUM]; \
vec4 u_##name##_minKeyCoef[MAX_KEY_NUM]; \
vec4 u_##name##_maxKeyCoef[MAX_KEY_NUM]; \
float u_##name##_maxKeyTime[MAX_KEY_NUM]; \
};
#define DECL_CURVE_STRUCT_INT(name) \
uniform CurveStructInt_##name## { \
int u_##name##_curveMode; \
float u_##name##_minConstant; \
float u_##name##_maxConstant; \
float u_##name##_minKeyTime[MAX_KEY_NUM]; \
vec4 u_##name##_minKeyCoef[MAX_KEY_NUM]; \
vec4 u_##name##_maxKeyCoef[MAX_KEY_NUM]; \
float u_##name##_maxKeyTime[MAX_KEY_NUM]; \
float u_##name##_minIntegral[MAX_KEY_NUM - 1]; \
float u_##name##_maxIntegral[MAX_KEY_NUM - 1]; \
};
#define DECL_GRADIENT_STRUCT(name) \
uniform GradientStruct_##name## { \
int u_##name##_rangeMode; \
int u_##name##_minGradMode; \
int u_##name##_maxGradMode; \
vec4 u_##name##_minColor; \
vec4 u_##name##_maxColor; \
vec3 u_##name##_minColorKeyValue[MAX_KEY_NUM]; \
float u_##name##_minColorKeyTime[MAX_KEY_NUM]; \
float u_##name##_minAlphaKeyValue[MAX_KEY_NUM]; \
float u_##name##_minAlphaKeyTime[MAX_KEY_NUM]; \
vec3 u_##name##_maxColorKeyValue[MAX_KEY_NUM]; \
float u_##name##_maxColorKeyTime[MAX_KEY_NUM]; \
float u_##name##_maxAlphaKeyValue[MAX_KEY_NUM]; \
float u_##name##_maxAlphaKeyTime[MAX_KEY_NUM]; \
};
#define EVAL_CURVE_RANGE(name, t, rnd) \
evaluateCurveRange(u_##name##_curveMode, u_##name##_minConstant, u_##name##_maxConstant, u_##name##_minKeyTime, u_##name##_minKeyCoef, u_##name##_maxKeyTime, u_##name##_maxKeyCoef, t, rnd)
#define EVAL_CURVE_INTEGRAL(name, t, ts, rnd) \
evaluateCurveRangeIntegral(u_##name##_curveMode, u_##name##_minConstant, u_##name##_maxConstant, u_##name##_minKeyTime, u_##name##_minKeyCoef, u_##name##_minIntegral, u_##name##_maxKeyTime, u_##name##_maxKeyCoef, u_##name##_maxIntegral, t, ts, rnd)
#define EVAL_CURVE_INTEGRAL_TWICE(name, t, ts, rnd) \
evaluateCurveRangeIntegralTwice(u_##name##_curveMode, u_##name##_minConstant, u_##name##_maxConstant, u_##name##_minKeyTime, u_##name##_minKeyCoef, u_##name##_minIntegral, u_##name##_maxKeyTime, u_##name##_maxKeyCoef, u_##name##_maxIntegral, t, ts, rnd)
#define EVAL_GRADIENT_RANGE(name, t, rnd) \
evaluateGradientRange(u_##name##_rangeMode, u_##name##_minColor, u_##name##_maxColor, \
u_##name##_minGradMode, u_##name##_minColorKeyValue, u_##name##_minColorKeyTime, u_##name##_minAlphaKeyValue, u_##name##_minAlphaKeyTime, \
u_##name##_maxGradMode, u_##name##_maxColorKeyValue, u_##name##_maxColorKeyTime, u_##name##_maxAlphaKeyValue, u_##name##_maxAlphaKeyTime, t, rnd);
in vec4 a_position_starttime; // center position,particle start time
in vec4 a_vertIdx_size_angle; // xy:vertex index,z:size,w:angle
in vec4 a_color;
in vec4 a_dir_life; // xyz:particle start velocity,w:particle lifetime
in float a_rndSeed;
uniform Constants2 {
vec4 u_worldRot;
float u_psTime;
int u_velocity_space;
float u_speedModifier;
int u_force_space;
};
#if VELOCITY_OVERTIME_MODULE_ENABLE
// DECL_CURVE_STRUCT_INT(velocity_pos_x)
// DECL_CURVE_STRUCT_INT(velocity_pos_y)
// DECL_CURVE_STRUCT_INT(velocity_pos_z)
#if USE_STRETCHED_BILLBOARD
// DECL_CURVE_STRUCT(velocity_x)
// DECL_CURVE_STRUCT(velocity_y)
// DECL_CURVE_STRUCT(velocity_z)
#endif
#endif
#if FORCE_OVERTIME_MODULE_ENABLE
// DECL_CURVE_STRUCT_INT(force_pos_x)
// DECL_CURVE_STRUCT_INT(force_pos_y)
// DECL_CURVE_STRUCT_INT(force_pos_z)
#if USE_STRETCHED_BILLBOARD
// DECL_CURVE_STRUCT_INT(force_vel_x)
// DECL_CURVE_STRUCT_INT(force_vel_y)
// DECL_CURVE_STRUCT_INT(force_vel_z)
#endif
#endif
#if SIZE_OVERTIME_MODULE_ENABLE
// DECL_CURVE_STRUCT(size)
#endif
#if COLOR_OVERTIME_MODULE_ENABLE
// DECL_GRADIENT_STRUCT(color)
#endif
#if TEXTURE_ANIMATION_ENABLE
// DECL_CURVE_STRUCT(frameOverTime)
uniform Animation {
float u_cycles;
int u_animation_mode;
bool u_random_row;
int u_row_index;
};
#endif
#if ROTATE_OVERTIME_MODULE_ENABLE
// DECL_CURVE_STRUCT_INT(rotate)
#endif
float repeat(float t, float length) {
return t - floor(t / length) * length;
}
vec4 rotateQuat(vec4 p, vec4 q) {
vec3 iv = cross(q.xyz, p.xyz) + q.w * p.xyz;
vec3 res = p.xyz + 2.0 * cross(q.xyz, iv);
return vec4(res.xyz, p.w);
}
float random(float seed) {
seed = mod(seed, 233280.);
float q = (seed * 9301. + 49297.) / 233280.;
return fract(q);
}
float calcCurveValue(vec4 coef, float t) {
return t * (t * (t * coef.x + coef.y) + coef.z) + coef.w;
}
float evaluateCurve(float keyTime[MAX_KEY_NUM], vec4 keyCoef[MAX_KEY_NUM], float normalizedTime) {
for (int i = 0; i < MAX_KEY_NUM; i++) {
if (keyTime[i] > normalizedTime) {
return calcCurveValue(keyCoef[i], normalizedTime - (i == 0 ? 0. : keyTime[i - 1]));
}
}
}
float evaluateIntegral(float keyTime[MAX_KEY_NUM], vec4 keyCoef[MAX_KEY_NUM], float integral[MAX_KEY_NUM - 1], float normalizedTime, float ts) {
for (int i = 0; i < MAX_KEY_NUM; i++) {
if (keyTime[i] > normalizedTime) {
float t = normalizedTime - (i == 0 ? 0. : keyTime[i - 1]);
return ts * ((i - 1 < 0 ? 0. : integral[i - 1]) + t * calcCurveValue(keyCoef[i], t));
}
}
}
float evaluateIntegralTwice(float keyTime[MAX_KEY_NUM], vec4 keyCoef[MAX_KEY_NUM], float integral[MAX_KEY_NUM - 1], float normalizedTime, float ts) {
for (int i = 0; i < MAX_KEY_NUM; i++) {
if (keyTime[i] > normalizedTime) {
float t = normalizedTime - (i == 0 ? 0. : keyTime[i - 1]);
return ts * ts * ((i - 1 < 0 ? 0. : integral[i - 1]) + t * t * calcCurveValue(keyCoef[i], t));
}
}
}
float evaluateCurveRange(int mode, float minConstant, float maxConstant
, float minKeyTime[MAX_KEY_NUM], vec4 minKeyCoef[MAX_KEY_NUM]
, float maxKeyTime[MAX_KEY_NUM], vec4 maxKeyCoef[MAX_KEY_NUM]
, float t, float rnd) {
if (mode == CURVE_MODE_CONSTANT) {
return minConstant;
} else if (mode == CURVE_MODE_RANDOM_CONSTANT) {
return mix(minConstant, maxConstant, random(rnd));
} else if (mode == CURVE_MODE_CURVE) {
return evaluateCurve(minKeyTime, minKeyCoef, t);
} else if (mode == CURVE_MODE_RANDOM_CURVE) {
return mix(evaluateCurve(minKeyTime, minKeyCoef, t), evaluateCurve(maxKeyTime, maxKeyCoef, t), random(rnd));
}
}
float evaluateCurveRangeIntegral(int mode, float minConstant, float maxConstant
, float minKeyTime[MAX_KEY_NUM], vec4 minKeyCoef[MAX_KEY_NUM], float minIntegral[MAX_KEY_NUM - 1]
, float maxKeyTime[MAX_KEY_NUM], vec4 maxKeyCoef[MAX_KEY_NUM], float maxIntegral[MAX_KEY_NUM - 1]
, float t, float ts, float rnd) {
if (mode == CURVE_MODE_CONSTANT) {
return minConstant * t * ts;
} else if (mode == CURVE_MODE_RANDOM_CONSTANT) {
return mix(minConstant, maxConstant, random(rnd)) * t * ts;
} else if (mode == CURVE_MODE_CURVE) {
return evaluateIntegral(minKeyTime, minKeyCoef, minIntegral, t, ts);
} else if (mode == CURVE_MODE_RANDOM_CURVE) {
return mix(evaluateIntegral(minKeyTime, minKeyCoef, minIntegral, t, ts), evaluateIntegral(maxKeyTime, maxKeyCoef, maxIntegral, t, ts), random(rnd));
}
}
float evaluateCurveRangeIntegralTwice(int mode, float minConstant, float maxConstant
, float minKeyTime[MAX_KEY_NUM], vec4 minKeyCoef[MAX_KEY_NUM], float minIntegral[MAX_KEY_NUM - 1]
, float maxKeyTime[MAX_KEY_NUM], vec4 maxKeyCoef[MAX_KEY_NUM], float maxIntegral[MAX_KEY_NUM - 1]
, float t, float ts, float rnd) {
if (mode == CURVE_MODE_CONSTANT) {
return minConstant * t * t * ts * ts / 2.;
} else if (mode == CURVE_MODE_RANDOM_CONSTANT) {
return mix(minConstant, maxConstant, random(rnd)) * t * t * ts * ts / 2.;
} else if (mode == CURVE_MODE_CURVE) {
return evaluateIntegralTwice(minKeyTime, minKeyCoef, minIntegral, t, ts);
} else if (mode == CURVE_MODE_RANDOM_CURVE) {
return mix(evaluateIntegralTwice(minKeyTime, minKeyCoef, minIntegral, t, ts), evaluateIntegralTwice(maxKeyTime, maxKeyCoef, maxIntegral, t, ts), random(rnd));
}
}
vec4 evaluateGradient(int mode, float colorKeyTime[MAX_KEY_NUM], vec3 colorKeyValue[MAX_KEY_NUM]
, float alphaKeyTime[MAX_KEY_NUM], float alphaKeyValue[MAX_KEY_NUM]
, float t){
vec4 ret;
for (int i = 0; i < MAX_KEY_NUM; i++) {
if (t < colorKeyTime[i]) {
if (mode == GRADIENT_MODE_FIX) {
ret.xyz = colorKeyValue[i];
} else if (mode == GRADIENT_MODE_BLEND) {
ret.xyz = mix(colorKeyValue[i - 1], colorKeyValue[i], (t - colorKeyTime[i - 1]) / (colorKeyTime[i] - colorKeyTime[i - 1]));
}
break;
}
}
for (int i = 0; i < MAX_KEY_NUM; i++) {
if (t < alphaKeyTime[i]) {
if (mode == GRADIENT_MODE_FIX) {
ret.w = alphaKeyValue[i];
} else if (mode == GRADIENT_MODE_BLEND) {
ret.w = mix(alphaKeyValue[i - 1], alphaKeyValue[i], (t - alphaKeyTime[i - 1]) / (alphaKeyTime[i] - alphaKeyTime[i - 1]));
}
break;
}
}
return ret;
}
vec4 evaluateGradientRange(int rangeMode, vec4 minColor, vec4 maxColor,
int minGradMode, vec3 minColorKeyValue[MAX_KEY_NUM], float minColorKeyTime[MAX_KEY_NUM], float minAlphaKeyValue[MAX_KEY_NUM], float minAlphaKeyTime[MAX_KEY_NUM],
int maxGradMode, vec3 maxColorKeyValue[MAX_KEY_NUM], float maxColorKeyTime[MAX_KEY_NUM], float maxAlphaKeyValue[MAX_KEY_NUM], float maxAlphaKeyTime[MAX_KEY_NUM],
float t, float rnd){
if (rangeMode == GRADIENT_RANGE_MODE_COLOR) {
return minColor;
} else if (rangeMode == GRADIENT_RANGE_MODE_TWO_COLOR) {
return mix(minColor, maxColor, rnd);
} else if (rangeMode == GRADIENT_RANGE_MODE_GRADIENT) {
return evaluateGradient(minGradMode, minColorKeyTime, minColorKeyValue, minAlphaKeyTime, minAlphaKeyValue, t);
} else if (rangeMode == GRADIENT_RANGE_MODE_TWO_GRADIENT) {
return mix(evaluateGradient(minGradMode, minColorKeyTime, minColorKeyValue, minAlphaKeyTime, minAlphaKeyValue, t),
evaluateGradient(maxGradMode, maxColorKeyTime, maxColorKeyValue, maxAlphaKeyTime, maxAlphaKeyValue, t), rnd);
}
}
vec4 gpvs_main() {
vec4 pos = vec4(a_position_starttime.xyz, 1.);
float activeTime = u_psTime - a_position_starttime.w;
float normalizedTime = activeTime / a_dir_life.w;
#if VELOCITY_OVERTIME_MODULE_ENABLE
float speedModifier = u_speedModifier;
#else
float speedModifier = 1.;
#endif
pos.xyz += a_dir_life.xyz * activeTime * speedModifier;
#if USE_STRETCHED_BILLBOARD
vec4 velocity = vec4(a_dir_life.xyz, 0.);
velocity *= speedModifier;
#endif
#if !USE_WORLD_SPACE
pos = cc_matWorld * pos;
#if USE_STRETCHED_BILLBOARD
velocity = rotateQuat(velocity, u_worldRot);
#endif
#endif
#if VELOCITY_OVERTIME_MODULE_ENABLE
vec4 velocityTrack = vec4(EVAL_CURVE_INTEGRAL(velocity_pos_x, normalizedTime, a_dir_life.w, a_rndSeed + VELOCITY_OVERTIME_RAND_OFFSET), EVAL_CURVE_INTEGRAL(velocity_pos_y, normalizedTime, a_dir_life.w, a_rndSeed + VELOCITY_OVERTIME_RAND_OFFSET), EVAL_CURVE_INTEGRAL(velocity_pos_z, normalizedTime, a_dir_life.w, a_rndSeed + VELOCITY_OVERTIME_RAND_OFFSET), 0);
velocityTrack = velocityTrack * speedModifier;
if (u_velocity_space == SIMULATE_SPACE_LOCAL) {
velocityTrack = rotateQuat(velocityTrack, u_worldRot);
}
pos += velocityTrack;
#if USE_STRETCHED_BILLBOARD
vec4 velocityVel = vec4(EVAL_CURVE_RANGE(velocity_x, normalizedTime, a_dir_life.w, a_rndSeed + VELOCITY_OVERTIME_RAND_OFFSET), EVAL_CURVE_RANGE(velocity_y, normalizedTime, a_dir_life.w, a_rndSeed + VELOCITY_OVERTIME_RAND_OFFSET), EVAL_CURVE_RANGE(velocity_z, normalizedTime, a_dir_life.w, a_rndSeed + VELOCITY_OVERTIME_RAND_OFFSET), 0);
if (u_velocity_space == SIMULATE_SPACE_LOCAL) {
velocityVel = rotateQuat(velocityVel, u_worldRot);
}
velocityVel *= speedModifier;
velocity += velocityVel;
#endif
#endif
#if FORCE_OVERTIME_MODULE_ENABLE
vec4 forceTrack = vec4(EVAL_CURVE_INTEGRAL_TWICE(force_pos_x, normalizedTime, a_dir_life.w, a_rndSeed + FORCE_OVERTIME_RAND_OFFSET), EVAL_CURVE_INTEGRAL_TWICE(force_pos_y, normalizedTime, a_dir_life.w, a_rndSeed + FORCE_OVERTIME_RAND_OFFSET), EVAL_CURVE_INTEGRAL_TWICE(force_pos_z, normalizedTime, a_dir_life.w, a_rndSeed + FORCE_OVERTIME_RAND_OFFSET), 0);
forceTrack = forceTrack * speedModifier;
if (u_force_space == SIMULATE_SPACE_LOCAL) {
forceTrack = rotateQuat(forceTrack, u_worldRot);
}
pos += forceTrack;
#if USE_STRETCHED_BILLBOARD
vec4 forceVel = vec4(EVAL_CURVE_INTEGRAL(force_vel_x, normalizedTime, a_dir_life.w, a_rndSeed + FORCE_OVERTIME_RAND_OFFSET), EVAL_CURVE_INTEGRAL(force_vel_y, normalizedTime, a_dir_life.w, a_rndSeed + FORCE_OVERTIME_RAND_OFFSET), EVAL_CURVE_INTEGRAL(force_vel_z, normalizedTime, a_dir_life.w, a_rndSeed + FORCE_OVERTIME_RAND_OFFSET), 0);
if (u_force_space == SIMULATE_SPACE_LOCAL) {
forceVel = rotateQuat(forceVel, u_worldRot);
}
forceVel *= speedModifier;
velocity += forceVel;
#endif
#endif
float size = a_vertIdx_size_angle.z;
#if SIZE_OVERTIME_MODULE_ENABLE
float sizeModifier = EVAL_CURVE_RANGE(size, normalizedTime, a_rndSeed + SIZE_OVERTIME_RAND_OFFSET);
size *= sizeModifier;
#endif
vec2 cornerOffset = vec2((a_vertIdx_size_angle.xy - 0.5) * size);
#if !USE_STRETCHED_BILLBOARD
float angle = a_vertIdx_size_angle.w;
#if ROTATE_OVERTIME_MODULE_ENABLE
angle += EVAL_CURVE_INTEGRAL(rotate, normalizedTime, a_dir_life.w, a_rndSeed + ROTATION_OVERTIME_RAND_OFFSET);
#endif
rotateCorner(cornerOffset, angle);
#endif
computeVertPos(pos, cornerOffset
#if USE_BILLBOARD || USE_VERTICAL_BILLBOARD
, cc_matView
#endif
#if USE_STRETCHED_BILLBOARD
, cc_cameraPos
, velocity
, velocityScale
, lengthScale
, size
, a_vertIdx_size_angle.x
#endif
);
pos = cc_matViewProj * pos;
float frameIndex = 0.;
#if TEXTURE_ANIMATION_ENABLE
if (u_animation_mode == ANIMATION_MODE_WHOLE_SHEET) {
frameIndex = repeat(u_cycles * EVAL_CURVE_RANGE(frameOverTime, normalizedTime, a_rndSeed + TEXTURE_ANIMATION_RAND_OFFSET), 1.);
} else if (u_animation_mode == ANIMATION_MODE_SINGLE_ROW) {
float rowLength = 1. / frameTile_velLenScale.y;
if (u_random_row) {
float f = repeat(u_cycles * EVAL_CURVE_RANGE(frameOverTime, normalizedTime, a_rndSeed + TEXTURE_ANIMATION_RAND_OFFSET), 1.);
float startRow = floor(random(floor(u_psTime * 1000.)) * frameTile_velLenScale.y);
float from = startRow * rowLength;
float to = from + rowLength;
frameIndex = mix(from, to, f);
}
else {
float from = float(u_row_index) * rowLength;
float to = from + rowLength;
frameIndex = mix(from, to, repeat(u_cycles * EVAL_CURVE_RANGE(frameOverTime, normalizedTime, a_rndSeed + TEXTURE_ANIMATION_RAND_OFFSET), 1.));
}
}
#endif
uv = computeUV(frameIndex, a_vertIdx_size_angle.xy, frameTile_velLenScale.xy) * mainTiling_Offset.xy + mainOffset.zw;
#if COLOR_OVERTIME_MODULE_ENABLE
color = a_color * EVAL_GRADIENT_RANGE(color, normalizedTime, a_rndSeed + COLOR_OVERTIME_RAND_OFFSET);
#else
color = a_color;
#endif
return pos;
}