Scene Changes and bug fixes #431
|
@ -67,8 +67,13 @@ public class GameManager : Script
|
||||||
stealFoodPopUpDone = false;
|
stealFoodPopUpDone = false;
|
||||||
PreviewLevelDone = false;
|
PreviewLevelDone = false;
|
||||||
|
|
||||||
AudioHandler.audioClipHandlers["BGMWin"] = Audio.CreateAudioClip("event:/Music/stingers/game_win");
|
var winAudio = Audio.CreateAudioClip("event:/Music/stingers/game_win");
|
||||||
AudioHandler.audioClipHandlers["BGMLose"] = Audio.CreateAudioClip("event:/Music/stingers/game_lose");
|
winAudio.DestroyOnSceneExit = false;
|
||||||
|
AudioHandler.audioClipHandlers["BGMWin"] = winAudio;
|
||||||
|
|
||||||
|
var loseAudio = Audio.CreateAudioClip("event:/Music/stingers/game_lose");
|
||||||
|
loseAudio.DestroyOnSceneExit = false;
|
||||||
|
AudioHandler.audioClipHandlers["BGMLose"] = loseAudio;
|
||||||
|
|
||||||
goingToWin = false;
|
goingToWin = false;
|
||||||
goingToLose = false;
|
goingToLose = false;
|
||||||
|
|
|
@ -1,24 +1,32 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
#define PI 3.14159265f
|
||||||
|
|
||||||
layout(local_size_x = 128) in;
|
layout(local_size_x = 128) in;
|
||||||
|
|
||||||
struct EmitterParameters
|
struct EmitterParameters
|
||||||
{
|
{
|
||||||
vec4 angularMin;
|
vec4 angularRangesAndOffsets;
|
||||||
vec4 angularMax;
|
float minSpeed;
|
||||||
|
float maxSpeed;
|
||||||
|
float rotationSpeed;
|
||||||
|
float rotationDecay;
|
||||||
vec4 lifeAndSizeRange; // min life, max life, min size, max size
|
vec4 lifeAndSizeRange; // min life, max life, min size, max size
|
||||||
}
|
float sizeDecay;
|
||||||
|
uint textureIndex;
|
||||||
|
float padding[2];
|
||||||
|
};
|
||||||
|
|
||||||
struct ParticleData
|
struct ParticleData
|
||||||
{
|
{
|
||||||
vec4 position;
|
vec4 position;
|
||||||
vec4 rotation;
|
vec4 orientationSpeedDecay;
|
||||||
vec4 velocity;
|
vec4 velocity;
|
||||||
vec4 acceleration;
|
vec4 acceleration;
|
||||||
vec4 scaleAndDecay;
|
vec4 scaleAndDecay;
|
||||||
float life;
|
float life;
|
||||||
uint textureIndex;
|
uint textureIndex;
|
||||||
}
|
};
|
||||||
|
|
||||||
struct GenericData
|
struct GenericData
|
||||||
{
|
{
|
||||||
|
@ -96,22 +104,86 @@ float rand(inout uint state)
|
||||||
return float(x)*uintBitsToFloat(0x2f800004u);
|
return float(x)*uintBitsToFloat(0x2f800004u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float map(float value, float inMin, float inMax, float outMin, float outMax)
|
||||||
|
{
|
||||||
|
return outMin + (outMax - outMin) * (value - inMin) / (inMax - inMin);
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
uint emitterInvocationIndex = gl_GlobalInvocationID.x;
|
uint emitterInvocationIndex = gl_GlobalInvocationID.x;
|
||||||
|
vec4 emitterPosition = emitterPushConstant.emitterPosition;
|
||||||
|
vec4 angularRangesAndOffsets = emitterParams.data.angularRangesAndOffsets;
|
||||||
|
float minSpeed = emitterParams.data.minSpeed;
|
||||||
|
float maxSpeed = emitterParams.data.maxSpeed;
|
||||||
|
|
||||||
if (emitterInvocationIndex >= emitterPushConstant.emissionCount)
|
if (emitterInvocationIndex >= emitterPushConstant.emissionCount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Freecount will start at max particles. Here we subtract every time we emit.
|
||||||
int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1;
|
int freelistIndex = atomicAdd (freelist.freeCount, -1) - 1;
|
||||||
if (freelistIndex < 0)
|
if (freelistIndex < 0)
|
||||||
atomicAdd (freelist.freeCount, 1);
|
atomicAdd (freelist.freeCount, 1);
|
||||||
|
|
||||||
ParticleData particle;
|
ParticleData particle;
|
||||||
|
|
||||||
int index = freelist.freeIndices[freelistIndex];
|
// Get seed for randomization
|
||||||
particle.position = emitterPosition;
|
uint pixel_index = uint (emitterPosition.x + emitterPosition.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1));
|
||||||
particle.life = emitterParams.10.0f;
|
uint seed = pcg_hash (pixel_index);
|
||||||
|
|
||||||
particles[index] = particle;
|
int index = freelist.freeIndices[freelistIndex];
|
||||||
|
|
||||||
|
// emit particle from emitter position
|
||||||
|
particle.position = vec4 (emitterPosition.xyz, 1.0f);
|
||||||
|
|
||||||
|
vec2 eulerAngles = vec2 (rand(seed) * angularRangesAndOffsets.x + angularRangesAndOffsets.z,
|
||||||
|
rand(seed) * angularRangesAndOffsets.y + angularRangesAndOffsets.w);
|
||||||
|
|
||||||
|
// Set its velocity
|
||||||
|
// particle.velocity.xyz = vec3 (cos(eulerAngles.x) * cos(eulerAngles.y),
|
||||||
|
// sin(eulerAngles.x) * cos(eulerAngles.y),
|
||||||
|
// sin(eulerAngles.y));
|
||||||
|
|
||||||
|
float bank = eulerAngles.y;
|
||||||
|
float cb = cos(bank);
|
||||||
|
float sb = sin(bank);
|
||||||
|
float ch = cos (eulerAngles.x);
|
||||||
|
float sh = sin (eulerAngles.x);
|
||||||
|
float cp = cos (0.0f);
|
||||||
|
float sp = sin (0.0f);
|
||||||
|
|
||||||
|
particle.velocity.xyz = mat3 (
|
||||||
|
(ch * cb + sh * sp * sb), (sb * cp), (-sh * cb + ch * sp * sb),
|
||||||
|
(-ch * sb + sh * sp * cb), (cb * cp), ( sb * sh + ch * sp * cb),
|
||||||
|
(sh * cp), (-sp), (ch * cp)
|
||||||
|
) * vec3 (1.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
|
||||||
|
particle.velocity *= map (rand (seed), 0.0f, 1.0f, minSpeed.x, maxSpeed.x);
|
||||||
|
|
||||||
|
// randomize life value that ranges from minLife to maxLife
|
||||||
|
particle.life = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.x, emitterParams.data.lifeAndSizeRange.y);
|
||||||
|
|
||||||
|
float particleSize = map (rand(seed), 0.0f, 1.0f, emitterParams.data.lifeAndSizeRange.z, emitterParams.data.lifeAndSizeRange.w);
|
||||||
|
|
||||||
|
// Set size of particle
|
||||||
|
particle.scaleAndDecay.x = particleSize;
|
||||||
|
particle.scaleAndDecay.y = particleSize;
|
||||||
|
particle.scaleAndDecay.z = emitterParams.data.sizeDecay;
|
||||||
|
particle.scaleAndDecay.w = emitterParams.data.sizeDecay;
|
||||||
|
|
||||||
|
// Set the texture for the particle
|
||||||
|
particle.textureIndex = emitterParams.data.textureIndex;
|
||||||
|
|
||||||
|
// Set orientation and rotation speed
|
||||||
|
if (emitterParams.data.rotationSpeed != 0.0f)
|
||||||
|
particle.orientationSpeedDecay = vec4 (rand(seed) * PI, emitterParams.data.rotationSpeed, emitterParams.data.rotationDecay, 0.0f);
|
||||||
|
else
|
||||||
|
particle.orientationSpeedDecay = vec4 (0.0f);
|
||||||
|
|
||||||
|
|
||||||
|
particle.acceleration = vec4 (0.0f, -0.058f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
|
||||||
|
inputParticles.data[index] = particle;
|
||||||
}
|
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
Name: ParticleEmit_CS
|
||||||
|
ID: 49959611
|
||||||
|
Type: 2
|
|
@ -0,0 +1,146 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(local_size_x = 128) in;
|
||||||
|
|
||||||
|
struct DrawArraysIndirectArgs
|
||||||
|
{
|
||||||
|
uint count;
|
||||||
|
uint instanceCount;
|
||||||
|
uint first;
|
||||||
|
uint baseInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParticleData
|
||||||
|
{
|
||||||
|
vec4 position;
|
||||||
|
vec4 orientationSpeedDecay;
|
||||||
|
vec4 velocity;
|
||||||
|
vec4 acceleration;
|
||||||
|
vec4 scaleAndDecay;
|
||||||
|
float life;
|
||||||
|
uint textureIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GenericData
|
||||||
|
{
|
||||||
|
//! Delta time
|
||||||
|
float dt;
|
||||||
|
|
||||||
|
//! Elapsed time of the application
|
||||||
|
float elapsedTime;
|
||||||
|
|
||||||
|
//! Viewport width of the scene (excluding imgui, that means smaller than window)
|
||||||
|
uint viewportWidth;
|
||||||
|
|
||||||
|
//! Ditto but for height
|
||||||
|
uint viewportHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform CameraData
|
||||||
|
{
|
||||||
|
vec4 position;
|
||||||
|
mat4 vpMat;
|
||||||
|
mat4 viewMat;
|
||||||
|
mat4 projMat;
|
||||||
|
} cameraData;
|
||||||
|
|
||||||
|
|
||||||
|
layout (set = 0, binding = 0) uniform GenericDataBuffer
|
||||||
|
{
|
||||||
|
GenericData data;
|
||||||
|
} genericDataBuffer;
|
||||||
|
|
||||||
|
layout (std430, set = 2, binding = 1) coherent restrict readonly buffer ParticlesInputBuffer
|
||||||
|
{
|
||||||
|
ParticleData data[];
|
||||||
|
} inputParticles;
|
||||||
|
|
||||||
|
// output buffer not needed
|
||||||
|
layout (std430, set = 2, binding = 2) coherent restrict buffer ParticlesOutputBuffer
|
||||||
|
{
|
||||||
|
ParticleData data[];
|
||||||
|
} outputParticles;
|
||||||
|
|
||||||
|
layout (std430, set = 2, binding = 3) coherent restrict buffer ParticlesFreelistBuffer
|
||||||
|
{
|
||||||
|
int freeCount;
|
||||||
|
int freeIndices[];
|
||||||
|
|
||||||
|
} freelist;
|
||||||
|
|
||||||
|
layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData
|
||||||
|
{
|
||||||
|
uint indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (std140, set = 2, binding = 5) coherent restrict buffer IndirectDrawArgs
|
||||||
|
{
|
||||||
|
DrawArraysIndirectArgs indirectArgs;
|
||||||
|
};
|
||||||
|
|
||||||
|
// push constants
|
||||||
|
layout(std140, push_constant) uniform EmitterPushConstant
|
||||||
|
{
|
||||||
|
vec4 emitterPosition;
|
||||||
|
uint emissionCount;
|
||||||
|
|
||||||
|
} emitterPushConstant;
|
||||||
|
|
||||||
|
uint pcg_hash(uint seed)
|
||||||
|
{
|
||||||
|
uint state = seed * 747796405u + 2891336453u;
|
||||||
|
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||||
|
return (word >> 22u) ^ word;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to advance the PCG state.
|
||||||
|
uint rand_pcg(inout uint rng_state)
|
||||||
|
{
|
||||||
|
uint state = rng_state;
|
||||||
|
rng_state = rng_state * 747796405u + 2891336453u;
|
||||||
|
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||||
|
return (word >> 22u) ^ word;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advances the prng state and returns the corresponding random float.
|
||||||
|
float rand(inout uint state)
|
||||||
|
{
|
||||||
|
uint x = rand_pcg(state);
|
||||||
|
state = x;
|
||||||
|
return float(x)*uintBitsToFloat(0x2f800004u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
uint index = gl_GlobalInvocationID.x;
|
||||||
|
|
||||||
|
ParticleData particle = inputParticles.data[index];
|
||||||
|
|
||||||
|
// Get seed for randomization
|
||||||
|
uint pixel_index = uint (particle.position.x + particle.position.y + floatBitsToUint(genericDataBuffer.data.elapsedTime) * (gl_GlobalInvocationID.x + 1));
|
||||||
|
uint seed = pcg_hash (pixel_index);
|
||||||
|
|
||||||
|
if (particle.life > 0.0f)
|
||||||
|
{
|
||||||
|
// update position from velocity
|
||||||
|
particle.position += particle.velocity * genericDataBuffer.data.dt;
|
||||||
|
particle.velocity += vec4 (rand(seed) * particle.acceleration.x, rand(seed) * particle.acceleration.y, rand(seed) * particle.acceleration.z, 1.0f);
|
||||||
|
particle.life -= genericDataBuffer.data.dt;
|
||||||
|
|
||||||
|
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
|
||||||
|
{
|
||||||
|
particle.life = 0.0f;
|
||||||
|
particle.position.x = 9999.0f;
|
||||||
|
|
||||||
|
outputParticles.data[index] = particle;
|
||||||
|
freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1);
|
||||||
|
indices[drawIndex] = index;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
outputParticles.data[index] = particle;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
Name: ParticleUpdateRandomAcc_CS
|
||||||
|
ID: 35838633
|
||||||
|
Type: 2
|
|
@ -13,13 +13,13 @@ struct DrawArraysIndirectArgs
|
||||||
struct ParticleData
|
struct ParticleData
|
||||||
{
|
{
|
||||||
vec4 position;
|
vec4 position;
|
||||||
vec4 rotation;
|
vec4 orientationSpeedDecay;
|
||||||
vec4 velocity;
|
vec4 velocity;
|
||||||
vec4 acceleration;
|
vec4 acceleration;
|
||||||
vec4 scaleAndDecay;
|
vec4 scaleAndDecay;
|
||||||
float life;
|
float life;
|
||||||
uint textureIndex;
|
uint textureIndex;
|
||||||
}
|
};
|
||||||
|
|
||||||
struct GenericData
|
struct GenericData
|
||||||
{
|
{
|
||||||
|
@ -73,10 +73,10 @@ layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData
|
||||||
uint indices[];
|
uint indices[];
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (std140, set = 2, binding = 5) coherent restrict uniform IndirectDrawArgs
|
layout (std140, set = 2, binding = 5) coherent restrict buffer IndirectDrawArgs
|
||||||
{
|
{
|
||||||
DrawArraysIndirectArgs indirectArgs;
|
DrawArraysIndirectArgs indirectArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
// push constants
|
// push constants
|
||||||
layout(std140, push_constant) uniform EmitterPushConstant
|
layout(std140, push_constant) uniform EmitterPushConstant
|
||||||
|
@ -116,26 +116,37 @@ void main()
|
||||||
|
|
||||||
ParticleData particle = inputParticles.data[index];
|
ParticleData particle = inputParticles.data[index];
|
||||||
|
|
||||||
if (particle.lifetime > 0.0f)
|
if (particle.life > 0.0f)
|
||||||
{
|
{
|
||||||
// particle.position += particle.velocity * dt;
|
// update position from velocity
|
||||||
|
particle.position += particle.velocity * genericDataBuffer.data.dt;
|
||||||
|
particle.velocity += particle.acceleration;
|
||||||
|
particle.life -= genericDataBuffer.data.dt;
|
||||||
|
particle.orientationSpeedDecay.x += particle.orientationSpeedDecay.y;
|
||||||
|
particle.scaleAndDecay.x *= particle.scaleAndDecay.z;
|
||||||
|
particle.scaleAndDecay.y *= particle.scaleAndDecay.w;
|
||||||
|
|
||||||
// particle.lifetime -= dt;
|
if (particle.orientationSpeedDecay.y > 0.0f)
|
||||||
// particle.size -= 1.2f * dt;
|
|
||||||
// particle.color += 1.0f * dt;
|
|
||||||
|
|
||||||
if (particle.lifetime < 0.0f || particle.size < 0.0f)
|
|
||||||
{
|
{
|
||||||
particle.lifetime = 0.0f;
|
particle.orientationSpeedDecay.y -= particle.orientationSpeedDecay.z * genericDataBuffer.data.dt;
|
||||||
particle.position.x = 99999.0f;
|
if (particle.orientationSpeedDecay.y < 0.0f)
|
||||||
|
particle.orientationSpeedDecay.y = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (particle.life < 0.0f || particle.scaleAndDecay.x < 0.0f || particle.scaleAndDecay.y < 0.0f)
|
||||||
|
{
|
||||||
|
particle.life = 0.0f;
|
||||||
|
particle.position.x = 9999.0f;
|
||||||
|
|
||||||
outputParticles.data[index] = particle;
|
outputParticles.data[index] = particle;
|
||||||
freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index);
|
freelist.freeIndices[atomicAdd(freelist.freeCount, 1)] = int (index);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
outputParticles.data[index] = particle;
|
|
||||||
uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1);
|
uint drawIndex = atomicAdd (indirectArgs.instanceCount, 1);
|
||||||
indices[drawIndex] = index;
|
indices[drawIndex] = index;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
outputParticles.data[index] = particle;
|
||||||
}
|
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
Name: ParticleUpdate_CS
|
||||||
|
ID: 36260925
|
||||||
|
Type: 2
|
|
@ -0,0 +1,26 @@
|
||||||
|
#version 460 core
|
||||||
|
#extension GL_EXT_nonuniform_qualifier : require
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
layout (set = 0, binding = 1) uniform sampler2D textures[]; // for textures (global)
|
||||||
|
|
||||||
|
// between shader stages
|
||||||
|
layout(location = 0) in struct
|
||||||
|
{
|
||||||
|
vec2 uv; // location = 0
|
||||||
|
} In;
|
||||||
|
|
||||||
|
// material stuff
|
||||||
|
layout(location = 1) flat in struct
|
||||||
|
{
|
||||||
|
uint textureIndex;
|
||||||
|
} InFlat;
|
||||||
|
|
||||||
|
|
||||||
|
void main ()
|
||||||
|
{
|
||||||
|
fragColor = vec4 (texture(textures [nonuniformEXT(InFlat.textureIndex)], In.uv));
|
||||||
|
if (fragColor.a < 0.01f)
|
||||||
|
discard;
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
Name: Particle_FS
|
||||||
|
ID: 42509714
|
||||||
|
Type: 2
|
|
@ -0,0 +1,101 @@
|
||||||
|
#version 460 core
|
||||||
|
|
||||||
|
struct GenericData
|
||||||
|
{
|
||||||
|
//! Delta time
|
||||||
|
float dt;
|
||||||
|
|
||||||
|
//! Elapsed time of the application
|
||||||
|
float elapsedTime;
|
||||||
|
|
||||||
|
//! Viewport width of the scene (excluding imgui, that means smaller than window)
|
||||||
|
uint viewportWidth;
|
||||||
|
|
||||||
|
//! Ditto but for height
|
||||||
|
uint viewportHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ParticleData
|
||||||
|
{
|
||||||
|
vec4 position;
|
||||||
|
vec4 orientationSpeedDecay;
|
||||||
|
vec4 velocity;
|
||||||
|
vec4 acceleration;
|
||||||
|
vec4 scaleAndDecay;
|
||||||
|
float life;
|
||||||
|
uint textureIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (set = 0, binding = 0) uniform GenericDataBuffer
|
||||||
|
{
|
||||||
|
GenericData data;
|
||||||
|
} genericDataBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
layout(set = 1, binding = 0) uniform CameraData
|
||||||
|
{
|
||||||
|
vec4 position;
|
||||||
|
mat4 vpMat;
|
||||||
|
mat4 viewMat;
|
||||||
|
mat4 projMat;
|
||||||
|
} cameraData;
|
||||||
|
|
||||||
|
// output buffer not needed
|
||||||
|
layout (std430, set = 2, binding = 2) coherent restrict buffer ParticlesOutputBuffer
|
||||||
|
{
|
||||||
|
ParticleData data[];
|
||||||
|
} outputParticles;
|
||||||
|
|
||||||
|
layout (std430, set = 2, binding = 4) coherent restrict buffer IndicesData
|
||||||
|
{
|
||||||
|
uint indices[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// between shader stages
|
||||||
|
layout(location = 0) out struct
|
||||||
|
{
|
||||||
|
vec2 uv; // location = 0
|
||||||
|
} Out;
|
||||||
|
|
||||||
|
// material stuff
|
||||||
|
layout(location = 1) out struct
|
||||||
|
{
|
||||||
|
uint textureIndex; // location = 1
|
||||||
|
} OutFlat;
|
||||||
|
|
||||||
|
vec2 CreateQuad (in uint vertexID)
|
||||||
|
{
|
||||||
|
uint b = 1 << vertexID;
|
||||||
|
return vec2 ((0x3 & b) != 0, (0x9 & b) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
// Create a quad and its texture coordinates
|
||||||
|
Out.uv = CreateQuad (gl_VertexIndex);
|
||||||
|
vec3 vertexPos = vec3 (Out.uv - vec2(0.5f), 0.0f);
|
||||||
|
|
||||||
|
ParticleData particle = outputParticles.data[indices[gl_InstanceIndex]];
|
||||||
|
|
||||||
|
vec3 normalized = normalize (particle.velocity.xyz);
|
||||||
|
float angle = particle.orientationSpeedDecay.x;
|
||||||
|
// float angle = atan (normalized.y, normalized.x);
|
||||||
|
vec2 particleScaleData = particle.scaleAndDecay.xy; // x and y
|
||||||
|
|
||||||
|
mat3 rotate = mat3 (1.0f);
|
||||||
|
rotate[0][0] = cos(angle);
|
||||||
|
rotate[0][1] = sin(angle);
|
||||||
|
rotate[1][0] = -sin(angle);
|
||||||
|
rotate[1][1] = cos(angle);
|
||||||
|
|
||||||
|
vec3 particlePos = rotate * vertexPos;
|
||||||
|
|
||||||
|
vec3 viewRight = normalize (vec3 (cameraData.viewMat[0][0], cameraData.viewMat[1][0], cameraData.viewMat[2][0]));
|
||||||
|
vec3 viewUp = normalize(vec3 (cameraData.viewMat[0][1], cameraData.viewMat[1][1], cameraData.viewMat[2][1]));
|
||||||
|
|
||||||
|
particlePos = particle.position.xyz + (viewRight * particlePos.x * particleScaleData.x) + (viewUp * particlePos.y * particleScaleData.y);
|
||||||
|
OutFlat.textureIndex = particle.textureIndex;
|
||||||
|
|
||||||
|
gl_Position = cameraData.vpMat * vec4(particlePos, 1.0f);
|
||||||
|
}
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
||||||
|
Name: Particle_VS
|
||||||
|
ID: 35035037
|
||||||
|
Type: 2
|
|
@ -8,7 +8,7 @@ const int ROTATION_KERNEL_W = 4;
|
||||||
const int ROTATION_KERNEL_H = 4;
|
const int ROTATION_KERNEL_H = 4;
|
||||||
|
|
||||||
// can perhaps pass in as push constant.
|
// can perhaps pass in as push constant.
|
||||||
const float RADIUS = 0.2f;
|
const float RADIUS = 0.35f;
|
||||||
const float BIAS = 0.0025f;
|
const float BIAS = 0.0025f;
|
||||||
|
|
||||||
layout(local_size_x = 16, local_size_y = 16) in;
|
layout(local_size_x = 16, local_size_y = 16) in;
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -822,6 +822,16 @@ namespace SHADE
|
||||||
instance->setVolume(volume);
|
instance->setVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioClip::GetDestroyOnSceneExit()
|
||||||
|
{
|
||||||
|
return destroyOnSceneExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioClip::SetDestroyOnSceneExit(bool value)
|
||||||
|
{
|
||||||
|
destroyOnSceneExit = value;
|
||||||
|
}
|
||||||
|
|
||||||
SHEventHandle SHAudioSystem::onStop(SHEventPtr onStopEvent)
|
SHEventHandle SHAudioSystem::onStop(SHEventPtr onStopEvent)
|
||||||
{
|
{
|
||||||
StopAllSounds();
|
StopAllSounds();
|
||||||
|
@ -841,8 +851,11 @@ namespace SHADE
|
||||||
auto [begin, end] = audioClipLibrary.GetDenseAccess();
|
auto [begin, end] = audioClipLibrary.GetDenseAccess();
|
||||||
for (auto& it = begin; it != end; ++it)
|
for (auto& it = begin; it != end; ++it)
|
||||||
{
|
{
|
||||||
it->instance->stop(FMOD_STUDIO_STOP_ALLOWFADEOUT);
|
if(it->destroyOnSceneExit)
|
||||||
it->instance->release();
|
{
|
||||||
|
it->instance->stop(FMOD_STUDIO_STOP_ALLOWFADEOUT);
|
||||||
|
it->instance->release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return onSceneExitEvent->handle;
|
return onSceneExitEvent->handle;
|
||||||
|
|
|
@ -37,10 +37,13 @@ namespace SHADE
|
||||||
float GetParameterValue(const char* paramName);
|
float GetParameterValue(const char* paramName);
|
||||||
float GetVolume();
|
float GetVolume();
|
||||||
void SetVolume(float volume);
|
void SetVolume(float volume);
|
||||||
|
bool GetDestroyOnSceneExit();
|
||||||
|
void SetDestroyOnSceneExit(bool value);
|
||||||
friend class SHAudioSystem;
|
friend class SHAudioSystem;
|
||||||
private:
|
private:
|
||||||
FMOD::Studio::EventInstance* instance = nullptr;
|
FMOD::Studio::EventInstance* instance = nullptr;
|
||||||
EntityID transformRef = MAX_EID;
|
EntityID transformRef = MAX_EID;
|
||||||
|
bool destroyOnSceneExit = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SH_API SHAudioSystem : public SHSystem
|
class SH_API SHAudioSystem : public SHSystem
|
||||||
|
|
|
@ -15,3 +15,4 @@
|
||||||
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
|
||||||
#include "AudioSystem/SHAudioListenerComponent.h"
|
#include "AudioSystem/SHAudioListenerComponent.h"
|
||||||
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
||||||
|
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"
|
|
@ -30,6 +30,7 @@
|
||||||
#include "../SHEditorWindowManager.h"
|
#include "../SHEditorWindowManager.h"
|
||||||
#include "../AssetBrowser/SHAssetBrowser.h"
|
#include "../AssetBrowser/SHAssetBrowser.h"
|
||||||
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
||||||
|
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"
|
||||||
#include "Animation/SHAnimationClip.h"
|
#include "Animation/SHAnimationClip.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
|
@ -804,4 +805,166 @@ namespace SHADE
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
static void DrawComponent(SHParticleEmitterComponent* component)
|
||||||
|
{
|
||||||
|
if (!component)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
|
||||||
|
|
||||||
|
ImGui::PushID(SHFamilyID<SHComponent>::GetID<SHParticleEmitterComponent>());
|
||||||
|
|
||||||
|
const auto componentType = rttr::type::get(*component);
|
||||||
|
|
||||||
|
SHEditorWidgets::CheckBox("##IsActive", [component]() {return component->isActive; }, [component](bool const& active) {component->isActive = active; }, "Is Component Active");
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::CollapsingHeader(componentType.get_name().data(), ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
|
{
|
||||||
|
DrawContextMenu(component);
|
||||||
|
|
||||||
|
SHEditorWidgets::DragInt("Emission Count", [comp = component]() {return comp->GetEmissionCount(); }, [comp = component](uint32_t count) {comp->SetEmissionCount(count);});
|
||||||
|
SHEditorWidgets::DragFloat("Emission Interval", [comp = component]() {return comp->GetEmissionInterval(); }, [comp = component](float interval) {comp->SetEmissionInterval(interval); });
|
||||||
|
SHEditorWidgets::DragFloat("Min Life", [comp = component]() {return comp->GetMinLife(); }, [comp = component](float val) {comp->SetMinLife(val); });
|
||||||
|
SHEditorWidgets::DragFloat("Max Life", [comp = component]() {return comp->GetMaxLife(); }, [comp = component](float val) {comp->SetMaxLife(val); });
|
||||||
|
SHEditorWidgets::DragFloat("Min Size", [comp = component]() {return comp->GetMinSize(); }, [comp = component](float val) {comp->SetMinSize(val); });
|
||||||
|
SHEditorWidgets::DragFloat("Max Size", [comp = component]() {return comp->GetMaxSize(); }, [comp = component](float val) {comp->SetMaxSize(val); });
|
||||||
|
SHEditorWidgets::DragFloat("Size Decay", [comp = component]() {return comp->GetSizeDecayMult(); }, [comp = component](float val) {comp->SetSizeDecayMult(val); }, {}, 0.0001f);
|
||||||
|
|
||||||
|
SHEditorWidgets::DragVec4("Angles and Offsets", {"yaw", "bank", "yaw off", "bank off"},
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
return comp->GetAngularRangesAndOffsets();
|
||||||
|
},
|
||||||
|
[comp = component](SHVec4 const& val)
|
||||||
|
{
|
||||||
|
comp->SetAngularRangesAndOffsets(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
SHEditorWidgets::DragFloat("Min Speed",
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
return comp->GetMinSpeed();
|
||||||
|
},
|
||||||
|
[comp = component](float val)
|
||||||
|
{
|
||||||
|
comp->SetMinSpeed(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
SHEditorWidgets::DragFloat("Max Speed",
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
return comp->GetMaxSpeed();
|
||||||
|
},
|
||||||
|
[comp = component](float val)
|
||||||
|
{
|
||||||
|
comp->SetMaxSpeed(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
SHEditorWidgets::DragFloat("Rotation Speed",
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
return comp->GetRotationSpeed();
|
||||||
|
},
|
||||||
|
[comp = component](float val)
|
||||||
|
{
|
||||||
|
comp->SetRotationSpeed(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
SHEditorWidgets::DragFloat("Rotation Decay",
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
return comp->GetRotationDecay();
|
||||||
|
},
|
||||||
|
[comp = component](float val)
|
||||||
|
{
|
||||||
|
comp->SetRotationDecay(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
SHEditorWidgets::DragInt("Texture Index",
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
return comp->GetTextureAssetID();
|
||||||
|
},
|
||||||
|
[comp = component](AssetID val)
|
||||||
|
{
|
||||||
|
comp->SetTextureAssetID(val);
|
||||||
|
});
|
||||||
|
if (SHDragDrop::BeginTarget())
|
||||||
|
{
|
||||||
|
if (AssetID* payload = SHDragDrop::AcceptPayload<AssetID>(SHDragDrop::DRAG_RESOURCE))
|
||||||
|
{
|
||||||
|
Handle<SHTexture> texture = SHResourceManager::LoadOrGet<SHTexture>(*payload);
|
||||||
|
gfxSystem->BuildTextures();
|
||||||
|
|
||||||
|
if (texture)
|
||||||
|
{
|
||||||
|
component->SetTextureIndex(texture->TextureArrayIndex);
|
||||||
|
component->SetTextureAssetID(*payload);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_WARNING("[] Attempted to load invalid texture! Texture for particle not set. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
SHDragDrop::EndTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SHEditorWidgets::InputText("Custom Update Shader",
|
||||||
|
[comp = component]()
|
||||||
|
{
|
||||||
|
auto customShader = comp->GetCustomUpdateShader();
|
||||||
|
|
||||||
|
if (customShader)
|
||||||
|
return customShader->GetName();
|
||||||
|
else
|
||||||
|
return std::string{};
|
||||||
|
|
||||||
|
},
|
||||||
|
[comp = component](std::string const& text)
|
||||||
|
{
|
||||||
|
}, {}, ImGuiSliderFlags_ReadOnly);
|
||||||
|
|
||||||
|
if (SHDragDrop::BeginTarget())
|
||||||
|
{
|
||||||
|
if (AssetID* payload = SHDragDrop::AcceptPayload<AssetID>(SHDragDrop::DRAG_RESOURCE))
|
||||||
|
{
|
||||||
|
Handle<SHVkShaderModule> shaderModule = SHResourceManager::LoadOrGet<SHVkShaderModule>(*payload);
|
||||||
|
|
||||||
|
if (shaderModule)
|
||||||
|
{
|
||||||
|
component->SetCustomUpdateShader(shaderModule);
|
||||||
|
component->SetCustomUpdateShaderAssetID(*payload);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_WARNING("[] Attempted to load invalid shader! Custom update shader for particles not set. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
SHDragDrop::EndTarget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Reset"))
|
||||||
|
{
|
||||||
|
component->SetCustomUpdateShader({});
|
||||||
|
component->SetCustomUpdateShaderAssetID(INVALID_ASSET_ID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SHEditorWidgets::CheckBox("Is Passive", [comp = component]() {return comp->GetPassive(); }, [comp = component](bool flag) {comp->SetPassive(flag); });
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawContextMenu(component);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "SHEditorComponentView.h"
|
#include "SHEditorComponentView.h"
|
||||||
#include "AudioSystem/SHAudioListenerComponent.h"
|
#include "AudioSystem/SHAudioListenerComponent.h"
|
||||||
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
|
||||||
|
#include "Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h"
|
||||||
#include "Camera/SHCameraSystem.h"
|
#include "Camera/SHCameraSystem.h"
|
||||||
#include "FRC/SHFramerateController.h"
|
#include "FRC/SHFramerateController.h"
|
||||||
|
|
||||||
|
@ -188,6 +189,10 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
DrawComponent(trajectoryComponent);
|
DrawComponent(trajectoryComponent);
|
||||||
}
|
}
|
||||||
|
if (auto particleComponent = SHComponentManager::GetComponent_s<SHParticleEmitterComponent>(eid))
|
||||||
|
{
|
||||||
|
DrawComponent(particleComponent);
|
||||||
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
// Render Scripts
|
// Render Scripts
|
||||||
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
|
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
|
||||||
|
@ -204,6 +209,7 @@ namespace SHADE
|
||||||
DrawAddComponentButton<SHToggleButtonComponent>(eid);
|
DrawAddComponentButton<SHToggleButtonComponent>(eid);
|
||||||
DrawAddComponentButton<SHSliderComponent>(eid);
|
DrawAddComponentButton<SHSliderComponent>(eid);
|
||||||
DrawAddComponentButton<SHTrajectoryRenderableComponent>(eid);
|
DrawAddComponentButton<SHTrajectoryRenderableComponent>(eid);
|
||||||
|
DrawAddComponentButton<SHParticleEmitterComponent>(eid);
|
||||||
|
|
||||||
// Components that require Transforms
|
// Components that require Transforms
|
||||||
|
|
||||||
|
@ -213,6 +219,7 @@ namespace SHADE
|
||||||
DrawAddComponentWithEnforcedComponentButton<SHTextRenderableComponent, SHTransformComponent>(eid);
|
DrawAddComponentWithEnforcedComponentButton<SHTextRenderableComponent, SHTransformComponent>(eid);
|
||||||
DrawAddComponentWithEnforcedComponentButton<SHAnimatorComponent, SHTransformComponent, SHRenderable>(eid);
|
DrawAddComponentWithEnforcedComponentButton<SHAnimatorComponent, SHTransformComponent, SHRenderable>(eid);
|
||||||
DrawAddComponentWithEnforcedComponentButton<SHAudioListenerComponent, SHTransformComponent>(eid);
|
DrawAddComponentWithEnforcedComponentButton<SHAudioListenerComponent, SHTransformComponent>(eid);
|
||||||
|
//DrawAddComponentWithEnforcedComponentButton<SHParticleEmitterComponent, SHTransformComponent>(eid);
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,7 +450,7 @@ namespace SHADE
|
||||||
*/
|
*/
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
void SHVkCommandBuffer::DrawMultiIndirect(Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount)
|
void SHVkCommandBuffer::DrawMultiIndirectIndexed(Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount)
|
||||||
{
|
{
|
||||||
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
{
|
{
|
||||||
|
@ -462,6 +462,19 @@ namespace SHADE
|
||||||
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
|
vkCommandBuffer.drawIndexedIndirect(indirectDrawData->GetVkBuffer(), 0, drawCount, sizeof(vk::DrawIndexedIndirectCommand));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHVkCommandBuffer::DrawMultiIndirect(Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount, uint32_t offset/* = 0*/)
|
||||||
|
{
|
||||||
|
if (cmdBufferState != SH_CMD_BUFFER_STATE::RECORDING)
|
||||||
|
{
|
||||||
|
SHLOG_ERROR("Command buffer must have started recording before a pipeline can be bound.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indirectDrawData)
|
||||||
|
vkCommandBuffer.drawIndirect(indirectDrawData->GetVkBuffer(), offset, drawCount, sizeof(vk::DrawIndirectCommand));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
|
void SHVkCommandBuffer::ComputeDispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept
|
||||||
{
|
{
|
||||||
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
|
vkCommandBuffer.dispatch (groupCountX, groupCountY, groupCountZ);
|
||||||
|
|
|
@ -128,9 +128,10 @@ namespace SHADE
|
||||||
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> const dynamicOffsets);
|
void BindDescriptorSet (Handle<SHVkDescriptorSetGroup> descSetGroup, SH_PIPELINE_TYPE bindPoint, uint32_t firstSet, std::span<uint32_t> const dynamicOffsets);
|
||||||
|
|
||||||
// Draw Commands
|
// Draw Commands
|
||||||
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
|
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
|
||||||
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
|
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
|
||||||
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
|
void DrawMultiIndirectIndexed (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount);
|
||||||
|
void DrawMultiIndirect (Handle<SHVkBuffer> indirectDrawData, uint32_t drawCount, uint32_t offset = 0);
|
||||||
|
|
||||||
// Compute Commands
|
// Compute Commands
|
||||||
void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;
|
void ComputeDispatch (uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) noexcept;
|
||||||
|
|
|
@ -755,7 +755,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
cmdBuffer->DrawMultiIndirect(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
|
cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer[frameIndex], static_cast<uint32_t>(drawData.size()));
|
||||||
cmdBuffer->EndLabeledSegment();
|
cmdBuffer->EndLabeledSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ namespace SHADE
|
||||||
// particle draw call binding
|
// particle draw call binding
|
||||||
SHVkDescriptorSetLayout::Binding particleDrawDataBinding
|
SHVkDescriptorSetLayout::Binding particleDrawDataBinding
|
||||||
{
|
{
|
||||||
.Type = vk::DescriptorType::eUniformBufferDynamic, // UBO (Because lesser data), dynamic (1 set for each frame)
|
.Type = vk::DescriptorType::eStorageBufferDynamic, // SSBO, dynamic (1 set for each frame)
|
||||||
.Stage = vk::ShaderStageFlagBits::eCompute,
|
.Stage = vk::ShaderStageFlagBits::eCompute,
|
||||||
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA,
|
.BindPoint = SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA,
|
||||||
.DescriptorCount = 1,
|
.DescriptorCount = 1,
|
||||||
|
|
|
@ -730,7 +730,7 @@ namespace SHADE
|
||||||
cmdBuffer->BindVertexBuffer(COLOR_BIND_PT, batch.InstanceColorBuffer[frameIndex], 0);
|
cmdBuffer->BindVertexBuffer(COLOR_BIND_PT, batch.InstanceColorBuffer[frameIndex], 0);
|
||||||
|
|
||||||
// Execute draw
|
// Execute draw
|
||||||
cmdBuffer->DrawMultiIndirect(batch.MDIBuffer[frameIndex], static_cast<uint32_t>(batch.MDIData.size()));
|
cmdBuffer->DrawMultiIndirectIndexed(batch.MDIBuffer[frameIndex], static_cast<uint32_t>(batch.MDIData.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHDebugDrawSystem::destroyBatch(MeshBatch& batch)
|
void SHDebugDrawSystem::destroyBatch(MeshBatch& batch)
|
||||||
|
|
|
@ -48,6 +48,7 @@ of DigiPen Institute of Technology is prohibited.
|
||||||
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
|
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
|
||||||
#include "Input/SHInputManager.h"
|
#include "Input/SHInputManager.h"
|
||||||
#include "Assets/Events/SHAssetManagerEvents.h"
|
#include "Assets/Events/SHAssetManagerEvents.h"
|
||||||
|
#include "Graphics/MiddleEnd/Particles/SHParticleSubSystem.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -144,6 +145,10 @@ namespace SHADE
|
||||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/Trajectory_FS.glsl", false);
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/Trajectory_FS.glsl", false);
|
||||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMapBlur_CS.glsl", false);
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/ShadowMapBlur_CS.glsl", false);
|
||||||
//SHAssetManager::CompileAsset("../../Assets/Shaders/Anim_VS.glsl", false);
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/Anim_VS.glsl", false);
|
||||||
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/Particle_VS.glsl", false);
|
||||||
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/Particle_FS.glsl", false);
|
||||||
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/ParticleEmit_CS.glsl", false);
|
||||||
|
//SHAssetManager::CompileAsset("../../Assets/Shaders/ParticleUpdate_CS.glsl", false);
|
||||||
|
|
||||||
// Load Built In Shaders
|
// Load Built In Shaders
|
||||||
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
|
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
|
||||||
|
@ -165,6 +170,10 @@ namespace SHADE
|
||||||
static constexpr AssetID TRAJECTORY_VS = 41042628; trajectoryVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_VS);
|
static constexpr AssetID TRAJECTORY_VS = 41042628; trajectoryVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_VS);
|
||||||
static constexpr AssetID TRAJECTORY_FS = 45635685; trajectoryFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_FS);
|
static constexpr AssetID TRAJECTORY_FS = 45635685; trajectoryFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(TRAJECTORY_FS);
|
||||||
static constexpr AssetID SHADOW_BLUR_CS = 38004013; shadowMapBlurCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_BLUR_CS);
|
static constexpr AssetID SHADOW_BLUR_CS = 38004013; shadowMapBlurCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(SHADOW_BLUR_CS);
|
||||||
|
static constexpr AssetID PARTICLE_VS = 35035037; particleVS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_VS);
|
||||||
|
static constexpr AssetID PARTICLE_FS = 42509714; particleFS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_FS);
|
||||||
|
static constexpr AssetID PARTICLE_EMIT_CS = 49959611; particleEmitCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_EMIT_CS);
|
||||||
|
static constexpr AssetID PARTICLE_UPDATE_CS = 36260925; particleUpdateCS = SHResourceManager::LoadOrGet<SHVkShaderModule>(PARTICLE_UPDATE_CS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,11 +352,16 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
auto vfxPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data(), { "Scene", "Depth Buffer" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data() });
|
auto vfxPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data(), { "Scene", "Depth Buffer" }, { SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data() });
|
||||||
auto vfxSubpass = vfxPass->AddSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS.data(), worldViewport, worldRenderer);
|
auto vfxSubpass = vfxPass->AddSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS.data(), worldViewport, worldRenderer);
|
||||||
|
//vfxPass->AddPreBeginFunction([=](Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex)
|
||||||
|
// {
|
||||||
|
// particleSubSystem->Run(cmdBuffer, frameIndex);
|
||||||
|
// });
|
||||||
vfxSubpass->AddColorOutput("Scene");
|
vfxSubpass->AddColorOutput("Scene");
|
||||||
vfxSubpass->AddDepthOutput("Depth Buffer");
|
vfxSubpass->AddDepthOutput("Depth Buffer");
|
||||||
vfxSubpass->AddExteriorDrawCalls([=](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
|
vfxSubpass->AddExteriorDrawCalls([=](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
|
||||||
{
|
{
|
||||||
trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex);
|
trajectoryRenderingSubSystem->Render(cmdBuffer, renderer, frameIndex);
|
||||||
|
particleSubSystem->Render(cmdBuffer, renderer, frameIndex);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
@ -490,6 +504,12 @@ namespace SHADE
|
||||||
|
|
||||||
trajectoryRenderingSubSystem = resourceManager.Create<SHTrajectoryRenderingSubSystem>();
|
trajectoryRenderingSubSystem = resourceManager.Create<SHTrajectoryRenderingSubSystem>();
|
||||||
|
|
||||||
|
auto vfxPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data());
|
||||||
|
|
||||||
|
// particle sub system initialization
|
||||||
|
particleSubSystem = resourceManager.Create<SHParticleSubSystem>();
|
||||||
|
particleSubSystem->Init(device, descPool, vfxPass->GetRenderpass(), vfxPass->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), particleVS, particleFS, particleEmitCS, particleUpdateCS);
|
||||||
|
|
||||||
auto vfxNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data());
|
auto vfxNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::VFX_PASS.data());
|
||||||
trajectoryRenderingSubSystem->Init(device, vfxNode->GetRenderpass(), vfxNode->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), trajectoryVS, trajectoryFS);
|
trajectoryRenderingSubSystem->Init(device, vfxNode->GetRenderpass(), vfxNode->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::VFX_SUBPASS), trajectoryVS, trajectoryFS);
|
||||||
|
|
||||||
|
@ -669,7 +689,6 @@ namespace SHADE
|
||||||
textRenderingSubSystem->Run(frameIndex);
|
textRenderingSubSystem->Run(frameIndex);
|
||||||
trajectoryRenderingSubSystem->Run(frameIndex);
|
trajectoryRenderingSubSystem->Run(frameIndex);
|
||||||
|
|
||||||
|
|
||||||
for (auto renderer : renderers)
|
for (auto renderer : renderers)
|
||||||
{
|
{
|
||||||
#ifdef SHEDITOR
|
#ifdef SHEDITOR
|
||||||
|
@ -688,9 +707,12 @@ namespace SHADE
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
renderGraph->Begin(frameIndex);
|
renderGraph->Begin(frameIndex);
|
||||||
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
|
auto cmdBuffer = renderGraph->GetCommandBuffer(frameIndex);
|
||||||
|
|
||||||
|
particleSubSystem->ResetInstanceCounts(cmdBuffer, frameIndex);
|
||||||
|
particleSubSystem->Run(cmdBuffer, frameIndex);
|
||||||
|
|
||||||
renderGraph->Execute(frameIndex, descPool, MESH_DATA);
|
renderGraph->Execute(frameIndex, descPool, MESH_DATA);
|
||||||
renderGraph->End(frameIndex);
|
renderGraph->End(frameIndex);
|
||||||
|
|
|
@ -59,6 +59,7 @@ namespace SHADE
|
||||||
class SHMaterialInstance;
|
class SHMaterialInstance;
|
||||||
class SHMousePickSystem;
|
class SHMousePickSystem;
|
||||||
class SHTextRenderingSubSystem;
|
class SHTextRenderingSubSystem;
|
||||||
|
class SHParticleSubSystem;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
|
@ -484,6 +485,10 @@ namespace SHADE
|
||||||
Handle<SHVkShaderModule> trajectoryVS;
|
Handle<SHVkShaderModule> trajectoryVS;
|
||||||
Handle<SHVkShaderModule> trajectoryFS;
|
Handle<SHVkShaderModule> trajectoryFS;
|
||||||
Handle<SHVkShaderModule> shadowMapBlurCS;
|
Handle<SHVkShaderModule> shadowMapBlurCS;
|
||||||
|
Handle<SHVkShaderModule> particleVS;
|
||||||
|
Handle<SHVkShaderModule> particleFS;
|
||||||
|
Handle<SHVkShaderModule> particleEmitCS;
|
||||||
|
Handle<SHVkShaderModule> particleUpdateCS;
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
Handle<SHFont> testFont;
|
Handle<SHFont> testFont;
|
||||||
|
@ -523,6 +528,7 @@ namespace SHADE
|
||||||
Handle<SHLightingSubSystem> lightingSubSystem;
|
Handle<SHLightingSubSystem> lightingSubSystem;
|
||||||
Handle<SHTextRenderingSubSystem> textRenderingSubSystem;
|
Handle<SHTextRenderingSubSystem> textRenderingSubSystem;
|
||||||
Handle<SHTrajectoryRenderingSubSystem> trajectoryRenderingSubSystem;
|
Handle<SHTrajectoryRenderingSubSystem> trajectoryRenderingSubSystem;
|
||||||
|
Handle<SHParticleSubSystem> particleSubSystem;
|
||||||
Handle<SHSSAO> ssaoStorage;
|
Handle<SHSSAO> ssaoStorage;
|
||||||
|
|
||||||
uint32_t resizeWidth = 1;
|
uint32_t resizeWidth = 1;
|
||||||
|
|
|
@ -20,4 +20,178 @@ namespace SHADE
|
||||||
toEmit = true;
|
toEmit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetEmissionCount(uint32_t count) noexcept
|
||||||
|
{
|
||||||
|
emissionCount = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetPassive(bool flag) noexcept
|
||||||
|
{
|
||||||
|
isPassive = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetEmissionInterval(float interval) noexcept
|
||||||
|
{
|
||||||
|
emissionInterval = interval;
|
||||||
|
timeBeforeEmission = emissionInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetMinLife(float val) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.lifeAndSizeRange.x = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetMaxLife(float val) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.lifeAndSizeRange.y = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetAngularRangesAndOffsets(SHVec4 const& ranges) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.angularRangesAndOffsets = SHVec4 (ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetMinSpeed(float speed) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.minSpeed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetMaxSpeed(float speed) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.maxSpeed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetRotationSpeed(float speed) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.rotationSpeed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetRotationDecay(float decay) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.rotationDecay = decay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetTextureIndex(uint32_t index) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.textureIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetTextureAssetID(AssetID id) noexcept
|
||||||
|
{
|
||||||
|
textureAssetID = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetCustomUpdateShaderAssetID(AssetID id) noexcept
|
||||||
|
{
|
||||||
|
customUpdateShaderID = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetMinSize(float size) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.lifeAndSizeRange.z = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetMaxSize(float size) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.lifeAndSizeRange.w = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetSizeDecayMult(float decay) noexcept
|
||||||
|
{
|
||||||
|
cpuEmitterData.sizeDecayMult = decay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleEmitterComponent::SetCustomUpdateShader(Handle<SHVkShaderModule> shaderModule) noexcept
|
||||||
|
{
|
||||||
|
customUpdateShader = shaderModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SHParticleEmitterComponent::GetEmissionCount(void) const noexcept
|
||||||
|
{
|
||||||
|
return emissionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHParticleEmitterComponent::GetPassive(void) const noexcept
|
||||||
|
{
|
||||||
|
return isPassive;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetEmissionInterval(void) const noexcept
|
||||||
|
{
|
||||||
|
return emissionInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetMinLife(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.lifeAndSizeRange.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetMaxLife(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.lifeAndSizeRange.y;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVec4 const& SHParticleEmitterComponent::GetAngularRangesAndOffsets(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.angularRangesAndOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetMinSpeed(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.minSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetMaxSpeed(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.maxSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetRotationSpeed(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.rotationSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetRotationDecay(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.rotationDecay;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t SHParticleEmitterComponent::GetTextureIndex(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.textureIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetID SHParticleEmitterComponent::GetTextureAssetID(void) const noexcept
|
||||||
|
{
|
||||||
|
return textureAssetID;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetID SHParticleEmitterComponent::GetCustomUpdateShaderAssetID(void) const noexcept
|
||||||
|
{
|
||||||
|
return customUpdateShaderID;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetMinSize(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.lifeAndSizeRange.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetMaxSize(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.lifeAndSizeRange.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float SHParticleEmitterComponent::GetSizeDecayMult(void) const noexcept
|
||||||
|
{
|
||||||
|
return cpuEmitterData.sizeDecayMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkShaderModule> SHParticleEmitterComponent::GetCustomUpdateShader(void) const noexcept
|
||||||
|
{
|
||||||
|
return customUpdateShader;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,29 +1,53 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Resource/SHHandle.h"
|
#include "Resource/SHHandle.h"
|
||||||
|
#include "Math/Vector/SHVec2.h"
|
||||||
#include "Math/Vector/SHVec4.h"
|
#include "Math/Vector/SHVec4.h"
|
||||||
#include "ECS_Base/Components/SHComponent.h"
|
#include "ECS_Base/Components/SHComponent.h"
|
||||||
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
|
#include "Graphics/MiddleEnd/Interface/SHGraphicsConstants.h"
|
||||||
|
#include <Assets/SHAssetMacros.h>
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
class SHVkBuffer;
|
class SHVkBuffer;
|
||||||
class SHVkDescriptorSetGroup;
|
class SHVkDescriptorSetGroup;
|
||||||
class SHVkDescriptorSetLayout;
|
class SHVkDescriptorSetLayout;
|
||||||
|
class SHVkShaderModule;
|
||||||
|
class SHVkPipeline;
|
||||||
|
|
||||||
class SHParticleEmitterComponent : public SHComponent
|
class SHParticleEmitterComponent : public SHComponent
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct GPUEmitterStruct
|
struct GPUEmitterStruct
|
||||||
{
|
{
|
||||||
//! Minimum emitting angular range
|
//! Angular ranges of emission
|
||||||
SHVec4 angularMin;
|
SHVec4 angularRangesAndOffsets;
|
||||||
|
|
||||||
//! Maximum emitting angular range
|
//! minimum starting velocity
|
||||||
SHVec4 angularMax;
|
float minSpeed;
|
||||||
|
|
||||||
|
//! Maximum starting velocity
|
||||||
|
float maxSpeed;
|
||||||
|
|
||||||
|
//! Rotational speed of the quad
|
||||||
|
float rotationSpeed;
|
||||||
|
|
||||||
|
//! Rotation decay rate
|
||||||
|
float rotationDecay;
|
||||||
|
|
||||||
//! Spawn lifetime and size range (min and max)
|
//! Spawn lifetime and size range (min and max)
|
||||||
SHVec4 lifeAndSizeRange;
|
SHVec4 lifeAndSizeRange;
|
||||||
|
|
||||||
|
//! Size decay for particles
|
||||||
|
float sizeDecayMult;
|
||||||
|
|
||||||
|
//! Texture used by the particle
|
||||||
|
uint32_t textureIndex;
|
||||||
|
|
||||||
|
//! Padding for the shader struct
|
||||||
|
float padding[2];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GPUParticleStruct
|
struct GPUParticleStruct
|
||||||
|
@ -84,6 +108,12 @@ namespace SHADE
|
||||||
//! will contain 2 bindings that point to 2 buffers (input and output).
|
//! will contain 2 bindings that point to 2 buffers (input and output).
|
||||||
Handle<SHVkDescriptorSetGroup> particleDescriptorSet;
|
Handle<SHVkDescriptorSetGroup> particleDescriptorSet;
|
||||||
|
|
||||||
|
//! Custom update shader for the particles in this component
|
||||||
|
Handle<SHVkShaderModule> customUpdateShader;
|
||||||
|
|
||||||
|
//! Internally the system will bind this pipeline when it detects that this is not a null handle
|
||||||
|
Handle<SHVkPipeline> customUpdatePipeline;
|
||||||
|
|
||||||
//! Emitter's data on the CPU side. To be copied to GPU.
|
//! Emitter's data on the CPU side. To be copied to GPU.
|
||||||
GPUEmitterStruct cpuEmitterData;
|
GPUEmitterStruct cpuEmitterData;
|
||||||
|
|
||||||
|
@ -99,12 +129,60 @@ namespace SHADE
|
||||||
//! For all the dynamic SSBOs in the descriptor set
|
//! For all the dynamic SSBOs in the descriptor set
|
||||||
std::array<std::array<uint32_t, 5>, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets{};
|
std::array<std::array<uint32_t, 5>, SHGraphicsConstants::NUM_FRAME_BUFFERS> dynamicOffsets{};
|
||||||
|
|
||||||
|
//! For the emitter to use to give particles their texture
|
||||||
|
AssetID textureAssetID;
|
||||||
|
|
||||||
|
//! Custom update shaders, similarly with textures, will be identified through their AssetID
|
||||||
|
AssetID customUpdateShaderID;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void OnCreate(void) override final;
|
void OnCreate(void) override final;
|
||||||
void OnDestroy(void) override final;
|
void OnDestroy(void) override final;
|
||||||
|
|
||||||
void Emit (void) noexcept;
|
void Emit (void) noexcept;
|
||||||
|
|
||||||
|
void SetEmissionCount (uint32_t count) noexcept;
|
||||||
|
void SetPassive (bool flag) noexcept;
|
||||||
|
void SetEmissionInterval (float interval) noexcept;
|
||||||
|
void SetMinLife (float val) noexcept;
|
||||||
|
void SetMaxLife (float val) noexcept;
|
||||||
|
void SetAngularRangesAndOffsets (SHVec4 const& ranges) noexcept;
|
||||||
|
void SetMinSpeed (float speed) noexcept;
|
||||||
|
void SetMaxSpeed (float speed) noexcept;
|
||||||
|
void SetRotationSpeed (float speed) noexcept;
|
||||||
|
void SetRotationDecay (float decay) noexcept;
|
||||||
|
void SetTextureIndex (uint32_t index) noexcept;
|
||||||
|
void SetMinSize (float size) noexcept;
|
||||||
|
void SetMaxSize (float size) noexcept;
|
||||||
|
void SetSizeDecayMult (float decay) noexcept;
|
||||||
|
void SetCustomUpdateShader (Handle<SHVkShaderModule> shaderModule) noexcept;
|
||||||
|
|
||||||
|
uint32_t GetEmissionCount (void) const noexcept;
|
||||||
|
bool GetPassive (void) const noexcept;
|
||||||
|
float GetEmissionInterval (void) const noexcept;
|
||||||
|
float GetMinLife (void) const noexcept;
|
||||||
|
float GetMaxLife (void) const noexcept;
|
||||||
|
SHVec4 const& GetAngularRangesAndOffsets (void) const noexcept;
|
||||||
|
float GetMinSpeed (void) const noexcept;
|
||||||
|
float GetMaxSpeed (void) const noexcept;
|
||||||
|
float GetRotationSpeed (void) const noexcept;
|
||||||
|
float GetRotationDecay (void) const noexcept;
|
||||||
|
uint32_t GetTextureIndex (void) const noexcept;
|
||||||
|
float GetMinSize (void) const noexcept;
|
||||||
|
float GetMaxSize (void) const noexcept;
|
||||||
|
float GetSizeDecayMult (void) const noexcept;
|
||||||
|
Handle<SHVkShaderModule> GetCustomUpdateShader (void) const noexcept;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* NON-INTERFACE FUNCTIONS */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
void SetTextureAssetID(AssetID id) noexcept;
|
||||||
|
void SetCustomUpdateShaderAssetID(AssetID id) noexcept;
|
||||||
|
|
||||||
|
AssetID GetTextureAssetID(void) const noexcept;
|
||||||
|
AssetID GetCustomUpdateShaderAssetID(void) const noexcept;
|
||||||
|
|
||||||
|
|
||||||
friend class SHParticleSubSystem;
|
friend class SHParticleSubSystem;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,29 +10,39 @@
|
||||||
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
|
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
|
||||||
#include "Math/Transform/SHTransformComponent.h"
|
#include "Math/Transform/SHTransformComponent.h"
|
||||||
#include "Graphics/Buffers/SHVkBuffer.h"
|
#include "Graphics/Buffers/SHVkBuffer.h"
|
||||||
|
#include "FRC/SHFramerateController.h"
|
||||||
|
#include "Graphics/Pipeline/SHVkPipeline.h"
|
||||||
|
#include "Graphics/RenderGraph/SHSubpass.h"
|
||||||
|
#include "Graphics/SHVkUtil.h"
|
||||||
|
#include "Graphics/Synchronization/SHVkFence.h"
|
||||||
|
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
|
||||||
void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept
|
void SHParticleSubSystem::InitializeComponent(SHParticleEmitterComponent& comp) noexcept
|
||||||
{
|
{
|
||||||
uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct));
|
|
||||||
uint32_t particleStructAligned = logicalDevice->PadUBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct));
|
|
||||||
uint32_t sizeofIndirectCmd = static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand));
|
|
||||||
uint32_t sizeofUint = static_cast<uint32_t>(sizeof(uint32_t));
|
|
||||||
|
|
||||||
// TODO: temporary only.
|
// TODO: temporary only.
|
||||||
static constexpr uint32_t NUM_PARTICLES = 500;
|
static constexpr uint32_t NUM_PARTICLES = 2000;
|
||||||
comp.maxParticles = NUM_PARTICLES;
|
comp.maxParticles = NUM_PARTICLES;
|
||||||
|
|
||||||
|
uint32_t sizeofUint = static_cast<uint32_t>(sizeof(uint32_t));
|
||||||
|
uint32_t sizeofIndirectCmdAligned = logicalDevice->PadSSBOSize(sizeof(vk::DrawIndirectCommand));
|
||||||
|
uint32_t emitterStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUEmitterStruct));
|
||||||
|
uint32_t particleChunkStructAligned = logicalDevice->PadSSBOSize(sizeof (SHParticleEmitterComponent::GPUParticleStruct)) * comp.maxParticles;
|
||||||
|
uint32_t indicesDataAligned = logicalDevice->PadSSBOSize(sizeofUint * comp.maxParticles);
|
||||||
|
|
||||||
|
|
||||||
// offset into the buffer for input and output
|
// offset into the buffer for input and output
|
||||||
uint32_t const PARTICLE_FRAME_CHUNK_SIZE = (particleStructAligned * comp.maxParticles);
|
uint32_t const PARTICLE_FRAME_CHUNK_SIZE = particleChunkStructAligned;
|
||||||
|
|
||||||
// Buffer Initialization
|
// Buffer Initialization
|
||||||
{
|
{
|
||||||
// count, value
|
// count, value. Initialize free count to max particles and indices to particle indices
|
||||||
std::vector<uint32_t> freelistInit(comp.maxParticles + 1, 0);
|
std::vector<uint32_t> freelistInit(comp.maxParticles + 1, 0);
|
||||||
freelistInit[0] = comp.maxParticles;
|
freelistInit[0] = comp.maxParticles;
|
||||||
|
for (uint32_t i = 0; i < comp.maxParticles; ++i)
|
||||||
|
freelistInit[i + 1] = i;
|
||||||
|
|
||||||
// Particle emitter buffer. Multiple copies, Host-visible mapped. We want multiple copies because we'll be writing to it from the CPU. We don't want to do that while the GPU
|
// Particle emitter buffer. Multiple copies, Host-visible mapped. We want multiple copies because we'll be writing to it from the CPU. We don't want to do that while the GPU
|
||||||
// is using it during compute operations so we write to another portion.
|
// is using it during compute operations so we write to another portion.
|
||||||
|
@ -40,14 +50,14 @@ namespace SHADE
|
||||||
|
|
||||||
// buffer for particle data: pure GPU memory, no transfers, no flags. We want to triple buffer this so that we can submit work to the GPU
|
// buffer for particle data: pure GPU memory, no transfers, no flags. We want to triple buffer this so that we can submit work to the GPU
|
||||||
// without having to wait for rendering to finish reading the data
|
// without having to wait for rendering to finish reading the data
|
||||||
comp.particleData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * particleStructAligned * NUM_PARTICLES, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, {});
|
comp.particleData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * particleChunkStructAligned, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, {});
|
||||||
|
|
||||||
// Buffer for freelist data. 1 copy only, host-visible mapped. We only need 1 copy because it is only required in compute. If it was used or read in another
|
// Buffer for freelist data. 1 copy only, host-visible mapped. We only need 1 copy because it is only required in compute. If it was used or read in another
|
||||||
// stage we would need more copies.
|
// stage we would need more copies.
|
||||||
comp.freelistData = logicalDevice->CreateBuffer(sizeofUint * (comp.maxParticles + 1), freelistInit.data(), sizeofUint * (comp.maxParticles + 1), vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
comp.freelistData = logicalDevice->CreateBuffer(sizeofUint * (comp.maxParticles + 1), freelistInit.data(), sizeofUint * (comp.maxParticles + 1), vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
||||||
|
|
||||||
// Buffer for indices. NUM_FRAME_BUFFERS copies since it's used in rendering. host-visible mapped.
|
// Buffer for indices. NUM_FRAME_BUFFERS copies since it's used in rendering. host-visible mapped.
|
||||||
comp.indicesData = logicalDevice->CreateBuffer(sizeofUint * comp.maxParticles, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
comp.indicesData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * indicesDataAligned, nullptr, 0, vk::BufferUsageFlagBits::eStorageBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
||||||
|
|
||||||
// Draw call data will not be tampered with after this initialization except for one variable: instanceCount, which will be modified from compute shader
|
// Draw call data will not be tampered with after this initialization except for one variable: instanceCount, which will be modified from compute shader
|
||||||
std::array<vk::DrawIndirectCommand, SHGraphicsConstants::NUM_FRAME_BUFFERS> indirectCommands{};
|
std::array<vk::DrawIndirectCommand, SHGraphicsConstants::NUM_FRAME_BUFFERS> indirectCommands{};
|
||||||
|
@ -60,7 +70,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered.
|
// buffer to store draw call data. Non-indexed, host-visible mapped, triple buffered.
|
||||||
comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmd, vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
comp.drawCallData = logicalDevice->CreateBuffer(SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, indirectCommands.data(), SHGraphicsConstants::NUM_FRAME_BUFFERS * sizeofIndirectCmdAligned, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer, VMA_MEMORY_USAGE_AUTO, VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +83,7 @@ namespace SHADE
|
||||||
static constexpr uint32_t PARTICLE_DATA_SET_INDEX = 0;
|
static constexpr uint32_t PARTICLE_DATA_SET_INDEX = 0;
|
||||||
|
|
||||||
// Variable desc counts, all ignored anyway (This is required but its a dumb interface. You can only blame yourself, Brandon. )
|
// Variable desc counts, all ignored anyway (This is required but its a dumb interface. You can only blame yourself, Brandon. )
|
||||||
std::vector const VARIABLE_COUNTS = {0u,0u,0u,0u,0u};
|
std::vector const VARIABLE_COUNTS = {0u};
|
||||||
|
|
||||||
// allocate new desc set
|
// allocate new desc set
|
||||||
comp.particleDescriptorSet = descPool->Allocate(descSetLayout, VARIABLE_COUNTS);
|
comp.particleDescriptorSet = descPool->Allocate(descSetLayout, VARIABLE_COUNTS);
|
||||||
|
@ -83,11 +93,18 @@ namespace SHADE
|
||||||
|
|
||||||
// After buffers are created, we want to populate all bindings(6) with the buffers
|
// After buffers are created, we want to populate all bindings(6) with the buffers
|
||||||
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA, { &comp.emitterData, 1 }, 0, emitterStructAligned);
|
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA, { &comp.emitterData, 1 }, 0, emitterStructAligned);
|
||||||
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE); // input and output will be th same until we bind using dynamic offsets
|
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned); // input and output will be th same until we bind using dynamic offsets
|
||||||
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, PARTICLE_FRAME_CHUNK_SIZE);
|
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA, { &comp.particleData, 1 }, 0, particleChunkStructAligned);
|
||||||
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, { &comp.freelistData, 1 }, 0, sizeofUint * (comp.maxParticles + 1));
|
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA, { &comp.freelistData, 1 }, 0, sizeofUint * (comp.maxParticles + 1));
|
||||||
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, sizeofUint * (comp.maxParticles));
|
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA, { &comp.indicesData, 1 }, 0, indicesDataAligned);
|
||||||
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmd);
|
set->ModifyWriteDescBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA, { &comp.drawCallData, 1 }, 0, sizeofIndirectCmdAligned);
|
||||||
|
|
||||||
|
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_EMITTER_DATA);
|
||||||
|
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INPUT_DATA);
|
||||||
|
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_OUTPUT_DATA);
|
||||||
|
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_FREELIST_DATA);
|
||||||
|
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_INDICES_DATA);
|
||||||
|
set->UpdateDescriptorSetBuffer(PARTICLE_DATA_SET_INDEX, SHGraphicsConstants::DescriptorSetBindings::PARTICLE_DRAW_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
comp.initialized = true;
|
comp.initialized = true;
|
||||||
|
@ -110,8 +127,8 @@ namespace SHADE
|
||||||
offsets[DYOFF_INDEX_EMITTER] = i * emitterStructAligned;
|
offsets[DYOFF_INDEX_EMITTER] = i * emitterStructAligned;
|
||||||
offsets[DYOFF_INDEX_PARTICLE_INPUT] = inputOffset;
|
offsets[DYOFF_INDEX_PARTICLE_INPUT] = inputOffset;
|
||||||
offsets[DYOFF_INDEX_PARTICLE_OUTPUT] = outputOffset;
|
offsets[DYOFF_INDEX_PARTICLE_OUTPUT] = outputOffset;
|
||||||
offsets[DYOFF_INDEX_INDICES_DATA] = i * sizeofUint * comp.maxParticles;
|
offsets[DYOFF_INDEX_INDICES_DATA] = i * indicesDataAligned;
|
||||||
offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmd;
|
offsets[DYOFF_INDEX_DRAW_DATA] = i * sizeofIndirectCmdAligned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +143,8 @@ namespace SHADE
|
||||||
cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE);
|
cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emitterPosition", transform->GetWorldPosition(), SH_PIPELINE_TYPE::COMPUTE);
|
||||||
cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE);
|
cmdBuffer->SetPushConstantVariable("EmitterPushConstant.emissionCount", comp.emissionCount, SH_PIPELINE_TYPE::COMPUTE);
|
||||||
|
|
||||||
|
cmdBuffer->SubmitPushConstants(SH_PIPELINE_TYPE::COMPUTE);
|
||||||
|
|
||||||
// emit particles
|
// emit particles
|
||||||
cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1);
|
cmdBuffer->ComputeDispatch((comp.emissionCount / EMITTER_WORKGROUP_SIZE) + 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
@ -134,13 +153,6 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
|
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
|
||||||
|
|
||||||
uint32_t instanceCountOffset = sizeof (vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount);
|
|
||||||
uint32_t ZERO = 0;
|
|
||||||
|
|
||||||
// reset instance count to 0
|
|
||||||
comp.drawCallData->WriteToMemory (&ZERO, sizeof(uint32_t), 0, instanceCountOffset);
|
|
||||||
|
|
||||||
|
|
||||||
// bind the descriptor sets required for emitting particles
|
// bind the descriptor sets required for emitting particles
|
||||||
cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]);
|
cmdBuffer->BindDescriptorSet(comp.particleDescriptorSet, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), comp.dynamicOffsets[frameIndex]);
|
||||||
|
|
||||||
|
@ -150,7 +162,110 @@ namespace SHADE
|
||||||
|
|
||||||
void SHParticleSubSystem::RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept
|
void SHParticleSubSystem::RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept
|
||||||
{
|
{
|
||||||
|
cmdBuffer->DrawMultiIndirect(comp.drawCallData, 1, static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand)) * frameIndex);
|
||||||
|
//cmdBuffer->DrawArrays(4, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleSubSystem::PreparePrePostUpdateBarriers(std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept
|
||||||
|
{
|
||||||
|
// pre-update particles data barrier. Note that this is for input because we want the input to be available before we use it.
|
||||||
|
vk::BufferMemoryBarrier inputParticleDataBarrierPreUpdate
|
||||||
|
{
|
||||||
|
.srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||||
|
.buffer = emitter.particleData->GetVkBuffer(),
|
||||||
|
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_INPUT],
|
||||||
|
.size = emitter.chunkSize
|
||||||
|
};
|
||||||
|
|
||||||
|
// pre-update free list data barrier.
|
||||||
|
vk::BufferMemoryBarrier freelistDataBarrierPreUpdate
|
||||||
|
{
|
||||||
|
.srcAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.buffer = emitter.freelistData->GetVkBuffer(),
|
||||||
|
.offset = 0, // Only 1 copy of freelist data, so offset is at 0
|
||||||
|
.size = static_cast<uint32_t>(sizeof (uint32_t)) * (emitter.maxParticles + 1)
|
||||||
|
};
|
||||||
|
|
||||||
|
// pre update indices data barrier.
|
||||||
|
vk::BufferMemoryBarrier indicesDataBarrierPreUpdate
|
||||||
|
{
|
||||||
|
|
||||||
|
.srcAccessMask = vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.buffer = emitter.indicesData->GetVkBuffer(),
|
||||||
|
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_INDICES_DATA],
|
||||||
|
.size = static_cast<uint32_t>(sizeof(uint32_t)) * emitter.maxParticles
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...copy assign barriers on heap
|
||||||
|
preUpdateBarriers.push_back(inputParticleDataBarrierPreUpdate);
|
||||||
|
preUpdateBarriers.push_back(freelistDataBarrierPreUpdate);
|
||||||
|
preUpdateBarriers.push_back(indicesDataBarrierPreUpdate);
|
||||||
|
|
||||||
|
// make new barrier on stack...
|
||||||
|
vk::BufferMemoryBarrier outputParticleDataBarrierPostUpdate
|
||||||
|
{
|
||||||
|
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||||
|
.buffer = emitter.particleData->GetVkBuffer(),
|
||||||
|
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_PARTICLE_OUTPUT],
|
||||||
|
.size = emitter.chunkSize
|
||||||
|
};
|
||||||
|
|
||||||
|
// make new barrier on stack...
|
||||||
|
vk::BufferMemoryBarrier indicesDataBarrierPostUpdate
|
||||||
|
{
|
||||||
|
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||||
|
.buffer = emitter.indicesData->GetVkBuffer(),
|
||||||
|
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_INDICES_DATA],
|
||||||
|
.size = static_cast<uint32_t>(sizeof(uint32_t)) * emitter.maxParticles
|
||||||
|
};
|
||||||
|
|
||||||
|
// make new barrier on stack...
|
||||||
|
vk::BufferMemoryBarrier drawDataBarrierPostUpdate
|
||||||
|
{
|
||||||
|
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
||||||
|
.dstAccessMask = vk::AccessFlagBits::eIndirectCommandRead,
|
||||||
|
.buffer = emitter.drawCallData->GetVkBuffer(),
|
||||||
|
.offset = emitter.dynamicOffsets[FRAME_INDEX][DYOFF_INDEX_DRAW_DATA],
|
||||||
|
.size = static_cast<uint32_t>(sizeof(vk::DrawIndirectCommand))
|
||||||
|
};
|
||||||
|
|
||||||
|
// ...copy assign barriers on heap
|
||||||
|
postUpdateBarriers.push_back(outputParticleDataBarrierPostUpdate);
|
||||||
|
postUpdateBarriers.push_back(indicesDataBarrierPostUpdate);
|
||||||
|
postUpdateBarriers.push_back(drawDataBarrierPostUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<SHVkPipeline> SHParticleSubSystem::GetCustomUpdatePipeline(Handle<SHVkShaderModule> customUpdateShader) noexcept
|
||||||
|
{
|
||||||
|
if (!customUpdateShader)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!customUpdatePipelineCache.contains(customUpdateShader))
|
||||||
|
{
|
||||||
|
SHPipelineLayoutParams plParams
|
||||||
|
{
|
||||||
|
.shaderModules = {customUpdateShader},
|
||||||
|
.predefinedDescSetLayouts = SHGraphicsPredefinedData::GetSystemData(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING).descSetLayouts
|
||||||
|
};
|
||||||
|
|
||||||
|
auto pipelineLayout = logicalDevice->CreatePipelineLayout(plParams);
|
||||||
|
auto newPipeline = logicalDevice->CreateComputePipeline(pipelineLayout);
|
||||||
|
newPipeline->ConstructPipeline();
|
||||||
|
|
||||||
|
if (!newPipeline)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto customUpdateShaderData = CustomPipeline{ newPipeline, pipelineLayout };
|
||||||
|
|
||||||
|
customUpdatePipelineCache.emplace (customUpdateShader, customUpdateShaderData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return customUpdatePipelineCache.at (customUpdateShader).customPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHParticleSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept
|
void SHParticleSubSystem::Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept
|
||||||
|
@ -170,6 +285,40 @@ namespace SHADE
|
||||||
renderingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(plParams);
|
renderingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(plParams);
|
||||||
renderingPipelineData.pipeline = logicalDevice->CreateGraphicsPipeline(renderingPipelineData.pipelineLayout, nullptr, compatibleRenderpass, subpass);
|
renderingPipelineData.pipeline = logicalDevice->CreateGraphicsPipeline(renderingPipelineData.pipelineLayout, nullptr, compatibleRenderpass, subpass);
|
||||||
|
|
||||||
|
SHColorBlendState colorBlendState{};
|
||||||
|
colorBlendState.logic_op_enable = VK_FALSE;
|
||||||
|
colorBlendState.logic_op = vk::LogicOp::eCopy;
|
||||||
|
|
||||||
|
auto const& subpassColorReferences = subpass->GetColorAttachmentReferences();
|
||||||
|
colorBlendState.attachments.reserve(subpassColorReferences.size());
|
||||||
|
|
||||||
|
|
||||||
|
for (auto& att : subpassColorReferences)
|
||||||
|
{
|
||||||
|
colorBlendState.attachments.push_back(vk::PipelineColorBlendAttachmentState
|
||||||
|
{
|
||||||
|
.blendEnable = SHVkUtil::IsBlendCompatible(subpass->GetFormatFromAttachmentReference(att.attachment)),
|
||||||
|
.srcColorBlendFactor = vk::BlendFactor::eSrcAlpha,
|
||||||
|
.dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
|
||||||
|
.colorBlendOp = vk::BlendOp::eAdd,
|
||||||
|
.srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha,
|
||||||
|
.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha,
|
||||||
|
.alphaBlendOp = vk::BlendOp::eAdd,
|
||||||
|
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderingPipelineData.pipeline->GetPipelineState().SetColorBlenState(colorBlendState);
|
||||||
|
|
||||||
|
// Sets the input assembly state for rendering particles
|
||||||
|
SHInputAssemblyState inputAssemblyState{};
|
||||||
|
inputAssemblyState.topology = vk::PrimitiveTopology::eTriangleFan;
|
||||||
|
renderingPipelineData.pipeline->GetPipelineState().SetInputAssemblyState(inputAssemblyState);
|
||||||
|
|
||||||
|
|
||||||
|
renderingPipelineData.pipeline->ConstructPipeline();
|
||||||
|
|
||||||
SHPipelineLayoutParams emitPlParams
|
SHPipelineLayoutParams emitPlParams
|
||||||
{
|
{
|
||||||
.shaderModules = {emitCS},
|
.shaderModules = {emitCS},
|
||||||
|
@ -178,6 +327,7 @@ namespace SHADE
|
||||||
|
|
||||||
emittingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(emitPlParams);
|
emittingPipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(emitPlParams);
|
||||||
emittingPipelineData.pipeline = logicalDevice->CreateComputePipeline(emittingPipelineData.pipelineLayout);
|
emittingPipelineData.pipeline = logicalDevice->CreateComputePipeline(emittingPipelineData.pipelineLayout);
|
||||||
|
emittingPipelineData.pipeline->ConstructPipeline();
|
||||||
|
|
||||||
SHPipelineLayoutParams defaultUpdatePlParams
|
SHPipelineLayoutParams defaultUpdatePlParams
|
||||||
{
|
{
|
||||||
|
@ -187,7 +337,7 @@ namespace SHADE
|
||||||
|
|
||||||
defaultUpdatePipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(defaultUpdatePlParams);
|
defaultUpdatePipelineData.pipelineLayout = logicalDevice->CreatePipelineLayout(defaultUpdatePlParams);
|
||||||
defaultUpdatePipelineData.pipeline = logicalDevice->CreateComputePipeline(defaultUpdatePipelineData.pipelineLayout);
|
defaultUpdatePipelineData.pipeline = logicalDevice->CreateComputePipeline(defaultUpdatePipelineData.pipelineLayout);
|
||||||
|
defaultUpdatePipelineData.pipeline->ConstructPipeline();
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* OTHER INITIALIZATION */
|
/* OTHER INITIALIZATION */
|
||||||
|
@ -195,18 +345,33 @@ namespace SHADE
|
||||||
SHComponentManager::CreateComponentSparseSet<SHParticleEmitterComponent>();
|
SHComponentManager::CreateComponentSparseSet<SHParticleEmitterComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHParticleSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, float dt) noexcept
|
void SHParticleSubSystem::Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, Handle<SHVkFence> waitFence) noexcept
|
||||||
{
|
{
|
||||||
|
float dt = static_cast<float>(SHFrameRateController::GetRawDeltaTime());
|
||||||
|
|
||||||
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
||||||
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
|
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
|
||||||
|
|
||||||
// Get offset into GPU emitter data (for updating)
|
// Get offset into GPU emitter data (for updating)
|
||||||
uint32_t emitterDataOffset = frameIndex * sizeof (SHParticleEmitterComponent::GPUEmitterStruct);
|
uint32_t emitterDataOffset = frameIndex * sizeof (SHParticleEmitterComponent::GPUEmitterStruct);
|
||||||
|
|
||||||
|
// TODO: OPTIONAL but eventually these barriers can be moved to the system as member variables. This would require additional bookkeeping
|
||||||
|
// but it will be more efficient than populating a vector every frame.
|
||||||
|
|
||||||
// Barriers to make sure emitting shader is done completely before update is run.
|
// Barriers to make sure emitting shader is done completely before update is run.
|
||||||
// Every emitter will have its own barrier.
|
// Every emitter will have its own barrier for its particle data and freelist data. Indices data is not needed since
|
||||||
|
// it's mainly used in update and rendering so a barrier for it is NOT needed here.
|
||||||
std::vector<vk::BufferMemoryBarrier> preUpdateBarriers{};
|
std::vector<vk::BufferMemoryBarrier> preUpdateBarriers{};
|
||||||
preUpdateBarriers.resize(emitters.size());
|
preUpdateBarriers.reserve(emitters.size() * 3);
|
||||||
|
|
||||||
|
// After we invoke the updates for the emitters, we need to make sure all particles and indices data are done updating
|
||||||
|
// before we issue them for rendering.
|
||||||
|
std::vector<vk::BufferMemoryBarrier> postUpdateBarriers{};
|
||||||
|
postUpdateBarriers.reserve(emitters.size() * 3);
|
||||||
|
|
||||||
|
std::vector<vk::BufferMemoryBarrier> preDrawBarriers{};
|
||||||
|
preDrawBarriers.reserve(emitters.size());
|
||||||
|
|
||||||
|
|
||||||
// If we wanted to be VERY safe, a barrier would be good here to make sure output particles have finish reading input particles in
|
// If we wanted to be VERY safe, a barrier would be good here to make sure output particles have finish reading input particles in
|
||||||
// the update compute. HOWEVER since a NUM_FRAME_BUFFERS frames would have passed by then, we will not insert 1 here.
|
// the update compute. HOWEVER since a NUM_FRAME_BUFFERS frames would have passed by then, we will not insert 1 here.
|
||||||
|
@ -215,8 +380,6 @@ namespace SHADE
|
||||||
/* BEGIN EMITTING PARTICES */
|
/* BEGIN EMITTING PARTICES */
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
// TODO: Might need to issue a barrier here for input particle data
|
|
||||||
|
|
||||||
// bind the pipeline for emitting particles
|
// bind the pipeline for emitting particles
|
||||||
cmdBuffer->BindPipeline(emittingPipelineData.pipeline);
|
cmdBuffer->BindPipeline(emittingPipelineData.pipeline);
|
||||||
|
|
||||||
|
@ -224,83 +387,135 @@ namespace SHADE
|
||||||
SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex);
|
SHGlobalDescriptorSets::BindGenericAndTextureData(logicalDevice, cmdBuffer, SH_PIPELINE_TYPE::COMPUTE, mappings.at(SHPredefinedDescriptorTypes::STATIC_DATA), frameIndex);
|
||||||
|
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
if (waitFence)
|
||||||
|
waitFence->Wait(true);
|
||||||
|
|
||||||
for (auto& emitter : emitters)
|
for (auto& emitter : emitters)
|
||||||
{
|
{
|
||||||
if (!emitter.initialized)
|
if (emitter.isActive)
|
||||||
InitializeComponent(emitter);
|
|
||||||
|
|
||||||
// Set emitter emit flag to true here if there are ready to be emitted
|
|
||||||
if (emitter.isPassive)
|
|
||||||
{
|
{
|
||||||
// decrement emission timer
|
if (!emitter.initialized)
|
||||||
emitter.timeBeforeEmission -= dt;
|
InitializeComponent(emitter);
|
||||||
|
|
||||||
// Check if time to emit
|
// Set emitter emit flag to true here if there are ready to be emitted
|
||||||
if (emitter.timeBeforeEmission <= 0.0f)
|
if (emitter.isPassive)
|
||||||
{
|
{
|
||||||
// reset timer
|
// decrement emission timer
|
||||||
emitter.timeBeforeEmission = emitter.emissionInterval;
|
emitter.timeBeforeEmission -= dt;
|
||||||
|
|
||||||
// Emit later
|
// Check if time to emit
|
||||||
emitter.toEmit = true;
|
if (emitter.timeBeforeEmission <= 0.0f)
|
||||||
|
{
|
||||||
|
// reset timer
|
||||||
|
emitter.timeBeforeEmission = emitter.emissionInterval;
|
||||||
|
|
||||||
|
// Emit later
|
||||||
|
emitter.toEmit = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (emitter.toEmit) // take note that if emitter is not passive, this can also be set to true outside of this function
|
||||||
|
{
|
||||||
|
// Copy data to host visible buffer of emitter
|
||||||
|
emitter.emitterData->WriteToMemory (&emitter.cpuEmitterData, sizeof (SHParticleEmitterComponent::GPUEmitterStruct), 0, emitterDataOffset);
|
||||||
|
|
||||||
|
// Call emit function here
|
||||||
|
EmitComponent(cmdBuffer, emitter, frameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare barriers
|
||||||
|
PreparePrePostUpdateBarriers(preUpdateBarriers, postUpdateBarriers, emitter, i, frameIndex);
|
||||||
|
|
||||||
|
// Emitter will emit once and stop emitting next frame (unless specified before reaching here to do so).
|
||||||
|
emitter.toEmit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emitter.toEmit) // take note that if emitter is not passive, this can also be set to true outside of this function
|
|
||||||
{
|
|
||||||
// Copy data to host visible buffer of emitter
|
|
||||||
emitter.emitterData->WriteToMemory (&emitter.cpuEmitterData, sizeof (SHParticleEmitterComponent::GPUEmitterStruct), 0, emitterDataOffset);
|
|
||||||
|
|
||||||
// Call emit function here
|
|
||||||
EmitComponent(cmdBuffer, emitter, frameIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make new barrier on stack...
|
|
||||||
vk::BufferMemoryBarrier barrier
|
|
||||||
{
|
|
||||||
.srcAccessMask = vk::AccessFlagBits::eShaderWrite,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
|
||||||
.buffer = emitter.particleData->GetVkBuffer(),
|
|
||||||
.offset = emitter.dynamicOffsets[frameIndex][DYOFF_INDEX_PARTICLE_INPUT],
|
|
||||||
.size = emitter.chunkSize
|
|
||||||
};
|
|
||||||
|
|
||||||
// ...copy assign barrier on heap
|
|
||||||
preUpdateBarriers[i] = barrier;
|
|
||||||
|
|
||||||
emitter.toEmit = false;
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// issue the barrier to wait
|
// issue the barrier to wait
|
||||||
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
|
if (!preUpdateBarriers.empty())
|
||||||
|
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect, vk::PipelineStageFlagBits::eComputeShader, {}, {}, preUpdateBarriers, {});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
|
/* EMITTING PARTICLES DONE, BEGIN UPDATES.... */
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
for (auto& emitter : emitters)
|
||||||
|
{
|
||||||
|
// If custom update shader is a valid handle in the component
|
||||||
|
if (emitter.customUpdateShader)
|
||||||
|
{
|
||||||
|
// Check if pipeline associated with shader is valid, if not create or get one from the cache
|
||||||
|
if (!emitter.customUpdatePipeline)
|
||||||
|
emitter.customUpdatePipeline = GetCustomUpdatePipeline(emitter.customUpdateShader);
|
||||||
|
|
||||||
// bind the pipeline for updating
|
// bind the custom pipeline for updating
|
||||||
cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline);
|
cmdBuffer->BindPipeline(emitter.customUpdatePipeline);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// bind the default upddate pipeline for updating
|
||||||
|
cmdBuffer->BindPipeline(defaultUpdatePipelineData.pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emitter.isActive)
|
||||||
|
UpdateCompoennt(cmdBuffer, emitter, frameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* AFTER UPDATING, RENDER PARTICLES */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
// issue the barrier to wait for output particles to be done updating and indices data to finish being modified.
|
||||||
|
if (!postUpdateBarriers.empty())
|
||||||
|
cmdBuffer->PipelineBarrier(vk::PipelineStageFlagBits::eComputeShader, vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eDrawIndirect | vk::PipelineStageFlagBits::eVertexShader, {}, {}, postUpdateBarriers, {});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHParticleSubSystem::ResetInstanceCounts(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept
|
||||||
|
{
|
||||||
|
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
||||||
|
|
||||||
for (auto& emitter : emitters)
|
for (auto& emitter : emitters)
|
||||||
{
|
{
|
||||||
UpdateCompoennt(cmdBuffer, emitter, frameIndex);
|
if (emitter.initialized)
|
||||||
}
|
{
|
||||||
|
//uint32_t instanceCountOffset = 20;
|
||||||
|
uint32_t instanceCountOffset = sizeof(vk::DrawIndirectCommand) * frameIndex + offsetof(vk::DrawIndirectCommand, instanceCount);
|
||||||
|
uint32_t ZERO = 0;
|
||||||
|
|
||||||
|
// reset instance count to 0
|
||||||
|
emitter.drawCallData->WriteToMemory(&ZERO, sizeof(uint32_t), 0, instanceCountOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHParticleSubSystem::Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept
|
void SHParticleSubSystem::Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept
|
||||||
{
|
{
|
||||||
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
auto& emitters = SHComponentManager::GetDense<SHParticleEmitterComponent>();
|
||||||
|
auto const& mappings = SHGraphicsPredefinedData::GetMappings(SHGraphicsPredefinedData::SystemType::PARTICLE_RENEDERING);
|
||||||
|
|
||||||
|
// bind the pipeline for updating
|
||||||
|
cmdBuffer->BindPipeline(renderingPipelineData.pipeline);
|
||||||
|
|
||||||
// TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem
|
// TODO: Issue barrier for output particle data. Semaphore should also be issued outside in SHGraphicsSystem
|
||||||
for (auto& emitter : emitters)
|
for (auto& emitter : emitters)
|
||||||
{
|
{
|
||||||
|
if (emitter.isActive)
|
||||||
|
{
|
||||||
|
// bind the descriptor sets required for emitting particles
|
||||||
|
cmdBuffer->BindDescriptorSet(emitter.particleDescriptorSet, SH_PIPELINE_TYPE::GRAPHICS, mappings.at(SHPredefinedDescriptorTypes::PARTICLES), emitter.dynamicOffsets[frameIndex]);
|
||||||
|
|
||||||
|
RenderComponent(cmdBuffer, emitter, frameIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHParticleSubSystem::Exit(void) noexcept
|
void SHParticleSubSystem::Exit(void) noexcept
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace SHADE
|
||||||
class SHVkShaderModule;
|
class SHVkShaderModule;
|
||||||
class SHRenderer;
|
class SHRenderer;
|
||||||
class SHParticleEmitterComponent;
|
class SHParticleEmitterComponent;
|
||||||
|
class SHVkFence;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,6 +34,12 @@ namespace SHADE
|
||||||
static constexpr uint32_t DYOFF_INDEX_INDICES_DATA = 3;
|
static constexpr uint32_t DYOFF_INDEX_INDICES_DATA = 3;
|
||||||
static constexpr uint32_t DYOFF_INDEX_DRAW_DATA = 4;
|
static constexpr uint32_t DYOFF_INDEX_DRAW_DATA = 4;
|
||||||
|
|
||||||
|
struct CustomPipeline
|
||||||
|
{
|
||||||
|
Handle<SHVkPipeline> customPipeline;
|
||||||
|
Handle<SHVkPipelineLayout> customPipelineLayout;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// To hold data for a pipeline and pipeline layout.
|
// To hold data for a pipeline and pipeline layout.
|
||||||
// We want this here because particles require 3 pipeline sets:
|
// We want this here because particles require 3 pipeline sets:
|
||||||
|
@ -72,19 +79,26 @@ namespace SHADE
|
||||||
//! Pipeline data for updating particles
|
//! Pipeline data for updating particles
|
||||||
PipelineData defaultUpdatePipelineData;
|
PipelineData defaultUpdatePipelineData;
|
||||||
|
|
||||||
//! Desc pool for particle component desc set allocation
|
//! Desc pool for particle component desc set allocation
|
||||||
Handle<SHVkDescriptorPool> descPool;
|
Handle<SHVkDescriptorPool> descPool;
|
||||||
|
|
||||||
|
std::unordered_map<Handle<SHVkShaderModule>, CustomPipeline> customUpdatePipelineCache;
|
||||||
|
|
||||||
|
|
||||||
void InitializeComponent (SHParticleEmitterComponent& comp) noexcept;
|
void InitializeComponent (SHParticleEmitterComponent& comp) noexcept;
|
||||||
void EmitComponent (Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
void EmitComponent (Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
||||||
void UpdateCompoennt(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
void UpdateCompoennt(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
||||||
void RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
void RenderComponent(Handle<SHVkCommandBuffer> cmdBuffer, SHParticleEmitterComponent& comp, uint32_t frameIndex) noexcept;
|
||||||
|
|
||||||
|
void PreparePrePostUpdateBarriers (std::vector<vk::BufferMemoryBarrier>& preUpdateBarriers, std::vector<vk::BufferMemoryBarrier>& postUpdateBarriers, SHParticleEmitterComponent const& emitter, uint32_t const EMITTER_INDEX, uint32_t const FRAME_INDEX) noexcept;
|
||||||
|
|
||||||
|
Handle<SHVkPipeline> GetCustomUpdatePipeline (Handle<SHVkShaderModule> customUpdateShader) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept;
|
void Init(Handle<SHVkLogicalDevice> device, Handle<SHVkDescriptorPool> inDescPool, Handle<SHVkRenderpass> compatibleRenderpass, Handle<SHSubpass> subpass, Handle<SHVkShaderModule> VS, Handle<SHVkShaderModule> FS, Handle<SHVkShaderModule> emitCS, Handle<SHVkShaderModule> defaultUpdateCS) noexcept;
|
||||||
|
|
||||||
void Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, float dt) noexcept;
|
void Run(Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex, Handle<SHVkFence> waitFence = {}) noexcept;
|
||||||
|
void ResetInstanceCounts (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t frameIndex) noexcept;
|
||||||
|
|
||||||
void Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept;
|
void Render(Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) noexcept;
|
||||||
void Exit(void) noexcept;
|
void Exit(void) noexcept;
|
||||||
|
|
|
@ -19,15 +19,16 @@ namespace SHADE
|
||||||
// generate samples
|
// generate samples
|
||||||
for (uint32_t i = 0; i < NUM_SAMPLES; ++i)
|
for (uint32_t i = 0; i < NUM_SAMPLES; ++i)
|
||||||
{
|
{
|
||||||
//SHVec3 temp
|
SHVec3 temp
|
||||||
//{
|
{
|
||||||
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
||||||
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
||||||
// distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
|
distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
|
||||||
//};
|
};
|
||||||
|
|
||||||
//temp = SHVec3::Normalise(temp);
|
temp = SHVec3::Normalise(temp);
|
||||||
//temp *= distrib(generator);
|
temp *= distrib(generator);
|
||||||
|
samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
|
||||||
|
|
||||||
//// This makes sure that most points are closer to fragment's position
|
//// This makes sure that most points are closer to fragment's position
|
||||||
//float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
|
//float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
|
||||||
|
@ -36,16 +37,16 @@ namespace SHADE
|
||||||
//samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
|
//samples[i] = SHVec4 (temp.x, temp.y, temp.z, 0.0f);
|
||||||
|
|
||||||
|
|
||||||
samples[i] = SHVec4
|
//samples[i] = SHVec4
|
||||||
{
|
//{
|
||||||
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
||||||
distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
// distrib(generator) * 2.0f - 1.0f, // -1.0f - 1.0f
|
||||||
distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
|
// distrib(generator), // 0.0f - 1.0f so that sample space is a hemisphere
|
||||||
0.0f
|
// 0.0f
|
||||||
};
|
//};
|
||||||
|
|
||||||
// This makes sure that most points are closer to fragment's position
|
// This makes sure that most points are closer to fragment's position
|
||||||
float scale = 1.0f / static_cast<float>(NUM_SAMPLES);
|
float scale = static_cast<float>(i) / static_cast<float>(NUM_SAMPLES);
|
||||||
scale = std::lerp(0.1f, 1.0f, scale * scale);
|
scale = std::lerp(0.1f, 1.0f, scale * scale);
|
||||||
samples[i] *= scale;
|
samples[i] *= scale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace SHADE
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
void SHTrajectoryRenderableComponent::OnCreate(void)
|
void SHTrajectoryRenderableComponent::OnCreate(void)
|
||||||
{
|
{
|
||||||
|
ResetSimulationInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHTrajectoryRenderableComponent::OnDestroy(void)
|
void SHTrajectoryRenderableComponent::OnDestroy(void)
|
||||||
|
@ -22,12 +23,13 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept
|
void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, float mass, SHVec3 force, float timestep, uint32_t maxSteps) noexcept
|
||||||
{
|
{
|
||||||
entityToSimulate = eid;
|
entityToSimulate = eid;
|
||||||
simulationForce = force;
|
simulationForce = force;
|
||||||
simulationTimestep = timestep;
|
simulationTimestep = timestep;
|
||||||
simulationMaxSteps = maxSteps;
|
simulationMaxSteps = maxSteps;
|
||||||
|
objectMass = mass;
|
||||||
}
|
}
|
||||||
|
|
||||||
float SHTrajectoryRenderableComponent::GetSimulationTimestep(void) const noexcept
|
float SHTrajectoryRenderableComponent::GetSimulationTimestep(void) const noexcept
|
||||||
|
@ -35,6 +37,11 @@ namespace SHADE
|
||||||
return simulationTimestep;
|
return simulationTimestep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SHTrajectoryRenderableComponent::GetObjectMass(void) const noexcept
|
||||||
|
{
|
||||||
|
return objectMass;
|
||||||
|
}
|
||||||
|
|
||||||
void SHTrajectoryRenderableComponent::ResetSimulationInfo(void) noexcept
|
void SHTrajectoryRenderableComponent::ResetSimulationInfo(void) noexcept
|
||||||
{
|
{
|
||||||
entityToSimulate = MAX_EID;
|
entityToSimulate = MAX_EID;
|
||||||
|
|
|
@ -36,6 +36,9 @@ namespace SHADE
|
||||||
//! plotting a point in the simulation
|
//! plotting a point in the simulation
|
||||||
float simulationTimestep;
|
float simulationTimestep;
|
||||||
|
|
||||||
|
//! mass of the object to simulate
|
||||||
|
float objectMass;
|
||||||
|
|
||||||
//! Entity to simulate trajectory of
|
//! Entity to simulate trajectory of
|
||||||
EntityID entityToSimulate;
|
EntityID entityToSimulate;
|
||||||
|
|
||||||
|
@ -68,12 +71,13 @@ namespace SHADE
|
||||||
SHVec3 GetSimulationForce (void) const noexcept;
|
SHVec3 GetSimulationForce (void) const noexcept;
|
||||||
uint32_t GetSimulationMaxSteps (void) const noexcept;
|
uint32_t GetSimulationMaxSteps (void) const noexcept;
|
||||||
float GetSimulationTimestep (void) const noexcept;
|
float GetSimulationTimestep (void) const noexcept;
|
||||||
|
float GetObjectMass (void) const noexcept;
|
||||||
|
|
||||||
void ResetSimulationInfo (void) noexcept;
|
void ResetSimulationInfo (void) noexcept;
|
||||||
void OnCreate(void) override final;
|
void OnCreate(void) override final;
|
||||||
void OnDestroy(void) override final;
|
void OnDestroy(void) override final;
|
||||||
|
|
||||||
void SimulateTrajectory (EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept;
|
void SimulateTrajectory (EntityID eid, float mass, SHVec3 force, float timestep, uint32_t maxSteps) noexcept;
|
||||||
|
|
||||||
RTTR_ENABLE()
|
RTTR_ENABLE()
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "SHpch.h"
|
#include "SHpch.h"
|
||||||
#include "SHTrajectoryRenderingSubSystem.h"
|
#include "SHTrajectoryRenderingSubSystem.h"
|
||||||
|
|
||||||
#include "ECS_Base/Managers/SHComponentManager.h"
|
#include "ECS_Base/Managers/SHComponentManager.h"
|
||||||
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
||||||
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
#include "Graphics/Devices/SHVkLogicalDevice.h"
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
|
#include "Graphics/MiddleEnd/Interface/SHRenderer.h"
|
||||||
#include "Physics/System/SHPhysicsSystem.h"
|
#include "Physics/System/SHPhysicsSystem.h"
|
||||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||||
|
#include <Physics/System/SHGhostBody.h>
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -85,20 +87,36 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
std::vector<SHVec3> positions{};
|
std::vector<SHVec3> positions{};
|
||||||
std::vector<SHQuaternion> quats{};
|
std::vector<SHQuaternion> quats{};
|
||||||
physicsSystem->SimulateBody
|
|
||||||
(positions, quats,
|
auto* rigidBodyComp = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(entityToSimulate);
|
||||||
SHPhysicsSystem::SimulateBodyInfo
|
if (!rigidBodyComp)
|
||||||
{
|
continue;
|
||||||
.bodyEID = entityToSimulate,
|
|
||||||
.force = comp.GetSimulationForce(),
|
SHGhostBody defaultGhostBody{*rigidBodyComp};
|
||||||
.continuousForce = false,
|
|
||||||
|
defaultGhostBody.mass = comp.GetObjectMass();
|
||||||
|
|
||||||
|
SHPhysicsSystem::SimulateBodyInfo simulateInfo
|
||||||
|
{
|
||||||
|
.bodyEID = entityToSimulate,
|
||||||
|
.force = comp.GetSimulationForce(),
|
||||||
|
.continuousForce = false,
|
||||||
.timeStep = comp.GetSimulationTimestep(),
|
.timeStep = comp.GetSimulationTimestep(),
|
||||||
.maxSteps = static_cast<int>(comp.GetSimulationMaxSteps()),
|
.maxSteps = static_cast<int>(comp.GetSimulationMaxSteps()),
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
SHPhysicsSystem::SimulateBodyOutput output
|
||||||
|
{
|
||||||
|
.positions = &positions
|
||||||
|
, .orientations = &quats
|
||||||
|
};
|
||||||
|
|
||||||
|
physicsSystem->SimulateBody(defaultGhostBody, simulateInfo, output);
|
||||||
|
|
||||||
comp.ResetSimulationInfo();
|
comp.ResetSimulationInfo();
|
||||||
|
|
||||||
|
std::cout << positions.size() << std::endl;
|
||||||
|
|
||||||
// If has positions, feed data to buffer.
|
// If has positions, feed data to buffer.
|
||||||
if (!positions.empty())
|
if (!positions.empty())
|
||||||
{
|
{
|
||||||
|
@ -198,7 +216,7 @@ namespace SHADE
|
||||||
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRAJECTORY_TRANSFORM, transformBuffer, 0);
|
cmdBuffer->BindVertexBuffer(SHGraphicsConstants::VertexBufferBindings::TRAJECTORY_TRANSFORM, transformBuffer, 0);
|
||||||
|
|
||||||
// call draw call
|
// call draw call
|
||||||
cmdBuffer->DrawMultiIndirect(drawDataBuffer, drawData.size());
|
cmdBuffer->DrawMultiIndirectIndexed(drawDataBuffer, drawData.size());
|
||||||
|
|
||||||
// clear CPU transform and draw data
|
// clear CPU transform and draw data
|
||||||
transformData.clear();
|
transformData.clear();
|
||||||
|
|
|
@ -299,6 +299,8 @@ namespace SHADE
|
||||||
, created{ false }
|
, created{ false }
|
||||||
|
|
||||||
{
|
{
|
||||||
|
if (pipelineLayout)
|
||||||
|
pipelineLayout->AddCallback([this]() {ConstructPipeline(); });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -372,6 +372,7 @@ namespace SHADE
|
||||||
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
|
, ISelfHandle<SHRenderGraphNode>{std::move(rhs)}
|
||||||
, dynamicIsActive {rhs.dynamicIsActive}
|
, dynamicIsActive {rhs.dynamicIsActive}
|
||||||
, isDynamic {rhs.isDynamic}
|
, isDynamic {rhs.isDynamic}
|
||||||
|
, preBeginFuncs{std::move(rhs.preBeginFuncs)}
|
||||||
|
|
||||||
{
|
{
|
||||||
rhs.renderpass = {};
|
rhs.renderpass = {};
|
||||||
|
@ -399,6 +400,7 @@ namespace SHADE
|
||||||
name = std::move(rhs.name);
|
name = std::move(rhs.name);
|
||||||
dynamicIsActive = rhs.dynamicIsActive;
|
dynamicIsActive = rhs.dynamicIsActive;
|
||||||
isDynamic = rhs.isDynamic;
|
isDynamic = rhs.isDynamic;
|
||||||
|
preBeginFuncs = std::move(rhs.preBeginFuncs);
|
||||||
|
|
||||||
rhs.renderpass = {};
|
rhs.renderpass = {};
|
||||||
|
|
||||||
|
@ -493,6 +495,11 @@ namespace SHADE
|
||||||
return nodeCompute;
|
return nodeCompute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHRenderGraphNode::AddPreBeginFunction(PreBeginFunction const& func) noexcept
|
||||||
|
{
|
||||||
|
preBeginFuncs.push_back(func);
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/*!
|
/*!
|
||||||
|
|
||||||
|
@ -664,6 +671,11 @@ namespace SHADE
|
||||||
|
|
||||||
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
|
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
|
||||||
{
|
{
|
||||||
|
for (auto& func : preBeginFuncs)
|
||||||
|
{
|
||||||
|
func(commandBuffer, frameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
if (renderpass)
|
if (renderpass)
|
||||||
{
|
{
|
||||||
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
|
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;
|
||||||
|
|
|
@ -27,6 +27,10 @@ namespace SHADE
|
||||||
|
|
||||||
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
|
class SH_API SHRenderGraphNode : public ISelfHandle<SHRenderGraphNode>
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
using PreBeginFunction = std::function<void(Handle<SHVkCommandBuffer>, uint32_t)>;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* PRIVATE MEMBER VARIABLES */
|
/* PRIVATE MEMBER VARIABLES */
|
||||||
|
@ -74,6 +78,9 @@ namespace SHADE
|
||||||
//! of drawing objects on the image (i.e. compute).
|
//! of drawing objects on the image (i.e. compute).
|
||||||
std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes;
|
std::vector<Handle<SHRenderGraphNodeCompute>> nodeComputes;
|
||||||
|
|
||||||
|
//! Calls before renderpass begins
|
||||||
|
std::vector<PreBeginFunction> preBeginFuncs;
|
||||||
|
|
||||||
//! Whether or not the node has finished execution
|
//! Whether or not the node has finished execution
|
||||||
bool executed;
|
bool executed;
|
||||||
|
|
||||||
|
@ -118,6 +125,7 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
|
Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
|
||||||
Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept;
|
Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, uint32_t variableDescCount = 0, float numWorkGroupScale = 1.0f) noexcept;
|
||||||
|
void AddPreBeginFunction (PreBeginFunction const& func) noexcept;
|
||||||
|
|
||||||
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
|
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
|
||||||
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
|
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
|
||||||
|
|
|
@ -94,8 +94,8 @@ namespace SHADE
|
||||||
|
|
||||||
Recompile();
|
Recompile();
|
||||||
|
|
||||||
//for (auto& callback : onChangeCallbacks)
|
for (auto& callback : onChangeCallbacks)
|
||||||
// callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHVkShaderModule::AddCallback(ChangeCallback&& callback) noexcept
|
void SHVkShaderModule::AddCallback(ChangeCallback&& callback) noexcept
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace SHADE
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* PUBLIC MEMBER FUNCTIONS */
|
/* PUBLIC MEMBER FUNCTIONS */
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
bool Wait (bool waitAll, uint64_t timer) noexcept;
|
bool Wait (bool waitAll, uint64_t timer = std::numeric_limits<uint32_t>::max()) noexcept;
|
||||||
void Reset (void) noexcept;
|
void Reset (void) noexcept;
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
|
@ -150,6 +150,16 @@ namespace SHADE
|
||||||
return rigidBody ? SHQuaternion{ rigidBody->getTransform().getOrientation() }.ToEuler() : SHVec3::Zero;
|
return rigidBody ? SHQuaternion{ rigidBody->getTransform().getOrientation() }.ToEuler() : SHVec3::Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHVec3 SHRigidBodyComponent::GetLocalInertia() const noexcept
|
||||||
|
{
|
||||||
|
return rigidBody ? SHVec3{ rigidBody->getLocalInertiaTensor() } : SHVec3::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHVec3 SHRigidBodyComponent::GetLocalCentroid() const noexcept
|
||||||
|
{
|
||||||
|
return rigidBody ? SHVec3{ rigidBody->getLocalCenterOfMass() } : SHVec3::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Setter Function Definitions */
|
/* Setter Function Definitions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -103,6 +103,9 @@ namespace SHADE
|
||||||
[[nodiscard]] SHVec3 GetPosition () const noexcept;
|
[[nodiscard]] SHVec3 GetPosition () const noexcept;
|
||||||
[[nodiscard]] SHVec3 GetRotation () const noexcept;
|
[[nodiscard]] SHVec3 GetRotation () const noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] SHVec3 GetLocalInertia () const noexcept;
|
||||||
|
[[nodiscard]] SHVec3 GetLocalCentroid () const noexcept;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Setter Functions */
|
/* Setter Functions */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/****************************************************************************************
|
||||||
|
* \file SHGhostBody.cpp
|
||||||
|
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||||
|
* \brief Implementation for the Ghost Body meant for Simulation.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
|
||||||
|
* disclosure of this file or its contents without the prior written consent
|
||||||
|
* of DigiPen Institute of Technology is prohibited.
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#include <SHpch.h>
|
||||||
|
|
||||||
|
// Primary Header
|
||||||
|
#include "SHGhostBody.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/* Constructors & Destructor Definitions */
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
SHGhostBody::SHGhostBody(const SHRigidBodyComponent& rigidBody) noexcept
|
||||||
|
: linearVelocity { rigidBody.GetLinearVelocity() }
|
||||||
|
, angularVelocity { rigidBody.GetAngularVelocity() }
|
||||||
|
, localCentroid { rigidBody.GetLocalCentroid() }
|
||||||
|
, accumulatedForce { rigidBody.GetForce() }
|
||||||
|
, accumulatedTorque{ rigidBody.GetTorque() }
|
||||||
|
, gravityScale { rigidBody.GetGravityScale() }
|
||||||
|
, mass { rigidBody.GetMass() }
|
||||||
|
, drag { rigidBody.GetDrag() }
|
||||||
|
, angularDrag { rigidBody.GetAngularDrag() }
|
||||||
|
, position { rigidBody.GetPosition() }
|
||||||
|
, orientation { SHQuaternion::FromEuler(rigidBody.GetRotation()) }
|
||||||
|
, useGravity { rigidBody.IsGravityEnabled() }
|
||||||
|
{
|
||||||
|
const SHVec3 LOCAL_INERTIA = rigidBody.GetLocalInertia();
|
||||||
|
localInvInertia.x = 1.0f / LOCAL_INERTIA.x;
|
||||||
|
localInvInertia.y = 1.0f / LOCAL_INERTIA.y;
|
||||||
|
localInvInertia.z = 1.0f / LOCAL_INERTIA.z;
|
||||||
|
|
||||||
|
linearLock.x = rigidBody.GetFreezePositionX() ? 0.0f : 1.0f;
|
||||||
|
linearLock.y = rigidBody.GetFreezePositionY() ? 0.0f : 1.0f;
|
||||||
|
linearLock.z = rigidBody.GetFreezePositionZ() ? 0.0f : 1.0f;
|
||||||
|
|
||||||
|
angularLock.x = rigidBody.GetFreezeRotationX() ? 0.0f : 1.0f;
|
||||||
|
angularLock.y = rigidBody.GetFreezeRotationY() ? 0.0f : 1.0f;
|
||||||
|
angularLock.z = rigidBody.GetFreezeRotationZ() ? 0.0f : 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace SHADE
|
|
@ -0,0 +1,64 @@
|
||||||
|
/****************************************************************************************
|
||||||
|
* \file SHGhostBody.h
|
||||||
|
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||||
|
* \brief Interface for the Ghost Body meant for Simulation.
|
||||||
|
*
|
||||||
|
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
|
||||||
|
* disclosure of this file or its contents without the prior written consent
|
||||||
|
* of DigiPen Institute of Technology is prohibited.
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Project Headers
|
||||||
|
#include "Physics/Interface/SHRigidBodyComponent.h"
|
||||||
|
|
||||||
|
namespace SHADE
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
/* Type Definitions */
|
||||||
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Encapsulates a rigid body that will be simulated in the world, but doesn't actually
|
||||||
|
* exist in the world.
|
||||||
|
*/
|
||||||
|
struct SHGhostBody
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Data Members */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
SHVec3 linearVelocity = SHVec3::Zero;
|
||||||
|
SHVec3 angularVelocity = SHVec3::Zero;
|
||||||
|
|
||||||
|
SHVec3 localInvInertia = SHVec3::One;
|
||||||
|
SHVec3 localCentroid = SHVec3::Zero;
|
||||||
|
SHVec3 accumulatedForce = SHVec3::Zero;
|
||||||
|
SHVec3 accumulatedTorque = SHVec3::Zero;
|
||||||
|
|
||||||
|
SHVec3 linearLock = SHVec3::One;
|
||||||
|
SHVec3 angularLock = SHVec3::One;
|
||||||
|
|
||||||
|
float gravityScale = 1.0f;
|
||||||
|
float mass = 1.0f;
|
||||||
|
float drag = 0.01f;
|
||||||
|
float angularDrag = 0.01f;
|
||||||
|
|
||||||
|
SHVec3 position = SHVec3::Zero;
|
||||||
|
SHQuaternion orientation = SHQuaternion::Identity;
|
||||||
|
bool useGravity = true;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
/* Constructors & Destructor */
|
||||||
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
SHGhostBody () noexcept = default;
|
||||||
|
SHGhostBody (const SHRigidBodyComponent& rigidBody) noexcept;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace SHADE
|
|
@ -24,6 +24,7 @@
|
||||||
#include "Physics/Interface/SHColliderComponent.h"
|
#include "Physics/Interface/SHColliderComponent.h"
|
||||||
#include "Scene/SHSceneManager.h"
|
#include "Scene/SHSceneManager.h"
|
||||||
#include "Scripting/SHScriptEngine.h"
|
#include "Scripting/SHScriptEngine.h"
|
||||||
|
#include "SHGhostBody.h"
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
@ -236,46 +237,22 @@ namespace SHADE
|
||||||
return IS_COLLIDING;
|
return IS_COLLIDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHPhysicsSystem::SimulateBody(std::vector<SHVec3>& positions, std::vector<SHQuaternion>& orientations, const SimulateBodyInfo& simInfo)
|
void SHPhysicsSystem::SimulateBody(SHGhostBody& ghostBody, SimulateBodyInfo& simInfo, SimulateBodyOutput& output)
|
||||||
{
|
{
|
||||||
// Check for a valid rigidbody
|
// Check for a valid rigidbody
|
||||||
const auto* rigidBody = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(simInfo.bodyEID);
|
const auto* rigidBody = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(simInfo.bodyEID);
|
||||||
if (!rigidBody)
|
if (!rigidBody)
|
||||||
{
|
{
|
||||||
SHLOG_WARNING("Entity {} does not have a rigid body to simulate!", simInfo.bodyEID)
|
SHLOG_WARNING("Entity {} does not have a rigid body to simulate! This body will collide with everything!", simInfo.bodyEID)
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore non-dynamic bodies
|
|
||||||
if (rigidBody->type != SHRigidBodyComponent::Type::DYNAMIC)
|
|
||||||
{
|
|
||||||
SHLOG_WARNING("Entity {} is not a dynamic body. We cannot simulate non-dynamic bodies!", simInfo.bodyEID)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare simulation info (I'm basically declaring an entire body here)
|
// Prepare simulation info (I'm basically declaring an entire body here)
|
||||||
SHVec3 bodyPosition = rigidBody->GetPosition();
|
float invMass = 1.0f / ghostBody.mass;
|
||||||
SHQuaternion bodyOrientation = SHQuaternion::FromEuler(rigidBody->GetRotation());
|
SHVec3 worldInvInertia = SHVec3::One;
|
||||||
SHVec3 linearVelocity = rigidBody->GetLinearVelocity();
|
SHVec3 worldCentroid = SHVec3::One;
|
||||||
SHVec3 angularVelocity = rigidBody->GetAngularVelocity();
|
|
||||||
float invMass = 1.0f / rigidBody->GetMass();
|
|
||||||
SHVec3 localInvInertia = rigidBody->rigidBody->getLocalInertiaTensor();
|
|
||||||
SHVec3 worldInvInertia = SHVec3::One;
|
|
||||||
SHVec3 localCentroid = rigidBody->rigidBody->getLocalCenterOfMass();
|
|
||||||
SHVec3 worldCentroid = SHVec3::One;
|
|
||||||
SHVec3 appliedForce = simInfo.force;
|
|
||||||
SHVec3 appliedTorque = simInfo.torque;
|
|
||||||
SHVec3 accumulatedForce = SHVec3::Zero;
|
|
||||||
SHVec3 accumulatedTorque = SHVec3::Zero;
|
|
||||||
|
|
||||||
const SHVec3& LINEAR_LOCK = rigidBody->rigidBody->getLinearLockAxisFactor();
|
// Asserts. Don't be an idiot.
|
||||||
const SHVec3& ANGULAR_LOCK = rigidBody->rigidBody->getAngularLockAxisFactor();
|
SHASSERT(invMass > 0, "GhostBody's mass in invalid")
|
||||||
|
|
||||||
// Invert the inertia
|
|
||||||
for (size_t i = 0; i < SHVec3::SIZE; ++i)
|
|
||||||
localInvInertia[i] = 1.0f / localInvInertia[i];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Build raycast layer from colliders. If none exist....then this never stops simulating technically.
|
// Build raycast layer from colliders. If none exist....then this never stops simulating technically.
|
||||||
// I'm too lazy to handle that case, so I'll just throw an error.
|
// I'm too lazy to handle that case, so I'll just throw an error.
|
||||||
|
@ -302,24 +279,24 @@ namespace SHADE
|
||||||
int iterationCounter = simInfo.maxSteps;
|
int iterationCounter = simInfo.maxSteps;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
raycastInfo.distance = linearVelocity.Length();
|
raycastInfo.distance = ghostBody.linearVelocity.Length() * simInfo.timeStep; // Do not take the entire velocity's length as that is for an entire second.
|
||||||
raycastInfo.ray.position = bodyPosition;
|
raycastInfo.ray.position = ghostBody.position;
|
||||||
raycastInfo.ray.direction = SHVec3::Normalise(linearVelocity);
|
raycastInfo.ray.direction = SHVec3::Normalise(ghostBody.linearVelocity);
|
||||||
|
|
||||||
terminate = !Raycast(raycastInfo).empty() || iterationCounter == 0;
|
terminate = !Raycast(raycastInfo).empty() || iterationCounter == 0;
|
||||||
if (terminate)
|
if (terminate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Compute world space data
|
// Compute world space data
|
||||||
const SHMatrix R = SHMatrix::Rotate(bodyOrientation);
|
const SHMatrix R = SHMatrix::Rotate(ghostBody.orientation);
|
||||||
const SHMatrix RT = SHMatrix::Transpose(R);
|
const SHMatrix RT = SHMatrix::Transpose(R);
|
||||||
|
|
||||||
SHMatrix localInertiaTensor = SHMatrix::Identity;
|
SHMatrix localInertiaTensor = SHMatrix::Identity;
|
||||||
|
|
||||||
// Set the diagonals
|
// Set the diagonals
|
||||||
localInertiaTensor.m[0][0] = localInvInertia.x;
|
localInertiaTensor.m[0][0] = ghostBody.localInvInertia.x;
|
||||||
localInertiaTensor.m[1][1] = localInvInertia.y;
|
localInertiaTensor.m[1][1] = ghostBody.localInvInertia.y;
|
||||||
localInertiaTensor.m[2][2] = localInvInertia.z;
|
localInertiaTensor.m[2][2] = ghostBody.localInvInertia.z;
|
||||||
|
|
||||||
localInertiaTensor *= RT;
|
localInertiaTensor *= RT;
|
||||||
const SHVec3 DIAGONALS { localInertiaTensor.m[0][0], localInertiaTensor.m[1][1], localInertiaTensor.m[2][2] };
|
const SHVec3 DIAGONALS { localInertiaTensor.m[0][0], localInertiaTensor.m[1][1], localInertiaTensor.m[2][2] };
|
||||||
|
@ -327,42 +304,47 @@ namespace SHADE
|
||||||
worldInvInertia = R * DIAGONALS;
|
worldInvInertia = R * DIAGONALS;
|
||||||
|
|
||||||
// Compute world centroid
|
// Compute world centroid
|
||||||
worldCentroid = (R * localCentroid) + bodyPosition;
|
worldCentroid = (R * ghostBody.localCentroid) + ghostBody.position;
|
||||||
|
|
||||||
// Apply forces
|
// Apply forces
|
||||||
accumulatedForce += appliedForce;
|
ghostBody.accumulatedForce += simInfo.force;
|
||||||
angularVelocity += worldInvInertia * SHVec3::Cross(bodyPosition + simInfo.forceOffset, simInfo.force);
|
ghostBody.angularVelocity += worldInvInertia * SHVec3::Cross(ghostBody.position + simInfo.forceOffset, simInfo.force);
|
||||||
accumulatedTorque += appliedTorque;
|
ghostBody.accumulatedTorque += simInfo.torque;
|
||||||
|
|
||||||
// Integrate Velocities
|
// Integrate Velocities
|
||||||
// Integrate forces and gravity into linear velocity
|
// Integrate forces and gravity into linear velocity
|
||||||
const SHVec3 LINEAR_ACCELERATION = accumulatedForce * invMass;
|
const SHVec3 LINEAR_ACCELERATION = ghostBody.accumulatedForce * invMass;
|
||||||
const SHVec3 GRAVITATIONAL_ACCELERATION = rigidBody->IsGravityEnabled() ? worldState.settings.gravity * rigidBody->GetGravityScale() : SHVec3::Zero;
|
const SHVec3 GRAVITATIONAL_ACCELERATION = ghostBody.gravityScale ? worldState.settings.gravity * ghostBody.gravityScale : SHVec3::Zero;
|
||||||
|
|
||||||
linearVelocity += (LINEAR_ACCELERATION + GRAVITATIONAL_ACCELERATION) * simInfo.timeStep * LINEAR_LOCK;
|
ghostBody.linearVelocity += (LINEAR_ACCELERATION + GRAVITATIONAL_ACCELERATION) * simInfo.timeStep * ghostBody.linearLock;
|
||||||
angularVelocity += worldInvInertia * (accumulatedTorque * simInfo.timeStep);
|
ghostBody.angularVelocity += worldInvInertia * (ghostBody.accumulatedTorque * simInfo.timeStep);
|
||||||
|
|
||||||
// Apply drag (exponentially applied)
|
// Apply drag (exponentially applied)
|
||||||
linearVelocity *= 1.0f / (1.0f + simInfo.timeStep * rigidBody->drag);
|
ghostBody.linearVelocity *= 1.0f / (1.0f + simInfo.timeStep * ghostBody.drag);
|
||||||
angularVelocity *= 1.0f / (1.0f + simInfo.timeStep * rigidBody->angularDrag);
|
ghostBody.angularVelocity *= 1.0f / (1.0f + simInfo.timeStep * ghostBody.angularDrag);
|
||||||
|
|
||||||
// Integrate Positions & Orientations
|
// Integrate Positions & Orientations
|
||||||
const SHQuaternion QV = SHQuaternion{ angularVelocity.x * simInfo.timeStep, angularVelocity.y * simInfo.timeStep, angularVelocity.z * simInfo.timeStep, 0.0f } * 0.5f;
|
const SHQuaternion QV = SHQuaternion{ ghostBody.angularVelocity.x * simInfo.timeStep, ghostBody.angularVelocity.y * simInfo.timeStep, ghostBody.angularVelocity.z * simInfo.timeStep, 0.0f } * 0.5f;
|
||||||
|
|
||||||
bodyPosition += linearVelocity * simInfo.timeStep;
|
ghostBody.position += ghostBody.linearVelocity * simInfo.timeStep;
|
||||||
bodyOrientation += bodyOrientation * QV * SHQuaternion::FromEuler(ANGULAR_LOCK);
|
ghostBody.orientation += ghostBody.orientation * QV * SHQuaternion::FromEuler(ghostBody.angularLock);
|
||||||
bodyOrientation = SHQuaternion::Normalise(bodyOrientation);
|
ghostBody.orientation = SHQuaternion::Normalise(ghostBody.orientation);
|
||||||
|
|
||||||
|
// Clear forces
|
||||||
|
ghostBody.accumulatedForce = SHVec3::Zero;
|
||||||
|
ghostBody.accumulatedTorque = SHVec3::Zero;
|
||||||
|
|
||||||
// Clear forces after the first frame
|
|
||||||
if (!simInfo.continuousForce)
|
if (!simInfo.continuousForce)
|
||||||
{
|
{
|
||||||
accumulatedForce = SHVec3::Zero;
|
simInfo.force = SHVec3::Zero;
|
||||||
accumulatedTorque = SHVec3::Zero;
|
simInfo.torque = SHVec3::Zero;
|
||||||
appliedForce = SHVec3::Zero;
|
|
||||||
appliedTorque = SHVec3::Zero;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
positions.emplace_back(bodyPosition);
|
if (output.positions)
|
||||||
|
output.positions->emplace_back(ghostBody.position);
|
||||||
|
|
||||||
|
if (output.orientations)
|
||||||
|
output.orientations->emplace_back(ghostBody.orientation);
|
||||||
|
|
||||||
--iterationCounter;
|
--iterationCounter;
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
|
struct SHGhostBody;
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
/* Type Definitions */
|
/* Type Definitions */
|
||||||
/*-----------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------*/
|
||||||
|
@ -51,40 +52,54 @@ namespace SHADE
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Used to simulate the motion of a rigid body, ignoring collision detection and response.
|
* Used to simulate the motion of a rigid body, ignoring collision detection and response.
|
||||||
* @param bodyEID
|
|
||||||
* The EntityID of the Rigid Body to simulate.
|
|
||||||
* @param force
|
|
||||||
* The force applied onto the Rigid Body.
|
|
||||||
* @param forceOffset
|
|
||||||
* The position to apply the force onto the body relative to it's local Center of Mass.
|
|
||||||
* @param torque
|
|
||||||
* The torque to apply onto the Rigid Body.
|
|
||||||
* @param continuousForce
|
|
||||||
* If the force should be applied every step throughout the simulation. Defaults to false. <br/>
|
|
||||||
* True : The force indicated is added to the body every step, therefore it has constant acceleration.
|
|
||||||
* False: The force is applied only in the first step, therefore it has constant speed.
|
|
||||||
* @param timeStep
|
|
||||||
* The timestep for each step of the simulation. Defaults to 0.016s (The default Fixed DT)
|
|
||||||
* @param maxSteps
|
|
||||||
* The number of steps to run the simulation for. Defaults to -1.
|
|
||||||
* < 0 : Runs until the object may hit something. Hit detection is done through raycasting.
|
|
||||||
* = 0 : Runs only the current step and checks if it may hit something.
|
|
||||||
* > 0 : Runs for the given number of steps or until it may hit something.
|
|
||||||
*/
|
*/
|
||||||
struct SimulateBodyInfo
|
struct SimulateBodyInfo
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// The EntityID of the Actual Rigid Body to simulate. If none is passed it,
|
||||||
|
// the Ghost Body will attempt to collide with everything.
|
||||||
EntityID bodyEID = MAX_EID;
|
EntityID bodyEID = MAX_EID;
|
||||||
|
|
||||||
|
// The force applied onto the Ghost Body.
|
||||||
SHVec3 force = SHVec3::Zero;
|
SHVec3 force = SHVec3::Zero;
|
||||||
|
|
||||||
|
// The position where the force is applied offset from the local centroid.
|
||||||
SHVec3 forceOffset = SHVec3::Zero;
|
SHVec3 forceOffset = SHVec3::Zero;
|
||||||
|
|
||||||
|
// The torque to apply onto the Ghost Body.
|
||||||
SHVec3 torque = SHVec3::Zero;
|
SHVec3 torque = SHVec3::Zero;
|
||||||
|
|
||||||
// Whether or not to clear the force after the first iteration
|
/*
|
||||||
|
If the force should be applied every step throughout the simulation. Defaults to false.
|
||||||
|
True : The force indicated is added to the body every step, therefore it has constant acceleration.
|
||||||
|
False: The force is applied only in the first step, therefore it has constant speed.
|
||||||
|
*/
|
||||||
bool continuousForce = false;
|
bool continuousForce = false;
|
||||||
|
|
||||||
|
// The timestep for each step of the simulation. Defaults to 0.016s (The default Fixed DT)
|
||||||
float timeStep = static_cast<float>(SHPhysicsConstants::DEFAULT_FIXED_DT);
|
float timeStep = static_cast<float>(SHPhysicsConstants::DEFAULT_FIXED_DT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
The number of steps to run the simulation for. Defaults to -1.
|
||||||
|
< 0 : Runs until the object may hit something. Hit detection is done through raycasting.
|
||||||
|
= 0 : Runs only the current step and checks if it may hit something.
|
||||||
|
> 0 : Runs for the given number of steps or until it may hit something.
|
||||||
|
*/
|
||||||
int maxSteps = -1;
|
int maxSteps = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Contains the output for the simulate body method.
|
||||||
|
*/
|
||||||
|
struct SimulateBodyOutput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<SHVec3>* positions = nullptr;
|
||||||
|
std::vector<SHQuaternion>* orientations = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Constructors & Destructor */
|
/* Constructors & Destructor */
|
||||||
|
@ -158,15 +173,16 @@ namespace SHADE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Simulates the motion of a body until it collides with something.
|
* Simulates a non-existent body in the physics world.
|
||||||
* @param positions
|
* The simulation will run based on the information passed in.
|
||||||
* The output vector for the position of the body in each timestep.
|
* @param ghostBody
|
||||||
* @param orientations
|
* The definition of the body passed in.
|
||||||
* The output vector for the orientations of the body in each timestep.
|
|
||||||
* @param simInfo
|
* @param simInfo
|
||||||
* The information for simulating the body.
|
* The information for how the simulation will run.
|
||||||
|
* @param output
|
||||||
|
* The transform results for position and orientations.
|
||||||
*/
|
*/
|
||||||
void SimulateBody(std::vector<SHVec3>& positions, std::vector<SHQuaternion>& orientations, const SimulateBodyInfo& simInfo);
|
void SimulateBody(SHGhostBody& ghostBody, SimulateBodyInfo& simInfo, SimulateBodyOutput& output);
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* System Routines */
|
/* System Routines */
|
||||||
|
|
|
@ -248,6 +248,7 @@ namespace SHADE
|
||||||
AddComponentToComponentNode<SHUIComponent>(components, eid);
|
AddComponentToComponentNode<SHUIComponent>(components, eid);
|
||||||
AddComponentToComponentNode<SHAudioListenerComponent>(components, eid);
|
AddComponentToComponentNode<SHAudioListenerComponent>(components, eid);
|
||||||
AddComponentToComponentNode<SHTrajectoryRenderableComponent>(components, eid);
|
AddComponentToComponentNode<SHTrajectoryRenderableComponent>(components, eid);
|
||||||
|
AddComponentToComponentNode<SHParticleEmitterComponent>(components, eid);
|
||||||
|
|
||||||
node[ComponentsNode] = components;
|
node[ComponentsNode] = components;
|
||||||
|
|
||||||
|
@ -310,6 +311,7 @@ namespace SHADE
|
||||||
AddComponentID<SHUIComponent>(componentIDList, componentsNode);
|
AddComponentID<SHUIComponent>(componentIDList, componentsNode);
|
||||||
AddComponentID<SHAudioListenerComponent>(componentIDList, componentsNode);
|
AddComponentID<SHAudioListenerComponent>(componentIDList, componentsNode);
|
||||||
AddComponentID<SHTrajectoryRenderableComponent>(componentIDList, componentsNode);
|
AddComponentID<SHTrajectoryRenderableComponent>(componentIDList, componentsNode);
|
||||||
|
AddComponentID<SHParticleEmitterComponent>(componentIDList, componentsNode);
|
||||||
|
|
||||||
return componentIDList;
|
return componentIDList;
|
||||||
}
|
}
|
||||||
|
@ -398,5 +400,6 @@ namespace SHADE
|
||||||
SHSerializationHelper::InitializeComponentFromNode<SHUIComponent>(componentsNode, eid);
|
SHSerializationHelper::InitializeComponentFromNode<SHUIComponent>(componentsNode, eid);
|
||||||
SHSerializationHelper::InitializeComponentFromNode<SHAudioListenerComponent>(componentsNode, eid);
|
SHSerializationHelper::InitializeComponentFromNode<SHAudioListenerComponent>(componentsNode, eid);
|
||||||
SHSerializationHelper::InitializeComponentFromNode<SHTrajectoryRenderableComponent>(componentsNode, eid);
|
SHSerializationHelper::InitializeComponentFromNode<SHTrajectoryRenderableComponent>(componentsNode, eid);
|
||||||
|
SHSerializationHelper::InitializeComponentFromNode<SHParticleEmitterComponent>(componentsNode, eid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
|
#include "Physics/Collision/CollisionTags/SHCollisionTagMatrix.h"
|
||||||
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
|
||||||
#include "Physics/Collision/Shapes/SHCapsule.h"
|
#include "Physics/Collision/Shapes/SHCapsule.h"
|
||||||
|
#include <Graphics/MiddleEnd/Particles/SHParticleEmitterComponent.h>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
|
@ -35,6 +36,9 @@ namespace YAML
|
||||||
struct HasYAMLConv<SHAnimatorComponent> : std::true_type {};
|
struct HasYAMLConv<SHAnimatorComponent> : std::true_type {};
|
||||||
template<>
|
template<>
|
||||||
struct HasYAMLConv<SHTrajectoryRenderableComponent> : std::true_type {};
|
struct HasYAMLConv<SHTrajectoryRenderableComponent> : std::true_type {};
|
||||||
|
template<>
|
||||||
|
struct HasYAMLConv<SHParticleEmitterComponent> : std::true_type {};
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct convert<SHVec4>
|
struct convert<SHVec4>
|
||||||
|
@ -497,4 +501,120 @@ namespace YAML
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct convert<SHParticleEmitterComponent>
|
||||||
|
{
|
||||||
|
static constexpr std::string_view EMISSION_COUNT_TAG = "Emission Count";
|
||||||
|
static constexpr std::string_view IS_PASSIVE_TAG = "Is Passive";
|
||||||
|
static constexpr std::string_view EMISSION_INTERVAL_TAG = "Emission Interval";
|
||||||
|
static constexpr std::string_view MIN_LIFE_TAG = "Min Life";
|
||||||
|
static constexpr std::string_view MAX_LIFE_TAG = "Max Life";
|
||||||
|
static constexpr std::string_view ANGULAR_RANGES_OFFSET_TAG = "Angular Ranges And Offset";
|
||||||
|
static constexpr std::string_view MIN_SIZE_TAG = "Minimum Size";
|
||||||
|
static constexpr std::string_view MAX_SIZE_TAG = "Maximum Size";
|
||||||
|
static constexpr std::string_view SIZE_DECAY_TAG = "Size Decay";
|
||||||
|
static constexpr std::string_view MIN_SPEED_TAG = "Minimum Speed";
|
||||||
|
static constexpr std::string_view MAX_SPEED_TAG = "Maximum Speed";
|
||||||
|
static constexpr std::string_view ROTATION_SPEED_TAG = "Rotation Speed";
|
||||||
|
static constexpr std::string_view ROTATION_DECAY_TAG = "Rotation Decay";
|
||||||
|
static constexpr std::string_view TEXTURE_ASSET_ID_TAG = "Texture Asset ID";
|
||||||
|
static constexpr std::string_view CUSTOM_UPDATE_SHADER_ASSET_ID_TAG = "Custom Update Shader Asset ID";
|
||||||
|
|
||||||
|
static YAML::Node encode(SHParticleEmitterComponent const& rhs)
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
node[EMISSION_COUNT_TAG.data()] = rhs.GetEmissionCount();
|
||||||
|
node[IS_PASSIVE_TAG.data()] = rhs.GetPassive();
|
||||||
|
node[EMISSION_INTERVAL_TAG.data()] = rhs.GetEmissionInterval();
|
||||||
|
node[MIN_LIFE_TAG.data()] = rhs.GetMinLife();
|
||||||
|
node[MAX_LIFE_TAG.data()] = rhs.GetMaxLife();
|
||||||
|
node[MIN_SPEED_TAG.data()] = rhs.GetMinSpeed();
|
||||||
|
node[MAX_SPEED_TAG.data()] = rhs.GetMaxSpeed();
|
||||||
|
node[MIN_SIZE_TAG.data()] = rhs.GetMinSize();
|
||||||
|
node[MAX_SIZE_TAG.data()] = rhs.GetMaxSize();
|
||||||
|
node[SIZE_DECAY_TAG.data()] = rhs.GetSizeDecayMult();
|
||||||
|
node[ANGULAR_RANGES_OFFSET_TAG.data()] = rhs.GetAngularRangesAndOffsets();
|
||||||
|
node[ROTATION_SPEED_TAG.data()] = rhs.GetRotationSpeed();
|
||||||
|
node[ROTATION_DECAY_TAG.data()] = rhs.GetRotationDecay();
|
||||||
|
node[TEXTURE_ASSET_ID_TAG.data()] = rhs.GetTextureAssetID();
|
||||||
|
node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()] = rhs.GetCustomUpdateShaderAssetID();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
static bool decode(YAML::Node const& node, SHParticleEmitterComponent& rhs)
|
||||||
|
{
|
||||||
|
auto gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
|
||||||
|
|
||||||
|
if (node[EMISSION_COUNT_TAG.data()].IsDefined())
|
||||||
|
rhs.SetEmissionCount(node[EMISSION_COUNT_TAG.data()].as<uint32_t>());
|
||||||
|
|
||||||
|
if (node[IS_PASSIVE_TAG.data()].IsDefined())
|
||||||
|
rhs.SetPassive(node[IS_PASSIVE_TAG.data()].as<bool>());
|
||||||
|
|
||||||
|
if (node[EMISSION_INTERVAL_TAG.data()].IsDefined())
|
||||||
|
rhs.SetEmissionInterval(node[EMISSION_INTERVAL_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[MIN_LIFE_TAG.data()].IsDefined())
|
||||||
|
rhs.SetMinLife(node[MIN_LIFE_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[MAX_LIFE_TAG.data()].IsDefined())
|
||||||
|
rhs.SetMaxLife(node[MAX_LIFE_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[SIZE_DECAY_TAG.data()].IsDefined())
|
||||||
|
rhs.SetSizeDecayMult(node[SIZE_DECAY_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[ANGULAR_RANGES_OFFSET_TAG.data()].IsDefined())
|
||||||
|
rhs.SetAngularRangesAndOffsets(node[ANGULAR_RANGES_OFFSET_TAG.data()].as<SHVec4>());
|
||||||
|
|
||||||
|
if (node[MIN_SPEED_TAG.data()].IsDefined())
|
||||||
|
rhs.SetMinSpeed(node[MIN_SPEED_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[MAX_SPEED_TAG.data()].IsDefined())
|
||||||
|
rhs.SetMaxSpeed (node[MAX_SPEED_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[MAX_SIZE_TAG.data()].IsDefined())
|
||||||
|
rhs.SetMaxSize(node[MAX_SIZE_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[ROTATION_SPEED_TAG.data()].IsDefined())
|
||||||
|
rhs.SetRotationSpeed(node[ROTATION_SPEED_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
if (node[ROTATION_DECAY_TAG.data()].IsDefined())
|
||||||
|
rhs.SetRotationDecay(node[ROTATION_DECAY_TAG.data()].as<float>());
|
||||||
|
|
||||||
|
|
||||||
|
if (node[TEXTURE_ASSET_ID_TAG.data()].IsDefined())
|
||||||
|
{
|
||||||
|
AssetID id = node[TEXTURE_ASSET_ID_TAG.data()].as<AssetID>();
|
||||||
|
|
||||||
|
Handle<SHTexture> texture = SHResourceManager::LoadOrGet<SHTexture>(id);
|
||||||
|
SHResourceManager::FinaliseChanges();
|
||||||
|
//gfxSystem->BuildTextures();
|
||||||
|
|
||||||
|
if (texture)
|
||||||
|
{
|
||||||
|
rhs.SetTextureIndex(texture->TextureArrayIndex);
|
||||||
|
rhs.SetTextureAssetID(id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SHLOG_WARNING ("Texture not set for particle emitter component: texture handle is null. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].IsDefined())
|
||||||
|
{
|
||||||
|
AssetID id = node[CUSTOM_UPDATE_SHADER_ASSET_ID_TAG.data()].as<AssetID>();
|
||||||
|
|
||||||
|
Handle<SHVkShaderModule> shaderModule = SHResourceManager::LoadOrGet<SHVkShaderModule>(id);
|
||||||
|
SHResourceManager::FinaliseChanges();
|
||||||
|
//gfxSystem->BuildTextures();
|
||||||
|
|
||||||
|
rhs.SetCustomUpdateShader(shaderModule);
|
||||||
|
rhs.SetTextureAssetID(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,16 @@ namespace SHADE
|
||||||
return SHResourceManagerInterface::GetAssetID(Convert::ToNative(audioClipInstHandle)).value_or(INVALID_ASSET_ID);
|
return SHResourceManagerInterface::GetAssetID(Convert::ToNative(audioClipInstHandle)).value_or(INVALID_ASSET_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioClipHandler::DestroyOnSceneExit::get()
|
||||||
|
{
|
||||||
|
return NativeObject->GetDestroyOnSceneExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioClipHandler::DestroyOnSceneExit::set(bool value)
|
||||||
|
{
|
||||||
|
NativeObject->SetDestroyOnSceneExit(value);
|
||||||
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
/* Constructors/Destructor */
|
/* Constructors/Destructor */
|
||||||
/*---------------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -64,6 +64,12 @@ namespace SHADE
|
||||||
AudioClipHandler(Handle<AudioClip> audioclip);
|
AudioClipHandler(Handle<AudioClip> audioclip);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
property bool DestroyOnSceneExit
|
||||||
|
{
|
||||||
|
bool get();
|
||||||
|
void set(bool value);
|
||||||
|
}
|
||||||
|
|
||||||
//to comment ltr
|
//to comment ltr
|
||||||
void Play();
|
void Play();
|
||||||
|
|
|
@ -13,9 +13,9 @@ namespace SHADE
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrajectoryRenderable::SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps)
|
void TrajectoryRenderable::SimulateTrajectory(EntityID eid, float mass, Vector3 force, float timestep, uint32_t maxSteps)
|
||||||
{
|
{
|
||||||
GetNativeComponent()->SimulateTrajectory(eid, Convert::ToNative(force), timestep, maxSteps);
|
GetNativeComponent()->SimulateTrajectory(eid, mass, Convert::ToNative(force), timestep, maxSteps);
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshAsset TrajectoryRenderable::Mesh::get()
|
MeshAsset TrajectoryRenderable::Mesh::get()
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace SHADE
|
||||||
void set(float val);
|
void set(float val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps);
|
void SimulateTrajectory(EntityID eid, float mass, Vector3 force, float timestep, uint32_t maxSteps);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue