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;