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
7 changed files with 375 additions and 43 deletions

View File

@ -180,6 +180,7 @@ set(SRC
engines/workbench/workbench_state.cc
engines/workbench/workbench_transparent.c
engines/workbench/workbench_volume.c
engines/workbench/workbench_volume_next.cc
engines/external/external_engine.c
engines/gpencil/gpencil_antialiasing.c
engines/gpencil/gpencil_cache_utils.c

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

@ -209,6 +209,12 @@ vec4 volume_integration(vec3 ray_ori, vec3 ray_dir, float ray_inc, float ray_max
/* accumulate and also take into account the transmittance from previous steps */
final_scattering += final_transmittance * Lscat;
final_transmittance *= Tr;
if (final_transmittance <= 0.01) {
/* Early out */
final_transmittance = 0.0;
pragma37 marked this conversation as resolved Outdated

Do not use implicit cast assignment. This is not supported by all drivers.

Do not use implicit cast assignment. This is not supported by all drivers.
break;
}
}
return vec4(final_scattering, final_transmittance);

View File

@ -34,6 +34,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 +76,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 +87,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) {
@ -138,9 +160,8 @@ class Instance {
if (md && BKE_modifier_is_enabled(scene_state.scene, md, eModifierMode_Realtime)) {
FluidModifierData *fmd = (FluidModifierData *)md;
if (fmd->domain) {
#if 0 /* TODO(@pragma37): */
workbench_volume_cache_populate(vedata, wpd->scene, ob, md, V3D_SHADING_SINGLE_COLOR);
#endif
volume_ps.object_sync_modifier(manager, resources, scene_state, ob_ref, md);
if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
return; /* Do not draw solid in this case. */
}
@ -163,14 +184,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 +227,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 +259,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 +368,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

@ -324,6 +324,52 @@ class ShadowPass {
bool force_fail_method);
};
class VolumePass {
bool active_ = true;
PassMain ps_ = {"Volume"};
Framebuffer fb_ = {"Volume"};
Texture dummy_shadow_tx_ = {"Volume.Dummy Shadow Tx"};
Texture dummy_volume_tx_ = {"Volume.Dummy Volume Tx"};
Texture dummy_coba_tx_ = {"Volume.Dummy Coba Tx"};
GPUShader *shaders_[2 /*slice*/][2 /*coba*/][3 /*interpolation*/][2 /*smoke*/];
public:
void sync(SceneResources &resources);
pragma37 marked this conversation as resolved Outdated
Follow class layout style https://wiki.blender.org/wiki/Style_Guide/C_Cpp#Class_Layout
void object_sync_volume(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
float3 color);
void object_sync_modifier(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
ModifierData *md);
void draw(Manager &manager, View &view, SceneResources &resources);
private:
GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke);
void draw_slice_ps(Manager &manager,
PassMain::Sub &ps,
ObjectRef &ob_ref,
int slice_axis_enum,
float slice_depth);
void draw_volume_ps(Manager &manager,
PassMain::Sub &ps,
ObjectRef &ob_ref,
int taa_sample,
float3 slice_count,
float3 world_size);
};
class OutlinePass {
private:
bool enabled_ = false;

View File

@ -0,0 +1,256 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "workbench_private.hh"
#include "BKE_volume.h"
#include "BKE_volume_render.h"
#include "BLI_rand.h"
#include "DNA_fluid_types.h"
#include "DNA_modifier_types.h"
namespace blender::workbench {
void VolumePass::sync(SceneResources &resources)
{
active_ = false;
ps_.init();
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));
dummy_volume_tx_.ensure_3d(GPU_RGBA8, int3(1), GPU_TEXTURE_USAGE_SHADER_READ, float4(0));
dummy_coba_tx_.ensure_1d(GPU_RGBA8, 1, GPU_TEXTURE_USAGE_SHADER_READ, float4(0));
}
void VolumePass::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;
}
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);
sub_ps.shader_set(get_shader(use_slice, false, volume->display.interpolation_method, false));
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));
if (use_slice) {
draw_slice_ps(
manager, sub_ps, ob_ref, volume->display.slice_axis, volume->display.slice_depth);
}
else {
float3 world_size;
float4x4 texture_to_world = float4x4(ob->object_to_world) * float4x4(grid->texture_to_object);
math::normalize_and_get_size(float3x3(texture_to_world), world_size);
int3 resolution;
GPU_texture_get_mipmap_size(grid->texture, 0, resolution);
float3 slice_count = float3(resolution) * 5.0f;
draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
}
}
void VolumePass::object_sync_modifier(Manager &manager,
SceneResources &resources,
const SceneState &scene_state,
ObjectRef &ob_ref,
ModifierData *md)
{
Object *ob = ob_ref.object;
FluidModifierData *modifier = reinterpret_cast<FluidModifierData *>(md);
FluidDomainSettings &settings = *modifier->domain;
if (!settings.fluid) {
return;
}
bool can_load = false;
if (settings.use_coba) {
DRW_smoke_ensure_coba_field(modifier);
can_load = settings.tex_field != nullptr;
}
else if (settings.type == FLUID_DOMAIN_TYPE_GAS) {
DRW_smoke_ensure(modifier, settings.flags & FLUID_DOMAIN_USE_NOISE);
can_load = settings.tex_density != nullptr || settings.tex_color != nullptr;
}
if (!can_load) {
return;
}
active_ = true;
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
const bool use_slice = settings.axis_slice_method == AXIS_SLICE_SINGLE;
sub_ps.shader_set(get_shader(use_slice, settings.use_coba, settings.interp_method, true));
if (settings.use_coba) {
const bool show_flags = settings.coba_field == FLUID_DOMAIN_FIELD_FLAGS;
const bool show_pressure = settings.coba_field == FLUID_DOMAIN_FIELD_PRESSURE;
const bool show_phi = ELEM(settings.coba_field,
FLUID_DOMAIN_FIELD_PHI,
FLUID_DOMAIN_FIELD_PHI_IN,
FLUID_DOMAIN_FIELD_PHI_OUT,
FLUID_DOMAIN_FIELD_PHI_OBSTACLE);
sub_ps.push_constant("showFlags", show_flags);
sub_ps.push_constant("showPressure", show_pressure);
sub_ps.push_constant("showPhi", show_phi);
sub_ps.push_constant("gridScale", settings.grid_scale);
if (show_flags) {
sub_ps.bind_texture("flagTexture", settings.tex_field);
}
else {
sub_ps.bind_texture("densityTexture", settings.tex_field);
}
if (!show_flags && !show_pressure && !show_phi) {
sub_ps.bind_texture("transferTexture", settings.tex_coba);
}
}
else {
bool use_constant_color = ((settings.active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 &&
(settings.active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0);
sub_ps.push_constant("activeColor",
use_constant_color ? float3(settings.active_color) : float3(1));
sub_ps.bind_texture("densityTexture",
settings.tex_color ? settings.tex_color : settings.tex_density);
sub_ps.bind_texture("flameTexture",
settings.tex_flame ? settings.tex_flame : dummy_volume_tx_);
sub_ps.bind_texture("flameColorTexture",
settings.tex_flame ? settings.tex_flame_coba : dummy_coba_tx_);
sub_ps.bind_texture("shadowTexture", settings.tex_shadow);
}
sub_ps.push_constant("densityScale", 10.0f * settings.display_thickness);
sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
if (use_slice) {
draw_slice_ps(manager, sub_ps, ob_ref, settings.slice_axis, settings.slice_depth);
}
else {
float3 world_size;
BKE_object_dimensions_get(ob, world_size);
float3 slice_count = float3(settings.res) * std::max(0.001f, settings.slice_per_voxel);
draw_volume_ps(manager, sub_ps, ob_ref, scene_state.sample, slice_count, world_size);
}
}
void VolumePass::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);
}
GPUShader *VolumePass::get_shader(bool slice, bool coba, int 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 += "_cubic";
break;
case VOLUME_DISPLAY_INTERP_CLOSEST:
create_info_name += "_closest";
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;
}
void VolumePass::draw_slice_ps(
Manager &manager, PassMain::Sub &ps, ObjectRef &ob_ref, int slice_axis_enum, float slice_depth)
{
float4x4 view_mat_inv;
DRW_view_viewmat_get(nullptr, view_mat_inv.ptr(), true);
const int axis = (slice_axis_enum == SLICE_AXIS_AUTO) ?
axis_dominant_v3_single(view_mat_inv[2]) :
slice_axis_enum - 1;
float3 dimensions;
BKE_object_dimensions_get(ob_ref.object, dimensions);
/* 0.05f to achieve somewhat the same opacity as the full view. */
float step_length = std::max(1e-16f, dimensions[axis] * 0.05f);
ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL);
ps.push_constant("slicePosition", slice_depth);
ps.push_constant("sliceAxis", axis);
ps.push_constant("stepLength", step_length);
ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref));
}
void VolumePass::draw_volume_ps(Manager &manager,
PassMain::Sub &ps,
ObjectRef &ob_ref,
int taa_sample,
float3 slice_count,
float3 world_size)
{
double noise_offset;
BLI_halton_1d(3, 0.0, taa_sample, &noise_offset);
int max_slice = std::max({UNPACK3(slice_count)});
float step_length = math::length((1.0f / slice_count) * world_size);
ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
ps.push_constant("samplesLen", max_slice);
ps.push_constant("stepLength", step_length);
ps.push_constant("noiseOfs", float(noise_offset));
ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
}
} // namespace blender::workbench

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")