forked from mirrors/0ad
Adds fixed orientation to particles
New features: * Relative position * Relative and absolute fixed axis * Local space * Axis along velocity vector
This commit is contained in:
@@ -9,6 +9,7 @@ END_DRAW_TEXTURES
|
|||||||
|
|
||||||
BEGIN_DRAW_UNIFORMS
|
BEGIN_DRAW_UNIFORMS
|
||||||
UNIFORM(mat4, modelViewMatrix)
|
UNIFORM(mat4, modelViewMatrix)
|
||||||
|
UNIFORM(mat4, spaceTransform)
|
||||||
END_DRAW_UNIFORMS
|
END_DRAW_UNIFORMS
|
||||||
|
|
||||||
BEGIN_MATERIAL_UNIFORMS
|
BEGIN_MATERIAL_UNIFORMS
|
||||||
@@ -17,6 +18,7 @@ BEGIN_MATERIAL_UNIFORMS
|
|||||||
UNIFORM(vec3, fogColor)
|
UNIFORM(vec3, fogColor)
|
||||||
UNIFORM(vec2, fogParams)
|
UNIFORM(vec2, fogParams)
|
||||||
UNIFORM(vec2, losTransform)
|
UNIFORM(vec2, losTransform)
|
||||||
|
UNIFORM(vec3, cameraPos)
|
||||||
END_MATERIAL_UNIFORMS
|
END_MATERIAL_UNIFORMS
|
||||||
|
|
||||||
VERTEX_OUTPUT(0, vec2, v_tex);
|
VERTEX_OUTPUT(0, vec2, v_tex);
|
||||||
|
|||||||
@@ -9,14 +9,40 @@ VERTEX_INPUT_ATTRIBUTE(0, vec3, a_vertex);
|
|||||||
VERTEX_INPUT_ATTRIBUTE(1, vec4, a_color);
|
VERTEX_INPUT_ATTRIBUTE(1, vec4, a_color);
|
||||||
VERTEX_INPUT_ATTRIBUTE(2, vec2, a_uv0);
|
VERTEX_INPUT_ATTRIBUTE(2, vec2, a_uv0);
|
||||||
VERTEX_INPUT_ATTRIBUTE(3, vec2, a_uv1);
|
VERTEX_INPUT_ATTRIBUTE(3, vec2, a_uv1);
|
||||||
|
VERTEX_INPUT_ATTRIBUTE(4, vec3, a_axisX);
|
||||||
|
VERTEX_INPUT_ATTRIBUTE(5, vec3, a_axisY);
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec3 axis1 = vec3(modelViewMatrix[0][0], modelViewMatrix[1][0], modelViewMatrix[2][0]);
|
vec3 viewAxisX = vec3(modelViewMatrix[0][0], modelViewMatrix[1][0], modelViewMatrix[2][0]);
|
||||||
vec3 axis2 = vec3(modelViewMatrix[0][1], modelViewMatrix[1][1], modelViewMatrix[2][1]);
|
vec3 viewAxisY = vec3(modelViewMatrix[0][1], modelViewMatrix[1][1], modelViewMatrix[2][1]);
|
||||||
vec2 offset = a_uv1;
|
vec2 offset = a_uv1;
|
||||||
|
|
||||||
vec3 position = axis1*offset.x + axis1*offset.y + axis2*offset.x + axis2*-offset.y + a_vertex;
|
vec3 axisX = (spaceTransform * vec4(a_axisX, 0.0)).xyz;
|
||||||
|
vec3 axisY = (spaceTransform * vec4(a_axisY, 0.0)).xyz;
|
||||||
|
vec3 particlePosition = (spaceTransform * vec4(a_vertex, 1.0)).xyz;
|
||||||
|
|
||||||
|
vec3 particleAxisX = viewAxisX;
|
||||||
|
vec3 particleAxisY = viewAxisY;
|
||||||
|
if (a_axisX != vec3(0.0))
|
||||||
|
{
|
||||||
|
particleAxisX = axisX;
|
||||||
|
if (a_axisY != vec3(0.0))
|
||||||
|
particleAxisY = axisY;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vec3 particleDirection = particlePosition - cameraPos;
|
||||||
|
float particleDirectionLength = length(particleDirection);
|
||||||
|
if (particleDirectionLength != 0.0)
|
||||||
|
{
|
||||||
|
particleDirection *= 1.0 / particleDirectionLength;
|
||||||
|
if (abs(dot(axisX, particleDirection)) < 1.0)
|
||||||
|
particleAxisY = normalize(cross(particleDirection, axisX));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 position = particleAxisX*offset.x + particleAxisX*offset.y + particleAxisY*offset.x + particleAxisY*-offset.y + particlePosition;
|
||||||
|
|
||||||
OUTPUT_VERTEX_POSITION(transform * vec4(position, 1.0));
|
OUTPUT_VERTEX_POSITION(transform * vec4(position, 1.0));
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
<stream name="color" attribute="a_color"/>
|
<stream name="color" attribute="a_color"/>
|
||||||
<stream name="uv0" attribute="a_uv0"/>
|
<stream name="uv0" attribute="a_uv0"/>
|
||||||
<stream name="uv1" attribute="a_uv1"/>
|
<stream name="uv1" attribute="a_uv1"/>
|
||||||
|
<stream name="uv2" attribute="a_axisX"/>
|
||||||
|
<stream name="uv3" attribute="a_axisY"/>
|
||||||
</vertex>
|
</vertex>
|
||||||
|
|
||||||
<fragment file="glsl/particle.fs"/>
|
<fragment file="glsl/particle.fs"/>
|
||||||
|
|||||||
@@ -29,18 +29,65 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<element name="particle">
|
||||||
|
<interleave>
|
||||||
|
<zeroOrMore>
|
||||||
|
<element name="fixed_orientation">
|
||||||
|
<attribute name="name"/>
|
||||||
|
<optional>
|
||||||
|
<attribute name="mode">
|
||||||
|
<choice>
|
||||||
|
<value>absolute</value>
|
||||||
|
<value>relative</value>
|
||||||
|
<value>velocity</value>
|
||||||
|
</choice>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="x">
|
||||||
|
<data type="float"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="y">
|
||||||
|
<data type="float"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<attribute name="z">
|
||||||
|
<data type="float"/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
|
</interleave>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<element name="start_full">
|
<element name="start_full">
|
||||||
<!-- flag; true if present -->
|
<!-- flag; true if present -->
|
||||||
<empty/>
|
<empty/>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<element name="use_relative_position">
|
||||||
|
<!-- flag; true if present -->
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
<optional>
|
<optional>
|
||||||
<element name="use_relative_velocity">
|
<element name="use_relative_velocity">
|
||||||
<!-- flag; true if present -->
|
<!-- flag; true if present -->
|
||||||
<empty/>
|
<empty/>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<element name="use_local_space">
|
||||||
|
<!-- flag; true if present -->
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
<zeroOrMore>
|
<zeroOrMore>
|
||||||
<element name="constant">
|
<element name="constant">
|
||||||
<interleave>
|
<interleave>
|
||||||
|
|||||||
@@ -12,4 +12,8 @@
|
|||||||
<uniform name="velocity.y" min="-10.0" max="-16.0"/>
|
<uniform name="velocity.y" min="-10.0" max="-16.0"/>
|
||||||
<uniform name="size" min="1.0" max="2.0"/>
|
<uniform name="size" min="1.0" max="2.0"/>
|
||||||
<force y="-6.0"/>
|
<force y="-6.0"/>
|
||||||
|
<constant name="angle" value="1.57079"/>
|
||||||
|
<particle>
|
||||||
|
<fixed_orientation name="axisX" y="1.0"/>
|
||||||
|
</particle>
|
||||||
</particles>
|
</particles>
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
|||||||
m_AttributeColor.format = Renderer::Backend::Format::R8G8B8A8_UNORM;
|
m_AttributeColor.format = Renderer::Backend::Format::R8G8B8A8_UNORM;
|
||||||
m_VertexArray.AddAttribute(&m_AttributeColor);
|
m_VertexArray.AddAttribute(&m_AttributeColor);
|
||||||
|
|
||||||
|
m_AttributeAxisX.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
|
||||||
|
m_VertexArray.AddAttribute(&m_AttributeAxisX);
|
||||||
|
|
||||||
|
m_AttributeAxisY.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
|
||||||
|
m_VertexArray.AddAttribute(&m_AttributeAxisY);
|
||||||
|
|
||||||
m_VertexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 4);
|
m_VertexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 4);
|
||||||
m_VertexArray.Layout();
|
m_VertexArray.Layout();
|
||||||
|
|
||||||
@@ -126,7 +132,7 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
|||||||
m_IndexArray.FreeBackingStore();
|
m_IndexArray.FreeBackingStore();
|
||||||
|
|
||||||
const uint32_t stride = m_VertexArray.GetStride();
|
const uint32_t stride = m_VertexArray.GetStride();
|
||||||
const std::array<Renderer::Backend::SVertexAttributeFormat, 4> attributes{{
|
const std::array<Renderer::Backend::SVertexAttributeFormat, 6> attributes{{
|
||||||
{Renderer::Backend::VertexAttributeStream::POSITION,
|
{Renderer::Backend::VertexAttributeStream::POSITION,
|
||||||
m_AttributePos.format, m_AttributePos.offset, stride,
|
m_AttributePos.format, m_AttributePos.offset, stride,
|
||||||
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
||||||
@@ -139,6 +145,12 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
|
|||||||
{Renderer::Backend::VertexAttributeStream::UV1,
|
{Renderer::Backend::VertexAttributeStream::UV1,
|
||||||
m_AttributeAxis.format, m_AttributeAxis.offset, stride,
|
m_AttributeAxis.format, m_AttributeAxis.offset, stride,
|
||||||
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
||||||
|
{Renderer::Backend::VertexAttributeStream::UV2,
|
||||||
|
m_AttributeAxisX.format, m_AttributeAxisX.offset, stride,
|
||||||
|
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
||||||
|
{Renderer::Backend::VertexAttributeStream::UV3,
|
||||||
|
m_AttributeAxisY.format, m_AttributeAxisY.offset, stride,
|
||||||
|
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
|
||||||
}};
|
}};
|
||||||
m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes);
|
m_VertexInputLayout = g_Renderer.GetVertexInputLayout(attributes);
|
||||||
}
|
}
|
||||||
@@ -165,6 +177,8 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
|||||||
VertexArrayIterator<float[2]> attrAxis = m_AttributeAxis.GetIterator<float[2]>();
|
VertexArrayIterator<float[2]> attrAxis = m_AttributeAxis.GetIterator<float[2]>();
|
||||||
VertexArrayIterator<float[2]> attrUV = m_AttributeUV.GetIterator<float[2]>();
|
VertexArrayIterator<float[2]> attrUV = m_AttributeUV.GetIterator<float[2]>();
|
||||||
VertexArrayIterator<SColor4ub> attrColor = m_AttributeColor.GetIterator<SColor4ub>();
|
VertexArrayIterator<SColor4ub> attrColor = m_AttributeColor.GetIterator<SColor4ub>();
|
||||||
|
VertexArrayIterator<CVector3D> attrAxisX = m_AttributeAxisX.GetIterator<CVector3D>();
|
||||||
|
VertexArrayIterator<CVector3D> attrAxisY = m_AttributeAxisY.GetIterator<CVector3D>();
|
||||||
|
|
||||||
ENSURE(m_Particles.size() <= m_Type->m_MaxParticles);
|
ENSURE(m_Particles.size() <= m_Type->m_MaxParticles);
|
||||||
|
|
||||||
@@ -255,6 +269,16 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
|
|||||||
*attrColor++ = color;
|
*attrColor++ = color;
|
||||||
*attrColor++ = color;
|
*attrColor++ = color;
|
||||||
*attrColor++ = color;
|
*attrColor++ = color;
|
||||||
|
|
||||||
|
*attrAxisX++ = particle.axisX;
|
||||||
|
*attrAxisX++ = particle.axisX;
|
||||||
|
*attrAxisX++ = particle.axisX;
|
||||||
|
*attrAxisX++ = particle.axisX;
|
||||||
|
|
||||||
|
*attrAxisY++ = particle.axisY;
|
||||||
|
*attrAxisY++ = particle.axisY;
|
||||||
|
*attrAxisY++ = particle.axisY;
|
||||||
|
*attrAxisY++ = particle.axisY;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ParticleBounds = bounds;
|
m_ParticleBounds = bounds;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2025 Wildfire Games.
|
/* Copyright (C) 2026 Wildfire Games.
|
||||||
* This file is part of 0 A.D.
|
* This file is part of 0 A.D.
|
||||||
*
|
*
|
||||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||||
@@ -52,6 +52,7 @@ struct SParticle
|
|||||||
SColor4ub color;
|
SColor4ub color;
|
||||||
float age;
|
float age;
|
||||||
float maxAge;
|
float maxAge;
|
||||||
|
CVector3D axisX, axisY;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
|
typedef std::shared_ptr<CParticleEmitter> CParticleEmitterPtr;
|
||||||
@@ -187,6 +188,7 @@ private:
|
|||||||
VertexArray::Attribute m_AttributeAxis;
|
VertexArray::Attribute m_AttributeAxis;
|
||||||
VertexArray::Attribute m_AttributeUV;
|
VertexArray::Attribute m_AttributeUV;
|
||||||
VertexArray::Attribute m_AttributeColor;
|
VertexArray::Attribute m_AttributeColor;
|
||||||
|
VertexArray::Attribute m_AttributeAxisX, m_AttributeAxisY;
|
||||||
|
|
||||||
Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr;
|
Renderer::Backend::IVertexInputLayout* m_VertexInputLayout = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -368,6 +368,8 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||||||
m_BlendMode = BlendMode::ADD;
|
m_BlendMode = BlendMode::ADD;
|
||||||
m_SortMode = SortMode::UNSPECIFIED;
|
m_SortMode = SortMode::UNSPECIFIED;
|
||||||
m_StartFull = false;
|
m_StartFull = false;
|
||||||
|
m_UseLocalSpace = false;
|
||||||
|
m_UseRelativePosition = false;
|
||||||
m_UseRelativeVelocity = false;
|
m_UseRelativeVelocity = false;
|
||||||
m_Texture = g_Renderer.GetTextureManager().GetErrorTexture();
|
m_Texture = g_Renderer.GetTextureManager().GetErrorTexture();
|
||||||
|
|
||||||
@@ -379,23 +381,27 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||||||
// Define all the elements and attributes used in the XML file
|
// Define all the elements and attributes used in the XML file
|
||||||
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
#define EL(x) int el_##x = XeroFile.GetElementID(#x)
|
||||||
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
#define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
|
||||||
EL(texture);
|
|
||||||
EL(blend);
|
EL(blend);
|
||||||
EL(start_full);
|
|
||||||
EL(use_relative_velocity);
|
|
||||||
EL(constant);
|
EL(constant);
|
||||||
EL(sort);
|
|
||||||
EL(uniform);
|
|
||||||
EL(copy);
|
EL(copy);
|
||||||
EL(expr);
|
EL(expr);
|
||||||
EL(force);
|
EL(force);
|
||||||
|
EL(fixed_orientation);
|
||||||
|
EL(particle);
|
||||||
|
EL(sort);
|
||||||
|
EL(start_full);
|
||||||
|
EL(texture);
|
||||||
|
EL(uniform);
|
||||||
|
EL(use_local_space);
|
||||||
|
EL(use_relative_position);
|
||||||
|
EL(use_relative_velocity);
|
||||||
|
AT(from);
|
||||||
|
AT(max);
|
||||||
|
AT(min);
|
||||||
AT(mode);
|
AT(mode);
|
||||||
|
AT(mul);
|
||||||
AT(name);
|
AT(name);
|
||||||
AT(value);
|
AT(value);
|
||||||
AT(min);
|
|
||||||
AT(max);
|
|
||||||
AT(mul);
|
|
||||||
AT(from);
|
|
||||||
AT(x);
|
AT(x);
|
||||||
AT(y);
|
AT(y);
|
||||||
AT(z);
|
AT(z);
|
||||||
@@ -439,6 +445,14 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||||||
{
|
{
|
||||||
m_StartFull = true;
|
m_StartFull = true;
|
||||||
}
|
}
|
||||||
|
else if (Child.GetNodeName() == el_use_local_space)
|
||||||
|
{
|
||||||
|
m_UseLocalSpace = true;
|
||||||
|
}
|
||||||
|
else if (Child.GetNodeName() == el_use_relative_position)
|
||||||
|
{
|
||||||
|
m_UseRelativePosition = true;
|
||||||
|
}
|
||||||
else if (Child.GetNodeName() == el_use_relative_velocity)
|
else if (Child.GetNodeName() == el_use_relative_velocity)
|
||||||
{
|
{
|
||||||
m_UseRelativeVelocity = true;
|
m_UseRelativeVelocity = true;
|
||||||
@@ -490,6 +504,36 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
|||||||
float z = Child.GetAttributes().GetNamedItem(at_z).ToFloat();
|
float z = Child.GetAttributes().GetNamedItem(at_z).ToFloat();
|
||||||
m_Effectors.push_back(IParticleEffectorPtr(new CParticleEffectorForce(x, y, z)));
|
m_Effectors.push_back(IParticleEffectorPtr(new CParticleEffectorForce(x, y, z)));
|
||||||
}
|
}
|
||||||
|
else if (Child.GetNodeName() == el_particle)
|
||||||
|
{
|
||||||
|
XERO_ITER_EL(Child, particleChild)
|
||||||
|
{
|
||||||
|
if (particleChild.GetNodeName() == el_fixed_orientation)
|
||||||
|
{
|
||||||
|
CVector3D axis{
|
||||||
|
particleChild.GetAttributes().GetNamedItem(at_x).ToFloat(),
|
||||||
|
particleChild.GetAttributes().GetNamedItem(at_y).ToFloat(),
|
||||||
|
particleChild.GetAttributes().GetNamedItem(at_z).ToFloat()};
|
||||||
|
// The axis must be a non-zero vector else it's not valid.
|
||||||
|
const float axisLength{axis.Length()};
|
||||||
|
if (axisLength > 0.0f)
|
||||||
|
axis *= 1.0f / axisLength;
|
||||||
|
else
|
||||||
|
axis = CVector3D{0.0f, 0.0f, 0.0f};
|
||||||
|
if (particleChild.GetAttributes().GetNamedItem(at_name) == "axisX")
|
||||||
|
{
|
||||||
|
m_AxisX = axis;
|
||||||
|
m_UseRelativeAxisX = particleChild.GetAttributes().GetNamedItem(at_mode) == "relative";
|
||||||
|
m_UseVelocityAsAxisX = particleChild.GetAttributes().GetNamedItem(at_mode) == "velocity";
|
||||||
|
}
|
||||||
|
else if (particleChild.GetAttributes().GetNamedItem(at_name) == "axisY")
|
||||||
|
{
|
||||||
|
m_AxisY = axis;
|
||||||
|
m_UseRelativeAxisY = particleChild.GetAttributes().GetNamedItem(at_mode) == "relative";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -533,6 +577,10 @@ void CParticleEmitterType::UpdateEmitterStep(CParticleEmitter& emitter, float dt
|
|||||||
// we'll immediately overwrite, so clamp it
|
// we'll immediately overwrite, so clamp it
|
||||||
newParticles = std::min(newParticles, (int)m_MaxParticles);
|
newParticles = std::min(newParticles, (int)m_MaxParticles);
|
||||||
|
|
||||||
|
const CMatrix3D rotationMatrix{emitter.GetRotation().ToMatrix()};
|
||||||
|
const CVector3D axisX{!m_UseLocalSpace && m_UseRelativeAxisX ? rotationMatrix.Transform(m_AxisX) : m_AxisX};
|
||||||
|
const CVector3D axisY{!m_UseLocalSpace && m_UseRelativeAxisY ? rotationMatrix.Transform(m_AxisY) : m_AxisY};
|
||||||
|
|
||||||
for (int i = 0; i < newParticles; ++i)
|
for (int i = 0; i < newParticles; ++i)
|
||||||
{
|
{
|
||||||
// Compute new particle state based on variables
|
// Compute new particle state based on variables
|
||||||
@@ -541,22 +589,20 @@ void CParticleEmitterType::UpdateEmitterStep(CParticleEmitter& emitter, float dt
|
|||||||
particle.pos.X = m_Variables[VAR_POSITION_X]->Evaluate(emitter);
|
particle.pos.X = m_Variables[VAR_POSITION_X]->Evaluate(emitter);
|
||||||
particle.pos.Y = m_Variables[VAR_POSITION_Y]->Evaluate(emitter);
|
particle.pos.Y = m_Variables[VAR_POSITION_Y]->Evaluate(emitter);
|
||||||
particle.pos.Z = m_Variables[VAR_POSITION_Z]->Evaluate(emitter);
|
particle.pos.Z = m_Variables[VAR_POSITION_Z]->Evaluate(emitter);
|
||||||
particle.pos += emitter.m_Pos;
|
|
||||||
|
|
||||||
if (m_UseRelativeVelocity)
|
particle.velocity.X = m_Variables[VAR_VELOCITY_X]->Evaluate(emitter);
|
||||||
|
particle.velocity.Y = m_Variables[VAR_VELOCITY_Y]->Evaluate(emitter);
|
||||||
|
particle.velocity.Z = m_Variables[VAR_VELOCITY_Z]->Evaluate(emitter);
|
||||||
|
|
||||||
|
if (!m_UseLocalSpace)
|
||||||
{
|
{
|
||||||
float xVel = m_Variables[VAR_VELOCITY_X]->Evaluate(emitter);
|
if (m_UseRelativeVelocity)
|
||||||
float yVel = m_Variables[VAR_VELOCITY_Y]->Evaluate(emitter);
|
particle.velocity = rotationMatrix.Transform(particle.velocity);
|
||||||
float zVel = m_Variables[VAR_VELOCITY_Z]->Evaluate(emitter);
|
if (m_UseRelativePosition)
|
||||||
CVector3D EmitterAngle = emitter.GetRotation().ToMatrix().Transform(CVector3D(xVel,yVel,zVel));
|
particle.pos = rotationMatrix.Transform(particle.pos);
|
||||||
particle.velocity.X = EmitterAngle.X;
|
particle.pos += emitter.m_Pos;
|
||||||
particle.velocity.Y = EmitterAngle.Y;
|
|
||||||
particle.velocity.Z = EmitterAngle.Z;
|
|
||||||
} else {
|
|
||||||
particle.velocity.X = m_Variables[VAR_VELOCITY_X]->Evaluate(emitter);
|
|
||||||
particle.velocity.Y = m_Variables[VAR_VELOCITY_Y]->Evaluate(emitter);
|
|
||||||
particle.velocity.Z = m_Variables[VAR_VELOCITY_Z]->Evaluate(emitter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
particle.angle = m_Variables[VAR_ANGLE]->Evaluate(emitter);
|
particle.angle = m_Variables[VAR_ANGLE]->Evaluate(emitter);
|
||||||
particle.angleSpeed = m_Variables[VAR_VELOCITY_ANGLE]->Evaluate(emitter);
|
particle.angleSpeed = m_Variables[VAR_VELOCITY_ANGLE]->Evaluate(emitter);
|
||||||
|
|
||||||
@@ -572,6 +618,16 @@ void CParticleEmitterType::UpdateEmitterStep(CParticleEmitter& emitter, float dt
|
|||||||
particle.age = 0.f;
|
particle.age = 0.f;
|
||||||
particle.maxAge = m_Variables[VAR_LIFETIME]->Evaluate(emitter);
|
particle.maxAge = m_Variables[VAR_LIFETIME]->Evaluate(emitter);
|
||||||
|
|
||||||
|
particle.axisX = axisX;
|
||||||
|
particle.axisY = axisY;
|
||||||
|
|
||||||
|
if (m_UseVelocityAsAxisX)
|
||||||
|
{
|
||||||
|
const float velocityLength{particle.velocity.Length()};
|
||||||
|
if (velocityLength > 1e-3f)
|
||||||
|
particle.axisX = particle.velocity * (1.0f / velocityLength);
|
||||||
|
}
|
||||||
|
|
||||||
emitter.AddParticle(particle);
|
emitter.AddParticle(particle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -590,6 +646,13 @@ void CParticleEmitterType::UpdateEmitterStep(CParticleEmitter& emitter, float dt
|
|||||||
p.age += dt;
|
p.age += dt;
|
||||||
p.size += p.sizeGrowthRate * dt;
|
p.size += p.sizeGrowthRate * dt;
|
||||||
|
|
||||||
|
if (m_UseVelocityAsAxisX)
|
||||||
|
{
|
||||||
|
const float velocityLength{p.velocity.Length()};
|
||||||
|
if (velocityLength > 1e-3f)
|
||||||
|
p.axisX = p.velocity * (1.0f / velocityLength);
|
||||||
|
}
|
||||||
|
|
||||||
// Make alpha fade in/out nicely
|
// Make alpha fade in/out nicely
|
||||||
// TODO: this should probably be done as a variable or something,
|
// TODO: this should probably be done as a variable or something,
|
||||||
// instead of hardcoding
|
// instead of hardcoding
|
||||||
|
|||||||
@@ -117,7 +117,14 @@ private:
|
|||||||
BlendMode m_BlendMode{BlendMode::ADD};
|
BlendMode m_BlendMode{BlendMode::ADD};
|
||||||
SortMode m_SortMode{SortMode::UNSPECIFIED};
|
SortMode m_SortMode{SortMode::UNSPECIFIED};
|
||||||
bool m_StartFull;
|
bool m_StartFull;
|
||||||
bool m_UseRelativeVelocity;
|
bool m_UseLocalSpace{false};
|
||||||
|
bool m_UseRelativePosition{false}, m_UseRelativeVelocity{false};
|
||||||
|
|
||||||
|
// A non-zero vector in case of a fixed axis for the corresponding direction.
|
||||||
|
CVector3D m_AxisX{}, m_AxisY{};
|
||||||
|
bool m_UseRelativeAxisX{false}, m_UseRelativeAxisY{false};
|
||||||
|
|
||||||
|
bool m_UseVelocityAsAxisX{false};
|
||||||
|
|
||||||
float m_MaxLifetime;
|
float m_MaxLifetime;
|
||||||
u16 m_MaxParticles;
|
u16 m_MaxParticles;
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ X(skyBoxRot)
|
|||||||
X(skyCube)
|
X(skyCube)
|
||||||
X(sky_simple)
|
X(sky_simple)
|
||||||
X(solid)
|
X(solid)
|
||||||
|
X(spaceTransform)
|
||||||
X(sunColor)
|
X(sunColor)
|
||||||
X(sunDir)
|
X(sunDir)
|
||||||
X(terrain_base)
|
X(terrain_base)
|
||||||
|
|||||||
@@ -181,15 +181,33 @@ void ParticleRenderer::RenderParticles(
|
|||||||
deviceCommandContext->BeginPass();
|
deviceCommandContext->BeginPass();
|
||||||
|
|
||||||
Renderer::Backend::IShaderProgram* shader = lastTech->GetShader();
|
Renderer::Backend::IShaderProgram* shader = lastTech->GetShader();
|
||||||
const CMatrix3D transform =
|
const CCamera& viewCamera{g_Renderer.GetSceneRenderer().GetViewCamera()};
|
||||||
g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection();
|
const CMatrix3D transform{viewCamera.GetViewProjection()};
|
||||||
const CMatrix3D modelViewMatrix =
|
const CMatrix3D modelViewMatrix{viewCamera.GetOrientation().GetInverse()};
|
||||||
g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse();
|
|
||||||
deviceCommandContext->SetUniform(
|
deviceCommandContext->SetUniform(
|
||||||
shader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
shader->GetBindingSlot(str_transform), transform.AsFloatArray());
|
||||||
deviceCommandContext->SetUniform(
|
deviceCommandContext->SetUniform(
|
||||||
shader->GetBindingSlot(str_modelViewMatrix), modelViewMatrix.AsFloatArray());
|
shader->GetBindingSlot(str_modelViewMatrix), modelViewMatrix.AsFloatArray());
|
||||||
|
deviceCommandContext->SetUniform(
|
||||||
|
shader->GetBindingSlot(str_cameraPos),
|
||||||
|
viewCamera.GetOrientation().GetTranslation().AsFloatArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const CMatrix3D rotationMatrix{emitter->GetRotation().ToMatrix()};
|
||||||
|
CMatrix3D spaceTransform;
|
||||||
|
if (emitter->m_Type->m_UseLocalSpace)
|
||||||
|
{
|
||||||
|
spaceTransform = rotationMatrix;
|
||||||
|
spaceTransform.Translate(emitter->GetPosition());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
spaceTransform.SetIdentity();
|
||||||
|
|
||||||
|
Renderer::Backend::IShaderProgram* shader = lastTech->GetShader();
|
||||||
|
deviceCommandContext->SetUniform(
|
||||||
|
shader->GetBindingSlot(str_spaceTransform), spaceTransform.AsFloatArray());
|
||||||
emitter->Bind(deviceCommandContext, lastTech->GetShader());
|
emitter->Bind(deviceCommandContext, lastTech->GetShader());
|
||||||
emitter->RenderArray(deviceCommandContext);
|
emitter->RenderArray(deviceCommandContext);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user