Group passes by material
This commit is contained in:
@@ -126,19 +126,18 @@ GPU_SHADER_CREATE_INFO(workbench_next_prepass)
|
||||
|
||||
GPU_SHADER_CREATE_INFO(workbench_color_material)
|
||||
.define("WORKBENCH_COLOR_MATERIAL")
|
||||
.storage_buf(WB_MATERIAL_SLOT, Qualifier::READ, "vec4", "materials_data[]");
|
||||
.push_constant(Type::VEC4, "material_data");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(workbench_color_texture)
|
||||
.define("WORKBENCH_COLOR_TEXTURE")
|
||||
.define("WORKBENCH_TEXTURE_IMAGE_ARRAY")
|
||||
.define("WORKBENCH_COLOR_MATERIAL")
|
||||
.storage_buf(WB_MATERIAL_SLOT, Qualifier::READ, "vec4", "materials_data[]")
|
||||
.sampler(1, ImageType::FLOAT_2D, "imageTexture", Frequency::BATCH)
|
||||
.sampler(2, ImageType::FLOAT_2D_ARRAY, "imageTileArray", Frequency::BATCH)
|
||||
.sampler(3, ImageType::FLOAT_1D_ARRAY, "imageTileData", Frequency::BATCH)
|
||||
.push_constant(Type::BOOL, "isImageTile")
|
||||
.push_constant(Type::BOOL, "imagePremult")
|
||||
.push_constant(Type::FLOAT, "imageTransparencyCutoff");
|
||||
.push_constant(Type::FLOAT, "imageTransparencyCutoff")
|
||||
.additional_info("workbench_color_material");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(workbench_color_vertex).define("WORKBENCH_COLOR_VERTEX");
|
||||
|
||||
|
@@ -17,7 +17,7 @@ void workbench_material_data_get(int handle,
|
||||
#else
|
||||
|
||||
# ifdef WORKBENCH_COLOR_MATERIAL
|
||||
vec4 data = materials_data[handle];
|
||||
vec4 data = material_data;
|
||||
# else
|
||||
vec4 data = vec4(0.0);
|
||||
# endif
|
||||
|
@@ -196,12 +196,7 @@ class Instance {
|
||||
if (batches[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
/* TODO(fclem): This create a cull-able instance for each sub-object. This is done
|
||||
* for simplicity to reduce complexity. But this increase the overhead per object.
|
||||
* Instead, we should use an indirection buffer to the material buffer. */
|
||||
ResourceHandle _handle = i == 0 ? handle : manager.resource_handle(ob_ref);
|
||||
|
||||
Material &mat = resources.material_buf.get_or_resize(_handle.resource_index());
|
||||
Material mat;
|
||||
|
||||
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) {
|
||||
mat = Material(*_mat);
|
||||
@@ -219,7 +214,7 @@ class Instance {
|
||||
get_material_image(ob_ref.object, i + 1, image, iuser, sampler_state);
|
||||
}
|
||||
|
||||
draw_mesh(ob_ref, mat, batches[i], _handle, image, sampler_state, iuser);
|
||||
draw_mesh(ob_ref, mat, batches[i], handle, image, sampler_state, iuser);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,7 +236,7 @@ class Instance {
|
||||
}
|
||||
|
||||
if (batch) {
|
||||
Material &mat = resources.material_buf.get_or_resize(handle.resource_index());
|
||||
Material mat;
|
||||
|
||||
if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) {
|
||||
mat = Material(*ob_ref.object);
|
||||
@@ -287,7 +282,7 @@ class Instance {
|
||||
const bool in_front = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0;
|
||||
|
||||
auto draw = [&](MeshPass &pass) {
|
||||
pass.draw(ob_ref, batch, handle, image, sampler_state, iuser);
|
||||
pass.draw(ob_ref, batch, handle, material, image, sampler_state, iuser);
|
||||
};
|
||||
|
||||
if (scene_state.xray_mode || material.is_transparent()) {
|
||||
|
@@ -34,6 +34,7 @@ void MeshPass::init_subpasses(ePipelineType pipeline,
|
||||
bool clip,
|
||||
ShaderCache &shaders)
|
||||
{
|
||||
material_subpass_map_.clear();
|
||||
texture_subpass_map_.clear();
|
||||
|
||||
static std::string pass_names[geometry_type_len][shader_type_len] = {};
|
||||
@@ -57,6 +58,7 @@ void MeshPass::init_subpasses(ePipelineType pipeline,
|
||||
void MeshPass::draw(ObjectRef &ref,
|
||||
GPUBatch *batch,
|
||||
ResourceHandle handle,
|
||||
Material material,
|
||||
::Image *image /* = nullptr */,
|
||||
eGPUSamplerState sampler_state /* = GPU_SAMPLER_DEFAULT */,
|
||||
ImageUser *iuser /* = nullptr */)
|
||||
@@ -64,6 +66,7 @@ void MeshPass::draw(ObjectRef &ref,
|
||||
is_empty_ = false;
|
||||
|
||||
eGeometryType geometry_type = geometry_type_from_object(ref.object);
|
||||
|
||||
if (image) {
|
||||
GPUTexture *texture = nullptr;
|
||||
GPUTexture *tilemap = nullptr;
|
||||
@@ -75,33 +78,47 @@ void MeshPass::draw(ObjectRef &ref,
|
||||
texture = BKE_image_get_gpu_texture(image, iuser, nullptr);
|
||||
}
|
||||
if (texture) {
|
||||
auto add_cb = [&] {
|
||||
PassMain::Sub *sub_pass =
|
||||
passes_[static_cast<int>(geometry_type)][static_cast<int>(eShaderType::TEXTURE)];
|
||||
sub_pass = &sub_pass->sub(image->id.name);
|
||||
auto add_texture_cb = [&] {
|
||||
PassMain::Sub &sub_pass =
|
||||
passes_[static_cast<int>(geometry_type)][static_cast<int>(eShaderType::TEXTURE)]->sub(
|
||||
image->id.name);
|
||||
|
||||
sub_pass.push_constant("material_data", *reinterpret_cast<float4 *>(&material));
|
||||
if (tilemap) {
|
||||
sub_pass->bind_texture(WB_TILE_ARRAY_SLOT, texture, sampler_state);
|
||||
sub_pass->bind_texture(WB_TILE_DATA_SLOT, tilemap);
|
||||
sub_pass.bind_texture(WB_TILE_ARRAY_SLOT, texture, sampler_state);
|
||||
sub_pass.bind_texture(WB_TILE_DATA_SLOT, tilemap);
|
||||
}
|
||||
else {
|
||||
sub_pass->bind_texture(WB_TEXTURE_SLOT, texture, sampler_state);
|
||||
sub_pass.bind_texture(WB_TEXTURE_SLOT, texture, sampler_state);
|
||||
}
|
||||
sub_pass->push_constant("isImageTile", tilemap != nullptr);
|
||||
sub_pass->push_constant("imagePremult", image && image->alpha_mode == IMA_ALPHA_PREMUL);
|
||||
sub_pass.push_constant("isImageTile", tilemap != nullptr);
|
||||
sub_pass.push_constant("imagePremult", image && image->alpha_mode == IMA_ALPHA_PREMUL);
|
||||
/* TODO(Miguel Pozo): This setting should be exposed on the user side,
|
||||
* either as a global parameter (and set it here)
|
||||
* or by reading the Material Clipping Threshold (and set it per material) */
|
||||
sub_pass->push_constant("imageTransparencyCutoff", 0.1f);
|
||||
return sub_pass;
|
||||
sub_pass.push_constant("imageTransparencyCutoff", 0.1f);
|
||||
return &sub_pass;
|
||||
};
|
||||
|
||||
texture_subpass_map_.lookup_or_add_cb(TextureSubPassKey(texture, geometry_type), add_cb)
|
||||
texture_subpass_map_
|
||||
.lookup_or_add_cb(TextureSubPassKey(texture, geometry_type), add_texture_cb)
|
||||
->draw(batch, handle);
|
||||
return;
|
||||
}
|
||||
}
|
||||
passes_[static_cast<int>(geometry_type)][static_cast<int>(eShaderType::MATERIAL)]->draw(batch,
|
||||
handle);
|
||||
|
||||
auto add_material_cb = [&] {
|
||||
PassMain::Sub &sub_pass =
|
||||
passes_[static_cast<int>(geometry_type)][static_cast<int>(eShaderType::MATERIAL)]->sub(
|
||||
"Material");
|
||||
|
||||
sub_pass.push_constant("material_data", *reinterpret_cast<float4 *>(&material));
|
||||
return &sub_pass;
|
||||
};
|
||||
|
||||
material_subpass_map_
|
||||
.lookup_or_add_cb(MaterialSubPassKey(material, geometry_type), add_material_cb)
|
||||
->draw(batch, handle);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -51,6 +51,16 @@ struct Material {
|
||||
static uint32_t pack_data(float metallic, float roughness, float alpha);
|
||||
|
||||
bool is_transparent();
|
||||
|
||||
inline bool operator==(const Material &a) const
|
||||
{
|
||||
return packed_data == a.packed_data && base_color == a.base_color;
|
||||
}
|
||||
|
||||
inline uint64_t hash() const
|
||||
{
|
||||
return get_default_hash_4(base_color.x, base_color.y, base_color.z, packed_data);
|
||||
}
|
||||
};
|
||||
|
||||
void get_material_image(Object *ob,
|
||||
@@ -161,8 +171,10 @@ struct SceneResources {
|
||||
|
||||
class MeshPass : public PassMain {
|
||||
private:
|
||||
using MaterialSubPassKey = std::pair<Material, eGeometryType>;
|
||||
using TextureSubPassKey = std::pair<GPUTexture *, eGeometryType>;
|
||||
|
||||
Map<MaterialSubPassKey, PassMain::Sub *> material_subpass_map_ = {};
|
||||
Map<TextureSubPassKey, PassMain::Sub *> texture_subpass_map_ = {};
|
||||
|
||||
PassMain::Sub *passes_[geometry_type_len][shader_type_len] = {{nullptr}};
|
||||
@@ -184,6 +196,7 @@ class MeshPass : public PassMain {
|
||||
void draw(ObjectRef &ref,
|
||||
GPUBatch *batch,
|
||||
ResourceHandle handle,
|
||||
Material material,
|
||||
::Image *image = nullptr,
|
||||
eGPUSamplerState sampler_state = eGPUSamplerState::GPU_SAMPLER_DEFAULT,
|
||||
ImageUser *iuser = nullptr);
|
||||
|
Reference in New Issue
Block a user