vulkan-renderer
vulkan-renderer copied to clipboard
Implement a material system for octree
Is your feature request related to a problem?
After rendergraph2 is finished, I initially wanted to implement a simple texture renderer. The best approach is to start with a material system for octrees now.
Description
Rendergraph is composed of different render modules. A simple renderer for octrees with textures could be introduced as a separate render module. The following questions come up now:
- The current render module design allows for an arbitrary number of pipelines, shaders, or passes per render module. If a render module should be separate instead of being part of another one (for example textured octree renderer should not be combined with colored triangles octree renderer), it is the responsibility of the programmer to account for the desired granularity of render modules!
- How to associate the
Cubeclass with renderers? We could give each render module astd::weak_ptr<Cube>to the cube that needs to be rendered. - The problem here is: Where to store the vertices and indices and the material data for the
Cubeclass? - Keep in mind that an instance of
Cubecan represent different things (see #561) - How to separate materials from material instances? A material is composed of the data required to build the pipeline for it, so it is currently associated with render modules, meaning that each render module can have one or many material (=pipelines) it can create and render. Where should the data for that rendering be kept though? The data should not be in the
Cubeclass and it should not be in the render module. Instead, the render module should have a vector of pointers to material instances (=the data required to render using a specific material). - Don't forget that each material also comes not only with its own shaders, but also
VkVertexInputAttributeDescriptionandstd::vector<VkVertexInputBindingDescription>. - During rendergraph compilation, the material instances and the instances of
Cubeassociated with it are sorted into the correct render modules automatically.
Alternatives
Implementing a simple textured octree renderer which applies one texture with fixed texture coordinates to all vertices of a cube works too, but we need to think towards abstraction anyways. Doing it the simple way now only produces more work for us later.
Affected Code
Rendergraph and render modules code, also cube code
Operating System
All
Additional Context
None
So it breaks down to:
- How to handle materials and material instances?
- A render module needs to know which materials are supported, and the render module must set up the pipelines for these materials and the passes which use them.
- I still think each render module should have the data required to build the pipelines as a member, because otherwise we need to pass the material to a render module, and this would break encapsulation and it would also make it harder to use the material in the passes I believe.
- Each render module should have a std::vector<Material> of supported materials, so if a material is added, the render module can accept or reject it. We can do this maybe even at compile time.
- Another approach would be to separate materials from render modules, and to organize them like this:
struct Material {
std::string name;
std::vector<Shader> shaders;
std::vector<VkVertexInputAttributeDescription> vertex_attributes;
std::vector<VkVertexInputBindingDescription> vertex_bindings;
std::function<GraphicsPipeline(GraphicsPipelineBuilder&)> pipeline_builder;
};
struct MaterialInstance {
std::shared_ptr<Material> material;
std::shared_ptr<BufferResource> vertex_buffer;
std::shared_ptr<BufferResource> index_buffer;
uint32_t index_count;
DescriptorSet descriptor_set; // From allocator
};
- Maybe using the materials and material instances in a render module are not that hard then?
- A major downside of keeping the material outside of the render module would be that rendergraph then would have to do more work to sort the passes and the required pipelines to render efficiently!
It should be noted that from every cube, an arbitrary number of instances can be rendered. Each instance has the same geometry as the original cube (vertices and indices), but material(s) can be assigned to the instance to it in various ways. If we would restrict to one material per instance, rendering would be somewhat simple, because rendergraph could render all cube instances based on the material.
However, the situation is more complex. For example we could have one cube which has several instances, but every instance has different textures on different part of the child cubes. In this case, rendering by sorted materials is difficult, especially since the vertex offsets are not trivial in this case. I need to think deeper about this problem.