diff --git a/binaries/data/mods/mod/shaders/glsl/particle.vs b/binaries/data/mods/mod/shaders/glsl/particle.vs
index b8d2291f39..49fb27d2e4 100644
--- a/binaries/data/mods/mod/shaders/glsl/particle.vs
+++ b/binaries/data/mods/mod/shaders/glsl/particle.vs
@@ -8,26 +8,37 @@
VERTEX_INPUT_ATTRIBUTE(0, vec3, a_vertex);
VERTEX_INPUT_ATTRIBUTE(1, vec4, a_color);
VERTEX_INPUT_ATTRIBUTE(2, vec2, a_uv0);
-VERTEX_INPUT_ATTRIBUTE(3, vec2, a_uv1);
-VERTEX_INPUT_ATTRIBUTE(4, vec3, a_axisX);
-VERTEX_INPUT_ATTRIBUTE(5, vec3, a_axisY);
+VERTEX_INPUT_ATTRIBUTE(3, vec4, a_axisX); // .w is a particle diagonal size
+VERTEX_INPUT_ATTRIBUTE(4, vec4, a_axisY); // .w is a particle angle
void main()
{
vec3 viewAxisX = vec3(modelViewMatrix[0][0], modelViewMatrix[1][0], modelViewMatrix[2][0]);
vec3 viewAxisY = vec3(modelViewMatrix[0][1], modelViewMatrix[1][1], modelViewMatrix[2][1]);
- vec2 offset = a_uv1;
- vec3 axisX = (spaceTransform * vec4(a_axisX, 0.0)).xyz;
- vec3 axisY = (spaceTransform * vec4(a_axisY, 0.0)).xyz;
+ const float PI_4 = 0.7853981633974483;
+ const float HALF_INV_SQRT2 = 0.35355339059327376;
+ float particleHalfSize = a_axisX.w * HALF_INV_SQRT2;
+ // Currently we store an angle to a particle corner.
+ float particleAngle = a_axisY.w - PI_4;
+ float sinParticleAngle = sin(particleAngle);
+ float cosParticleAngle = cos(particleAngle);
+ mat2 rotationMatrix = mat2(
+ cosParticleAngle, -sinParticleAngle,
+ sinParticleAngle, cosParticleAngle
+ );
+ vec2 offset = rotationMatrix * ((a_uv0 * 2.0 - 1.0) * particleHalfSize);
+
+ vec3 axisX = (spaceTransform * vec4(a_axisX.xyz, 0.0)).xyz;
+ vec3 axisY = (spaceTransform * vec4(a_axisY.xyz, 0.0)).xyz;
vec3 particlePosition = (spaceTransform * vec4(a_vertex, 1.0)).xyz;
vec3 particleAxisX = viewAxisX;
vec3 particleAxisY = viewAxisY;
- if (a_axisX != vec3(0.0))
+ if (a_axisX.xyz != vec3(0.0))
{
particleAxisX = axisX;
- if (a_axisY != vec3(0.0))
+ if (a_axisY.xyz != vec3(0.0))
particleAxisY = axisY;
else
{
diff --git a/binaries/data/mods/mod/shaders/glsl/particle.xml b/binaries/data/mods/mod/shaders/glsl/particle.xml
index 7cd239c3b5..a449804699 100644
--- a/binaries/data/mods/mod/shaders/glsl/particle.xml
+++ b/binaries/data/mods/mod/shaders/glsl/particle.xml
@@ -5,9 +5,8 @@
-
-
-
+
+
diff --git a/binaries/data/mods/mod/shaders/glsl/particle_solid.xml b/binaries/data/mods/mod/shaders/glsl/particle_solid.xml
index 7cd239c3b5..a449804699 100644
--- a/binaries/data/mods/mod/shaders/glsl/particle_solid.xml
+++ b/binaries/data/mods/mod/shaders/glsl/particle_solid.xml
@@ -5,9 +5,8 @@
-
-
-
+
+
diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp
index 5820af3147..5ce0370b56 100644
--- a/source/graphics/ParticleEmitter.cpp
+++ b/source/graphics/ParticleEmitter.cpp
@@ -97,19 +97,16 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_AttributePos.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
m_VertexArray.AddAttribute(&m_AttributePos);
- m_AttributeAxis.format = Renderer::Backend::Format::R32G32_SFLOAT;
- m_VertexArray.AddAttribute(&m_AttributeAxis);
-
m_AttributeUV.format = Renderer::Backend::Format::R32G32_SFLOAT;
m_VertexArray.AddAttribute(&m_AttributeUV);
m_AttributeColor.format = Renderer::Backend::Format::R8G8B8A8_UNORM;
m_VertexArray.AddAttribute(&m_AttributeColor);
- m_AttributeAxisX.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
+ m_AttributeAxisX.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT;
m_VertexArray.AddAttribute(&m_AttributeAxisX);
- m_AttributeAxisY.format = Renderer::Backend::Format::R32G32B32_SFLOAT;
+ m_AttributeAxisY.format = Renderer::Backend::Format::R32G32B32A32_SFLOAT;
m_VertexArray.AddAttribute(&m_AttributeAxisY);
m_VertexArray.SetNumberOfVertices(m_Type->m_MaxParticles * 4);
@@ -131,7 +128,7 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_IndexArray.FreeBackingStore();
const uint32_t stride = m_VertexArray.GetStride();
- const std::array attributes{{
+ const std::array attributes{{
{Renderer::Backend::VertexAttributeStream::POSITION,
m_AttributePos.format, m_AttributePos.offset, stride,
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
@@ -142,12 +139,9 @@ CParticleEmitter::CParticleEmitter(const CParticleEmitterTypePtr& type) :
m_AttributeUV.format, m_AttributeUV.offset, stride,
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
{Renderer::Backend::VertexAttributeStream::UV1,
- m_AttributeAxis.format, m_AttributeAxis.offset, stride,
- 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,
+ {Renderer::Backend::VertexAttributeStream::UV2,
m_AttributeAxisY.format, m_AttributeAxisY.offset, stride,
Renderer::Backend::VertexAttributeRate::PER_VERTEX, 0},
}};
@@ -173,11 +167,10 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
// Regenerate the vertex array data:
VertexArrayIterator attrPos = m_AttributePos.GetIterator();
- VertexArrayIterator attrAxis = m_AttributeAxis.GetIterator();
VertexArrayIterator attrUV = m_AttributeUV.GetIterator();
VertexArrayIterator attrColor = m_AttributeColor.GetIterator();
- VertexArrayIterator attrAxisX = m_AttributeAxisX.GetIterator();
- VertexArrayIterator attrAxisY = m_AttributeAxisY.GetIterator();
+ VertexArrayIterator attrAxisX = m_AttributeAxisX.GetIterator();
+ VertexArrayIterator attrAxisY = m_AttributeAxisY.GetIterator();
ENSURE(m_Particles.size() <= m_Type->m_MaxParticles);
@@ -223,26 +216,6 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
*attrPos++ = particle.pos;
*attrPos++ = particle.pos;
- // Compute corner offsets, split into sin/cos components so the vertex
- // shader can multiply by the camera-right (or left?) and camera-up vectors
- // to get rotating billboards:
-
- float s = sin(particle.angle) * particle.size * 0.5f;
- float c = cos(particle.angle) * particle.size * 0.5f;
-
- (*attrAxis)[0] = c;
- (*attrAxis)[1] = s;
- ++attrAxis;
- (*attrAxis)[0] = s;
- (*attrAxis)[1] = -c;
- ++attrAxis;
- (*attrAxis)[0] = -c;
- (*attrAxis)[1] = -s;
- ++attrAxis;
- (*attrAxis)[0] = -s;
- (*attrAxis)[1] = c;
- ++attrAxis;
-
(*attrUV)[0] = 1;
(*attrUV)[1] = 0;
++attrUV;
@@ -273,15 +246,20 @@ void CParticleEmitter::UpdateArrayData(int frameNumber)
*attrColor++ = color;
*attrColor++ = color;
- *attrAxisX++ = particle.axisX;
- *attrAxisX++ = particle.axisX;
- *attrAxisX++ = particle.axisX;
- *attrAxisX++ = particle.axisX;
+ const CVector4D axisXAndSize{
+ particle.axisX.X, particle.axisX.Y, particle.axisX.Z, particle.size};
+ const CVector4D axisYAndAngle{
+ particle.axisY.X, particle.axisY.Y, particle.axisY.Z, particle.angle};
- *attrAxisY++ = particle.axisY;
- *attrAxisY++ = particle.axisY;
- *attrAxisY++ = particle.axisY;
- *attrAxisY++ = particle.axisY;
+ *attrAxisX++ = axisXAndSize;
+ *attrAxisX++ = axisXAndSize;
+ *attrAxisX++ = axisXAndSize;
+ *attrAxisX++ = axisXAndSize;
+
+ *attrAxisY++ = axisYAndAngle;
+ *attrAxisY++ = axisYAndAngle;
+ *attrAxisY++ = axisYAndAngle;
+ *attrAxisY++ = axisYAndAngle;
}
m_ParticleBounds = bounds;
diff --git a/source/graphics/ParticleEmitter.h b/source/graphics/ParticleEmitter.h
index af20de07d2..e7e1517eba 100644
--- a/source/graphics/ParticleEmitter.h
+++ b/source/graphics/ParticleEmitter.h
@@ -186,7 +186,6 @@ private:
VertexArray m_VertexArray;
VertexArray::Attribute m_AttributePos;
- VertexArray::Attribute m_AttributeAxis;
VertexArray::Attribute m_AttributeUV;
VertexArray::Attribute m_AttributeColor;
VertexArray::Attribute m_AttributeAxisX, m_AttributeAxisY;