Vulkan, what variables does an object need? As in a separate mesh that can be updated individually - vulkan

So I have been experimenting, and I can add a new "object" by adding every model in the scene to the same vertex buffer, but this isn't good for a voxel game because I don't want to have to reorganize the entire world's vertices every time a player destroys a block.
And it appears I can also add a new "object" by creating a new vertex and index buffer for it, and simply binding both it and all other vertex buffers to the command buffers array at the same time like this:
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[i], 0, nullptr);
// mesh 1
VkBuffer vertexBuffers[] = { vertexBuffer };
VkDeviceSize offsets[] = { 0 };
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
// mesh 2
VkBuffer vertexBuffers2[] = { vertexBuffer2 };
vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers2, offsets);
vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer2, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
vkCmdEndRenderPass(commandBuffers[i]);
But then this requires me to bind ALL vertex buffers to the command buffers array every time even when only a single one of those meshes is updated or created/destroyed. So how would I "add" a new "game object," the vertices and indices of which can be updated without having to loop through everything else in the scene too? Or is it relatively quick to bind to an already calculated vertex and index buffer and this is standard?
And I have tried this with a command buffer per object:
VkSubmitInfo submits[] = { submitInfo, submitInfo2 };
if (vkQueueSubmit(graphicsQueue, 2, submits, inFlightFences[currentFrame]) != VK_SUCCESS) {
throw std::runtime_error("failed to submit draw command buffer!");
}
But it only renders the last object in the queue (it will render the first object if I say the submit size is 1).
I have tried adding a separate descriptorset, descritor pool, and pipeline as well and it still only renders the last command buffer in the queue. I tried adding a new commandpool for each object but commandPool is used by dozens of other functions and it really seems like there is supposed to be only one of those.

You split your world into chunks, and draw one chunk at a time. All chunks have some space reserved for them in (a single) vertex buffer, and when something has changed, you only update that one chunk. If a chunk grows too large... Well, you will probably need some sort of a memory allocation system.
Do NOT create separate buffers for every little thing. Buffers just hold data. Any data. You can even store different vertex formats for different pipelines in one same buffer - just in different places within it and binding it with an offset. Do not rebind just to draw a different mesh if all your vertices are packed neatly into array (they most likely are). If you want to only draw a part of a buffer - just use what draw commands give you.
Command buffers are just a block of instructions for the gpu. You dont need one per object. However, one cannot be used and written to at the same time, so you will need at least one per frame in flight and one to write to. Pipelines(descriptor sets, and pretty much whatever else you bind) are just a bunch of state that your gpu starts using once you bind it. At the start of command buffer, the state is undefined - it is NOT inherited between command buffers in any way.

Related

what's the difference between .descriptorCount in VkDescriptorPoolSize and in VkDescriptorSetLayoutBinding(VkDescriptorSetLayoutCreateInfo)? how set?

what's the difference between .descriptorCount in VkDescriptorPoolSize and in VkDescriptorSetLayoutBinding(VkDescriptorSetLayoutCreateInfo)?
how to set them when there are many shaders, how to set them correctly?
eg.
layout(binding = 0) uniform Buffers {
uint x[];
} buffers[5];
then:
VkDescriptorSetLayoutBinding.descriptorCount = 5,//not 1,
VkDescriptorPoolSize.descriptorCount = 5,//not 1,
what if this same uniform Buffers are in many shaders? should add 5 to descriptorCount when it exist in 1 more shader?
In the case of VkDescriptorSetLayoutBinding::descriptorCount. The spec says:
descriptorCount is the number of descriptors contained in the binding,
accessed in a shader as an array, except if descriptorType is
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK in which case descriptorCount
is the size in bytes of the inline uniform block. If descriptorCount
is zero this binding entry is reserved and the resource must not be
accessed from any stage via this binding within any pipeline using the
set layout.
So most likely be 1, unless you have an array of textures or array of uniform buffers (which is not very common).
VkDescriptorPoolSize::descriptorCount has nothing to do with the previous one. A descriptor pool is used for allocating descriptors. So descriptorCount here is how many descriptors this pool can provide. The spec says:
descriptorCount is the number of descriptors of that type to allocate.
If type is VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK then
descriptorCount is the number of bytes to allocate for descriptors of
this type.
You can use the same pool for allocating multiple descriptor sets of multiple different layouts. So this most likely needs to be a fairly large number.
Anyways, I think you need to keep studying the general basic concepts around descriptors!

Correctly computing index for offsetting into frame-resource buffers

Lets say, for a rendering setup, that we have a renderer that can be either double or triple buffered, and this buffering can be changed dynamically, at runtime. So, at any time, it's 2 or 3 frames in flight (FIF).
Frame resources, like buffers, are duplicated to match the FIF-count. Buffers are created large enough to hold (frame-data-size * FIF-count), and reading/writing into those buffers are offsetted accordingly.
For the purpose of offsetting into buffers, is it good enough to use a monotonic clycling index which would go like so:
double buffer: 0, 1, 0, 1, 0, 1, ...
triple buffer: 0, 1, 2, 0, 1, 2, ...
Then, if a change is made to the FIF-count a runtime, we first WaitIdle() on the GPU, and then reset this index to 0.
Is this a safe way of offsetting into buffers, such that we don't trample on data still being used by the GPU?
I'm particularly unsure how this may play with a triple-buffer setup with a swapchain mailbox present-mode.
we first WaitIdle() on the GPU, and then reset this index to 0.
Presumably, you're talking about vkDeviceWaitIdle (which is a function you should almost never use). If so, then as far as non-swapchain assets are concerned, this is safe. vkDeviceWaitIdle will halt the CPU until the GPU device has done all of the work it has been given.
The rules for swapchains don't change just because you waited. You still need to acquire the next image before trying to use it and so forth.
However, waiting doesn't really make sense here. If all you do is just reset the index to 0, that means you didn't reallocate any memory. So if you went from 3 buffers to 2, you still have three buffers worth of storage, and you're only using two of them.
So what did you wait accomplish? You can just keep cycling through your 3 buffers worth of storage even if you only have 2 swapchain images.
The only point in waiting would be if you need to release storage (or allocate more if you're going from 2 to 3 buffers). And even then, the only reason to wait is if it is absolutely imperative to delete your existing memory before allocating new memory.

Can I overlap two framebuffer attachments outputs in a fragment shader?

Right now I am writing out to a colour buffer in the fragment shader, which is a float format.
layout (location = 0) out vec4 outColour;
I need to have a way to write the object's id to a framebuffer for picking. There are a number of ways I've thought about doing this. I can compile two versions for each shader, one a normal one, and another for the picking, which basically only needs to do the vertex position transformations and then skip everything else, lighting calculations, texturing, etc. This probably isn't ideal because this is essentially doubling the number of shaders I have to write.
An easier method I've thought is to do a conditional branch (preferably over a specialisation constant), and for picking purposes compile a picking version of the graphics pipeline with the picking boolean value set to true. This sounds better. For the ordinary passes I can write to multiple attachments. Will it be best to compile that picking pipeline with a new render pass that writes to only one framebuffer attachment, an integer one? If I swap the render pass for one that writes an integer at attachment 0 instead of the float 4 can I alias this in the fragment shader?
layout (location = 0) out vec4 outColour;
layout (location = 0) out ivec4 out_id;
void main()
{
vec4 colour;
int object_id;
if (bPicking)
out_id = ivec4(object_id, 0, 0, 0); // y, z, w not used
else
out_colour = colour;
}
I'm guessing I really need a different render pass because instead of writing to a R32G32B32A32_SFLOAT image I'm writing to a R8_UINT image for the IDs. This is really confusing what's the best way to do this?

How do I make multiple copies of a set of polygons in a Vertex Buffer Array?

In OpengL 1, in Visual Basic with OpenTK, if I want a hundred cubes all arranged in circle i'd write
glRef = GL.GenLists(1)
GL.NewList(glRef, ListMode.Compile)
GL.Begin(PrimitiveType.Traingles)
GL.Vertex3....for the vertices of a cube
GL.End()
GL.EndList()
which would give me glRef as a handle with which I could do
For i = 0 to 100
GL.PushMatrix()
GL.Rotate(3.6*i, 0, 0, 1)
GL.Translate(5.0, 0.0, 0.0)
GL.CallList(glRef)
GL.PopMatrix()
Next
and get a hundred cubes all arranged in a circle.
How do I do the same sort of thing in Open GL 2.0 or higher with Vertex Buffer Objects?
I start off with
GL.GenBuffer(VBOid)
Dim VertexArray() As Single = {....for the vertices of a cube }
then do some binding of it to a vertex buffer
GL.BindBuffer(BufferTarget.ArrayBuffer, VBOid(0))
GL.BufferData(BufferTarget.ArrayBuffer, SizeOf(GetType(Single)) * VertexArray.Count, VertexArray, BufferUsageHint.StaticDraw)
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, False, 0, VertexArray)
and then in my draw routine I do something along the lines of
GL.EnableClientState(ArrayCap.VertexArray)
GL.BindBuffer(BufferTarget.ArrayBuffer, PrimitiveID(0))
GL.DrawElements(PrimitiveType.Triangles)
but at this point adding a second DrawBuffer command together with transforms doesn't seem to create me a second cube. I've been bashing my head against a wall, looking all over the internet and I can't find a straight forward reference which tells me how to do it, or even confirmation that it's possible.
Is this not the way its supposed to work, am I just supposed to send a hundred sets of cube vertices, or is there a way to copy a vertex buffer object and apply transforms to it? (Or is I'm probably doing it wrong somewhere and I need to go on a bug hunt - any tips for that would be helpful)
I don't think GL.DrawBuffer is the correct command in this place. It is used to specify in the context of FBOs which attachment points can be written.
Since you try to draw a VBO here, I would expect the use of GL.DrawArrays or GL.DrawElements.

Obj loader in directX 9

I wrote a program to load an obj file in directx 9. All I do is read the vertex data and the index data from the file ( I did not read any texture or vertex normal data). Then I plug this data directly into the vertex and index buffers.
When I run the code, the objects are rendered, but they are not the correct shape. The mesh gets deformed. Here is my code -
D3DXCreateMeshFVF(
index_size, // NumFaces
vertex_size, // NumVertices
D3DXMESH_MANAGED, // Options
D3DFVF_XYZ, // FVF
Device, // The Device
&Mesh[id].MeshData); // The Mesh
VOID* pVertices;
// Copy the vertices into the buffer
Mesh[id].MeshData->LockVertexBuffer(D3DLOCK_DISCARD, (void**)&pVertices);
memcpy( pVertices, VertexData, vertex_size*sizeof(FLOAT)*3); // VertexData is the vertex data that I obtained form the obj file
// Unlock the vertex buffer
Mesh[id].MeshData->UnlockVertexBuffer();
// Prepare to copy the indices into the index buffer
VOID* IndexPtr;
// Lock the index buffer
Mesh[id].MeshData->LockIndexBuffer( 0, &IndexPtr );
// Check to make sure the index buffer can be locked
// Copy the indices into the buffer
memcpy( IndexPtr, IndexData, index_size*sizeof(WORD));// IndexData is the list of indices I obtained form he obj file.
// Unlock the buffer
Mesh[id].MeshData->UnlockIndexBuffer();
When I display a cube, it displays only half of it, and some of the faces are missing.
I susupect it is some problem with the index buffer, but I don't know how to fix it.
I really need help.
Thanks all.
I dont have time now to read the code, but as far as i remember, the index data in .obj files do not start on 0 but on 1, what i mean is that once you load all the index data, you should substract -1 to every index.
if you compare .OBJ with .X files you will see the difference between the index data.