Workbench Next Volumes #105501

Merged
Miguel Pozo merged 10 commits from pragma37/blender:pull-workbench-next-volumes into main 2023-05-16 16:56:27 +02:00
4 changed files with 229 additions and 40 deletions
Showing only changes of commit 78861a0035 - Show all commits

View File

@ -6,7 +6,7 @@
/** \name Volume shader base
* \{ */
GPU_SHADER_CREATE_INFO(workbench_volume)
GPU_SHADER_CREATE_INFO(workbench_volume_common)
.vertex_in(0, Type::VEC3, "pos")
.fragment_out(0, Type::VEC4, "fragColor")
.sampler(0, ImageType::DEPTH_2D, "depthBuffer")
@ -16,27 +16,44 @@ GPU_SHADER_CREATE_INFO(workbench_volume)
.push_constant(Type::FLOAT, "stepLength")
.push_constant(Type::FLOAT, "densityScale")
.vertex_source("workbench_volume_vert.glsl")
.fragment_source("workbench_volume_frag.glsl")
.additional_info("draw_object_infos");
.fragment_source("workbench_volume_frag.glsl");
GPU_SHADER_CREATE_INFO(workbench_volume)
.additional_info("workbench_volume_common", "draw_object_infos");
GPU_SHADER_CREATE_INFO(workbench_next_volume)
.define("WORKBENCH_NEXT")
.additional_info("workbench_volume_common", "draw_object_infos_new", "draw_view");
/** \} */
/* -------------------------------------------------------------------- */
/** \name Smoke variation
* \{ */
GPU_SHADER_CREATE_INFO(workbench_volume_smoke)
GPU_SHADER_CREATE_INFO(workbench_volume_smoke_common)
.define("VOLUME_SMOKE")
.sampler(2, ImageType::FLOAT_3D, "flameTexture")
.sampler(3, ImageType::FLOAT_1D, "flameColorTexture")
.additional_info("draw_mesh", "draw_resource_id_varying");
.additional_info("draw_resource_id_varying");
GPU_SHADER_CREATE_INFO(workbench_volume_object)
GPU_SHADER_CREATE_INFO(workbench_volume_object_common)
.define("VOLUME_OBJECT")
.push_constant(Type::MAT4, "volumeTextureToObject")
/* FIXME(fclem): This overflow the push_constant limit. */
.push_constant(Type::MAT4, "volumeObjectToTexture")
.additional_info("draw_volume", "draw_resource_id_varying");
.additional_info("draw_resource_id_varying");
GPU_SHADER_CREATE_INFO(workbench_volume_smoke)
.additional_info("workbench_volume_smoke_common", "draw_mesh");
GPU_SHADER_CREATE_INFO(workbench_volume_object)
.additional_info("workbench_volume_object_common", "draw_volume");
GPU_SHADER_CREATE_INFO(workbench_next_volume_smoke)
.additional_info("workbench_volume_smoke_common", "draw_modelmat_new");
GPU_SHADER_CREATE_INFO(workbench_next_volume_object)
.additional_info("workbench_volume_object_common", "draw_volume_new");
/** \} */
@ -111,4 +128,10 @@ GPU_SHADER_CREATE_INFO(workbench_volume_slice)
WORKBENCH_VOLUME_SMOKE_VARIATIONS(workbench_volume, "workbench_volume")
#define WORKBENCH_NEXT_VOLUME_SMOKE_VARIATIONS(prefix, ...) \
WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_smoke, "workbench_next_volume_smoke", __VA_ARGS__) \
WORKBENCH_VOLUME_INTERP_VARIATIONS(prefix##_object, "workbench_next_volume_object", __VA_ARGS__)
WORKBENCH_NEXT_VOLUME_SMOKE_VARIATIONS(workbench_next_volume, "workbench_next_volume")
/** \} */

View File

@ -13,14 +13,178 @@
#include "ED_view3d.h"
#include "GPU_capabilities.h"
#include "draw_common.hh"
#include "workbench_private.hh"
#include "BKE_volume.h"
#include "BKE_volume_render.h"
#include "BLI_rand.h"
#include "workbench_engine.h" /* Own include. */
namespace blender::workbench {
using namespace draw;
class VolumePass {
PassMain ps_ = {"Volume Ps"};
Framebuffer fb_ = {"Volume Fb"};
bool active_ = true;
Texture dummy_shadow_tx = {"Dummy Shadow"};
GPUShader *shaders[2][2][3][2];
GPUShader *get_shader(bool slice, bool coba, VolumeDisplayInterpMethod interpolation, bool smoke)
{
GPUShader *&shader = shaders[slice][coba][interpolation][smoke];
if (shader == nullptr) {
std::string create_info_name = "workbench_next_volume";
create_info_name += (smoke) ? "_smoke" : "_object";
switch (interpolation) {
case VOLUME_DISPLAY_INTERP_LINEAR:
create_info_name += "_linear";
break;
case VOLUME_DISPLAY_INTERP_CUBIC:
create_info_name += "_linear";
break;
case VOLUME_DISPLAY_INTERP_CLOSEST:
create_info_name += "_linear";
break;
default:
BLI_assert_unreachable();
}
create_info_name += (coba) ? "_coba" : "_no_coba";
create_info_name += (slice) ? "_slice" : "_no_slice";
shader = GPU_shader_create_from_info_name(create_info_name.c_str());
}
return shader;
}
public:
void sync(SceneResources &resources)
{
active_ = false;
ps_.init();
ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf);
dummy_shadow_tx.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(1));
}
void object_sync_volume(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
float3 color)
{
Object *ob = ob_ref.object;
/* Create 3D textures. */
Volume *volume = static_cast<Volume *>(ob->data);
BKE_volume_load(volume, G.main);
const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
if (volume_grid == nullptr) {
return;
}
#if 0
/* TODO (Miguel Pozo): Use common API? */
Vector<VolumeAttribute> attrs = {
{"densityTexture", BKE_volume_grid_name(volume_grid), eGPUDefaultValue::GPU_DEFAULT_1}};
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
if (!volume_sub_pass(ps_, nullptr, nullptr, attrs)) {
return;
}
#endif
DRWVolumeGrid *grid = DRW_volume_batch_cache_get_grid(volume, volume_grid);
if (grid == nullptr) {
return;
}
active_ = true;
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE);
VolumeDisplayInterpMethod interpolation = static_cast<VolumeDisplayInterpMethod>(
volume->display.interpolation_method);
sub_ps.shader_set(get_shader(use_slice, false, interpolation, false));
if (use_slice) {
float4x4 view_mat_inv;
DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true);
const int axis = (volume->display.slice_axis == SLICE_AXIS_AUTO) ?
axis_dominant_v3_single(view_mat_inv[2]) :
volume->display.slice_axis - 1;
float3 dim;
BKE_object_dimensions_get(ob, dim);
/* 0.05f to achieve somewhat the same opacity as the full view. */
float step_length = max_ff(1e-16f, dim[axis] * 0.05f);
const float slice_position = volume->display.slice_depth;
/*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */
sub_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL |
~DRW_STATE_CULL_FRONT);
sub_ps.push_constant("slicePosition", slice_position);
sub_ps.push_constant("sliceAxis", axis);
sub_ps.push_constant("stepLength", step_length);
}
else {
/* Compute world space dimensions for step size. */
float4x4 texture_to_world = float4x4(ob->object_to_world) *
float4x4(grid->texture_to_object);
float3 world_size;
math::normalize_and_get_size(float3x3(texture_to_world), world_size);
/* Compute step parameters. */
double noise_offset;
BLI_halton_1d(3, 0.0, scene_state.sample, &noise_offset);
int3 resolution;
GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
float3 slice_count = math::max(float3(0.01f), float3(resolution)) * 5.0f;
int max_slice = std::max({UNPACK3(slice_count)});
float step_length = math::length((1.0f / slice_count) * world_size);
sub_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL |
DRW_STATE_CULL_FRONT);
sub_ps.push_constant("samplesLen", max_slice);
sub_ps.push_constant("stepLength", step_length);
sub_ps.push_constant("noiseOfs", float(noise_offset));
}
const float density_scale = volume->display.density *
BKE_volume_density_scale(volume, ob->object_to_world);
sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
sub_ps.bind_texture("densityTexture", grid->texture);
/* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
sub_ps.bind_texture("shadowTexture", dummy_shadow_tx);
sub_ps.push_constant("activeColor", color);
sub_ps.push_constant("densityScale", density_scale);
sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture));
sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object));
sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
}
void draw(Manager &manager, View &view, SceneResources &resources)
{
if (!active_) {
return;
}
fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(resources.color_tx));
fb_.bind();
manager.submit(ps_, view);
}
};
class Instance {
public:
View view = {"DefaultView"};
@ -34,6 +198,7 @@ class Instance {
TransparentDepthPass transparent_depth_ps;
ShadowPass shadow_ps;
VolumePass volume_ps;
OutlinePass outline_ps;
DofPass dof_ps;
AntiAliasingPass anti_aliasing_ps;
@ -75,6 +240,7 @@ class Instance {
transparent_depth_ps.sync(scene_state, resources);
shadow_ps.sync();
volume_ps.sync(resources);
outline_ps.sync(resources);
dof_ps.sync(resources);
anti_aliasing_ps.sync(resources, scene_state.resolution);
@ -85,6 +251,26 @@ class Instance {
resources.material_buf.push_update();
}
Material get_material(ObjectRef ob_ref, eV3DShadingColorType color_type, int slot = 0)
{
switch (color_type) {
case V3D_SHADING_OBJECT_COLOR:
return Material(*ob_ref.object);
case V3D_SHADING_RANDOM_COLOR:
return Material(*ob_ref.object, true);
case V3D_SHADING_SINGLE_COLOR:
return scene_state.material_override;
case V3D_SHADING_VERTEX_COLOR:
return scene_state.material_attribute_color;
case V3D_SHADING_MATERIAL_COLOR:
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, slot + 1)) {
return Material(*_mat);
}
default:
return Material(*BKE_material_default_empty());
}
}
void object_sync(Manager &manager, ObjectRef &ob_ref)
{
if (scene_state.render_finished) {
@ -163,14 +349,16 @@ class Instance {
#if 0 /* TODO(@pragma37): */
DRWShadingGroup *grp = workbench_material_hair_setup(
wpd, ob, CURVES_MATERIAL_NR, object_state.color_type);
DRW_shgroup_curves_create_sub(ob, grp, NULL);
DRW_shgroup_curves_create_sub(ob, grp, nullptr);
#endif
}
else if (ob->type == OB_VOLUME) {
if (scene_state.shading.type != OB_WIRE) {
#if 0 /* TODO(@pragma37): */
workbench_volume_cache_populate(vedata, wpd->scene, ob, NULL, object_state.color_type);
#endif
volume_ps.object_sync_volume(manager,
resources,
scene_state,
ob_ref,
get_material(ob_ref, object_state.color_type).base_color);
}
}
}
@ -204,15 +392,7 @@ class Instance {
continue;
}
Material mat;
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) {
mat = Material(*_mat);
}
else {
mat = Material(*BKE_material_default_empty());
}
Material mat = get_material(ob_ref, object_state.color_type, i);
has_transparent_material = has_transparent_material || mat.is_transparent();
::Image *image = nullptr;
@ -244,24 +424,7 @@ class Instance {
}
if (batch) {
Material mat;
if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) {
mat = Material(*ob_ref.object);
}
else if (object_state.color_type == V3D_SHADING_RANDOM_COLOR) {
mat = Material(*ob_ref.object, true);
}
else if (object_state.color_type == V3D_SHADING_SINGLE_COLOR) {
mat = scene_state.material_override;
}
else if (object_state.color_type == V3D_SHADING_VERTEX_COLOR) {
mat = scene_state.material_attribute_color;
}
else {
mat = Material(*BKE_material_default_empty());
}
Material mat = get_material(ob_ref, object_state.color_type);
has_transparent_material = has_transparent_material || mat.is_transparent();
draw_mesh(ob_ref,
@ -370,8 +533,7 @@ class Instance {
transparent_ps.draw(manager, view, resources, resolution);
transparent_depth_ps.draw(manager, view, resources);
// volume_ps.draw_prepass(manager, view, resources.depth_tx);
volume_ps.draw(manager, view, resources);
outline_ps.draw(manager, resources);
dof_ps.draw(manager, view, resources, resolution);
anti_aliasing_ps.draw(manager, view, resources, resolution, depth_tx, color_tx);

View File

@ -297,6 +297,7 @@ static bool volume_object_grids_init(PassMain::Sub &ps, Object *ob, Span<VolumeA
Volume *volume = (Volume *)ob->data;
BKE_volume_load(volume, G.main);
/* TODO (Miguel Pozo): Should have *= volume->display.density ? */
volume_infos.density_scale = BKE_volume_density_scale(volume, ob->object_to_world);
volume_infos.color_mul = float4(1.0f);
volume_infos.temperature_mul = 1.0f;

View File

@ -126,6 +126,9 @@ GPU_SHADER_CREATE_INFO(draw_pointcloud)
GPU_SHADER_CREATE_INFO(draw_volume).additional_info("draw_modelmat", "draw_resource_id_uniform");
GPU_SHADER_CREATE_INFO(draw_volume_new)
.additional_info("draw_modelmat_new", "draw_resource_handle_new");
GPU_SHADER_CREATE_INFO(draw_gpencil)
.typedef_source("gpencil_shader_shared.h")
.define("DRW_GPENCIL_INFO")