mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
Single Laser tr3 - Tripwire (#1336)
* first try of the TR3 laserbeams - nothing to see * update laser; thickness with ocb * fixed collision * SLOT-change. NEWSlot ID #426 replaced ID_TRIPWIRE with ID_LASER_BEAM * Rename files * Rename functions * Cleanup * Simplify laser beam * Cleanup * Construct laser beam cylinder * changed shader * Set beam radius with OCB * fixed shader for laserbeam * fixed shader for single laserbeam; finished code * Update TombEngine.sln Win32 restored on lines 18 and 19 * update ObjectsIDs.h * moved laser effects into SpriteEffects.hlsli --------- Co-authored-by: Sezz <sezzary@outlook.com>
This commit is contained in:
parent
c8cbb73ed9
commit
ffd9c21d50
15 changed files with 612 additions and 165 deletions
|
@ -924,6 +924,7 @@ FISHTANK
|
|||
DOPPELGANGER_ORIGIN
|
||||
CORPSE
|
||||
WRAITH_TRAP
|
||||
SINGLE_LASER
|
||||
MESHSWAP1
|
||||
MESHSWAP2
|
||||
MESHSWAP3
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "Objects/TR5/Emitter/tr5_rats_emitter.h"
|
||||
#include "Objects/TR5/Emitter/tr5_spider_emitter.h"
|
||||
#include "Objects/TR5/Trap/LaserBarrier.h"
|
||||
#include "Objects/TR5/Trap/LaserBeam.h"
|
||||
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
|
||||
#include "Scripting/Include/Objects/ScriptInterfaceObjectsHandler.h"
|
||||
#include "Scripting/Include/ScriptInterfaceGame.h"
|
||||
|
@ -430,6 +431,7 @@ void CleanUp()
|
|||
ClearDrips();
|
||||
ClearRipples();
|
||||
ClearLaserBarrierEffects();
|
||||
ClearLaserBeamEffects();
|
||||
DisableSmokeParticles();
|
||||
DisableSparkParticles();
|
||||
DisableDebris();
|
||||
|
|
231
TombEngine/Objects/TR5/Trap/LaserBeam.cpp
Normal file
231
TombEngine/Objects/TR5/Trap/LaserBeam.cpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
#include "framework.h"
|
||||
#include "Objects/TR5/Trap/LaserBeam.h"
|
||||
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/collision/floordata.h"
|
||||
#include "Game/control/los.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/effects/item_fx.h"
|
||||
#include "Game/effects/spark.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/people.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/Renderer.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Effects::Items;
|
||||
using namespace TEN::Effects::Spark;
|
||||
using namespace TEN::Math;
|
||||
using namespace TEN::Renderer;
|
||||
|
||||
namespace TEN::Traps::TR5
|
||||
{
|
||||
constexpr auto LASER_BEAM_LIGHT_INTENSITY = 50.0f;
|
||||
constexpr auto LASER_BEAM_LIGHT_AMPLITUDE = 31.0f;
|
||||
|
||||
extern std::unordered_map<int, LaserBeamEffect> LaserBeams = {};
|
||||
|
||||
void LaserBeamEffect::Initialize(const ItemInfo& item)
|
||||
{
|
||||
constexpr auto RADIUS_STEP = BLOCK(0.002f);
|
||||
|
||||
Color = item.Model.Color;
|
||||
Color.w = 1.0f;
|
||||
Radius = (item.TriggerFlags == 0) ? RADIUS_STEP : (abs(item.TriggerFlags) * RADIUS_STEP);
|
||||
IsLethal = (item.TriggerFlags > 0);
|
||||
IsHeavyActivator = (item.TriggerFlags <= 0);
|
||||
|
||||
Update(item);
|
||||
}
|
||||
|
||||
static void SpawnLaserSpark(const GameVector& pos, short angle, int count, const Vector4& colorStart)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
float ang = TO_RAD(angle);
|
||||
auto vel = Vector3(
|
||||
sin(ang + Random::GenerateFloat(-PI_DIV_2, PI_DIV_2)),
|
||||
Random::GenerateFloat(-1, 1),
|
||||
cos(ang + Random::GenerateFloat(-PI_DIV_2, PI_DIV_2)));
|
||||
vel += Vector3(Random::GenerateFloat(-64, 64), Random::GenerateFloat(-64, 64), Random::GenerateFloat(-64, 64));
|
||||
vel.Normalize(vel);
|
||||
|
||||
auto& spark = GetFreeSparkParticle();
|
||||
|
||||
spark = {};
|
||||
spark.age = 0;
|
||||
spark.life = Random::GenerateFloat(10, 20);
|
||||
spark.friction = 0.98f;
|
||||
spark.gravity = 1.2f;
|
||||
spark.width = 7.0f;
|
||||
spark.height = 34.0f;
|
||||
spark.room = pos.RoomNumber;
|
||||
spark.pos = pos.ToVector3();
|
||||
spark.velocity = vel * Random::GenerateFloat(17, 24);
|
||||
spark.sourceColor = colorStart;
|
||||
spark.destinationColor = Vector4::Zero;
|
||||
spark.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void SpawnLaserBeamLight(const Vector3& pos, int roomNumber, const Color& color, float intensity, float amplitude)
|
||||
{
|
||||
constexpr auto FALLOFF = 8;
|
||||
|
||||
float intensityNorm = intensity - Random::GenerateFloat(0.0f, amplitude);
|
||||
TriggerDynamicLight(
|
||||
pos.x, pos.y, pos.z,
|
||||
FALLOFF,
|
||||
intensityNorm * (color.x / 2),
|
||||
intensityNorm * (color.y / 2),
|
||||
intensityNorm * (color.z / 2));
|
||||
}
|
||||
|
||||
void LaserBeamEffect::Update(const ItemInfo& item)
|
||||
{
|
||||
auto orient = EulerAngles(item.Pose.Orientation.x + ANGLE(180.0f), item.Pose.Orientation.y, item.Pose.Orientation.z);
|
||||
auto dir = orient.ToDirection();
|
||||
auto rotMatrix = orient.ToRotationMatrix();
|
||||
|
||||
auto origin = GameVector(item.Pose.Position, item.RoomNumber);
|
||||
auto target = GameVector(
|
||||
Geometry::TranslatePoint(origin.ToVector3(), dir, MAX_VISIBILITY_DISTANCE),
|
||||
GetCollision(origin.ToVector3i(), origin.RoomNumber, dir, MAX_VISIBILITY_DISTANCE).RoomNumber);
|
||||
|
||||
// Hit wall; spawn sparks and light.
|
||||
if (!LOS(&origin, &target))
|
||||
{
|
||||
if (item.TriggerFlags > 0)
|
||||
{
|
||||
SpawnLaserSpark(target, Random::GenerateAngle(), 3, Color);
|
||||
SpawnLaserSpark(target, Random::GenerateAngle(), 3, Color);
|
||||
}
|
||||
|
||||
SpawnLaserBeamLight(target.ToVector3(), target.RoomNumber, item.Model.Color, LASER_BEAM_LIGHT_INTENSITY, LASER_BEAM_LIGHT_AMPLITUDE);
|
||||
}
|
||||
|
||||
float length = Vector3::Distance(origin.ToVector3(), target.ToVector3());
|
||||
|
||||
// Calculate cylinder vertices.
|
||||
float angle = 0.0f;
|
||||
for (int i = 0; i < LaserBeamEffect::SUBDIVISION_COUNT; i++)
|
||||
{
|
||||
float sinAngle = sin(angle);
|
||||
float cosAngle = cos(angle);
|
||||
|
||||
auto relVertex = Vector3(Radius * sinAngle, Radius * cosAngle, 0.0f);
|
||||
auto vertex = item.Pose.Position.ToVector3() + Vector3::Transform(relVertex, rotMatrix);
|
||||
|
||||
Vertices[i] = vertex;
|
||||
Vertices[SUBDIVISION_COUNT + i] = Geometry::TranslatePoint(vertex, dir, length);
|
||||
|
||||
angle += PI_MUL_2 / SUBDIVISION_COUNT;
|
||||
}
|
||||
|
||||
// Calculate bounding box.
|
||||
float boxApothem = (Radius - ((Radius * SQRT_2) - Radius) + Radius) / 2;
|
||||
auto center = (origin.ToVector3() + target.ToVector3()) / 2;
|
||||
auto extents = Vector3(boxApothem, boxApothem, length / 2);
|
||||
BoundingBox = BoundingOrientedBox(center, extents, orient.ToQuaternion());
|
||||
}
|
||||
|
||||
void InitializeLaserBeam(short itemNumber)
|
||||
{
|
||||
const auto& item = g_Level.Items[itemNumber];
|
||||
|
||||
auto beam = LaserBeamEffect{};
|
||||
beam.Initialize(item);
|
||||
|
||||
LaserBeams.insert({ itemNumber, beam });
|
||||
}
|
||||
|
||||
void ControlLaserBeam(short itemNumber)
|
||||
{
|
||||
if (!LaserBeams.count(itemNumber))
|
||||
return;
|
||||
|
||||
auto& item = g_Level.Items[itemNumber];
|
||||
auto& beam = LaserBeams.at(itemNumber);
|
||||
|
||||
if (!TriggerActive(&item))
|
||||
{
|
||||
beam.IsActive = false;
|
||||
beam.Color.w = 0.0f;
|
||||
item.Model.Color.w = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
// Brightness fade-in and distortion.
|
||||
if (item.Model.Color.w < 1.0f)
|
||||
item.Model.Color.w += 0.02f;
|
||||
|
||||
if (beam.Color.w < 1.0f)
|
||||
beam.Color.w += 0.02f;
|
||||
|
||||
// TODO: Weird.
|
||||
if (item.Model.Color.w > 8.0f)
|
||||
{
|
||||
beam.Color.w = 0.8f;
|
||||
item.Model.Color.w = 0.8f;
|
||||
}
|
||||
|
||||
beam.IsActive = true;
|
||||
beam.Update(item);
|
||||
|
||||
if (item.Model.Color.w >= 0.8f)
|
||||
SpawnLaserBeamLight(item.Pose.Position.ToVector3(), item.RoomNumber, item.Model.Color, LASER_BEAM_LIGHT_INTENSITY, LASER_BEAM_LIGHT_AMPLITUDE);
|
||||
|
||||
SoundEffect(SFX_TR5_DOOR_BEAM, &item.Pose);
|
||||
}
|
||||
|
||||
void CollideLaserBeam(short itemNumber, ItemInfo* playerItem, CollisionInfo* coll)
|
||||
{
|
||||
constexpr auto LASER_BEAM_LIGHT_INTENSITY_MODIFY = 255.0f;
|
||||
constexpr auto LASER_BEAM_LIGHT_AMPLITUDE_MODIFY = 100.0f;
|
||||
|
||||
if (!LaserBeams.count(itemNumber))
|
||||
return;
|
||||
|
||||
auto& item = g_Level.Items[itemNumber];
|
||||
auto& beam = LaserBeams.at(itemNumber);
|
||||
|
||||
if (!beam.IsActive)
|
||||
return;
|
||||
|
||||
auto origin = GameVector(item.Pose.Position, item.RoomNumber);
|
||||
auto basePos = origin.ToVector3();
|
||||
|
||||
auto rotMatrix = EulerAngles(item.Pose.Orientation.x + ANGLE(180.0f), item.Pose.Orientation.y, item.Pose.Orientation.z);
|
||||
auto target = GameVector(Geometry::TranslatePoint(origin.ToVector3(), rotMatrix, MAX_VISIBILITY_DISTANCE), 0);
|
||||
|
||||
auto pointColl = GetCollision(target.ToVector3i(),item.RoomNumber);
|
||||
if (pointColl.RoomNumber != target.RoomNumber)
|
||||
target.RoomNumber = pointColl.RoomNumber;
|
||||
|
||||
bool los2 = LOS(&origin, &target);
|
||||
|
||||
auto hitPos = Vector3i::Zero;
|
||||
if (ObjectOnLOS2(&origin, &target, &hitPos, nullptr, ID_LARA) == LaraItem->Index && !los2)
|
||||
{
|
||||
if (beam.IsLethal &&
|
||||
playerItem->HitPoints > 0 && playerItem->Effect.Type != EffectType::Smoke)
|
||||
{
|
||||
ItemRedLaserBurn(playerItem, 2.0f * FPS);
|
||||
DoDamage(playerItem, MAXINT);
|
||||
}
|
||||
else if (beam.IsHeavyActivator)
|
||||
{
|
||||
TestTriggers(&item, true, item.Flags & IFLAG_ACTIVATION_MASK);
|
||||
}
|
||||
|
||||
beam.Color.w = Random::GenerateFloat(0.6f, 1.0f);
|
||||
SpawnLaserBeamLight(item.Pose.Position.ToVector3(), item.RoomNumber, item.Model.Color, LASER_BEAM_LIGHT_INTENSITY_MODIFY, LASER_BEAM_LIGHT_AMPLITUDE_MODIFY);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearLaserBeamEffects()
|
||||
{
|
||||
LaserBeams.clear();
|
||||
}
|
||||
}
|
35
TombEngine/Objects/TR5/Trap/LaserBeam.h
Normal file
35
TombEngine/Objects/TR5/Trap/LaserBeam.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "Math/Math.h"
|
||||
|
||||
using namespace TEN::Math;
|
||||
|
||||
struct CollisionInfo;
|
||||
struct ItemInfo;
|
||||
|
||||
namespace TEN::Traps::TR5
|
||||
{
|
||||
struct LaserBeamEffect
|
||||
{
|
||||
static constexpr auto SUBDIVISION_COUNT = 8;
|
||||
|
||||
Vector4 Color = Vector4::Zero;
|
||||
BoundingOrientedBox BoundingBox = {};
|
||||
std::array<Vector3, SUBDIVISION_COUNT * 2> Vertices = {};
|
||||
|
||||
float Radius = 0.0f;
|
||||
|
||||
bool IsActive = false;
|
||||
bool IsLethal = false;
|
||||
bool IsHeavyActivator = false;
|
||||
|
||||
void Initialize(const ItemInfo& item);
|
||||
void Update(const ItemInfo& item);
|
||||
};
|
||||
|
||||
extern std::unordered_map<int, LaserBeamEffect> LaserBeams;
|
||||
|
||||
void InitializeLaserBeam(short itemNumber);
|
||||
void ControlLaserBeam(short itemNumber);
|
||||
void CollideLaserBeam(short itemNumber, ItemInfo* playerItem, CollisionInfo* coll);
|
||||
void ClearLaserBeamEffects();
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
#include "Specific/level.h"
|
||||
|
||||
// Creatures
|
||||
#include "Objects/TR5/Entity/AutoGun.h" // OK
|
||||
#include "Objects/TR5/Entity/AutoGun.h" // OK
|
||||
#include "Objects/TR5/Entity/HeavyGuard.h" // OK
|
||||
#include "Objects/TR5/Entity/tr5_brownbeast.h" // OK
|
||||
#include "Objects/TR5/Entity/tr5_chef.h" // OK
|
||||
|
@ -58,6 +58,7 @@
|
|||
#include "Objects/Effects/EmberEmitter.h"
|
||||
#include "Objects/Effects/tr5_electricity.h"
|
||||
#include "Objects/TR5/Trap/LaserBarrier.h"
|
||||
#include "Objects/TR5/Trap/LaserBeam.h"
|
||||
#include "Objects/TR5/Trap/ZipLine.h"
|
||||
#include "Objects/TR5/Object/tr5_rollingball.h"
|
||||
#include "Objects/TR5/Trap/tr5_ventilator.h"
|
||||
|
@ -947,6 +948,16 @@ static void StartTrap(ObjectInfo *obj)
|
|||
obj->drawRoutine = nullptr;
|
||||
obj->usingDrawAnimatingItem = false;
|
||||
}
|
||||
|
||||
obj = &Objects[ID_LASER_BEAM];
|
||||
if (obj->loaded)
|
||||
{
|
||||
obj->Initialize = InitializeLaserBeam;
|
||||
obj->control = ControlLaserBeam;
|
||||
obj->collision = CollideLaserBeam;
|
||||
obj->drawRoutine = nullptr;
|
||||
obj->usingDrawAnimatingItem = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void StartSwitch(ObjectInfo *obj)
|
||||
|
|
|
@ -343,7 +343,7 @@ enum GAME_OBJECT_ID : short
|
|||
ID_EXPANDING_PLATFORM,
|
||||
ID_SQUISHY_BLOCK1,
|
||||
ID_SQUISHY_BLOCK2,
|
||||
ID_TRIPWIRE,
|
||||
ID_LASER_BEAM,
|
||||
ID_MINE_DETECTOR,
|
||||
ID_MAP,
|
||||
ID_SECRET_MAP,
|
||||
|
|
|
@ -412,6 +412,7 @@ namespace TEN::Renderer
|
|||
void InitializeSky();
|
||||
void DrawAllStrings();
|
||||
void PrepareLaserBarriers(RenderView& view);
|
||||
void PrepareSingleLaserBeam(RenderView& view);
|
||||
void DrawHorizonAndSky(RenderView& renderView, ID3D11DepthStencilView* depthTarget);
|
||||
void DrawRooms(RenderView& view, RendererPass rendererPass);
|
||||
void DrawItems(RenderView& view, RendererPass rendererPass);
|
||||
|
|
|
@ -1556,6 +1556,7 @@ namespace TEN::Renderer
|
|||
PrepareRopes(view);
|
||||
PrepareStreamers(view);
|
||||
PrepareLaserBarriers(view);
|
||||
PrepareSingleLaserBeam(view);
|
||||
|
||||
// Sprites grouped in buckets for instancing. Non-commutative sprites are collected for a later stage.
|
||||
SortAndPrepareSprites(view);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "Game/Setup.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Objects/TR5/Trap/LaserBarrier.h"
|
||||
#include "Objects/TR5/Trap/LaserBeam.h"
|
||||
#include "Objects/Utils/object_helper.h"
|
||||
#include "Renderer/Structures/RendererSprite2D.h"
|
||||
#include "Renderer/Structures/RendererSprite.h"
|
||||
|
@ -62,10 +63,7 @@ namespace TEN::Renderer
|
|||
|
||||
void Renderer::PrepareLaserBarriers(RenderView& view)
|
||||
{
|
||||
if (LaserBarriers.empty())
|
||||
return;
|
||||
|
||||
for (const auto& [entityID, barrier] : LaserBarriers)
|
||||
for (const auto& [itemNumber, barrier] : LaserBarriers)
|
||||
{
|
||||
for (const auto& beam : barrier.Beams)
|
||||
{
|
||||
|
@ -79,11 +77,59 @@ namespace TEN::Renderer
|
|||
}
|
||||
}
|
||||
|
||||
void Renderer::PrepareSingleLaserBeam(RenderView& view)
|
||||
{
|
||||
for (const auto& [itemNumber, beam] : LaserBeams)
|
||||
{
|
||||
// Prepare cylinder tube.
|
||||
for (int i = 0; i < LaserBeamEffect::SUBDIVISION_COUNT; i++)
|
||||
{
|
||||
bool isLastSubdivision = (i == (LaserBeamEffect::SUBDIVISION_COUNT - 1));
|
||||
|
||||
AddColoredQuad(
|
||||
beam.Vertices[i],
|
||||
beam.Vertices[isLastSubdivision ? 0 : (i + 1)],
|
||||
beam.Vertices[LaserBeamEffect::SUBDIVISION_COUNT + (isLastSubdivision ? 0 : (i + 1))],
|
||||
beam.Vertices[LaserBeamEffect::SUBDIVISION_COUNT + i],
|
||||
beam.Color, beam.Color,
|
||||
beam.Color, beam.Color,
|
||||
BlendMode::Additive, view, SpriteRenderType::LaserBeam);
|
||||
}
|
||||
|
||||
// Prepare cylinder caps.
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int baseIndex = LaserBeamEffect::SUBDIVISION_COUNT * i;
|
||||
|
||||
AddColoredQuad(
|
||||
beam.Vertices[baseIndex + 0], beam.Vertices[baseIndex + 1],
|
||||
beam.Vertices[baseIndex + 2], beam.Vertices[baseIndex + 3],
|
||||
beam.Color, beam.Color,
|
||||
beam.Color, beam.Color,
|
||||
BlendMode::Additive, view, SpriteRenderType::LaserBeam);
|
||||
|
||||
AddColoredQuad(
|
||||
beam.Vertices[baseIndex + 0], beam.Vertices[baseIndex + 3],
|
||||
beam.Vertices[baseIndex + 4], beam.Vertices[baseIndex + 7],
|
||||
beam.Color, beam.Color,
|
||||
beam.Color, beam.Color,
|
||||
BlendMode::Additive, view, SpriteRenderType::LaserBeam);
|
||||
|
||||
AddColoredQuad(
|
||||
beam.Vertices[baseIndex + 4], beam.Vertices[baseIndex + 5],
|
||||
beam.Vertices[baseIndex + 6], beam.Vertices[baseIndex + 7],
|
||||
beam.Color, beam.Color,
|
||||
beam.Color, beam.Color,
|
||||
BlendMode::Additive, view, SpriteRenderType::LaserBeam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::PrepareStreamers(RenderView& view)
|
||||
{
|
||||
constexpr auto BLEND_MODE_DEFAULT = BlendMode::Additive;
|
||||
constexpr auto DEFAULT_BLEND_MODE = BlendMode::Additive;
|
||||
|
||||
for (const auto& [entityNumber, module] : StreamerEffect.Modules)
|
||||
for (const auto& [itemNumber, module] : StreamerEffect.Modules)
|
||||
{
|
||||
for (const auto& [tag, pool] : module.Pools)
|
||||
{
|
||||
|
@ -96,9 +142,9 @@ namespace TEN::Renderer
|
|||
|
||||
if (segment.Life <= 0.0f)
|
||||
continue;
|
||||
|
||||
|
||||
// Determine blend mode.
|
||||
auto blendMode = BLEND_MODE_DEFAULT;
|
||||
auto blendMode = DEFAULT_BLEND_MODE;
|
||||
if (segment.Flags & (int)StreamerFlags::BlendModeAdditive)
|
||||
blendMode = BlendMode::AlphaBlend;
|
||||
|
||||
|
|
|
@ -232,7 +232,8 @@ enum class RendererPass
|
|||
enum class SpriteRenderType
|
||||
{
|
||||
Default,
|
||||
LaserBarrier
|
||||
LaserBarrier,
|
||||
LaserBeam
|
||||
};
|
||||
|
||||
enum class RendererObjectType
|
||||
|
|
|
@ -346,7 +346,7 @@ The following constants are inside ObjID.
|
|||
EXPANDING_PLATFORM
|
||||
SQUISHY_BLOCK1
|
||||
SQUISHY_BLOCK2
|
||||
TRIPWIRE
|
||||
LASER_BEAM
|
||||
MINE_DETECTOR
|
||||
MAP
|
||||
SECRET_MAP
|
||||
|
@ -1521,7 +1521,7 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> kObjIDs {
|
|||
{ "EXPANDING_PLATFORM", ID_EXPANDING_PLATFORM },
|
||||
{ "SQUISHY_BLOCK1", ID_SQUISHY_BLOCK1 },
|
||||
{ "SQUISHY_BLOCK2", ID_SQUISHY_BLOCK2 },
|
||||
{ "TRIPWIRE", ID_TRIPWIRE },
|
||||
{ "LASER_BEAM", ID_LASER_BEAM },
|
||||
{ "MINE_DETECTOR", ID_MINE_DETECTOR },
|
||||
{ "MAP", ID_MAP },
|
||||
{ "SECRET_MAP", ID_SECRET_MAP },
|
||||
|
|
|
@ -24,182 +24,89 @@
|
|||
|
||||
cbuffer BlendingBuffer : register(b12)
|
||||
{
|
||||
uint BlendMode;
|
||||
int AlphaTest;
|
||||
float AlphaThreshold;
|
||||
uint BlendMode;
|
||||
int AlphaTest;
|
||||
float AlphaThreshold;
|
||||
};
|
||||
|
||||
void DoAlphaTest(float4 inputColor)
|
||||
{
|
||||
if (AlphaTest == ALPHATEST_GREATER_THAN && inputColor.w < AlphaThreshold)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
else if (AlphaTest == ALPHATEST_LESS_THAN && inputColor.w > AlphaThreshold)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (AlphaTest == ALPHATEST_GREATER_THAN && inputColor.w < AlphaThreshold)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
else if (AlphaTest == ALPHATEST_LESS_THAN && inputColor.w > AlphaThreshold)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float4 DoDistanceFogForPixel(float4 sourceColor, float4 fogColor, float value)
|
||||
{
|
||||
switch (BlendMode)
|
||||
{
|
||||
case BLENDMODE_ADDITIVE:
|
||||
case BLENDMODE_SCREEN:
|
||||
case BLENDMODE_LIGHTEN:
|
||||
fogColor.xyz *= Luma(sourceColor.xyz);
|
||||
break;
|
||||
switch (BlendMode)
|
||||
{
|
||||
case BLENDMODE_ADDITIVE:
|
||||
case BLENDMODE_SCREEN:
|
||||
case BLENDMODE_LIGHTEN:
|
||||
fogColor.xyz *= Luma(sourceColor.xyz);
|
||||
break;
|
||||
|
||||
case BLENDMODE_SUBTRACTIVE:
|
||||
case BLENDMODE_EXCLUDE:
|
||||
fogColor.xyz *= 1.0f - Luma(sourceColor.xyz);
|
||||
break;
|
||||
case BLENDMODE_SUBTRACTIVE:
|
||||
case BLENDMODE_EXCLUDE:
|
||||
fogColor.xyz *= 1.0f - Luma(sourceColor.xyz);
|
||||
break;
|
||||
|
||||
case BLENDMODE_ALPHABLEND:
|
||||
fogColor.w = sourceColor.w;
|
||||
break;
|
||||
case BLENDMODE_ALPHABLEND:
|
||||
fogColor.w = sourceColor.w;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (fogColor.w > sourceColor.w)
|
||||
fogColor.w = sourceColor.w;
|
||||
if (fogColor.w > sourceColor.w)
|
||||
fogColor.w = sourceColor.w;
|
||||
|
||||
float4 result = lerp(sourceColor, fogColor, value);
|
||||
return result;
|
||||
float4 result = lerp(sourceColor, fogColor, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 DoFogBulbsForPixel(float4 sourceColor, float4 fogColor)
|
||||
{
|
||||
switch (BlendMode)
|
||||
{
|
||||
case BLENDMODE_ADDITIVE:
|
||||
case BLENDMODE_SCREEN:
|
||||
case BLENDMODE_LIGHTEN:
|
||||
fogColor.xyz *= Luma(sourceColor);
|
||||
break;
|
||||
switch (BlendMode)
|
||||
{
|
||||
case BLENDMODE_ADDITIVE:
|
||||
case BLENDMODE_SCREEN:
|
||||
case BLENDMODE_LIGHTEN:
|
||||
fogColor.xyz *= Luma(sourceColor);
|
||||
break;
|
||||
|
||||
case BLENDMODE_SUBTRACTIVE:
|
||||
case BLENDMODE_EXCLUDE:
|
||||
fogColor.xyz *= 1.0f - Luma(sourceColor.xyz);
|
||||
break;
|
||||
case BLENDMODE_SUBTRACTIVE:
|
||||
case BLENDMODE_EXCLUDE:
|
||||
fogColor.xyz *= 1.0f - Luma(sourceColor.xyz);
|
||||
break;
|
||||
|
||||
case BLENDMODE_ALPHABLEND:
|
||||
fogColor.w = sourceColor.w;
|
||||
break;
|
||||
case BLENDMODE_ALPHABLEND:
|
||||
fogColor.w = sourceColor.w;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (fogColor.w > sourceColor.w)
|
||||
fogColor.w = sourceColor.w;
|
||||
if (fogColor.w > sourceColor.w)
|
||||
fogColor.w = sourceColor.w;
|
||||
|
||||
float4 result = sourceColor;
|
||||
float4 result = sourceColor;
|
||||
|
||||
result.xyz += saturate(fogColor.xyz);
|
||||
result.xyz += saturate(fogColor.xyz);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float4 DoLaserBarrierEffect(float3 input, float4 output, float2 uv, float faceFactor, float timeUniform)
|
||||
{
|
||||
float2 noiseTexture = input.xy / uv;
|
||||
noiseTexture *= uv.x / uv.y;
|
||||
float noiseValue = FractalNoise(noiseTexture * 8.0f - timeUniform);
|
||||
|
||||
float4 color = output;
|
||||
float gradL = smoothstep(0.0, 1.0, uv.x);
|
||||
float gradR = smoothstep(1.0, 0.0, uv.x);
|
||||
float gradT = smoothstep(0.0, 0.25, uv.y);
|
||||
float gradB = 1.0 - smoothstep(0.75, 1.0, uv.y);
|
||||
|
||||
float distortion = timeUniform / 1024;
|
||||
|
||||
float3 noisix = SimplexNoise
|
||||
(
|
||||
SimplexNoise(float3(input.r * distortion, input.g, input.b))
|
||||
);
|
||||
float3 shadowx = SimplexNoise
|
||||
(
|
||||
cos(SimplexNoise(sin(timeUniform + input.rgb * 400)))
|
||||
);
|
||||
|
||||
noisix.x = noisix.x > 0.9 ? 0.7 : noisix.x;
|
||||
noisix.y = noisix.y > 0.9 ? 0.7 : noisix.y;
|
||||
noisix.z = noisix.z > 0.9 ? 0.7 : noisix.z;
|
||||
color.rgb += noisix + 0.5f;
|
||||
color.rgb -= noisix + 0.2f;
|
||||
|
||||
float frequency = 0.1;
|
||||
float amplitude = 0.8;
|
||||
float persistence = 0.5;
|
||||
float noiseValue2 = 0;
|
||||
float noiseValue3 = 0;
|
||||
|
||||
float2 uv84 = (uv * 2.4);
|
||||
uv84.y = (uv84.y - 1.3);
|
||||
uv84.x = (uv84.x / 1.3);
|
||||
float2 uv85 = (uv / 2.4);
|
||||
|
||||
noiseValue2 = AnimatedNebula(uv84, timeUniform * 0.1f);
|
||||
|
||||
frequency = 2.5;
|
||||
amplitude = 0.2;
|
||||
persistence = 4.7;
|
||||
|
||||
float2 uv83 = uv * 8;
|
||||
uv83.y = (uv.y + (timeUniform * 0.02));
|
||||
noiseValue3 = NebularNoise(uv83, frequency, amplitude, persistence);
|
||||
|
||||
noiseValue2 += AnimatedNebula(uv/2, timeUniform * 0.05f);
|
||||
|
||||
color.rgb *= noiseValue2 + 0.6f;
|
||||
color.rgb += noiseValue3;
|
||||
color.a *= noiseValue + 0.01f;
|
||||
|
||||
color.rgb -= shadowx + 0.1f;
|
||||
|
||||
color.a *= noiseValue2 + 0.9f;
|
||||
color.a *= noiseValue3 + 2.0f;
|
||||
|
||||
float fade0 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradL, gradT)));
|
||||
float fade1 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradL, gradB)));
|
||||
float fade2 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradR, gradB)));
|
||||
float fade3 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradR, gradT)));
|
||||
|
||||
float fadeL = 1.40f * faceFactor * faceFactor * (1.0 - gradL);
|
||||
float fadeB = 2.75f * faceFactor * faceFactor * (1.0 - gradB);
|
||||
float fadeR = 1.40f * faceFactor * faceFactor * (1.0 - gradR);
|
||||
float fadeT = 2.75f * faceFactor * faceFactor * (1.0 - gradT);
|
||||
|
||||
float fade = max(
|
||||
max(max(fade0, fade1), max(fade2, fade3)),
|
||||
max(max(fadeL, fadeR), max(fadeB, fadeT)));
|
||||
|
||||
float scale = 1.0 - fade;
|
||||
|
||||
color *= scale;
|
||||
float decayFactor = 1.0f;
|
||||
if (uv.y > 0.5f && uv.y < 1.0f)
|
||||
{
|
||||
decayFactor = uv.y / 2;
|
||||
}
|
||||
if (uv.y < 0.5f && uv.y > 0.0f)
|
||||
{
|
||||
decayFactor = (1.0f - uv.y) / 2;
|
||||
}
|
||||
color *= decayFactor;
|
||||
|
||||
color.rgb = smoothstep(ZERO, EIGHT_FIVE, color.rgb);
|
||||
return color;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // BLENDINGSHADER
|
||||
|
|
200
TombEngine/Shaders/SpriteEffects.hlsli
Normal file
200
TombEngine/Shaders/SpriteEffects.hlsli
Normal file
|
@ -0,0 +1,200 @@
|
|||
#ifndef SPRITEEFFECTSSHADER
|
||||
#define SPRITEEFFECTSSHADER
|
||||
|
||||
#include "./Math.hlsli"
|
||||
|
||||
#define ZERO float3(0.0f, 0.0f, 0.0f)
|
||||
#define EIGHT_FIVE float3( 0.85f, 0.85f, 0.85f)
|
||||
#define BLENDING 0.707f
|
||||
|
||||
float4 DoLaserBarrierEffect(float3 input, float4 output, float2 uv, float faceFactor, float timeUniform)
|
||||
{
|
||||
float2 noiseTexture = input.xy / uv;
|
||||
noiseTexture *= uv.x / uv.y;
|
||||
float noiseValue = FractalNoise(noiseTexture * 8.0f - timeUniform);
|
||||
|
||||
float4 color = output;
|
||||
float gradL = smoothstep(0.0, 1.0, uv.x);
|
||||
float gradR = smoothstep(1.0, 0.0, uv.x);
|
||||
float gradT = smoothstep(0.0, 0.25, uv.y);
|
||||
float gradB = 1.0 - smoothstep(0.75, 1.0, uv.y);
|
||||
|
||||
float distortion = timeUniform / 1024;
|
||||
|
||||
float3 noisix = SimplexNoise
|
||||
(
|
||||
SimplexNoise(float3(input.r * distortion, input.g, input.b))
|
||||
);
|
||||
float3 shadowx = SimplexNoise
|
||||
(
|
||||
cos(SimplexNoise(sin(timeUniform + input.rgb * 400)))
|
||||
);
|
||||
|
||||
noisix.x = noisix.x > 0.9 ? 0.7 : noisix.x;
|
||||
noisix.y = noisix.y > 0.9 ? 0.7 : noisix.y;
|
||||
noisix.z = noisix.z > 0.9 ? 0.7 : noisix.z;
|
||||
color.rgb += noisix + 0.5f;
|
||||
color.rgb -= noisix + 0.2f;
|
||||
|
||||
float frequency = 0.1;
|
||||
float amplitude = 0.8;
|
||||
float persistence = 0.5;
|
||||
float noiseValue2 = 0;
|
||||
float noiseValue3 = 0;
|
||||
|
||||
float2 uv84 = (uv * 2.4);
|
||||
uv84.y = (uv84.y - 1.3);
|
||||
uv84.x = (uv84.x / 1.3);
|
||||
float2 uv85 = (uv / 2.4);
|
||||
|
||||
noiseValue2 = AnimatedNebula(uv84, timeUniform * 0.1f);
|
||||
|
||||
frequency = 2.5;
|
||||
amplitude = 0.2;
|
||||
persistence = 4.7;
|
||||
|
||||
float2 uv83 = uv * 8;
|
||||
uv83.y = (uv.y + (timeUniform * 0.02));
|
||||
noiseValue3 = NebularNoise(uv83, frequency, amplitude, persistence);
|
||||
|
||||
noiseValue2 += AnimatedNebula(uv / 2, timeUniform * 0.05f);
|
||||
|
||||
color.rgb *= noiseValue2 + 0.6f;
|
||||
color.rgb += noiseValue3;
|
||||
color.a *= noiseValue + 0.01f;
|
||||
|
||||
color.rgb -= shadowx + 0.1f;
|
||||
|
||||
color.a *= noiseValue2 + 0.9f;
|
||||
color.a *= noiseValue3 + 2.0f;
|
||||
|
||||
float fade0 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradL, gradT)));
|
||||
float fade1 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradL, gradB)));
|
||||
float fade2 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradR, gradB)));
|
||||
float fade3 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradR, gradT)));
|
||||
|
||||
float fadeL = 1.40f * faceFactor * faceFactor * (1.0 - gradL);
|
||||
float fadeB = 2.75f * faceFactor * faceFactor * (1.0 - gradB);
|
||||
float fadeR = 1.40f * faceFactor * faceFactor * (1.0 - gradR);
|
||||
float fadeT = 2.75f * faceFactor * faceFactor * (1.0 - gradT);
|
||||
|
||||
float fade = max(
|
||||
max(max(fade0, fade1), max(fade2, fade3)),
|
||||
max(max(fadeL, fadeR), max(fadeB, fadeT)));
|
||||
|
||||
float scale = 1.0 - fade;
|
||||
|
||||
color *= scale;
|
||||
float decayFactor = 1.0f;
|
||||
if (uv.y > 0.5f && uv.y < 1.0f)
|
||||
{
|
||||
decayFactor = uv.y / 2;
|
||||
}
|
||||
if (uv.y < 0.5f && uv.y > 0.0f)
|
||||
{
|
||||
decayFactor = (1.0f - uv.y) / 2;
|
||||
}
|
||||
color *= decayFactor;
|
||||
|
||||
color.rgb = smoothstep(ZERO, EIGHT_FIVE, color.rgb);
|
||||
return color;
|
||||
}
|
||||
|
||||
float4 DoLaserBeamEffect(float3 input, float4 output, float2 uv, float faceFactor, float timeUniform)
|
||||
{
|
||||
float2 noiseTexture = input.xy / uv;
|
||||
noiseTexture *= uv.x / uv.y;
|
||||
float noiseValue = FractalNoise(noiseTexture * 0.1f - timeUniform);
|
||||
|
||||
float4 color = output;
|
||||
float gradL = smoothstep(0.0, 0.0, uv.x);
|
||||
float gradR = smoothstep(0.0, 0.0, uv.x);
|
||||
float gradT = smoothstep(0.0, 0.25, uv.y);
|
||||
float gradB = 1.0 - smoothstep(0.75, 1.0, uv.y);
|
||||
|
||||
// Stretching the UV coordinates
|
||||
float stretchFactor = 0.005f;
|
||||
uv.x *= stretchFactor;
|
||||
|
||||
float distortion = timeUniform / 1024;
|
||||
|
||||
float3 noisix = SimplexNoise
|
||||
(
|
||||
SimplexNoise(float3(input.r * distortion, input.g, input.b))
|
||||
);
|
||||
float3 shadowx = SimplexNoise
|
||||
(
|
||||
cos(SimplexNoise(sin(timeUniform + input.rgb * 400)))
|
||||
);
|
||||
|
||||
noisix.x = noisix.x > 0.9 ? 0.7 : noisix.x;
|
||||
noisix.y = noisix.y > 0.9 ? 0.7 : noisix.y;
|
||||
noisix.z = noisix.z > 0.9 ? 0.7 : noisix.z;
|
||||
color.rgb += noisix + 0.5f;
|
||||
color.rgb -= noisix + 0.2f;
|
||||
|
||||
float frequency = 0.1;
|
||||
float amplitude = 0.8;
|
||||
float persistence = 0.5;
|
||||
float noiseValue2 = 0;
|
||||
float noiseValue3 = 0;
|
||||
|
||||
float2 uv84 = (uv * 1.4);
|
||||
uv84.y = (uv84.y - 1.3);
|
||||
uv84.x = (uv84.x / 1.3);
|
||||
float2 uv85 = (uv / 1.4);
|
||||
|
||||
noiseValue2 = AnimatedNebula(uv84, timeUniform * 0.1f);
|
||||
|
||||
frequency = 2.5;
|
||||
amplitude = 0.2;
|
||||
persistence = 4.7;
|
||||
|
||||
float2 uv83 = uv * 6;
|
||||
uv83.y = (uv.y + (timeUniform * 0.02));
|
||||
noiseValue3 = NebularNoise(uv83, frequency, amplitude, persistence);
|
||||
|
||||
noiseValue2 += AnimatedNebula(uv / 2, timeUniform * 0.05f);
|
||||
|
||||
color.rgb *= noiseValue2 + 0.6f;
|
||||
color.rgb += noiseValue3;
|
||||
color.a *= noiseValue + 0.01f;
|
||||
|
||||
color.rgb -= shadowx + 0.1f;
|
||||
|
||||
color.a *= noiseValue2 + 0.9f;
|
||||
color.a *= noiseValue3 + 2.0f;
|
||||
|
||||
float fade0 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradL, gradT)));
|
||||
float fade1 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradL, gradB)));
|
||||
float fade2 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradR, gradB)));
|
||||
float fade3 = faceFactor * max(0.0, 1.0 - dot(float2(BLENDING, BLENDING), float2(gradR, gradT)));
|
||||
|
||||
float fadeL = 0; //fade out hight
|
||||
float fadeB = 0.3f * faceFactor * faceFactor * (0.3 - gradB); //fade out width
|
||||
float fadeR = 0; //fade out hight
|
||||
float fadeT = 0.3f * faceFactor * faceFactor * (0.3 - gradT); //fade out width
|
||||
|
||||
float fade = max(
|
||||
max(max(fade0, fade1), max(fade2, fade3)),
|
||||
max(max(fadeL, fadeR), max(fadeB, fadeT)));
|
||||
|
||||
float scale = 1.0 - fade;
|
||||
|
||||
color *= scale;
|
||||
float decayFactor = 1.0f;
|
||||
if (uv.y > 0.5f && uv.y < 1.0f)
|
||||
{
|
||||
decayFactor = uv.y / 2;
|
||||
}
|
||||
if (uv.y < 0.5f && uv.y > 0.0f)
|
||||
{
|
||||
decayFactor = (1.0f - uv.y) / 2;
|
||||
}
|
||||
color *= decayFactor;
|
||||
color.rgb *= 0.17; // Reduce brightness. Don't change
|
||||
color.rgb = smoothstep(ZERO, EIGHT_FIVE, color.rgb);
|
||||
return color;
|
||||
}
|
||||
|
||||
#endif // SPRITEEFFECTSSHADER
|
|
@ -3,6 +3,7 @@
|
|||
#include "./VertexInput.hlsli"
|
||||
#include "./Math.hlsli"
|
||||
#include "./ShaderLight.hlsli"
|
||||
#include "./SpriteEffects.hlsli"
|
||||
|
||||
// NOTE: This shader is used for all 3D and alpha blended sprites, because we send aleady transformed vertices to the GPU
|
||||
// instead of instances
|
||||
|
@ -77,9 +78,14 @@ float4 PS(PixelShaderInput input) : SV_TARGET
|
|||
output = DoLaserBarrierEffect(input.Position, output, input.UV, FADE_FACTOR, Frame);
|
||||
}
|
||||
|
||||
if (RenderType == 2)
|
||||
{
|
||||
output = DoLaserBeamEffect(input.Position, output, input.UV, FADE_FACTOR, Frame);
|
||||
}
|
||||
|
||||
output.xyz -= float3(input.FogBulbs.w, input.FogBulbs.w, input.FogBulbs.w);
|
||||
output.xyz = saturate(output.xyz);
|
||||
|
||||
|
||||
output = DoDistanceFogForPixel(output, float4(0.0f, 0.0f, 0.0f, 0.0f), input.DistanceFog);
|
||||
|
||||
return output;
|
||||
|
|
|
@ -668,6 +668,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
|||
<ClInclude Include="Objects\TR5\Switch\tr5_crowdove_switch.h" />
|
||||
<ClInclude Include="Objects\TR5\Switch\tr5_raisingcog.h" />
|
||||
<ClInclude Include="Objects\TR5\Trap\LaserBarrier.h" />
|
||||
<ClInclude Include="Objects\TR5\Trap\LaserBeam.h" />
|
||||
<ClInclude Include="Objects\TR5\Trap\tr5_explosion.h" />
|
||||
<ClInclude Include="Objects\TR5\Trap\tr5_fallingceiling.h" />
|
||||
<ClInclude Include="Objects\TR5\Trap\tr5_romehammer.h" />
|
||||
|
@ -1162,6 +1163,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
|||
<ClCompile Include="Objects\TR5\Switch\tr5_raisingcog.cpp" />
|
||||
<ClCompile Include="Objects\TR5\tr5_objects.cpp" />
|
||||
<ClCompile Include="Objects\TR5\Trap\LaserBarrier.cpp" />
|
||||
<ClCompile Include="Objects\TR5\Trap\LaserBeam.cpp" />
|
||||
<ClCompile Include="Objects\TR5\Trap\tr5_explosion.cpp" />
|
||||
<ClCompile Include="Objects\TR5\Trap\tr5_fallingceiling.cpp" />
|
||||
<ClCompile Include="Objects\TR5\Trap\tr5_romehammer.cpp" />
|
||||
|
@ -1273,6 +1275,9 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
|
|||
<DeploymentContent>true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="Shaders\Shadows.hlsli" />
|
||||
<None Include="Shaders\SpriteEffects.hlsli">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
</None>
|
||||
<None Include="Shaders\VertexEffects.hlsli" />
|
||||
<None Include="Shaders\VertexInput.hlsli">
|
||||
<DeploymentContent>true</DeploymentContent>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue