Packs particle size and angle to axes

We need to have per-vertex data to be constant to use instancing.
Now we have only UV coordinates.
This commit is contained in:
Vladislav Belov
2026-06-22 23:18:26 +02:00
parent e82f8ac5ac
commit 1380a93077
5 changed files with 42 additions and 56 deletions
@@ -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
{
@@ -5,9 +5,8 @@
<stream name="pos" attribute="a_vertex"/>
<stream name="color" attribute="a_color"/>
<stream name="uv0" attribute="a_uv0"/>
<stream name="uv1" attribute="a_uv1"/>
<stream name="uv2" attribute="a_axisX"/>
<stream name="uv3" attribute="a_axisY"/>
<stream name="uv1" attribute="a_axisX"/>
<stream name="uv2" attribute="a_axisY"/>
</vertex>
<fragment file="glsl/particle.fs"/>
@@ -5,9 +5,8 @@
<stream name="pos" attribute="a_vertex"/>
<stream name="color" attribute="a_color"/>
<stream name="uv0" attribute="a_uv0"/>
<stream name="uv1" attribute="a_uv1"/>
<stream name="uv2" attribute="a_axisX"/>
<stream name="uv3" attribute="a_axisY"/>
<stream name="uv1" attribute="a_axisX"/>
<stream name="uv2" attribute="a_axisY"/>
</vertex>
<fragment file="glsl/particle.fs"/>
+19 -41
View File
@@ -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<Renderer::Backend::SVertexAttributeFormat, 6> attributes{{
const std::array<Renderer::Backend::SVertexAttributeFormat, 5> 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<CVector3D> attrPos = m_AttributePos.GetIterator<CVector3D>();
VertexArrayIterator<float[2]> attrAxis = m_AttributeAxis.GetIterator<float[2]>();
VertexArrayIterator<float[2]> attrUV = m_AttributeUV.GetIterator<float[2]>();
VertexArrayIterator<SColor4ub> attrColor = m_AttributeColor.GetIterator<SColor4ub>();
VertexArrayIterator<CVector3D> attrAxisX = m_AttributeAxisX.GetIterator<CVector3D>();
VertexArrayIterator<CVector3D> attrAxisY = m_AttributeAxisY.GetIterator<CVector3D>();
VertexArrayIterator<CVector4D> attrAxisX = m_AttributeAxisX.GetIterator<CVector4D>();
VertexArrayIterator<CVector4D> attrAxisY = m_AttributeAxisY.GetIterator<CVector4D>();
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;
-1
View File
@@ -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;