Allow streamers to have start and end colours

This commit is contained in:
Sezz 2025-03-03 16:12:21 +11:00
parent 9b9c27937a
commit 6bf0ff2c43
4 changed files with 45 additions and 37 deletions

View file

@ -24,9 +24,12 @@ namespace TEN::Effects::Streamer
{ {
StoreInterpolationData(); StoreInterpolationData();
// Update opacity. // Update color.
if (Color.w > 0.0f) float alpha = (float)Life / (float)LifeMax;
Color.w = EaseInOutSine(0.0f, OpacityMax, Life / LifeMax); Color.x = EaseInOutSine(ColorEnd.x, ColorStart.x, alpha);
Color.y = EaseInOutSine(ColorEnd.y, ColorStart.y, alpha);
Color.z = EaseInOutSine(ColorEnd.z, ColorStart.z, alpha);
Color.w = EaseInOutSine(ColorEnd.w, ColorStart.w, alpha);
// TODO: Not working. Make it work. -- Sezz 2025.03.02 // TODO: Not working. Make it work. -- Sezz 2025.03.02
// Update orientation. // Update orientation.
@ -36,7 +39,7 @@ namespace TEN::Effects::Streamer
TransformVertices(Velocity, ExpRate); TransformVertices(Velocity, ExpRate);
// Update life. // Update life.
Life -= 1.0f; Life--;
} }
void Streamer::StreamerSegment::TransformVertices(float vel, float expRate) void Streamer::StreamerSegment::TransformVertices(float vel, float expRate)
@ -95,24 +98,25 @@ namespace TEN::Effects::Streamer
return _isBroken; return _isBroken;
} }
void Streamer::AddSegment(const Vector3& pos, const Vector3& dir, short orient, const Vector4& color, void Streamer::AddSegment(const Vector3& pos, const Vector3& dir, short orient, const Color& colorStart, const Color& colorEnd,
float width, float life, float vel, float expRate, short rot, unsigned int segmentCount) float width, float life, float vel, float expRate, short rot, unsigned int segmentCount)
{ {
constexpr auto FADE_IN_COEFF = 3.0f; constexpr auto FADE_IN_COEFF = 3.0f;
auto& segment = GetNewSegment(); auto& segment = GetNewSegment();
// Avoid "clipped" streamers by clamping max life according to max segment count. // Avoid creating "clipped" streamers by clamping max life according to max segment count.
float lifeMax = std::min(round(life * FPS), (float)SEGMENT_COUNT_MAX); int lifeMax = (int)std::min(round(life * FPS), (float)SEGMENT_COUNT_MAX);
float alpha = (segmentCount / lifeMax) * FADE_IN_COEFF; float alpha = ((float)segmentCount / (float)lifeMax) * FADE_IN_COEFF;
float opacityMax = EaseInOutSine(0.0f, color.w, alpha); float opacityMax = EaseInOutSine(colorEnd.w, colorStart.w, alpha);
segment.Orientation = AxisAngle(dir, orient); segment.Orientation = AxisAngle(dir, orient);
segment.Color = Vector4(color.x, color.y, color.z, opacityMax); segment.Color =
segment.ColorStart = Vector4(colorStart.x, colorStart.y, colorStart.z, opacityMax);
segment.ColorEnd = colorEnd;
segment.Life = segment.Life =
segment.LifeMax = lifeMax; segment.LifeMax = lifeMax;
segment.OpacityMax = opacityMax;
segment.Velocity = vel; segment.Velocity = vel;
segment.ExpRate = expRate; segment.ExpRate = expRate;
segment.Rotation = rot; segment.Rotation = rot;
@ -153,7 +157,7 @@ namespace TEN::Effects::Streamer
return _pools; return _pools;
} }
void StreamerGroup::AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color, void StreamerGroup::AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Color& colorStart, const Color& colorEnd,
float width, float life, float vel, float expRate, short rot, float width, float life, float vel, float expRate, short rot,
StreamerFeatherType featherType, BlendMode blendMode) StreamerFeatherType featherType, BlendMode blendMode)
{ {
@ -165,7 +169,7 @@ namespace TEN::Effects::Streamer
// Get new streamer iteration or extend existing streamer iteration with new segment. // Get new streamer iteration or extend existing streamer iteration with new segment.
auto& streamer = GetStreamerIteration(tag, featherType, blendMode); auto& streamer = GetStreamerIteration(tag, featherType, blendMode);
streamer.AddSegment(pos, dir, orient, color, width, life, vel, expRate, rot, (unsigned int)streamer.GetSegments().size()); streamer.AddSegment(pos, dir, orient, colorStart, colorEnd, width, life, vel, expRate, rot, (unsigned int)streamer.GetSegments().size());
} }
void StreamerGroup::Update() void StreamerGroup::Update()
@ -247,7 +251,7 @@ namespace TEN::Effects::Streamer
return _groups; return _groups;
} }
void StreamerEffectController::Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color, void StreamerEffectController::Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& dir, short orient, const Color& colorStart, const Color& colorEnd,
float width, float life, float vel, float expRate, short rot, float width, float life, float vel, float expRate, short rot,
StreamerFeatherType featherType, BlendMode blendMode) StreamerFeatherType featherType, BlendMode blendMode)
{ {
@ -259,7 +263,7 @@ namespace TEN::Effects::Streamer
// Get group and extend streamer within pool. // Get group and extend streamer within pool.
auto& group = GetGroup(itemNumber); auto& group = GetGroup(itemNumber);
group.AddStreamer(tag, pos, dir, orient, color, width, life, vel, expRate, rot, featherType, blendMode); group.AddStreamer(tag, pos, dir, orient, colorStart, colorEnd, width, life, vel, expRate, rot, featherType, blendMode);
} }
void StreamerEffectController::Update() void StreamerEffectController::Update()

View file

@ -28,13 +28,14 @@ namespace TEN::Effects::Streamer
{ {
static constexpr auto VERTEX_COUNT = 2; static constexpr auto VERTEX_COUNT = 2;
std::array<Vector3, VERTEX_COUNT> Vertices = {}; std::array<Vector3, VERTEX_COUNT> Vertices = {}; // TODO: Refactor vertices to be calculated by renderer instead of by internal effect logic.
AxisAngle Orientation = AxisAngle::Identity; // TODO: Interpolate? AxisAngle Orientation = AxisAngle::Identity; // TODO: Interpolate?
Vector4 Color = Vector4::Zero; Vector4 Color = Vector4::Zero;
Vector4 ColorStart = Vector4::Zero;
Vector4 ColorEnd = Vector4::Zero;
float Life = 0.0f; int Life = 0; // Time in game frames.
float LifeMax = 0.0f; int LifeMax = 0; // Time in game frames.
float OpacityMax = 0.0f;
float Velocity = 0.0f; float Velocity = 0.0f;
float ExpRate = 0.0f; float ExpRate = 0.0f;
short Rotation = 0; short Rotation = 0;
@ -81,7 +82,7 @@ namespace TEN::Effects::Streamer
// Utilities // Utilities
void AddSegment(const Vector3& pos, const Vector3& dir, short orient, const Vector4& color, void AddSegment(const Vector3& pos, const Vector3& dir, short orient, const Color& colorStart, const Color& colorEnd,
float width, float life, float vel, float expRate, short rot, unsigned int segmentCount); float width, float life, float vel, float expRate, short rot, unsigned int segmentCount);
void Update(); void Update();
@ -111,7 +112,7 @@ namespace TEN::Effects::Streamer
// Utilities // Utilities
void AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color, void AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Color& colorStart, const Color& colorEnd,
float width, float life, float vel, float expRate, short rot, float width, float life, float vel, float expRate, short rot,
StreamerFeatherType featherType, BlendMode blendMode); StreamerFeatherType featherType, BlendMode blendMode);
void Update(); void Update();
@ -143,7 +144,8 @@ namespace TEN::Effects::Streamer
// Utilities // Utilities
void Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color, // TODO: Use seconds.
void Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& dir, short orient, const Color& colorStart, const Color& colorEnd,
float width, float life, float vel, float expRate, short rot, float width, float life, float vel, float expRate, short rot,
StreamerFeatherType featherType = StreamerFeatherType::None, BlendMode blendMode = BlendMode::AlphaBlend); StreamerFeatherType featherType = StreamerFeatherType::None, BlendMode blendMode = BlendMode::AlphaBlend);
void Update(); void Update();

View file

@ -38,11 +38,12 @@ namespace TEN::Entities::TR4
static void SpawnWraithTails(const ItemInfo& item) static void SpawnWraithTails(const ItemInfo& item)
{ {
constexpr auto OFFSET = Vector3(0.0f, -10.0f, -50.0f); constexpr auto OFFSET = Vector3(0.0f, -10.0f, -50.0f);
constexpr auto WIDTH = 8.0f; constexpr auto COLOR_END = Color(0.0f, 0.0f, 0.0f, 0.0f);
constexpr auto LIFE_MAX = 0.5f; constexpr auto WIDTH = 8.0f;
constexpr auto VEL = 4.0f; constexpr auto LIFE_MAX = 0.5f;
constexpr auto EXP_RATE = 1.0f; constexpr auto VEL = 4.0f;
constexpr auto EXP_RATE = 1.0f;
enum class TailTag enum class TailTag
{ {
@ -51,20 +52,20 @@ namespace TEN::Entities::TR4
Third Third
}; };
auto color = Vector4::Zero; auto colorStart = Vector4::Zero;
switch (item.ObjectNumber) switch (item.ObjectNumber)
{ {
default: default:
case ID_WRAITH1: case ID_WRAITH1:
color = Vector4(1.0f, 0.6f, 0.0f, 1.0f); colorStart = Vector4(1.0f, 0.6f, 0.0f, 1.0f);
break; break;
case ID_WRAITH2: case ID_WRAITH2:
color = Vector4(0.0f, 0.5f, 1.0f, 1.0f); colorStart = Vector4(0.0f, 0.5f, 1.0f, 1.0f);
break; break;
case ID_WRAITH3: case ID_WRAITH3:
color = Vector4(1.0f); colorStart = Vector4(1.0f);
break; break;
} }
@ -81,21 +82,21 @@ namespace TEN::Entities::TR4
// Spawn first tail. // Spawn first tail.
StreamerEffect.Spawn( StreamerEffect.Spawn(
item.Index, (int)TailTag::First, item.Index, (int)TailTag::First,
pos, dir0, orient2D, color, pos, dir0, orient2D, colorStart, COLOR_END,
WIDTH, LIFE_MAX, VEL, EXP_RATE, 0, WIDTH, LIFE_MAX, VEL, EXP_RATE, 0,
StreamerFeatherType::Center, BlendMode::Additive); StreamerFeatherType::Center, BlendMode::Additive);
// Spawn second tail. // Spawn second tail.
StreamerEffect.Spawn( StreamerEffect.Spawn(
item.Index, (int)TailTag::Second, item.Index, (int)TailTag::Second,
pos, dir1, orient2D, color, pos, dir1, orient2D, colorStart, COLOR_END,
WIDTH, LIFE_MAX, VEL, EXP_RATE, 0, WIDTH, LIFE_MAX, VEL, EXP_RATE, 0,
StreamerFeatherType::Center, BlendMode::Additive); StreamerFeatherType::Center, BlendMode::Additive);
// Spawn third tail. // Spawn third tail.
StreamerEffect.Spawn( StreamerEffect.Spawn(
item.Index, (int)TailTag::Third, item.Index, (int)TailTag::Third,
pos, dir2, orient2D, color, pos, dir2, orient2D, colorStart, COLOR_END,
WIDTH, LIFE_MAX, VEL, EXP_RATE, 0, WIDTH, LIFE_MAX, VEL, EXP_RATE, 0,
StreamerFeatherType::Center, BlendMode::Additive); StreamerFeatherType::Center, BlendMode::Additive);
} }

View file

@ -355,7 +355,8 @@ namespace TEN::Entities::Vehicles
void SpawnVehicleWake(const ItemInfo& vehicleItem, const Vector3& relOffset, int waterHeight, bool isUnderwater) void SpawnVehicleWake(const ItemInfo& vehicleItem, const Vector3& relOffset, int waterHeight, bool isUnderwater)
{ {
constexpr auto COLOR = Vector4(0.75f); constexpr auto COLOR_START = Color(0.75f, 0.75f, 0.75f, 0.75f);
constexpr auto COLOR_END = Color(0.0f, 0.0f, 0.0f, 0.0f);
constexpr auto LIFE_MAX = 2.5f; constexpr auto LIFE_MAX = 2.5f;
constexpr auto VEL_ABS = 4.0f; constexpr auto VEL_ABS = 4.0f;
constexpr auto EXP_RATE_ON_WATER = 6.0f; constexpr auto EXP_RATE_ON_WATER = 6.0f;
@ -382,14 +383,14 @@ namespace TEN::Entities::Vehicles
// Spawn left wake. // Spawn left wake.
StreamerEffect.Spawn( StreamerEffect.Spawn(
vehicleItem.Index, (int)tagLeft, vehicleItem.Index, (int)tagLeft,
positions.first, dir, orient2D, COLOR, positions.first, dir, orient2D, COLOR_START, COLOR_END,
0.0f, life, vel, expRate, 0, 0.0f, life, vel, expRate, 0,
StreamerFeatherType::Right, BlendMode::Additive); StreamerFeatherType::Right, BlendMode::Additive);
// Spawn right wake. // Spawn right wake.
StreamerEffect.Spawn( StreamerEffect.Spawn(
vehicleItem.Index, (int)tagRight, vehicleItem.Index, (int)tagRight,
positions.second, dir, orient2D, COLOR, positions.second, dir, orient2D, COLOR_START, COLOR_END,
0.0f, life, vel, expRate, 0, 0.0f, life, vel, expRate, 0,
StreamerFeatherType::Left, BlendMode::Additive); StreamerFeatherType::Left, BlendMode::Additive);
} }