[2.2] Declaring and passing StructuredBuffer per particle-based Renderable. Topic is solved
-
- Halfling
- Posts: 68
- Joined: Sun May 11, 2014 7:55 pm
- Location: Poland
- x 21
[2.2] Declaring and passing StructuredBuffer per particle-based Renderable.
Hi!
I am trying to make particle system and wanted to store their data (particle pos, colour, size etc.) in vertex shader.
From what I have seen in https://github.com/turanszkij/WickedEng ... cleVS.hlsl, particle data are stored in StructuredBuffer. How to create such buffer and associate with particle-based renderables In Ogre? Right now I don't want GPU particle simulation (maybe later), only pass particle data necessary for vertex shader.
I have already read viewtopic.php?t=94959 (although some links pointing to bitbucket are dead).
I already created ParticleSetRendarable with Ogre::BT_IMMUTABLE index buffer and Ogre::BT_DYNAMIC_PERSISTENT vertex buffer (I plan to change it to Ogre::BT_DEFAULT after it will be calculated via vertex shader). I also subclassed HlmsUnlit into HlmsParticle (https://spotcpp.com/creating-a-custom-h ... d-and-fog/ was really helpful here). Right now particles are rendered by filling vertex buffer each frame on CPU side.
I am trying to make particle system and wanted to store their data (particle pos, colour, size etc.) in vertex shader.
From what I have seen in https://github.com/turanszkij/WickedEng ... cleVS.hlsl, particle data are stored in StructuredBuffer. How to create such buffer and associate with particle-based renderables In Ogre? Right now I don't want GPU particle simulation (maybe later), only pass particle data necessary for vertex shader.
I have already read viewtopic.php?t=94959 (although some links pointing to bitbucket are dead).
I already created ParticleSetRendarable with Ogre::BT_IMMUTABLE index buffer and Ogre::BT_DYNAMIC_PERSISTENT vertex buffer (I plan to change it to Ogre::BT_DEFAULT after it will be calculated via vertex shader). I also subclassed HlmsUnlit into HlmsParticle (https://spotcpp.com/creating-a-custom-h ... d-and-fog/ was really helpful here). Right now particles are rendered by filling vertex buffer each frame on CPU side.
-
- OGRE Team Member
- Posts: 5446
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1348
Re: [2.2] Declaring and passing StructuredBuffer per particle-based Renderable.
In the case of Ogre 2.2, if you want to use StructuredBuffers you'll have to create an UavBufferPacked and then call UavBufferPacked::getAsTexBufferView.
In the case of Ogre 2.3, ReadOnlyBufferPacked were introduced which support structured buffers
As for one BufferPacked per Renderable, you'll have to create your own Renderable class (and a custom MovableObject, see Samples/2.0/ApiUsage/CustomRenderable sample) and a custom Hlms that downcasts to your custom class, accesses the per-Renderable ReadOnlyBufferPacked, and binds it.
Colibri shows one way to to 'tag' MovableObjects so that Hlms can identity your custom classes that need a special path and thus make sure it's
safe for downcasting.
Note that your custom MovableObject class should set the CustomParameter. The numbers 6372 & 6373 used in Colibri were completely arbitrary and will work as long as they are uniquely used for this purpose.
Cheers
In the case of Ogre 2.3, ReadOnlyBufferPacked were introduced which support structured buffers
As for one BufferPacked per Renderable, you'll have to create your own Renderable class (and a custom MovableObject, see Samples/2.0/ApiUsage/CustomRenderable sample) and a custom Hlms that downcasts to your custom class, accesses the per-Renderable ReadOnlyBufferPacked, and binds it.
Colibri shows one way to to 'tag' MovableObjects so that Hlms can identity your custom classes that need a special path and thus make sure it's
safe for downcasting.
Note that your custom MovableObject class should set the CustomParameter. The numbers 6372 & 6373 used in Colibri were completely arbitrary and will work as long as they are uniquely used for this purpose.
Cheers
-
- Halfling
- Posts: 68
- Joined: Sun May 11, 2014 7:55 pm
- Location: Poland
- x 21
Re: [2.2] Declaring and passing StructuredBuffer per particle-based Renderable.
Thanks. I still got something wrong with binding buffer or filling it. I try to send particle data and replace just colour in vertex shader. But I don't see any particle (I expect they end up with (0.0, 0.0, 0.0, 0.0) colour, although I upload buffer with (0.0, 0.0, 1.0, 1.0)).
Fragments of generated VertexShader:
If I comment this line
particles are shown with vertex buffer colour (I still have cpu calculation of vertex buffer).
Byte size of this struct:
Initializing (the same place where indexBuffer and vertexBuffer are created):
Filling buffer:
Renderable binding (With ParticleDataTexSlot=14, MaxParticles = 1000):
Fragments of generated VertexShader:
Code: Select all
...
struct Particle {
float3 pos;
float rot;
float4 colour;
float2 size;
float spriteNumber;
};
RWStructuredBuffer<Particle> particleDataList : register(u14);
struct VS_INPUT
{
float4 vertex : POSITION;
float4 colour : COLOR0;
float2 uv0 : TEXCOORD0;
uint drawId : DRAWID;
uint vertexId : SV_VertexID;
};
struct PS_INPUT
{
nointerpolation uint drawId : TEXCOORD0;
float4 colour : TEXCOORD1;
float2 uv0 : TEXCOORD2;
float4 gl_Position : SV_Position;
};
PS_INPUT main( VS_INPUT input )
{
...
outVs.colour = input.colour;
...
uint particleIdx = inVs_vertexId / 4;
uint vertexInQuad = inVs_vertexId % 4;
Particle particle = particleDataList[particleIdx];
outVs.colour = particle.colour;
return outVs;
}
Code: Select all
outVs.colour = particle.colour;
Byte size of this struct:
Code: Select all
const int ParticleSetRenderable::ParticleDataStructSize = sizeof(float) * 11u; // count number of floats inside 'Particle' struct
Code: Select all
mInstanceBuffer = vaoManager->createUavBuffer(maxParticles, ParticleDataStructSize, BB_FLAG_UAV|BB_FLAG_TEX, 0, false);
mInstanceBufferAsTex = mInstanceBuffer->getAsTexBufferView( PFG_RGBA32_FLOAT );
// use CPU copy to fill it and then send to GPU.
mCpuInstanceBuffer = reinterpret_cast<float*>( OGRE_MALLOC_SIMD( maxParticles * ParticleDataStructSize, MEMCATEGORY_GENERAL ) );
Code: Select all
void ParticleSetRenderable::updateToGPU2(const std::vector<Particle>& particles)
{
float * RESTRICT_ALIAS instanceBuffer = reinterpret_cast<float*>( mCpuInstanceBuffer );
const float *instanceBufferStart = instanceBuffer;
int count = Geometry::min<int>(particles.size(), mMaxParticles);
for (int i = 0; i < count; ++i) {
const Particle& particle = particles[i];
Ogre::ColourValue colour = particle.colour;
// Just to check if vertex shader uses UAV buffer data, set each particle colour to blue.
colour = Ogre::ColourValue(0.0f, 0.0f, 1.0f, 1.0f);
*instanceBuffer++ = particle.pos.x;
*instanceBuffer++ = particle.pos.y;
*instanceBuffer++ = particle.pos.z;
*instanceBuffer++ = particle.rot;
*instanceBuffer++ = colour.r;
*instanceBuffer++ = colour.g;
*instanceBuffer++ = colour.b;
*instanceBuffer++ = colour.a;
*instanceBuffer++ = particle.size.x;
*instanceBuffer++ = particle.size.y;
*instanceBuffer++ = (float)particle.spriteNumber;
}
OGRE_ASSERT_LOW( (size_t)(instanceBuffer - instanceBufferStart) * sizeof(float) <=
mInstanceBuffer->getTotalSizeBytes() );
//Fill the remaining bytes with 0
memset( instanceBuffer, 0, mInstanceBuffer->getTotalSizeBytes() -
(static_cast<size_t>(instanceBuffer - instanceBufferStart) * sizeof(float)) );
mInstanceBuffer->upload( mCpuInstanceBuffer, 0u, mInstanceBuffer->getNumElements() );
}
Renderable binding (With ParticleDataTexSlot=14, MaxParticles = 1000):
Code: Select all
Ogre::uint32 HlmsParticle::fillBuffersFor(const Ogre::HlmsCache* cache, const Ogre::QueuedRenderable& queuedRenderable, bool casterPass, Ogre::uint32 lastCacheHash, Ogre::CommandBuffer* commandBuffer, bool isV1)
{
const Ogre::Renderable::CustomParameterMap &customParams = queuedRenderable.renderable->getCustomParameters();
if( customParams.find( RenderManager::ParticleRenderable ) != customParams.end() )
{
ParticleSetRenderable* particleSetRenderable = dynamic_cast<ParticleSetRenderable*>(queuedRenderable.renderable);
Ogre::TexBufferPacked* particleDataTexBuffer = particleSetRenderable->getInstanceBufferAsTex();
int totalSize = ParticleSetRenderable::ParticleDataStructSize * particleSetRenderable->getMaxParticles();
*commandBuffer->addCommand<Ogre::CbShaderBuffer>() = Ogre::CbShaderBuffer(Ogre::VertexShader, ParticleDataTexSlot, particleDataTexBuffer, 0, totalSize);
*commandBuffer->addCommand<Ogre::CbShaderBuffer>() = Ogre::CbShaderBuffer(Ogre::PixelShader, ParticleDataTexSlot, particleDataTexBuffer, 0, totalSize);
// rebindTexBuffer( commandBuffer );
}
return Ogre::HlmsUnlit::fillBuffersFor(cache, queuedRenderable, casterPass, lastCacheHash, commandBuffer, isV1);
}
-
- OGRE Team Member
- Posts: 5446
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1348
Re: [2.2] Declaring and passing StructuredBuffer per particle-based Renderable.
This code:
Should be:
If you really want to use RWStructuredBuffer (which doesn't seem so), then you have to bind mInstanceBuffer instead of mInstanceBufferAsTex
Code: Select all
RWStructuredBuffer<Particle> particleDataList : register(u14);
Code: Select all
StructuredBuffer<Particle> particleDataList : register(t14);
-
- Halfling
- Posts: 68
- Joined: Sun May 11, 2014 7:55 pm
- Location: Poland
- x 21
Re: [2.2] Declaring and passing StructuredBuffer per particle-based Renderable.
It works! Thanks a lot for your help!
If I understand correctly, if I want to make particle simulation I should bind mInstanceBuffer and use RWStructuredBuffer in compute job (something like in OgreVctVoxelizer.cpp). And the same buffer should still be binded as tex to VertexShader (and used as StructuredBuffer there)?
If I understand correctly, if I want to make particle simulation I should bind mInstanceBuffer and use RWStructuredBuffer in compute job (something like in OgreVctVoxelizer.cpp). And the same buffer should still be binded as tex to VertexShader (and used as StructuredBuffer there)?
-
- OGRE Team Member
- Posts: 5446
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1348
Re: [2.2] Declaring and passing StructuredBuffer per particle-based Renderable.
That's correct.
Great that it works!
Great that it works!