Workbench Next Volumes #105501
|
@ -28,16 +28,20 @@ namespace blender::workbench {
|
||||||
using namespace draw;
|
using namespace draw;
|
||||||
|
|
||||||
class VolumePass {
|
class VolumePass {
|
||||||
|
bool active_ = true;
|
||||||
|
|
||||||
PassMain ps_ = {"Volume Ps"};
|
PassMain ps_ = {"Volume Ps"};
|
||||||
Framebuffer fb_ = {"Volume Fb"};
|
Framebuffer fb_ = {"Volume Fb"};
|
||||||
bool active_ = true;
|
|
||||||
Texture dummy_shadow_tx = {"Dummy Shadow"};
|
|
||||||
|
|
||||||
GPUShader *shaders[2][2][3][2];
|
Texture dummy_shadow_tx_ = {"Dummy Shadow"};
|
||||||
|
Texture dummy_volume_tx_ = {"Dummy Volume"};
|
||||||
|
Texture dummy_coba_tx_ = {"Dummy Coba"};
|
||||||
|
|
||||||
GPUShader *get_shader(bool slice, bool coba, VolumeDisplayInterpMethod interpolation, bool smoke)
|
GPUShader *shaders_[2][2][3][2];
|
||||||
|
|
||||||
|
GPUShader *get_shader(bool slice, bool coba, int interpolation, bool smoke)
|
||||||
{
|
{
|
||||||
GPUShader *&shader = shaders[slice][coba][interpolation][smoke];
|
GPUShader *&shader = shaders_[slice][coba][interpolation][smoke];
|
||||||
|
|
||||||
if (shader == nullptr) {
|
if (shader == nullptr) {
|
||||||
std::string create_info_name = "workbench_next_volume";
|
std::string create_info_name = "workbench_next_volume";
|
||||||
|
@ -62,6 +66,43 @@ class VolumePass {
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setup_slice_ps(PassMain::Sub &ps, Object *ob, 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, dimensions);
|
||||||
|
/* 0.05f to achieve somewhat the same opacity as the full view. */
|
||||||
|
float step_length = max_ff(1e-16f, dimensions[axis] * 0.05f);
|
||||||
|
|
||||||
|
/*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */
|
||||||
|
ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | ~DRW_STATE_CULL_FRONT);
|
||||||
|
ps.push_constant("slicePosition", slice_depth);
|
||||||
|
ps.push_constant("sliceAxis", axis);
|
||||||
|
ps.push_constant("stepLength", step_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_non_slice_ps(
|
||||||
|
PassMain::Sub &ps, Object *ob, 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);
|
||||||
|
|
||||||
|
/*TODO (Miguel Pozo): Does this override or replace the parent pass state ? */
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void sync(SceneResources &resources)
|
void sync(SceneResources &resources)
|
||||||
{
|
{
|
||||||
|
@ -70,7 +111,9 @@ class VolumePass {
|
||||||
ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT);
|
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);
|
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_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 object_sync_volume(Manager &manager,
|
void object_sync_volume(Manager &manager,
|
||||||
|
@ -108,56 +151,8 @@ class VolumePass {
|
||||||
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
|
PassMain::Sub &sub_ps = ps_.sub(ob->id.name);
|
||||||
|
|
||||||
const bool use_slice = (volume->display.axis_slice_method == AXIS_SLICE_SINGLE);
|
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));
|
sub_ps.shader_set(get_shader(use_slice, false, volume->display.interpolation_method, 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 *
|
const float density_scale = volume->display.density *
|
||||||
BKE_volume_density_scale(volume, ob->object_to_world);
|
BKE_volume_density_scale(volume, ob->object_to_world);
|
||||||
|
@ -165,15 +160,128 @@ class VolumePass {
|
||||||
sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
|
sub_ps.bind_texture("depthBuffer", &resources.depth_tx);
|
||||||
sub_ps.bind_texture("densityTexture", grid->texture);
|
sub_ps.bind_texture("densityTexture", grid->texture);
|
||||||
/* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
|
/* TODO: implement shadow texture, see manta_smoke_calc_transparency. */
|
||||||
sub_ps.bind_texture("shadowTexture", dummy_shadow_tx);
|
sub_ps.bind_texture("shadowTexture", dummy_shadow_tx_);
|
||||||
sub_ps.push_constant("activeColor", color);
|
sub_ps.push_constant("activeColor", color);
|
||||||
sub_ps.push_constant("densityScale", density_scale);
|
sub_ps.push_constant("densityScale", density_scale);
|
||||||
sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture));
|
sub_ps.push_constant("volumeObjectToTexture", float4x4(grid->object_to_texture));
|
||||||
sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object));
|
sub_ps.push_constant("volumeTextureToObject", float4x4(grid->texture_to_object));
|
||||||
|
|
||||||
|
if (use_slice) {
|
||||||
|
setup_slice_ps(sub_ps, ob, 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;
|
||||||
|
|
||||||
|
setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size);
|
||||||
|
}
|
||||||
|
|
||||||
sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
|
sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void 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) {
|
||||||
|
setup_slice_ps(sub_ps, ob, settings.slice_axis, settings.slice_depth);
|
||||||
|
/* TODO (Miguel Pozo): Why is a quad used here, but not in volume? */
|
||||||
|
sub_ps.draw(DRW_cache_quad_get(), manager.resource_handle(ob_ref));
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
|
||||||
|
setup_non_slice_ps(sub_ps, ob, scene_state.sample, slice_count, world_size);
|
||||||
|
sub_ps.draw(DRW_cache_cube_get(), manager.resource_handle(ob_ref));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void draw(Manager &manager, View &view, SceneResources &resources)
|
void draw(Manager &manager, View &view, SceneResources &resources)
|
||||||
{
|
{
|
||||||
if (!active_) {
|
if (!active_) {
|
||||||
|
@ -324,9 +432,8 @@ class Instance {
|
||||||
if (md && BKE_modifier_is_enabled(scene_state.scene, md, eModifierMode_Realtime)) {
|
if (md && BKE_modifier_is_enabled(scene_state.scene, md, eModifierMode_Realtime)) {
|
||||||
FluidModifierData *fmd = (FluidModifierData *)md;
|
FluidModifierData *fmd = (FluidModifierData *)md;
|
||||||
if (fmd->domain) {
|
if (fmd->domain) {
|
||||||
#if 0 /* TODO(@pragma37): */
|
volume_ps.object_sync_modifier(manager, resources, scene_state, ob_ref, md);
|
||||||
workbench_volume_cache_populate(vedata, wpd->scene, ob, md, V3D_SHADING_SINGLE_COLOR);
|
|
||||||
#endif
|
|
||||||
if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
|
if (fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) {
|
||||||
return; /* Do not draw solid in this case. */
|
return; /* Do not draw solid in this case. */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue