WIP: Brush assets project #106303

Draft
Julian Eisel wants to merge 358 commits from brush-assets-project into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
165 changed files with 2831 additions and 1223 deletions
Showing only changes of commit 3f0259fad9 - Show all commits

View File

@ -723,6 +723,8 @@ struct GWL_SeatStatePointerScroll {
int32_t discrete_xy[2] = {0, 0};
/** Discrete scrolling, v8 of the seat API (handled & reset with pointer "frame" callback). */
int32_t discrete120_xy[2] = {0, 0};
/** Accumulated value from `discrete120_xy`, not reset between "frame" callbacks. */
int32_t discrete120_xy_accum[2] = {0, 0};
/** True when the axis is inverted (also known is "natural" scrolling). */
bool inverted_xy[2] = {false, false};
/** The source of scroll event. */
@ -3813,12 +3815,13 @@ static void pointer_handle_frame(void *data, wl_pointer * /*wl_pointer*/)
/* Handle value120 to discrete steps first. */
if (seat->pointer_scroll.discrete120_xy[0] || seat->pointer_scroll.discrete120_xy[1]) {
/* The values will have been normalized so 120 represents a single click-step. */
seat->pointer_scroll.discrete_xy[0] = seat->pointer_scroll.discrete120_xy[0] / 120;
seat->pointer_scroll.discrete_xy[1] = seat->pointer_scroll.discrete120_xy[1] / 120;
seat->pointer_scroll.discrete120_xy[0] = 0;
seat->pointer_scroll.discrete120_xy[1] = 0;
for (int i = 0; i < 2; i++) {
seat->pointer_scroll.discrete120_xy_accum[i] += seat->pointer_scroll.discrete120_xy[i];
seat->pointer_scroll.discrete120_xy[i] = 0;
/* The values will have been normalized so 120 represents a single click-step. */
seat->pointer_scroll.discrete_xy[i] = seat->pointer_scroll.discrete120_xy_accum[i] / 120;
seat->pointer_scroll.discrete120_xy_accum[i] -= seat->pointer_scroll.discrete_xy[i] * 120;
}
}
/* Multiple wheel events may have been generated and it's not known which.

View File

@ -4,7 +4,6 @@ options = eevee.ray_tracing_options
eevee.ray_tracing_method = 'SCREEN'
options.resolution_scale = '2'
options.sample_clamp = 10.0
options.trace_max_roughness = 0.5
options.screen_trace_quality = 0.25
options.screen_trace_thickness = 0.20000000298023224

View File

@ -541,7 +541,6 @@ class AddPresetEEVEERaytracing(AddPresetBase, Operator):
preset_values = [
"eevee.ray_tracing_method",
"options.resolution_scale",
"options.sample_clamp",
"options.trace_max_roughness",
"options.screen_trace_quality",
"options.screen_trace_thickness",

View File

@ -720,6 +720,7 @@ class NODE_MT_geometry_node_GEO_VOLUME_OPERATIONS(Menu):
node_add_menu.add_node_type(layout, "GeometryNodeVolumeToMesh")
if context.preferences.experimental.use_new_volume_nodes:
node_add_menu.add_node_type(layout, "GeometryNodeGridToMesh")
node_add_menu.add_node_type(layout, "GeometryNodeSDFGridBoolean")
node_add_menu.draw_assets_for_catalog(layout, "Volume/Operations")

View File

@ -721,11 +721,9 @@ class RENDER_PT_eevee_next_clamping_surface(RenderButtonsPanel, Panel):
scene = context.scene
props = scene.eevee
# TODO(fclem): Add clamp properties
options = props.ray_tracing_options
layout.prop(options, "sample_clamp", text="Indirect Light")
# layout.prop(props, "clamp_surface_direct", text="Direct Light")
# layout.prop(props, "clamp_surface_indirect", text="Indirect Light")
col = layout.column(align=True)
col.prop(props, "clamp_surface_direct", text="Direct Light")
col.prop(props, "clamp_surface_indirect", text="Indirect Light")
class RENDER_PT_eevee_next_clamping_volume(RenderButtonsPanel, Panel):
@ -743,9 +741,10 @@ class RENDER_PT_eevee_next_clamping_volume(RenderButtonsPanel, Panel):
layout.use_property_decorate = False
scene = context.scene
props = scene.eevee
layout.prop(props, "volumetric_light_clamp", text="Direct Light")
# layout.prop(props, "clamp_volumetric_direct", text="Direct Light")
# layout.prop(props, "clamp_volumetric_indirect", text="Indirect Light")
col = layout.column(align=True)
col.prop(props, "clamp_volume_direct", text="Direct Light")
col.prop(props, "clamp_volume_indirect", text="Indirect Light")
class RENDER_PT_eevee_next_sampling_shadows(RenderButtonsPanel, Panel):

View File

@ -2764,6 +2764,7 @@ class SEQUENCER_PT_snapping(Panel):
col = layout.column(heading="Snap to", align=True)
col.prop(sequencer_tool_settings, "snap_to_current_frame")
col.prop(sequencer_tool_settings, "snap_to_hold_offset")
col.prop(sequencer_tool_settings, "snap_to_markers")
col = layout.column(heading="Ignore", align=True)
col.prop(sequencer_tool_settings, "snap_ignore_muted", text="Muted Strips")

View File

@ -2720,6 +2720,23 @@ class _defs_gpencil_weight:
]
class _defs_grease_pencil_weight:
@staticmethod
def generate_from_brushes(context):
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
icon_prefix="ops.gpencil.sculpt_",
type=bpy.types.Brush,
# Uses GPv2 tool settings
attr="gpencil_weight_tool",
# tooldef_keywords=dict(
# operator="grease_pencil.weight_paint",
# ),
)
class _defs_curves_sculpt:
@staticmethod
@ -3533,6 +3550,11 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_annotate,
],
'WEIGHT_GREASE_PENCIL': [
_defs_grease_pencil_weight.generate_from_brushes,
None,
*_tools_annotate,
],
'VERTEX_GPENCIL': [
_defs_gpencil_vertex.generate_from_brushes,
None,

View File

@ -1188,12 +1188,11 @@ class VIEW3D_MT_editor_menus(Menu):
elif mode_string == 'VERTEX_GPENCIL':
layout.menu("VIEW3D_MT_select_edit_gpencil")
elif mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX', 'PAINT_TEXTURE'}:
if obj.type == 'MESH':
mesh = obj.data
if mesh.use_paint_mask:
layout.menu("VIEW3D_MT_select_paint_mask")
elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
layout.menu("VIEW3D_MT_select_paint_mask_vertex")
mesh = obj.data
if mesh.use_paint_mask:
layout.menu("VIEW3D_MT_select_paint_mask")
elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
layout.menu("VIEW3D_MT_select_paint_mask_vertex")
elif mode_string not in {'SCULPT', 'SCULPT_CURVES', 'PAINT_GREASE_PENCIL', 'SCULPT_GREASE_PENCIL'}:
layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
@ -3611,10 +3610,8 @@ class VIEW3D_MT_paint_weight(Menu):
layout.menu("VIEW3D_MT_paint_weight_lock", text="Locks")
def draw(self, context):
obj = context.active_object
if obj.type == 'MESH':
self.draw_generic(self.layout, is_editmode=False)
def draw(self, _context):
self.draw_generic(self.layout, is_editmode=False)
class VIEW3D_MT_sculpt(Menu):

View File

@ -37,6 +37,9 @@ enum class SingleKeyingResult {
FCURVE_NOT_KEYFRAMEABLE,
NO_KEY_NEEDED,
UNABLE_TO_INSERT_TO_NLA_STACK,
ID_NOT_EDITABLE,
ID_NOT_ANIMATABLE,
CANNOT_RESOLVE_PATH,
/* Make sure to always keep this at the end of the enum. */
_KEYING_RESULT_MAX,
};
@ -85,15 +88,14 @@ void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop);
* \param array_index: The index to key or -1 keys all array indices.
* \return The number of key-frames inserted.
*/
int insert_keyframe(Main *bmain,
ReportList *reports,
ID *id,
const char group[],
const char rna_path[],
int array_index,
const AnimationEvalContext *anim_eval_context,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag);
CombinedKeyingResult insert_keyframe(Main *bmain,
ID &id,
const char group[],
const char rna_path[],
int array_index,
const AnimationEvalContext *anim_eval_context,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag);
/**
* \brief Secondary Insert Key-framing API call.

View File

@ -127,6 +127,40 @@ void CombinedKeyingResult::generate_reports(ReportList *reports)
error_count > 1 ? "s have" : " has"));
}
if (this->get_count(SingleKeyingResult::ID_NOT_EDITABLE) > 0) {
const int error_count = this->get_count(SingleKeyingResult::ID_NOT_EDITABLE);
if (error_count == 1) {
errors.append("Inserting keys for one ID has been skipped because it is not editable.");
}
else {
errors.append(
fmt::format("{} IDs have been skipped because they are not editable.", error_count));
}
}
if (this->get_count(SingleKeyingResult::ID_NOT_ANIMATABLE) > 0) {
const int error_count = this->get_count(SingleKeyingResult::ID_NOT_ANIMATABLE);
if (error_count == 1) {
errors.append("Inserting keys for one ID has been skipped because it cannot be animated.");
}
else {
errors.append(
fmt::format("{} IDs have been skipped because they cannot be animated.", error_count));
}
}
if (this->get_count(SingleKeyingResult::CANNOT_RESOLVE_PATH) > 0) {
const int error_count = this->get_count(SingleKeyingResult::CANNOT_RESOLVE_PATH);
if (error_count == 1) {
errors.append(
"Inserting keys for one ID has been skipped because the RNA path wasn't valid for it");
}
else {
errors.append(fmt::format(
"{} IDs have been skipped because the RNA path wasn't valid for them.", error_count));
}
}
if (errors.is_empty()) {
BKE_report(reports, RPT_WARNING, "Encountered unhandled error during keyframing");
return;
@ -556,54 +590,40 @@ static SingleKeyingResult insert_keyframe_fcurve_value(Main *bmain,
return result;
}
int insert_keyframe(Main *bmain,
ReportList *reports,
ID *id,
const char group[],
const char rna_path[],
int array_index,
const AnimationEvalContext *anim_eval_context,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag)
CombinedKeyingResult insert_keyframe(Main *bmain,
ID &id,
const char group[],
const char rna_path[],
int array_index,
const AnimationEvalContext *anim_eval_context,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag)
{
if (id == nullptr) {
BKE_reportf(reports, RPT_ERROR, "No ID block to insert keyframe in (path = %s)", rna_path);
return 0;
}
CombinedKeyingResult combined_result;
if (!BKE_id_is_editable(bmain, id)) {
BKE_reportf(reports, RPT_ERROR, "'%s' on %s is not editable", rna_path, id->name + 2);
return 0;
if (!BKE_id_is_editable(bmain, &id)) {
combined_result.add(SingleKeyingResult::ID_NOT_EDITABLE);
return combined_result;
}
PointerRNA ptr;
PropertyRNA *prop = nullptr;
PointerRNA id_ptr = RNA_id_pointer_create(id);
PointerRNA id_ptr = RNA_id_pointer_create(&id);
if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop) == false) {
BKE_reportf(
reports,
RPT_ERROR,
"Could not insert keyframe, as RNA path is invalid for the given ID (ID = %s, path = %s)",
(id) ? id->name : RPT_("<Missing ID block>"),
rna_path);
return 0;
combined_result.add(SingleKeyingResult::CANNOT_RESOLVE_PATH);
return combined_result;
}
bAction *act = id_action_ensure(bmain, id);
bAction *act = id_action_ensure(bmain, &id);
if (act == nullptr) {
BKE_reportf(reports,
RPT_ERROR,
"Could not insert keyframe, as this type does not support animation data (ID = "
"%s, path = %s)",
id->name,
rna_path);
return 0;
combined_result.add(SingleKeyingResult::ID_NOT_ANIMATABLE);
return combined_result;
}
/* Apply NLA-mapping to frame to use (if applicable). */
NlaKeyframingContext *nla_context = nullptr;
ListBase nla_cache = {nullptr, nullptr};
AnimData *adt = BKE_animdata_from_id(id);
AnimData *adt = BKE_animdata_from_id(&id);
const float nla_mapped_frame = nla_time_remap(
anim_eval_context, &id_ptr, adt, act, &nla_cache, &nla_context);
@ -611,17 +631,15 @@ int insert_keyframe(Main *bmain,
Vector<float> values = get_keyframe_values(&ptr, prop, visual_keyframing);
bool force_all;
BitVector<> successful_remaps = nla_map_keyframe_values_and_generate_reports(
values.as_mutable_span(),
array_index,
ptr,
*prop,
nla_context,
anim_eval_context,
reports,
&force_all);
CombinedKeyingResult combined_result;
BitVector<> successful_remaps(values.size(), false);
BKE_animsys_nla_remap_keyframe_values(nla_context,
&ptr,
prop,
values,
array_index,
anim_eval_context,
&force_all,
successful_remaps);
/* Key the entire array. */
int key_count = 0;
@ -738,11 +756,7 @@ int insert_keyframe(Main *bmain,
}
}
if (key_count == 0) {
combined_result.generate_reports(reports);
}
return key_count;
return combined_result;
}
/* ************************************************** */

View File

@ -99,6 +99,10 @@ bool autokeyframe_cfra_can_key(const Scene *scene, ID *id)
void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span<std::string> rna_paths)
{
BLI_assert(ob != nullptr);
BLI_assert(scene != nullptr);
BLI_assert(C != nullptr);
ID *id = &ob->id;
if (!autokeyframe_cfra_can_key(scene, id)) {
return;
@ -134,16 +138,20 @@ void autokeyframe_object(bContext *C, Scene *scene, Object *ob, Span<std::string
Main *bmain = CTX_data_main(C);
if (adt && adt->action) {
CombinedKeyingResult combined_result;
LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) {
insert_keyframe(bmain,
reports,
id,
(fcu->grp ? fcu->grp->name : nullptr),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
CombinedKeyingResult result = insert_keyframe(bmain,
*id,
(fcu->grp ? fcu->grp->name : nullptr),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
combined_result.merge(result);
}
if (combined_result.get_count(SingleKeyingResult::SUCCESS) == 0) {
combined_result.generate_reports(reports);
}
}
return;
@ -206,6 +214,11 @@ void autokeyframe_pose_channel(bContext *C,
Span<std::string> rna_paths,
short targetless_ik)
{
BLI_assert(C != nullptr);
BLI_assert(scene != nullptr);
BLI_assert(ob != nullptr);
BLI_assert(pose_channel != nullptr);
Main *bmain = CTX_data_main(C);
ID *id = &ob->id;
AnimData *adt = ob->adt;
@ -234,12 +247,12 @@ void autokeyframe_pose_channel(bContext *C,
flag |= INSERTKEY_MATRIX;
}
blender::Vector<PointerRNA> sources;
Vector<PointerRNA> sources;
/* Add data-source override for the camera object. */
ANIM_relative_keyingset_add_source(sources, id, &RNA_PoseBone, pose_channel);
/* only insert into active keyingset? */
if (blender::animrig::is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) {
if (is_keying_flag(scene, AUTOKEY_FLAG_ONLYKEYINGSET) && (active_ks)) {
/* Run the active Keying Set on the current data-source. */
ANIM_apply_keyingset(
C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
@ -247,7 +260,7 @@ void autokeyframe_pose_channel(bContext *C,
}
/* only insert into available channels? */
if (blender::animrig::is_keying_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
if (is_keying_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
if (!act) {
return;
}
@ -262,15 +275,17 @@ void autokeyframe_pose_channel(bContext *C,
* NOTE: this will do constraints too, but those are ok to do here too?
*/
if (STREQ(pchan_name, pose_channel->name)) {
blender::animrig::insert_keyframe(bmain,
reports,
id,
((fcu->grp) ? (fcu->grp->name) : (nullptr)),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
CombinedKeyingResult result = insert_keyframe(bmain,
*id,
((fcu->grp) ? (fcu->grp->name) : (nullptr)),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
if (result.get_count(SingleKeyingResult::SUCCESS) == 0) {
result.generate_reports(reports);
}
}
}
return;
@ -302,7 +317,6 @@ bool autokeyframe_property(bContext *C,
bAction *action;
bool driven;
bool special;
bool changed = false;
/* For entire array buttons we check the first component, it's not perfect
* but works well enough in typical cases. */
@ -313,13 +327,14 @@ bool autokeyframe_property(bContext *C,
/* Only early out when we actually want an existing F-curve already
* (e.g. auto-keyframing from buttons). */
if (fcu == nullptr && (driven || special || only_if_property_keyed)) {
return changed;
return false;
}
if (driven) {
return false;
}
bool changed = false;
if (special) {
/* NLA Strip property. */
if (is_autokey_on(scene)) {
@ -343,7 +358,6 @@ bool autokeyframe_property(bContext *C,
/* TODO: this should probably respect the keyingset only option for anim */
if (autokeyframe_cfra_can_key(scene, id)) {
ReportList *reports = CTX_wm_reports(C);
ToolSettings *ts = scene->toolsettings;
const eInsertKeyFlags flag = get_autokey_flags(scene);
const std::optional<std::string> path = RNA_path_from_ID_to_property(ptr, prop);
@ -354,16 +368,16 @@ bool autokeyframe_property(bContext *C,
* E.g., color wheels (see #42567). */
BLI_assert((fcu->array_index == rnaindex) || (rnaindex == -1));
}
changed = insert_keyframe(bmain,
reports,
id,
(fcu && fcu->grp) ? fcu->grp->name : nullptr,
fcu ? fcu->rna_path : (path ? path->c_str() : nullptr),
rnaindex,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag) != 0;
CombinedKeyingResult result = insert_keyframe(bmain,
*id,
(fcu && fcu->grp) ? fcu->grp->name : nullptr,
fcu ? fcu->rna_path :
(path ? path->c_str() : nullptr),
rnaindex,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
changed = result.get_count(SingleKeyingResult::SUCCESS) != 0;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, nullptr);
}
}

View File

@ -142,8 +142,9 @@ enum eContextObjectMode {
CTX_MODE_SCULPT_CURVES,
CTX_MODE_PAINT_GREASE_PENCIL,
CTX_MODE_SCULPT_GREASE_PENCIL,
CTX_MODE_WEIGHT_GREASE_PENCIL,
};
#define CTX_MODE_NUM (CTX_MODE_SCULPT_GREASE_PENCIL + 1)
#define CTX_MODE_NUM (CTX_MODE_WEIGHT_GREASE_PENCIL + 1)
/* Context */

View File

@ -1277,6 +1277,7 @@ void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index
#define GEO_NODE_POINTS_TO_SDF_GRID 2128
#define GEO_NODE_GRID_TO_MESH 2129
#define GEO_NODE_DISTRIBUTE_POINTS_IN_GRID 2130
#define GEO_NODE_SDF_GRID_BOOLEAN 2131
/** \} */

View File

@ -17,6 +17,7 @@ set(INC
../makesrna
../modifiers
../nodes
../nodes/geometry/include
../render
../sequencer
../shader_fx

View File

@ -1197,7 +1197,12 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
}
}
if (object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) {
return CTX_MODE_WEIGHT_GPENCIL_LEGACY;
if (ob->type == OB_GPENCIL_LEGACY) {
return CTX_MODE_WEIGHT_GPENCIL_LEGACY;
}
if (ob->type == OB_GREASE_PENCIL) {
return CTX_MODE_WEIGHT_GREASE_PENCIL;
}
}
if (object_mode & OB_MODE_VERTEX_GPENCIL_LEGACY) {
return CTX_MODE_VERTEX_GPENCIL_LEGACY;
@ -1252,6 +1257,7 @@ static const char *data_mode_strings[] = {
"curves_sculpt",
"grease_pencil_paint",
"grease_pencil_sculpt",
"grease_pencil_weight",
nullptr,
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1,

View File

@ -2934,9 +2934,6 @@ static void read_drawing_array(GreasePencil &grease_pencil, BlendDataReader *rea
break;
}
case GP_DRAWING_REFERENCE: {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
BLO_read_data_address(reader, &drawing_reference->id_reference);
break;
}
}

View File

@ -83,6 +83,10 @@
#include "NOD_common.h"
#include "NOD_composite.hh"
#include "NOD_geo_bake.hh"
#include "NOD_geo_index_switch.hh"
#include "NOD_geo_repeat.hh"
#include "NOD_geo_simulation.hh"
#include "NOD_geometry.hh"
#include "NOD_geometry_nodes_lazy_function.hh"
#include "NOD_node_declaration.hh"
@ -90,7 +94,6 @@
#include "NOD_shader.h"
#include "NOD_socket.hh"
#include "NOD_texture.h"
#include "NOD_zone_socket_items.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"

View File

@ -606,6 +606,7 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref)
return PaintMode::VertexGPencil;
case CTX_MODE_SCULPT_GPENCIL_LEGACY:
return PaintMode::SculptGPencil;
case CTX_MODE_WEIGHT_GREASE_PENCIL:
case CTX_MODE_WEIGHT_GPENCIL_LEGACY:
return PaintMode::WeightGPencil;
case CTX_MODE_SCULPT_CURVES:

View File

@ -499,20 +499,20 @@ int BLI_gset_buckets_len(const GSet *gs);
*
* Smaller is better!
*/
double BLI_ghash_calc_quality_ex(GHash *gh,
double BLI_ghash_calc_quality_ex(const GHash *gh,
double *r_load,
double *r_variance,
double *r_prop_empty_buckets,
double *r_prop_overloaded_buckets,
int *r_biggest_bucket);
double BLI_gset_calc_quality_ex(GSet *gs,
double BLI_gset_calc_quality_ex(const GSet *gs,
double *r_load,
double *r_variance,
double *r_prop_empty_buckets,
double *r_prop_overloaded_buckets,
int *r_biggest_bucket);
double BLI_ghash_calc_quality(GHash *gh);
double BLI_gset_calc_quality(GSet *gs);
double BLI_ghash_calc_quality(const GHash *gh);
double BLI_gset_calc_quality(const GSet *gs);
#endif /* GHASH_INTERNAL_API */
/** \} */

View File

@ -36,7 +36,7 @@ typedef struct LinkNodePair {
} LinkNodePair;
int BLI_linklist_count(const LinkNode *list) ATTR_WARN_UNUSED_RESULT;
int BLI_linklist_index(const LinkNode *list, void *ptr) ATTR_WARN_UNUSED_RESULT;
int BLI_linklist_index(const LinkNode *list, const void *ptr) ATTR_WARN_UNUSED_RESULT;
LinkNode *BLI_linklist_find(LinkNode *list, int index) ATTR_WARN_UNUSED_RESULT;
LinkNode *BLI_linklist_find_last(LinkNode *list) ATTR_WARN_UNUSED_RESULT;

View File

@ -1089,7 +1089,7 @@ int BLI_gset_buckets_len(const GSet *gs)
return BLI_ghash_buckets_len((const GHash *)gs);
}
double BLI_ghash_calc_quality_ex(GHash *gh,
double BLI_ghash_calc_quality_ex(const GHash *gh,
double *r_load,
double *r_variance,
double *r_prop_empty_buckets,
@ -1176,14 +1176,14 @@ double BLI_ghash_calc_quality_ex(GHash *gh,
((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
}
}
double BLI_gset_calc_quality_ex(GSet *gs,
double BLI_gset_calc_quality_ex(const GSet *gs,
double *r_load,
double *r_variance,
double *r_prop_empty_buckets,
double *r_prop_overloaded_buckets,
int *r_biggest_bucket)
{
return BLI_ghash_calc_quality_ex((GHash *)gs,
return BLI_ghash_calc_quality_ex((const GHash *)gs,
r_load,
r_variance,
r_prop_empty_buckets,
@ -1191,11 +1191,11 @@ double BLI_gset_calc_quality_ex(GSet *gs,
r_biggest_bucket);
}
double BLI_ghash_calc_quality(GHash *gh)
double BLI_ghash_calc_quality(const GHash *gh)
{
return BLI_ghash_calc_quality_ex(gh, NULL, NULL, NULL, NULL, NULL);
}
double BLI_gset_calc_quality(GSet *gs)
double BLI_gset_calc_quality(const GSet *gs)
{
return BLI_ghash_calc_quality_ex((GHash *)gs, NULL, NULL, NULL, NULL, NULL);
}

View File

@ -32,7 +32,7 @@ int BLI_linklist_count(const LinkNode *list)
return len;
}
int BLI_linklist_index(const LinkNode *list, void *ptr)
int BLI_linklist_index(const LinkNode *list, const void *ptr)
{
int index;

View File

@ -197,7 +197,7 @@ BLI_INLINE uint mempool_maxchunks(const uint elem_num, const uint pchunk)
return (elem_num <= pchunk) ? 1 : ((elem_num / pchunk) + 1);
}
static BLI_mempool_chunk *mempool_chunk_alloc(BLI_mempool *pool)
static BLI_mempool_chunk *mempool_chunk_alloc(const BLI_mempool *pool)
{
return MEM_mallocN(sizeof(BLI_mempool_chunk) + (size_t)pool->csize, "mempool chunk");
}

View File

@ -66,6 +66,7 @@
#include "BKE_tracking.h"
#include "SEQ_iterator.hh"
#include "SEQ_sequencer.hh"
#include "ANIM_armature_iter.hh"
#include "ANIM_bone_collections.hh"
@ -2859,7 +2860,6 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
scene->eevee.ray_tracing_options.screen_trace_quality = 0.25f;
scene->eevee.ray_tracing_options.screen_trace_thickness = 0.2f;
scene->eevee.ray_tracing_options.trace_max_roughness = 0.5f;
scene->eevee.ray_tracing_options.sample_clamp = 10.0f;
scene->eevee.ray_tracing_options.resolution_scale = 2;
}
}
@ -3216,6 +3216,17 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
/* Keep legacy EEVEE old behavior. */
scene->eevee.flag |= SCE_EEVEE_VOLUME_CUSTOM_RANGE;
}
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
scene->eevee.clamp_surface_indirect = 10.0f;
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 20)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
SequencerToolSettings *sequencer_tool_settings = SEQ_tool_settings_ensure(scene);
sequencer_tool_settings->snap_mode |= SEQ_SNAP_TO_MARKERS;
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 20)) {

View File

@ -125,8 +125,8 @@ MemoryBuffer *MemoryBuffer::inflate() const
float MemoryBuffer::get_max_value() const
{
float result = buffer_[0];
const uint size = this->buffer_len();
uint i;
const int64_t size = this->buffer_len();
int64_t i;
const float *fp_src = buffer_;
@ -408,7 +408,7 @@ void MemoryBuffer::fill_from(const MemoryBuffer &src)
void MemoryBuffer::write_pixel(int x, int y, const float color[4])
{
if (x >= rect_.xmin && x < rect_.xmax && y >= rect_.ymin && y < rect_.ymax) {
const int offset = get_coords_offset(x, y);
const intptr_t offset = get_coords_offset(x, y);
memcpy(&buffer_[offset], color, sizeof(float) * num_channels_);
}
}
@ -416,7 +416,7 @@ void MemoryBuffer::write_pixel(int x, int y, const float color[4])
void MemoryBuffer::add_pixel(int x, int y, const float color[4])
{
if (x >= rect_.xmin && x < rect_.xmax && y >= rect_.ymin && y < rect_.ymax) {
const int offset = get_coords_offset(x, y);
const intptr_t offset = get_coords_offset(x, y);
float *dst = &buffer_[offset];
const float *src = color;
for (int i = 0; i < num_channels_; i++, dst++, src++) {

View File

@ -15,6 +15,7 @@
#include "BLI_math_vector_types.hh"
#include "BLI_rect.h"
#include <cstdint>
#include <cstring>
struct ColormanageProcessor;
@ -285,6 +286,12 @@ class MemoryBuffer {
get_relative_y(y));
}
void read_elem_bicubic_bspline(float x, float y, float *out) const
{
math::interpolate_cubic_bspline_fl(
buffer_, out, this->get_width(), this->get_height(), num_channels_, x, y);
}
void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const
{
switch (sampler) {
@ -292,10 +299,12 @@ class MemoryBuffer {
read_elem_checked(x, y, out);
break;
case PixelSampler::Bilinear:
case PixelSampler::Bicubic:
/* No bicubic. Current implementation produces fuzzy results. */
read_elem_bilinear(x, y, out);
break;
case PixelSampler::Bicubic:
/* Using same method as GPU compositor. Final results may still vary. */
read_elem_bicubic_bspline(x, y, out);
break;
}
}
@ -649,9 +658,9 @@ class MemoryBuffer {
private:
void set_strides();
const int buffer_len() const
const int64_t buffer_len() const
{
return get_memory_width() * get_memory_height();
return int64_t(get_memory_width()) * int64_t(get_memory_height());
}
void clear_elem(float *out) const

View File

@ -17,6 +17,7 @@
#include "BKE_geometry_set.hh"
#include "BKE_idprop.hh"
#include "BKE_layer.hh"
#include "BKE_modifier.hh"
#include "BKE_node.hh"
#include "BKE_object.hh"
#include "BKE_object_types.hh"
@ -302,6 +303,38 @@ DEGObjectIterData &DEGObjectIterData::operator=(const DEGObjectIterData &other)
return *this;
}
static Object *find_object_with_preview_geometry(const ViewerPath &viewer_path)
{
if (BLI_listbase_is_empty(&viewer_path.path)) {
return nullptr;
}
const ViewerPathElem *elem = static_cast<const ViewerPathElem *>(viewer_path.path.first);
if (elem->type != VIEWER_PATH_ELEM_TYPE_ID) {
return nullptr;
}
const IDViewerPathElem *id_elem = reinterpret_cast<const IDViewerPathElem *>(elem);
if (id_elem->id == nullptr) {
return nullptr;
}
if (GS(id_elem->id->name) != ID_OB) {
return nullptr;
}
Object *object = reinterpret_cast<Object *>(id_elem->id);
if (elem->next->type != VIEWER_PATH_ELEM_TYPE_MODIFIER) {
return nullptr;
}
const ModifierViewerPathElem *modifier_elem = reinterpret_cast<const ModifierViewerPathElem *>(
elem->next);
ModifierData *md = BKE_modifiers_findby_name(object, modifier_elem->modifier_name);
if (md == nullptr) {
return nullptr;
}
if (!(md->mode & eModifierMode_Realtime)) {
return nullptr;
}
return reinterpret_cast<Object *>(id_elem->id);
}
void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
{
Depsgraph *depsgraph = data->graph;
@ -329,17 +362,7 @@ void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
/* Determine if the preview of any object should be in the iterator. */
const ViewerPath *viewer_path = data->settings->viewer_path;
if (viewer_path != nullptr) {
if (!BLI_listbase_is_empty(&viewer_path->path)) {
const ViewerPathElem *elem = static_cast<const ViewerPathElem *>(viewer_path->path.first);
if (elem->type == VIEWER_PATH_ELEM_TYPE_ID) {
const IDViewerPathElem *id_elem = reinterpret_cast<const IDViewerPathElem *>(elem);
if (id_elem->id != nullptr) {
if (GS(id_elem->id->name) == ID_OB) {
data->object_orig_with_preview = reinterpret_cast<Object *>(id_elem->id);
}
}
}
}
data->object_orig_with_preview = find_object_with_preview_geometry(*viewer_path);
}
DEG_iterator_objects_next(iter);

View File

@ -681,11 +681,11 @@ enum EEVEE_EffectsFlag {
EFFECT_TAA = (1 << 8),
EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */
EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */
EFFECT_RADIANCE_BUFFER = (1 << 10), /* Not really an effect but a feature */
EFFECT_SSS = (1 << 11),
EFFECT_VELOCITY_BUFFER = (1 << 12), /* Not really an effect but a feature */
EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */
EFFECT_DEPTH_DOUBLE_BUFFER = (1 << 14), /* Not really an effect but a feature */
EFFECT_RADIANCE_BUFFER = (1 << 11), /* Not really an effect but a feature */
EFFECT_SSS = (1 << 12),
EFFECT_VELOCITY_BUFFER = (1 << 13), /* Not really an effect but a feature */
EFFECT_TAA_REPROJECT = (1 << 14), /* should be mutually exclusive with EFFECT_TAA */
EFFECT_DEPTH_DOUBLE_BUFFER = (1 << 15), /* Not really an effect but a feature */
};
ENUM_OPERATORS(EEVEE_EffectsFlag, EFFECT_DEPTH_DOUBLE_BUFFER)

View File

@ -154,7 +154,7 @@ class Instance {
depth_of_field(*this),
cryptomatte(*this),
hiz_buffer(*this, uniform_data.data.hiz),
sampling(*this),
sampling(*this, uniform_data.data.clamp),
camera(*this, uniform_data.data.camera),
film(*this, uniform_data.data.film),
render_buffers(*this, uniform_data.data.render_pass),

View File

@ -248,6 +248,7 @@ void VolumeProbeModule::set_view(View & /*view*/)
if (do_update_world_) {
grid_upload_ps_.init();
grid_upload_ps_.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_WORLD));
grid_upload_ps_.bind_resources(inst_.uniform_data);
grid_upload_ps_.bind_ssbo("harmonic_buf", &inst_.sphere_probes.spherical_harmonics_buf());
grid_upload_ps_.bind_ubo("grids_infos_buf", &grids_infos_buf_);
grid_upload_ps_.bind_ssbo("bricks_infos_buf", &bricks_infos_buf_);
@ -364,6 +365,7 @@ void VolumeProbeModule::set_view(View & /*view*/)
grid_upload_ps_.init();
grid_upload_ps_.shader_set(inst_.shaders.static_shader_get(LIGHTPROBE_IRRADIANCE_LOAD));
grid_upload_ps_.bind_resources(inst_.uniform_data);
grid_upload_ps_.push_constant("validity_threshold", grid->validity_threshold);
grid_upload_ps_.push_constant("dilation_threshold", grid->dilation_threshold);
grid_upload_ps_.push_constant("dilation_radius", grid->dilation_radius);
@ -1034,7 +1036,7 @@ void IrradianceBake::surfels_lights_eval()
inst_.render_buffers.acquire(int2(1));
inst_.hiz_buffer.set_source(&inst_.render_buffers.depth_tx);
inst_.lights.set_view(view_z_, grid_pixel_extent_.xy());
inst_.shadows.set_view(view_z_, inst_.render_buffers.depth_tx);
inst_.shadows.set_view(view_z_, grid_pixel_extent_.xy());
inst_.render_buffers.release();
inst_.manager->submit(surfel_light_eval_ps_, view_z_);

View File

@ -86,14 +86,6 @@ void LightProbeModule::sync_volume(const Object *ob, ObjectHandle &handle)
grid.object_to_world = ob->object_to_world();
grid.cache = ob->lightprobe_cache;
/* Needed for display. */
// LightProbeGridCacheFrame *cache = grid.cache ? grid.cache->grid_static_cache : nullptr;
// if (cache != nullptr) {
// int3 grid_size = int3(cache->size);
// /* Offset sample placement so that border texels are on the edges of the volume. */
// float3 grid_scale = float3(grid_size) / float3(grid_size + 1);
// grid.object_to_world *= math::from_scale<float4x4>(grid_scale);
// }
grid.world_to_object = float4x4(
math::normalize(math::transpose(float3x3(grid.object_to_world))));
@ -150,7 +142,8 @@ void LightProbeModule::sync_sphere(const Object *ob, ObjectHandle &handle)
return (bl_shape_type == LIGHTPROBE_SHAPE_BOX) ? SHAPE_CUBOID : SHAPE_ELIPSOID;
};
cube.influence_shape = to_eevee_shape(light_probe.attenuation_type);
cube.parallax_shape = to_eevee_shape(light_probe.parallax_type);
cube.parallax_shape = to_eevee_shape(use_custom_parallax ? light_probe.parallax_type :
light_probe.attenuation_type);
float4x4 object_to_world = math::scale(ob->object_to_world(), float3(influence_distance));
cube.location = object_to_world.location();

View File

@ -403,7 +403,10 @@ PassMain::Sub *ForwardPipeline::material_transparent_add(const Object *ob,
return pass;
}
void ForwardPipeline::render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb)
void ForwardPipeline::render(View &view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
int2 extent)
{
if (!has_transparent_ && !has_opaque_) {
inst_.volume.draw_resolve(view);
@ -417,7 +420,7 @@ void ForwardPipeline::render(View &view, Framebuffer &prepass_fb, Framebuffer &c
inst_.hiz_buffer.set_dirty();
inst_.shadows.set_view(view, inst_.render_buffers.depth_tx);
inst_.shadows.set_view(view, extent);
inst_.volume_probes.set_view(view);
if (has_opaque_) {
@ -528,9 +531,24 @@ void DeferredLayer::begin_sync()
this->gbuffer_pass_sync(inst_);
}
void DeferredLayer::end_sync()
void DeferredLayer::end_sync(bool is_first_pass, bool is_last_pass)
{
use_combined_lightprobe_eval = inst_.pipelines.data.use_combined_lightprobe_eval;
const SceneEEVEE &sce_eevee = inst_.scene->eevee;
const bool has_transmit_closure = (closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_TRANSLUCENT));
const bool has_reflect_closure = (closure_bits_ & (CLOSURE_REFLECTION | CLOSURE_DIFFUSE));
use_raytracing_ = (has_transmit_closure || has_reflect_closure) &&
(sce_eevee.flag & SCE_EEVEE_SSR_ENABLED) != 0;
use_clamp_direct_ = sce_eevee.clamp_surface_direct != 0.0f;
use_clamp_indirect_ = sce_eevee.clamp_surface_indirect != 0.0f;
/* The first pass will never have any surfaces behind it. Nothing is refracted except the
* environment. So in this case, disable tracing and fallback to probe. */
use_screen_transmission_ = use_raytracing_ && has_transmit_closure && !is_first_pass;
use_screen_reflection_ = use_raytracing_ && has_reflect_closure;
use_split_radiance_ = use_raytracing_ || (use_clamp_direct_ || use_clamp_indirect_);
use_feedback_output_ = use_raytracing_ && (!is_last_pass || use_screen_reflection_);
{
RenderBuffersInfoData &rbuf_data = inst_.render_buffers.data;
@ -569,6 +587,7 @@ void DeferredLayer::end_sync()
pass.init();
{
const bool use_split_indirect = !use_raytracing_ && use_split_radiance_;
PassSimple::Sub &sub = pass.sub("Eval.Light");
/* Use depth test to reject background pixels which have not been stencil cleared. */
/* WORKAROUND: Avoid rasterizer discard by enabling stencil write, but the shaders actually
@ -585,7 +604,8 @@ void DeferredLayer::end_sync()
* OpenGL and Vulkan implementation which aren't fully supporting the specialize
* constant. */
sub.specialize_constant(sh, "render_pass_shadow_enabled", rbuf_data.shadow_id != -1);
sub.specialize_constant(sh, "use_lightprobe_eval", use_combined_lightprobe_eval);
sub.specialize_constant(sh, "use_split_indirect", use_split_indirect);
sub.specialize_constant(sh, "use_lightprobe_eval", !use_raytracing_);
const ShadowSceneData &shadow_scene = inst_.shadows.get_data();
sub.specialize_constant(sh, "shadow_ray_count", &shadow_scene.ray_count);
sub.specialize_constant(sh, "shadow_ray_step_count", &shadow_scene.step_count);
@ -593,6 +613,9 @@ void DeferredLayer::end_sync()
sub.bind_image("direct_radiance_1_img", &direct_radiance_txs_[0]);
sub.bind_image("direct_radiance_2_img", &direct_radiance_txs_[1]);
sub.bind_image("direct_radiance_3_img", &direct_radiance_txs_[2]);
sub.bind_image("indirect_radiance_1_img", &indirect_result_.closures[0]);
sub.bind_image("indirect_radiance_2_img", &indirect_result_.closures[1]);
sub.bind_image("indirect_radiance_3_img", &indirect_result_.closures[2]);
sub.bind_resources(inst_.uniform_data);
sub.bind_resources(inst_.gbuffer);
sub.bind_resources(inst_.lights);
@ -621,8 +644,10 @@ void DeferredLayer::end_sync()
"render_pass_specular_light_enabled",
(rbuf_data.specular_light_id != -1) ||
(rbuf_data.specular_color_id != -1));
pass.specialize_constant(sh, "use_split_radiance", use_split_radiance_);
pass.specialize_constant(
sh, "use_radiance_feedback", use_feedback_output_ && use_clamp_direct_);
pass.specialize_constant(sh, "render_pass_normal_enabled", rbuf_data.normal_id != -1);
pass.specialize_constant(sh, "use_combined_lightprobe_eval", use_combined_lightprobe_eval);
pass.shader_set(sh);
/* Use stencil test to reject pixels not written by this layer. */
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL | DRW_STATE_STENCIL_NEQUAL);
@ -631,11 +656,12 @@ void DeferredLayer::end_sync()
pass.bind_texture("direct_radiance_1_tx", &direct_radiance_txs_[0]);
pass.bind_texture("direct_radiance_2_tx", &direct_radiance_txs_[1]);
pass.bind_texture("direct_radiance_3_tx", &direct_radiance_txs_[2]);
pass.bind_texture("indirect_radiance_1_tx", &indirect_radiance_txs_[0]);
pass.bind_texture("indirect_radiance_2_tx", &indirect_radiance_txs_[1]);
pass.bind_texture("indirect_radiance_3_tx", &indirect_radiance_txs_[2]);
pass.bind_texture("indirect_radiance_1_tx", &indirect_result_.closures[0]);
pass.bind_texture("indirect_radiance_2_tx", &indirect_result_.closures[1]);
pass.bind_texture("indirect_radiance_3_tx", &indirect_result_.closures[2]);
pass.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx);
pass.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
pass.bind_image("radiance_feedback_img", &radiance_feedback_tx_);
pass.bind_resources(inst_.gbuffer);
pass.bind_resources(inst_.uniform_data);
pass.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS);
@ -675,50 +701,28 @@ PassMain::Sub *DeferredLayer::material_add(::Material *blender_mat, GPUMaterial
return &pass->sub(GPU_material_get_name(gpumat));
}
void DeferredLayer::render(View &main_view,
View &render_view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
Framebuffer &gbuffer_fb,
int2 extent,
RayTraceBuffer &rt_buffer,
bool is_first_pass)
GPUTexture *DeferredLayer::render(View &main_view,
View &render_view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
Framebuffer &gbuffer_fb,
int2 extent,
RayTraceBuffer &rt_buffer,
GPUTexture *radiance_behind_tx)
{
if (closure_count_ == 0) {
return;
return nullptr;
}
RenderBuffers &rb = inst_.render_buffers;
/* The first pass will never have any surfaces behind it. Nothing is refracted except the
* environment. So in this case, disable tracing and fallback to probe. */
bool do_screen_space_refraction = !is_first_pass &&
(closure_bits_ & (CLOSURE_REFRACTION | CLOSURE_TRANSLUCENT));
bool do_screen_space_reflection = (closure_bits_ & (CLOSURE_REFLECTION | CLOSURE_DIFFUSE));
constexpr eGPUTextureUsage usage_read = GPU_TEXTURE_USAGE_SHADER_READ;
constexpr eGPUTextureUsage usage_write = GPU_TEXTURE_USAGE_SHADER_WRITE;
constexpr eGPUTextureUsage usage_rw = usage_read | usage_write;
if (do_screen_space_reflection) {
if (radiance_feedback_tx_.ensure_2d(rb.color_format, extent, usage_read)) {
radiance_feedback_tx_.clear(float4(0.0));
radiance_feedback_persmat_ = render_view.persmat();
}
}
else {
/* Dummy texture. Will not be used. */
radiance_feedback_tx_.ensure_2d(rb.color_format, int2(1), GPU_TEXTURE_USAGE_SHADER_READ);
}
if (do_screen_space_refraction) {
if (use_screen_transmission_) {
/* Update for refraction. */
inst_.hiz_buffer.update();
radiance_behind_tx_.ensure_2d(rb.color_format, extent, usage_read);
GPU_texture_copy(radiance_behind_tx_, rb.combined_tx);
}
else {
/* Dummy texture. Will not be used. */
radiance_behind_tx_.ensure_2d(rb.color_format, int2(1), GPU_TEXTURE_USAGE_SHADER_READ);
}
GPU_framebuffer_bind(prepass_fb);
@ -729,7 +733,7 @@ void DeferredLayer::render(View &main_view,
inst_.hiz_buffer.update();
inst_.volume_probes.set_view(render_view);
inst_.shadows.set_view(render_view, inst_.render_buffers.depth_tx);
inst_.shadows.set_view(render_view, extent);
inst_.gbuffer.bind(gbuffer_fb);
inst_.manager->submit(gbuffer_ps_, render_view);
@ -739,53 +743,48 @@ void DeferredLayer::render(View &main_view,
(closure_count_ > i) ? extent : int2(1), DEFERRED_RADIANCE_FORMAT, usage_rw);
}
RayTraceResult indirect_result;
if (use_combined_lightprobe_eval) {
float4 data(0.0f);
/* Subsurface writes (black) to that texture. */
dummy_black_tx.ensure_2d(RAYTRACE_RADIANCE_FORMAT, int2(1), usage_rw, data);
for (int i = 0; i < 3; i++) {
indirect_radiance_txs_[i] = dummy_black_tx;
}
if (use_raytracing_) {
indirect_result_ = inst_.raytracing.render(
rt_buffer, radiance_behind_tx, closure_bits_, main_view, render_view);
}
else if (use_split_radiance_) {
indirect_result_ = inst_.raytracing.alloc_only(rt_buffer);
}
else {
indirect_result = inst_.raytracing.render(rt_buffer,
radiance_behind_tx_,
radiance_feedback_tx_,
radiance_feedback_persmat_,
closure_bits_,
main_view,
render_view,
do_screen_space_refraction);
for (int i = 0; i < 3; i++) {
indirect_radiance_txs_[i] = indirect_result.closures[i].get();
}
indirect_result_ = inst_.raytracing.alloc_dummy(rt_buffer);
}
GPU_framebuffer_bind(combined_fb);
inst_.manager->submit(eval_light_ps_, render_view);
inst_.subsurface.render(
direct_radiance_txs_[0], indirect_radiance_txs_[0], closure_bits_, render_view);
direct_radiance_txs_[0], indirect_result_.closures[0], closure_bits_, render_view);
radiance_feedback_tx_ = rt_buffer.feedback_ensure(!use_feedback_output_, extent);
if (use_feedback_output_ && use_clamp_direct_) {
/* We need to do a copy before the combine pass (otherwise we have a dependency issue) to save
* the emission and the previous layer's radiance. */
GPU_texture_copy(radiance_feedback_tx_, rb.combined_tx);
}
GPU_framebuffer_bind(combined_fb);
inst_.manager->submit(combine_ps_);
if (!use_combined_lightprobe_eval) {
indirect_result.release();
if (use_feedback_output_ && !use_clamp_direct_) {
/* We skip writting the radiance during the combine pass. Do a simple fast copy. */
GPU_texture_copy(radiance_feedback_tx_, rb.combined_tx);
}
indirect_result_.release();
for (int i = 0; i < ARRAY_SIZE(direct_radiance_txs_); i++) {
direct_radiance_txs_[i].release();
}
if (do_screen_space_reflection) {
GPU_texture_copy(radiance_feedback_tx_, rb.combined_tx);
radiance_feedback_persmat_ = render_view.persmat();
}
inst_.pipelines.deferred.debug_draw(render_view, combined_fb);
return use_feedback_output_ ? radiance_feedback_tx_ : nullptr;
}
/** \} */
@ -800,8 +799,7 @@ void DeferredPipeline::begin_sync()
{
Instance &inst = opaque_layer_.inst_;
const bool use_raytracing = (inst.scene->eevee.flag & SCE_EEVEE_SSR_ENABLED);
inst.pipelines.data.use_combined_lightprobe_eval = !use_raytracing;
const bool use_raytracing = (inst.scene->eevee.flag & SCE_EEVEE_SSR_ENABLED) != 0;
use_combined_lightprobe_eval = !use_raytracing;
opaque_layer_.begin_sync();
@ -810,8 +808,8 @@ void DeferredPipeline::begin_sync()
void DeferredPipeline::end_sync()
{
opaque_layer_.end_sync();
refraction_layer_.end_sync();
opaque_layer_.end_sync(true, refraction_layer_.is_empty());
refraction_layer_.end_sync(opaque_layer_.is_empty(), true);
debug_pass_sync();
}
@ -892,26 +890,28 @@ void DeferredPipeline::render(View &main_view,
RayTraceBuffer &rt_buffer_opaque_layer,
RayTraceBuffer &rt_buffer_refract_layer)
{
GPUTexture *feedback_tx = nullptr;
DRW_stats_group_start("Deferred.Opaque");
opaque_layer_.render(main_view,
render_view,
prepass_fb,
combined_fb,
gbuffer_fb,
extent,
rt_buffer_opaque_layer,
true);
feedback_tx = opaque_layer_.render(main_view,
render_view,
prepass_fb,
combined_fb,
gbuffer_fb,
extent,
rt_buffer_opaque_layer,
feedback_tx);
DRW_stats_group_end();
DRW_stats_group_start("Deferred.Refract");
refraction_layer_.render(main_view,
render_view,
prepass_fb,
combined_fb,
gbuffer_fb,
extent,
rt_buffer_refract_layer,
false);
feedback_tx = refraction_layer_.render(main_view,
render_view,
prepass_fb,
combined_fb,
gbuffer_fb,
extent,
rt_buffer_refract_layer,
feedback_tx);
DRW_stats_group_end();
}
@ -1222,8 +1222,10 @@ void DeferredProbePipeline::render(View &view,
inst_.manager->submit(opaque_layer_.prepass_ps_, view);
inst_.hiz_buffer.set_source(&inst_.render_buffers.depth_tx);
inst_.hiz_buffer.update();
inst_.lights.set_view(view, extent);
inst_.shadows.set_view(view, inst_.render_buffers.depth_tx);
inst_.shadows.set_view(view, extent);
inst_.volume_probes.set_view(view);
/* Update for lighting pass. */
@ -1336,13 +1338,12 @@ void PlanarProbePipeline::render(View &view,
/* TODO(fclem): This is the only place where we use the layer source to HiZ.
* This is because the texture layer view is still a layer texture. */
inst_.hiz_buffer.set_source(&depth_layer_tx, 0);
inst_.lights.set_view(view, extent);
inst_.shadows.set_view(view, depth_layer_tx);
inst_.volume_probes.set_view(view);
/* Update for lighting pass. */
inst_.hiz_buffer.update();
inst_.lights.set_view(view, extent);
inst_.shadows.set_view(view, extent);
inst_.volume_probes.set_view(view);
inst_.gbuffer.bind(gbuffer_fb);
inst_.manager->submit(gbuffer_ps_, view);

View File

@ -18,6 +18,7 @@
#include "draw_shader_shared.hh"
#include "eevee_lut.hh"
#include "eevee_raytrace.hh"
#include "eevee_subsurface.hh"
namespace blender::eevee {
@ -163,7 +164,7 @@ class ForwardPipeline {
::Material *blender_mat,
GPUMaterial *gpumat);
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb);
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent);
};
/** \} */
@ -248,9 +249,13 @@ class DeferredLayer : DeferredLayerBase {
*/
TextureFromPool direct_radiance_txs_[3] = {
{"direct_radiance_1"}, {"direct_radiance_2"}, {"direct_radiance_3"}};
Texture dummy_black_tx = {"dummy_black_tx"};
/* NOTE: Only used when `use_split_radiance` is true. */
TextureFromPool indirect_radiance_txs_[3] = {
{"indirect_radiance_1"}, {"indirect_radiance_2"}, {"indirect_radiance_3"}};
/* Used when there is no indirect radiance buffer. */
Texture dummy_black = {"dummy_black"};
/* Reference to ray-tracing results. */
GPUTexture *indirect_radiance_txs_[3] = {nullptr};
GPUTexture *radiance_feedback_tx_ = nullptr;
/**
* Tile texture containing several bool per tile indicating presence of feature.
@ -258,34 +263,52 @@ class DeferredLayer : DeferredLayerBase {
*/
Texture tile_mask_tx_ = {"tile_mask_tx_"};
/* TODO(fclem): This should be a TextureFromPool. */
Texture radiance_behind_tx_ = {"radiance_behind_tx"};
/* TODO(fclem): This shouldn't be part of the pipeline but of the view. */
Texture radiance_feedback_tx_ = {"radiance_feedback_tx"};
float4x4 radiance_feedback_persmat_;
RayTraceResult indirect_result_;
bool use_combined_lightprobe_eval = true;
bool use_split_radiance_ = true;
/* Output radiance from the combine shader instead of copy. Allow passing unclamped result. */
bool use_feedback_output_ = false;
bool use_raytracing_ = false;
bool use_screen_transmission_ = false;
bool use_screen_reflection_ = false;
bool use_clamp_direct_ = false;
bool use_clamp_indirect_ = false;
public:
DeferredLayer(Instance &inst) : inst_(inst){};
DeferredLayer(Instance &inst) : inst_(inst)
{
float4 data(0.0f);
dummy_black.ensure_2d(RAYTRACE_RADIANCE_FORMAT,
int2(1),
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE,
data);
}
void begin_sync();
void end_sync();
void end_sync(bool is_first_pass, bool is_last_pass);
PassMain::Sub *prepass_add(::Material *blender_mat, GPUMaterial *gpumat, bool has_motion);
PassMain::Sub *material_add(::Material *blender_mat, GPUMaterial *gpumat);
void render(View &main_view,
View &render_view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
Framebuffer &gbuffer_fb,
int2 extent,
RayTraceBuffer &rt_buffer,
bool is_first_pass);
bool is_empty() const
{
return closure_count_ != 0;
}
/* Returns the radiance buffer to feed the next layer. */
GPUTexture *render(View &main_view,
View &render_view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
Framebuffer &gbuffer_fb,
int2 extent,
RayTraceBuffer &rt_buffer,
GPUTexture *radiance_behind_tx);
};
class DeferredPipeline {
friend DeferredLayer;
private:
/* Gbuffer filling passes. We could have an arbitrary number of them but for now we just have
* a hardcoded number of them. */

View File

@ -30,6 +30,10 @@ void RayTraceModule::init()
ray_tracing_options_ = sce_eevee.ray_tracing_options;
tracing_method_ = RaytraceEEVEE_Method(sce_eevee.ray_tracing_method);
float4 data(0.0f);
radiance_dummy_black_tx_.ensure_2d(
RAYTRACE_RADIANCE_FORMAT, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, data);
}
void RayTraceModule::sync()
@ -323,16 +327,19 @@ void RayTraceModule::debug_draw(View & /*view*/, GPUFrameBuffer * /*view_fb*/) {
RayTraceResult RayTraceModule::render(RayTraceBuffer &rt_buffer,
GPUTexture *screen_radiance_back_tx,
GPUTexture *screen_radiance_front_tx,
const float4x4 &screen_radiance_persmat,
eClosureBits active_closures,
/* TODO(fclem): Maybe wrap these two in some other class. */
View &main_view,
View &render_view,
bool do_refraction_tracing)
View &render_view)
{
using namespace blender::math;
screen_radiance_front_tx_ = rt_buffer.radiance_feedback_tx.is_valid() ?
rt_buffer.radiance_feedback_tx :
radiance_dummy_black_tx_;
screen_radiance_back_tx_ = screen_radiance_back_tx ? screen_radiance_back_tx :
screen_radiance_front_tx_;
RaytraceEEVEE options = ray_tracing_options_;
bool use_horizon_scan = options.trace_max_roughness < 1.0f;
@ -386,10 +393,9 @@ RayTraceResult RayTraceModule::render(RayTraceBuffer &rt_buffer,
data_.roughness_mask_bias = data_.roughness_mask_scale * roughness_mask_start;
/* Data for the radiance setup. */
data_.brightness_clamp = (options.sample_clamp > 0.0) ? options.sample_clamp : 1e20;
data_.resolution_scale = resolution_scale;
data_.resolution_bias = int2(inst_.sampling.rng_2d_get(SAMPLING_RAYTRACE_V) * resolution_scale);
data_.radiance_persmat = screen_radiance_persmat;
data_.radiance_persmat = render_view.persmat();
data_.full_resolution = extent;
data_.full_resolution_inv = 1.0f / float2(extent);
@ -410,26 +416,16 @@ RayTraceResult RayTraceModule::render(RayTraceBuffer &rt_buffer,
inst_.manager->submit(tile_classify_ps_);
}
data_.trace_refraction = do_refraction_tracing;
data_.trace_refraction = screen_radiance_back_tx != nullptr;
for (int i = 0; i < 3; i++) {
result.closures[i] = trace(i,
(closure_count > i),
options,
rt_buffer,
screen_radiance_back_tx,
screen_radiance_front_tx,
screen_radiance_persmat,
main_view,
render_view);
result.closures[i] = trace(i, (closure_count > i), options, rt_buffer, main_view, render_view);
}
if (has_active_closure) {
if (use_horizon_scan) {
DRW_stats_group_start("Horizon Scan");
screen_radiance_front_tx_ = screen_radiance_front_tx;
downsampled_in_radiance_tx_.acquire(tracing_res_horizon, RAYTRACE_RADIANCE_FORMAT, usage_rw);
downsampled_in_normal_tx_.acquire(tracing_res_horizon, GPU_RGB10_A2, usage_rw);
@ -440,7 +436,7 @@ RayTraceResult RayTraceModule::render(RayTraceBuffer &rt_buffer,
horizon_radiance_denoised_tx_[i].acquire(tracing_res_horizon, GPU_RGBA8, usage_rw);
}
for (int i : IndexRange(3)) {
horizon_scan_output_tx_[i] = result.closures[i].get();
horizon_scan_output_tx_[i] = result.closures[i];
}
horizon_tracing_dispatch_buf_.clear_to_zero();
@ -465,6 +461,8 @@ RayTraceResult RayTraceModule::render(RayTraceBuffer &rt_buffer,
DRW_stats_group_end();
rt_buffer.history_persmat = render_view.persmat();
return result;
}
@ -473,9 +471,6 @@ RayTraceResultTexture RayTraceModule::trace(
bool active_layer,
RaytraceEEVEE options,
RayTraceBuffer &rt_buffer,
GPUTexture *screen_radiance_back_tx,
GPUTexture *screen_radiance_front_tx,
const float4x4 &screen_radiance_persmat,
/* TODO(fclem): Maybe wrap these two in some other class. */
View &main_view,
View &render_view)
@ -512,7 +507,6 @@ RayTraceResultTexture RayTraceModule::trace(
data_.thickness = options.screen_trace_thickness;
data_.quality = 1.0f - 0.95f * options.screen_trace_quality;
data_.brightness_clamp = (options.sample_clamp > 0.0) ? options.sample_clamp : 1e20;
float roughness_mask_start = options.trace_max_roughness;
float roughness_mask_fade = 0.2f;
@ -522,7 +516,7 @@ RayTraceResultTexture RayTraceModule::trace(
data_.resolution_scale = resolution_scale;
data_.resolution_bias = int2(inst_.sampling.rng_2d_get(SAMPLING_RAYTRACE_V) * resolution_scale);
data_.history_persmat = denoise_buf->history_persmat;
data_.radiance_persmat = screen_radiance_persmat;
data_.radiance_persmat = render_view.persmat();
data_.full_resolution = extent;
data_.full_resolution_inv = 1.0f / float2(extent);
data_.skip_denoise = !use_spatial_denoise;
@ -540,9 +534,6 @@ RayTraceResultTexture RayTraceModule::trace(
ray_time_tx_.acquire(tracing_res, RAYTRACE_RAYTIME_FORMAT);
ray_radiance_tx_.acquire(tracing_res, RAYTRACE_RADIANCE_FORMAT);
screen_radiance_front_tx_ = screen_radiance_front_tx;
screen_radiance_back_tx_ = screen_radiance_back_tx;
inst_.manager->submit(generate_ps_, render_view);
if (tracing_method_ == RAYTRACE_EEVEE_METHOD_SCREEN) {
if (inst_.planar_probes.enabled()) {
@ -638,6 +629,32 @@ RayTraceResultTexture RayTraceModule::trace(
return result;
}
RayTraceResult RayTraceModule::alloc_only(RayTraceBuffer &rt_buffer)
{
const int2 extent = inst_.film.render_extent_get();
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
RayTraceResult result;
for (int i = 0; i < 3; i++) {
RayTraceBuffer::DenoiseBuffer *denoise_buf = &rt_buffer.closures[i];
denoise_buf->denoised_bilateral_tx.acquire(extent, RAYTRACE_RADIANCE_FORMAT, usage_rw);
result.closures[i] = {denoise_buf->denoised_bilateral_tx};
}
return result;
}
RayTraceResult RayTraceModule::alloc_dummy(RayTraceBuffer &rt_buffer)
{
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
RayTraceResult result;
for (int i = 0; i < 3; i++) {
RayTraceBuffer::DenoiseBuffer *denoise_buf = &rt_buffer.closures[i];
denoise_buf->denoised_bilateral_tx.acquire(int2(1), RAYTRACE_RADIANCE_FORMAT, usage_rw);
result.closures[i] = {denoise_buf->denoised_bilateral_tx};
}
return result;
}
/** \} */
} // namespace blender::eevee

View File

@ -28,7 +28,7 @@ class Instance;
* \{ */
/**
* Contain persistent buffer that need to be stored per view, per layer.
* Contain persistent buffer that need to be stored per view, per deferred layer.
*/
struct RayTraceBuffer {
/** Set of buffers that need to be allocated for each ray type. */
@ -54,6 +54,26 @@ struct RayTraceBuffer {
* One for each closure. Not to be mistaken with deferred layer type.
*/
DenoiseBuffer closures[3];
/**
* Radiance feedback of the deferred layer for next sample's reflection or next layer's
* transmission.
*/
Texture radiance_feedback_tx = {"radiance_feedback_tx"};
/**
* Perspective matrix for which the radiance feedback buffer was recorded.
* Can be different from de-noise buffer's history matrix.
*/
float4x4 history_persmat;
GPUTexture *feedback_ensure(bool is_dummy, int2 extent)
{
eGPUTextureUsage usage_rw = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
if (radiance_feedback_tx.ensure_2d(GPU_RGBA16F, is_dummy ? int2(1) : extent, usage_rw)) {
radiance_feedback_tx.clear(float4(0.0f));
}
return radiance_feedback_tx;
}
};
/**
@ -65,18 +85,26 @@ class RayTraceResultTexture {
private:
/** Result is in a temporary texture that needs to be released. */
TextureFromPool *result_ = nullptr;
/** Value of `result_->tx_` that can be referenced in advance. */
GPUTexture *tx_ = nullptr;
/** History buffer to swap the temporary texture that does not need to be released. */
Texture *history_ = nullptr;
public:
RayTraceResultTexture() = default;
RayTraceResultTexture(TextureFromPool &result) : result_(result.ptr()){};
RayTraceResultTexture(TextureFromPool &result) : result_(result.ptr()), tx_(result){};
RayTraceResultTexture(TextureFromPool &result, Texture &history)
: result_(result.ptr()), history_(history.ptr()){};
: result_(result.ptr()), tx_(result), history_(history.ptr()){};
GPUTexture *get()
operator GPUTexture *() const
{
return *result_;
BLI_assert(tx_ != nullptr);
return tx_;
}
GPUTexture **operator&()
{
return &tx_;
}
void release()
@ -186,6 +214,7 @@ class RayTraceModule {
GPUTexture *screen_radiance_front_tx_ = nullptr;
GPUTexture *screen_radiance_back_tx_ = nullptr;
Texture radiance_dummy_black_tx_ = {"radiance_dummy_black_tx"};
/** Dummy texture when the tracing is disabled. */
TextureFromPool dummy_result_tx_ = {"dummy_result_tx"};
/** Pointer to `inst_.render_buffers.depth_tx` updated before submission. */
@ -223,13 +252,20 @@ class RayTraceModule {
*/
RayTraceResult render(RayTraceBuffer &rt_buffer,
GPUTexture *screen_radiance_back_tx,
GPUTexture *screen_radiance_front_tx,
const float4x4 &screen_radiance_persmat,
eClosureBits active_closures,
/* TODO(fclem): Maybe wrap these two in some other class. */
View &main_view,
View &render_view,
bool do_refraction_tracing);
View &render_view);
/**
* Only allocate the RayTraceResult results buffers to be used by other passes.
*/
RayTraceResult alloc_only(RayTraceBuffer &rt_buffer);
/**
* Only allocate the RayTraceResult results buffers as dummy texture to ensure correct bindings.
*/
RayTraceResult alloc_dummy(RayTraceBuffer &rt_buffer);
void debug_pass_sync();
void debug_draw(View &view, GPUFrameBuffer *view_fb);
@ -239,9 +275,6 @@ class RayTraceModule {
bool active_layer,
RaytraceEEVEE options,
RayTraceBuffer &rt_buffer,
GPUTexture *screen_radiance_back_tx,
GPUTexture *screen_radiance_front_tx,
const float4x4 &screen_radiance_persmat,
/* TODO(fclem): Maybe wrap these two in some other class. */
View &main_view,
View &render_view);

View File

@ -34,9 +34,6 @@ void SphereProbeModule::begin_sync()
LightProbeModule &light_probes = instance_.light_probes;
SphereProbeData &world_data = *static_cast<SphereProbeData *>(&light_probes.world_sphere_);
{
const RaytraceEEVEE &options = instance_.scene->eevee.ray_tracing_options;
float probe_brightness_clamp = (options.sample_clamp > 0.0) ? options.sample_clamp : 1e20;
GPUShader *shader = instance_.shaders.static_shader_get(SPHERE_PROBE_REMAP);
PassSimple &pass = remap_ps_;
@ -50,7 +47,7 @@ void SphereProbeModule::begin_sync()
pass.push_constant("probe_coord_packed", reinterpret_cast<int4 *>(&probe_sampling_coord_));
pass.push_constant("write_coord_packed", reinterpret_cast<int4 *>(&probe_write_coord_));
pass.push_constant("world_coord_packed", reinterpret_cast<int4 *>(&world_data.atlas_coord));
pass.push_constant("probe_brightness_clamp", probe_brightness_clamp);
pass.bind_resources(instance_.uniform_data);
pass.dispatch(&dispatch_probe_pack_);
}
{
@ -85,6 +82,7 @@ void SphereProbeModule::begin_sync()
pass.bind_ssbo("reflection_probe_buf", &data_buf_);
instance_.volume_probes.bind_resources(pass);
instance_.sampling.bind_resources(pass);
pass.bind_resources(instance_.uniform_data);
pass.dispatch(&dispatch_probe_select_);
pass.barrier(GPU_BARRIER_UNIFORM);
}

View File

@ -60,6 +60,13 @@ void Sampling::init(const Scene *scene)
/* Only multiply after to have full the full DoF web pattern for each time steps. */
sample_count_ *= motion_blur_steps_;
auto clamp_value_load = [](float value) { return (value > 0.0) ? value : 1e20; };
clamp_data_.surface_direct = clamp_value_load(scene->eevee.clamp_surface_direct);
clamp_data_.surface_indirect = clamp_value_load(scene->eevee.clamp_surface_indirect);
clamp_data_.volume_direct = clamp_value_load(scene->eevee.clamp_volume_direct);
clamp_data_.volume_indirect = clamp_value_load(scene->eevee.clamp_volume_indirect);
}
void Sampling::init(const Object &probe_object)

View File

@ -65,8 +65,10 @@ class Sampling {
SamplingDataBuf data_;
ClampData &clamp_data_;
public:
Sampling(Instance &inst) : inst_(inst){};
Sampling(Instance &inst, ClampData &clamp_data) : inst_(inst), clamp_data_(clamp_data){};
~Sampling(){};
void init(const Scene *scene);

View File

@ -1622,6 +1622,20 @@ BLI_STATIC_ASSERT_ALIGN(HiZData, 16)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Light Clamping
* \{ */
struct ClampData {
float surface_direct;
float surface_indirect;
float volume_direct;
float volume_indirect;
};
BLI_STATIC_ASSERT_ALIGN(ClampData, 16)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Ray-Tracing
* \{ */
@ -1685,8 +1699,6 @@ struct RayTraceData {
int horizon_resolution_scale;
/** Determine how fast the sample steps are getting bigger. */
float quality;
/** Maximum brightness during lighting evaluation. */
float brightness_clamp;
/** Maximum roughness for which we will trace a ray. */
float roughness_mask_scale;
float roughness_mask_bias;
@ -1697,6 +1709,7 @@ struct RayTraceData {
/** Closure being ray-traced. */
int closure_index;
int _pad0;
int _pad1;
};
BLI_STATIC_ASSERT_ALIGN(RayTraceData, 16)
@ -1821,7 +1834,7 @@ BLI_STATIC_ASSERT_ALIGN(PlanarProbeDisplayData, 16)
struct PipelineInfoData {
float alpha_hash_scale;
bool32_t is_probe_reflection;
bool32_t use_combined_lightprobe_eval;
float _pad1;
float _pad2;
};
BLI_STATIC_ASSERT_ALIGN(PipelineInfoData, 16)
@ -1836,6 +1849,7 @@ BLI_STATIC_ASSERT_ALIGN(PipelineInfoData, 16)
struct UniformData {
AOData ao;
CameraData camera;
ClampData clamp;
FilmData film;
HiZData hiz;
RayTraceData raytrace;

View File

@ -863,7 +863,9 @@ void ShadowModule::begin_sync()
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
sub.bind_texture("depth_tx", &src_depth_tx_);
sub.push_constant("tilemap_proj_ratio", &data_.tilemap_projection_ratio);
sub.push_constant("input_depth_extent", &input_depth_extent_);
sub.bind_resources(inst_.lights);
sub.bind_resources(inst_.hiz_buffer.front);
sub.dispatch(&dispatch_depth_scan_size_);
}
{
@ -1357,29 +1359,26 @@ int ShadowModule::max_view_per_tilemap()
return max_view_count;
}
void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
void ShadowModule::set_view(View &view, int2 extent)
{
if (enabled_ == false) {
/* All lights have been tagged to have no shadow. */
return;
}
input_depth_extent_ = extent;
GPUFrameBuffer *prev_fb = GPU_framebuffer_active_get();
src_depth_tx_ = depth_tx;
int3 target_size(1);
GPU_texture_get_mipmap_size(depth_tx, 0, target_size);
dispatch_depth_scan_size_ = math::divide_ceil(target_size, int3(SHADOW_DEPTH_SCAN_GROUP_SIZE));
dispatch_depth_scan_size_ = int3(math::divide_ceil(extent, int2(SHADOW_DEPTH_SCAN_GROUP_SIZE)),
1);
max_view_per_tilemap_ = max_view_per_tilemap();
pixel_world_radius_ = screen_pixel_radius(view, int2(target_size));
pixel_world_radius_ = screen_pixel_radius(view, extent);
data_.tilemap_projection_ratio = tilemap_pixel_radius() / pixel_world_radius_;
inst_.uniform_data.push_update();
usage_tag_fb_resolution_ = math::divide_ceil(int2(target_size),
int2(std::exp2(usage_tag_fb_lod_)));
usage_tag_fb_resolution_ = math::divide_ceil(extent, int2(std::exp2(usage_tag_fb_lod_)));
usage_tag_fb.ensure(usage_tag_fb_resolution_);
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_MEMORYLESS;

View File

@ -260,6 +260,7 @@ class ShadowModule {
int2 usage_tag_fb_resolution_;
int usage_tag_fb_lod_ = 5;
int max_view_per_tilemap_ = 1;
int2 input_depth_extent_;
/* Statistics that are read back to CPU after a few frame (to avoid stall). */
SwapChain<ShadowStatisticsBuf, 5> statistics_buf_;
@ -349,8 +350,9 @@ class ShadowModule {
/* Update all shadow regions visible inside the view.
* If called multiple time for the same view, it will only do the depth buffer scanning
* to check any new opaque surfaces.
* Expect the HiZ buffer to be up to date.
* Needs to be called after `LightModule::set_view();`. */
void set_view(View &view, GPUTexture *depth_tx = nullptr);
void set_view(View &view, int2 extent);
void debug_end_sync();
void debug_draw(View &view, GPUFrameBuffer *view_fb);

View File

@ -144,7 +144,7 @@ void ShadingView::render()
// inst_.lookdev.render_overlay(view_fb_);
inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_);
inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_, extent_);
render_transparent_pass(rbufs);
@ -176,7 +176,7 @@ void ShadingView::render_transparent_pass(RenderBuffers &rbufs)
float4 clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
GPU_framebuffer_bind(transparent_fb_);
GPU_framebuffer_clear_color(transparent_fb_, clear_color);
inst_.pipelines.forward.render(render_view_, prepass_fb_, transparent_fb_);
inst_.pipelines.forward.render(render_view_, prepass_fb_, transparent_fb_, rbufs.extent_get());
}
}

View File

@ -366,6 +366,9 @@ void VolumeModule::draw_prepass(View &main_view)
inst_.pipelines.world_volume.render(main_view);
volume_view.sync(main_view.viewmat(), winmat_infinite);
/* TODO(fclem): The infinite projection matrix makes the culling test unreliable (see #115595).
* We need custom culling for these but that's not implemented yet. */
volume_view.visibility_test(false);
if (inst_.pipelines.volume.is_enabled()) {
inst_.pipelines.volume.render(volume_view, occupancy_tx_);

View File

@ -78,11 +78,9 @@ World::~World()
void World::sync()
{
::World *bl_world = inst_.use_studio_light() ? nullptr : inst_.scene->world;
bool has_update = false;
if (bl_world) {
if (inst_.scene->world != nullptr) {
/* Detect world update before overriding it. */
WorldHandle wo_handle = inst_.sync.sync_world();
has_update = wo_handle.recalc != 0;
@ -91,8 +89,9 @@ void World::sync()
/* Sync volume first since its result can override the surface world. */
sync_volume();
::World *bl_world;
if (inst_.use_studio_light()) {
has_update = lookdev_world_.sync(LookdevParameters(inst_.v3d));
has_update |= lookdev_world_.sync(LookdevParameters(inst_.v3d));
bl_world = lookdev_world_.world_get();
}
else if ((inst_.view_layer->layflag & SCE_LAY_SKY) == 0) {

View File

@ -48,40 +48,43 @@ void main()
GBufferReader gbuf = gbuffer_read(gbuf_header_tx, gbuf_closure_tx, gbuf_normal_tx, texel);
vec3 diffuse_color = vec3(0.0);
vec3 diffuse_light = vec3(0.0);
vec3 diffuse_direct = vec3(0.0);
vec3 diffuse_indirect = vec3(0.0);
vec3 specular_color = vec3(0.0);
vec3 specular_light = vec3(0.0);
vec3 specular_direct = vec3(0.0);
vec3 specular_indirect = vec3(0.0);
vec3 out_direct = vec3(0.0);
vec3 out_indirect = vec3(0.0);
vec3 average_normal = vec3(0.0);
out_combined = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
if (cl.type == CLOSURE_NONE_ID) {
continue;
}
int layer_index = gbuffer_closure_get_bin_index(gbuf, i);
vec3 closure_light = load_radiance_direct(texel, layer_index);
vec3 closure_direct_light = load_radiance_direct(texel, layer_index);
vec3 closure_indirect_light = vec3(0.0);
if (!use_combined_lightprobe_eval) {
closure_light += load_radiance_indirect(texel, layer_index);
if (use_split_radiance) {
closure_indirect_light = load_radiance_indirect(texel, layer_index);
}
average_normal += cl.N * reduce_add(cl.color);
switch (cl.type) {
case CLOSURE_BSDF_TRANSLUCENT_ID:
case CLOSURE_BSSRDF_BURLEY_ID:
case CLOSURE_BSDF_DIFFUSE_ID:
diffuse_color += cl.color;
diffuse_light += closure_light;
average_normal += cl.N * reduce_add(cl.color);
diffuse_direct += closure_direct_light;
diffuse_indirect += closure_indirect_light;
break;
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
specular_color += cl.color;
specular_light += closure_light;
average_normal += cl.N * reduce_add(cl.color);
break;
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */
specular_direct += closure_direct_light;
specular_indirect += closure_indirect_light;
break;
}
@ -93,16 +96,36 @@ void main()
cl.color *= cl.color;
}
closure_light *= cl.color;
out_combined.rgb += closure_light;
out_direct += closure_direct_light * cl.color;
out_indirect += closure_indirect_light * cl.color;
}
if (use_radiance_feedback) {
/* Output unmodified radiance for indirect lighting. */
vec3 out_radiance = imageLoad(radiance_feedback_img, texel).rgb;
out_radiance += out_direct + out_indirect;
imageStore(radiance_feedback_img, texel, vec4(out_radiance, 0.0));
}
/* Light clamping. */
float clamp_direct = uniform_buf.clamp.surface_direct;
float clamp_indirect = uniform_buf.clamp.surface_indirect;
out_direct = colorspace_brightness_clamp_max(out_direct, clamp_direct);
out_indirect = colorspace_brightness_clamp_max(out_indirect, clamp_indirect);
/* TODO(fcleù): Shouldn't we clamp these relative the main clamp? */
diffuse_direct = colorspace_brightness_clamp_max(diffuse_direct, clamp_direct);
diffuse_indirect = colorspace_brightness_clamp_max(diffuse_indirect, clamp_indirect);
specular_direct = colorspace_brightness_clamp_max(specular_direct, clamp_direct);
specular_indirect = colorspace_brightness_clamp_max(specular_indirect, clamp_indirect);
/* Light passes. */
if (render_pass_diffuse_light_enabled) {
vec3 diffuse_light = diffuse_direct + diffuse_indirect;
output_renderpass_color(uniform_buf.render_pass.diffuse_color_id, vec4(diffuse_color, 1.0));
output_renderpass_color(uniform_buf.render_pass.diffuse_light_id, vec4(diffuse_light, 1.0));
}
if (render_pass_specular_light_enabled) {
vec3 specular_light = specular_direct + specular_indirect;
output_renderpass_color(uniform_buf.render_pass.specular_color_id, vec4(specular_color, 1.0));
output_renderpass_color(uniform_buf.render_pass.specular_light_id, vec4(specular_light, 1.0));
}
@ -113,9 +136,7 @@ void main()
output_renderpass_color(uniform_buf.render_pass.normal_id, vec4(average_normal, 1.0));
}
if (any(isnan(out_combined))) {
out_combined = vec4(1.0, 0.0, 1.0, 0.0);
}
out_combined = vec4(out_direct + out_indirect, 0.0);
out_combined = any(isnan(out_combined)) ? vec4(1.0, 0.0, 1.0, 0.0) : out_combined;
out_combined = colorspace_safe_color(out_combined);
}

View File

@ -91,9 +91,29 @@ void main()
if (use_lightprobe_eval) {
LightProbeSample samp = lightprobe_load(P, Ng, V);
float clamp_indirect = uniform_buf.clamp.surface_indirect;
samp.volume_irradiance = spherical_harmonics_clamp(samp.volume_irradiance, clamp_indirect);
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < gbuf.closure_count; i++) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);
lightprobe_eval(samp, cl, P, V, gbuf.thickness, stack.cl[i].light_shadowed);
vec3 indirect_light = lightprobe_eval(samp, cl, P, V, gbuf.thickness);
if (use_split_indirect) {
int layer_index = gbuffer_closure_get_bin_index(gbuf, i);
/* TODO(fclem): Layered texture. */
if (layer_index == 0) {
imageStore(indirect_radiance_1_img, texel, vec4(indirect_light, 1.0));
}
else if (layer_index == 1) {
imageStore(indirect_radiance_2_img, texel, vec4(indirect_light, 1.0));
}
else if (layer_index == 2) {
imageStore(indirect_radiance_3_img, texel, vec4(indirect_light, 1.0));
}
}
else {
stack.cl[i].light_shadowed += indirect_light;
}
}
}

View File

@ -12,6 +12,7 @@
#pragma BLENDER_REQUIRE(eevee_subsurface_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_colorspace_lib.glsl)
#if CLOSURE_BIN_COUNT != LIGHT_CLOSURE_EVAL_COUNT
# error Closure data count and eval count must match
@ -64,21 +65,37 @@ void forward_lighting_eval(float thickness, out vec3 radiance, out vec3 transmit
LightProbeSample samp = lightprobe_load(g_data.P, g_data.Ng, V);
float clamp_indirect_sh = uniform_buf.clamp.surface_indirect;
samp.volume_irradiance = spherical_harmonics_clamp(samp.volume_irradiance, clamp_indirect_sh);
/* Combine all radiance. */
radiance = g_emission;
vec3 radiance_direct = vec3(0.0);
vec3 radiance_indirect = vec3(0.0);
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT; i++) {
ClosureUndetermined cl = g_closure_get(i);
lightprobe_eval(samp, cl, g_data.P, V, thickness, stack.cl[i].light_shadowed);
if (cl.weight > 1e-5) {
vec3 direct_light = stack.cl[i].light_shadowed;
vec3 indirect_light = lightprobe_eval(samp, cl, g_data.P, V, thickness);
if ((cl.type == CLOSURE_BSDF_TRANSLUCENT_ID ||
cl.type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) &&
(thickness > 0.0))
{
/* We model two transmission event, so the surface color need to be applied twice. */
stack.cl[i].light_shadowed *= cl.color;
cl.color *= cl.color;
}
radiance += stack.cl[i].light_shadowed * cl.color * cl.weight;
cl.color *= cl.weight;
radiance_direct += direct_light * cl.color;
radiance_indirect += indirect_light * cl.color;
}
}
/* Light clamping. */
float clamp_direct = uniform_buf.clamp.surface_direct;
float clamp_indirect = uniform_buf.clamp.surface_indirect;
radiance_direct = colorspace_brightness_clamp_max(radiance_direct, clamp_direct);
radiance_indirect = colorspace_brightness_clamp_max(radiance_indirect, clamp_indirect);
radiance = radiance_direct + radiance_indirect + g_emission;
transmittance = g_transmittance;
}

View File

@ -411,31 +411,32 @@ void gbuffer_skip_data(inout GBufferReader gbuf)
/**
* Set the dedicated normal bit for the last added closure.
* Expects `layer_id` to be in [0..2].
* Expects `bin_id` to be in [0..2].
* Expects `normal_id` to be in [0..3].
*/
void gbuffer_header_normal_layer_id_set(inout uint header, int layer_id, uint normal_id)
void gbuffer_header_normal_layer_id_set(inout uint header, int bin_id, uint normal_id)
{
/* Layer 0 will always have normal id 0. It doesn't have to be encoded. Skip it. */
if (layer_id == 0) {
if (bin_id == 0) {
return;
}
/* -2 is to skip the layer_id 0 and start encoding for layer_id 1. This keeps the FMA. */
header |= normal_id << ((GBUFFER_NORMAL_BITS_SHIFT - 2) + layer_id * 2);
/* -2 is to skip the bin_id 0 and start encoding for bin_id 1. This keeps the FMA. */
header |= normal_id << ((GBUFFER_NORMAL_BITS_SHIFT - 2) + bin_id * 2);
}
int gbuffer_header_normal_layer_id_get(uint header, int layer_id)
int gbuffer_header_normal_layer_id_get(uint header, int bin_id)
{
/* Layer 0 will always have normal id 0. */
if (layer_id == 0) {
if (bin_id == 0) {
return 0;
}
/* -2 is to skip the layer_id 0 and start encoding for layer_id 1. This keeps the FMA. */
return int(3u & (header >> ((GBUFFER_NORMAL_BITS_SHIFT - 2) + layer_id * 2)));
/* -2 is to skip the bin_id 0 and start encoding for bin_id 1. This keeps the FMA. */
return int(3u & (header >> ((GBUFFER_NORMAL_BITS_SHIFT - 2) + bin_id * 2)));
}
void gbuffer_append_normal(inout GBufferWriter gbuf, vec3 normal)
{
vec2 packed_N = gbuffer_normal_pack(normal);
/* Assumes this function is called after gbuffer_append_closure. */
int layer_id = gbuf.bins_len - 1;
/* Try to reuse previous normals. */
#if GBUFFER_NORMAL_MAX > 1
@ -478,9 +479,9 @@ void gbuffer_append_normal(inout GBufferWriter gbuf, vec3 normal)
}
gbuf.normal_len++;
}
vec3 gbuffer_normal_get(inout GBufferReader gbuf, int layer_id, samplerGBufferNormal normal_tx)
vec3 gbuffer_normal_get(inout GBufferReader gbuf, int bin_id, samplerGBufferNormal normal_tx)
{
int normal_layer_id = gbuffer_header_normal_layer_id_get(gbuf.header, layer_id);
int normal_layer_id = gbuffer_header_normal_layer_id_get(gbuf.header, bin_id);
vec2 normal_packed = fetchGBuffer(normal_tx, gbuf.texel, normal_layer_id).rg;
gbuf.normal_len = max(gbuf.normal_len, normal_layer_id + 1);
return gbuffer_normal_unpack(normal_packed);
@ -534,6 +535,7 @@ void gbuffer_closure_diffuse_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_diffuse_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -541,7 +543,7 @@ void gbuffer_closure_diffuse_load(inout GBufferReader gbuf,
ClosureUndetermined cl = closure_new(CLOSURE_BSDF_DIFFUSE_ID);
cl.color = gbuffer_closure_color_unpack(data0);
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -560,6 +562,7 @@ void gbuffer_closure_translucent_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_translucent_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -567,7 +570,7 @@ void gbuffer_closure_translucent_load(inout GBufferReader gbuf,
ClosureUndetermined cl = closure_new(CLOSURE_BSDF_TRANSLUCENT_ID);
cl.color = gbuffer_closure_color_unpack(data0);
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -588,6 +591,7 @@ void gbuffer_closure_subsurface_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_subsurface_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -597,7 +601,7 @@ void gbuffer_closure_subsurface_load(inout GBufferReader gbuf,
ClosureUndetermined cl = closure_new(CLOSURE_BSSRDF_BURLEY_ID);
cl.color = gbuffer_closure_color_unpack(data0);
cl.data.rgb = gbuffer_sss_radii_unpack(data1);
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -618,6 +622,7 @@ void gbuffer_closure_reflection_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_reflection_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -627,7 +632,7 @@ void gbuffer_closure_reflection_load(inout GBufferReader gbuf,
ClosureUndetermined cl = closure_new(CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID);
cl.color = gbuffer_closure_color_unpack(data0);
cl.data.x = data1.x;
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -648,6 +653,7 @@ void gbuffer_closure_refraction_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_refraction_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -658,7 +664,7 @@ void gbuffer_closure_refraction_load(inout GBufferReader gbuf,
cl.color = gbuffer_closure_color_unpack(data0);
cl.data.x = data1.x;
cl.data.y = gbuffer_ior_unpack(data1.y);
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -686,6 +692,7 @@ void gbuffer_closure_reflection_colorless_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_reflection_colorless_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -695,7 +702,7 @@ void gbuffer_closure_reflection_colorless_load(inout GBufferReader gbuf,
cl.data.x = data0.x;
cl.color = vec3(gbuffer_closure_intensity_unpack(data0.zw));
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -715,6 +722,7 @@ void gbuffer_closure_refraction_colorless_skip(inout GBufferReader gbuf)
}
void gbuffer_closure_refraction_colorless_load(inout GBufferReader gbuf,
int layer,
int bin_index,
samplerGBufferClosure closure_tx,
samplerGBufferNormal normal_tx)
{
@ -725,7 +733,7 @@ void gbuffer_closure_refraction_colorless_load(inout GBufferReader gbuf,
cl.data.y = gbuffer_ior_unpack(data0.y);
cl.color = vec3(gbuffer_closure_intensity_unpack(data0.zw));
cl.N = gbuffer_normal_get(gbuf, layer, normal_tx);
cl.N = gbuffer_normal_get(gbuf, bin_index, normal_tx);
gbuffer_register_closure(gbuf, cl, layer);
}
@ -831,6 +839,9 @@ GBufferWriter gbuffer_pack(GBufferData data_in)
}
has_additional_data = true;
break;
default:
gbuf.bins_len++;
break;
}
}
@ -881,19 +892,6 @@ ClosureType gbuffer_closure_type_get_by_bin(uint header, int bin_index)
return gbuffer_mode_to_closure_type(mode);
}
/* Only read closure types out of the header. The rest of GBufferReader is undefined. */
GBufferReader gbuffer_read_header_closure_types(uint header)
{
GBufferReader gbuf;
for (int bin = 0; bin < GBUFFER_LAYER_MAX; bin++) {
GBufferMode mode = gbuffer_header_unpack(header, bin);
ClosureType closure_type = gbuffer_mode_to_closure_type(mode);
gbuffer_register_closure(gbuf, closure_new(closure_type), bin);
}
return gbuf;
}
/* Return the bin index of a closure using its layer index. */
int gbuffer_closure_get_bin_index(GBufferReader gbuf, int layer_index)
{
@ -965,34 +963,36 @@ GBufferReader gbuffer_read(samplerGBufferHeader header_tx,
case GBUF_NONE:
break;
case GBUF_DIFFUSE:
gbuffer_closure_diffuse_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_diffuse_load(gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_TRANSLUCENT:
gbuffer_closure_translucent_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_translucent_load(gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
has_additional_data = true;
break;
case GBUF_SUBSURFACE:
gbuffer_closure_subsurface_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_subsurface_load(gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
has_additional_data = true;
break;
case GBUF_REFLECTION:
gbuffer_closure_reflection_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_reflection_load(gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_REFRACTION:
gbuffer_closure_refraction_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_refraction_load(gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
has_additional_data = true;
break;
case GBUF_REFLECTION_COLORLESS:
gbuffer_closure_reflection_colorless_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_reflection_colorless_load(
gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
break;
case GBUF_REFRACTION_COLORLESS:
gbuffer_closure_refraction_colorless_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_refraction_colorless_load(
gbuf, gbuf.closure_count, bin, closure_tx, normal_tx);
gbuf.closure_count++;
has_additional_data = true;
break;
@ -1028,7 +1028,7 @@ ClosureUndetermined gbuffer_read_bin(uint header,
for (int bin = 0; bin < GBUFFER_LAYER_MAX; bin++) {
mode = gbuffer_header_unpack(gbuf.header, bin);
if (mode != GBUF_NONE && bin >= bin_index) {
if (bin >= bin_index) {
break;
}
@ -1066,25 +1066,27 @@ ClosureUndetermined gbuffer_read_bin(uint header,
gbuffer_register_closure(gbuf, closure_new(CLOSURE_NONE_ID), gbuf.closure_count);
break;
case GBUF_DIFFUSE:
gbuffer_closure_diffuse_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_diffuse_load(gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
case GBUF_TRANSLUCENT:
gbuffer_closure_translucent_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_translucent_load(gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
case GBUF_SUBSURFACE:
gbuffer_closure_subsurface_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_subsurface_load(gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
case GBUF_REFLECTION:
gbuffer_closure_reflection_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_reflection_load(gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
case GBUF_REFRACTION:
gbuffer_closure_refraction_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_refraction_load(gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
case GBUF_REFLECTION_COLORLESS:
gbuffer_closure_reflection_colorless_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_reflection_colorless_load(
gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
case GBUF_REFRACTION_COLORLESS:
gbuffer_closure_refraction_colorless_load(gbuf, gbuf.closure_count, closure_tx, normal_tx);
gbuffer_closure_refraction_colorless_load(
gbuf, gbuf.closure_count, bin_index, closure_tx, normal_tx);
break;
}

View File

@ -111,6 +111,11 @@ void main()
cl3.color = vec3(1);
cl3.N = normalize(vec3(0.3, 0.2, 0.1));
ClosureUndetermined cl_none = closure_new(CLOSURE_NONE);
cl_none.weight = 1.0;
cl_none.color = vec3(1);
cl_none.N = normalize(vec3(0.0, 0.0, 1.0));
TEST(eevee_gbuffer, NormalReuseDoubleFirst)
{
data_in = gbuffer_new();
@ -228,4 +233,43 @@ void main()
EXPECT_NEAR(cl2.N, gbuffer_closure_get(data_out, 1).N, 1e-5);
EXPECT_NEAR(cl3.N, gbuffer_closure_get(data_out, 2).N, 1e-5);
}
TEST(eevee_gbuffer, NormalReuseSingleHole)
{
data_in = gbuffer_new();
data_in.closure[0] = cl1;
data_in.closure[1] = cl_none;
data_in.closure[2] = cl3;
g_data_packed = gbuffer_pack(data_in);
EXPECT_EQ(g_data_packed.normal_len, 2);
data_out = gbuffer_read(header_tx, closure_tx, normal_tx, ivec2(0));
EXPECT_EQ(data_out.closure_count, 2);
EXPECT_EQ(data_out.normal_len, 2);
EXPECT_NEAR(cl1.N, gbuffer_closure_get(data_out, 0).N, 1e-5);
EXPECT_NEAR(cl3.N, gbuffer_closure_get(data_out, 1).N, 1e-5);
EXPECT_NEAR(cl3.N, gbuffer_closure_get_by_bin(data_out, 2).N, 1e-5);
}
TEST(eevee_gbuffer, NormalReuseDoubleHole)
{
data_in = gbuffer_new();
data_in.closure[0] = cl_none;
data_in.closure[1] = cl_none;
data_in.closure[2] = cl3;
g_data_packed = gbuffer_pack(data_in);
EXPECT_EQ(g_data_packed.normal_len, 1);
data_out = gbuffer_read(header_tx, closure_tx, normal_tx, ivec2(0));
EXPECT_EQ(data_out.closure_count, 1);
EXPECT_EQ(data_out.normal_len, 1);
EXPECT_NEAR(cl3.N, gbuffer_closure_get(data_out, 0).N, 1e-5);
EXPECT_NEAR(cl3.N, gbuffer_closure_get_by_bin(data_out, 2).N, 1e-5);
}
}

View File

@ -122,6 +122,9 @@ void main()
LightProbeSample samp = lightprobe_load(P, Ng, V);
float clamp_indirect = uniform_buf.clamp.surface_indirect;
samp.volume_irradiance = spherical_harmonics_clamp(samp.volume_irradiance, clamp_indirect);
for (int i = 0; i < GBUFFER_LAYER_MAX && i < gbuf.closure_count; i++) {
ClosureUndetermined cl = gbuffer_closure_get(gbuf, i);

View File

@ -53,7 +53,7 @@ void main()
vec3 ssP_prev = drw_ndc_to_screen(project_point(uniform_buf.raytrace.radiance_persmat, P));
vec4 radiance = texture(in_radiance_tx, ssP_prev.xy);
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.raytrace.brightness_clamp);
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.clamp.surface_indirect);
imageStore(out_radiance_img, texel, radiance);
}

View File

@ -68,7 +68,7 @@ vec3 lightprobe_spherical_sample_normalized_with_parallax(
{
SphereProbeData probe = reflection_probe_buf[probe_index];
ReflectionProbeLowFreqLight shading_sh = reflection_probes_extract_low_freq(P_sh);
vec3 normalization_factor = reflection_probes_normalization_eval(
float normalization_factor = reflection_probes_normalization_eval(
L, shading_sh, probe.low_freq_light);
L = lightprobe_sphere_parallax(probe, P, L);
return normalization_factor * reflection_probes_sample(L, lod, probe.atlas_coord).rgb;
@ -139,32 +139,23 @@ vec3 lightprobe_eval(LightProbeSample samp, ClosureRefraction cl, vec3 P, vec3 V
return mix(radiance_cube, radiance_sh, fac);
}
void lightprobe_eval(LightProbeSample samp,
ClosureUndetermined cl,
vec3 P,
vec3 V,
float thickness,
inout vec3 radiance)
vec3 lightprobe_eval(
LightProbeSample samp, ClosureUndetermined cl, vec3 P, vec3 V, float thickness)
{
switch (cl.type) {
case CLOSURE_BSDF_TRANSLUCENT_ID:
radiance += lightprobe_eval(samp, to_closure_translucent(cl), P, V, thickness);
break;
return lightprobe_eval(samp, to_closure_translucent(cl), P, V, thickness);
case CLOSURE_BSSRDF_BURLEY_ID:
/* TODO: Support translucency in ray tracing first. Otherwise we have a discrepancy. */
return vec3(0.0);
case CLOSURE_BSDF_DIFFUSE_ID:
radiance += lightprobe_eval(samp, to_closure_diffuse(cl), P, V);
break;
return lightprobe_eval(samp, to_closure_diffuse(cl), P, V);
case CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID:
radiance += lightprobe_eval(samp, to_closure_reflection(cl), P, V);
break;
return lightprobe_eval(samp, to_closure_reflection(cl), P, V);
case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
radiance += lightprobe_eval(samp, to_closure_refraction(cl), P, V, thickness);
break;
case CLOSURE_NONE_ID:
/* TODO(fclem): Assert. */
break;
return lightprobe_eval(samp, to_closure_refraction(cl), P, V, thickness);
}
return vec3(0.0);
}
#endif /* SPHERE_PROBE */

View File

@ -13,6 +13,7 @@
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_ray_types_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_ray_trace_screen_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_spherical_harmonics_lib.glsl)
void main()
{
@ -60,12 +61,16 @@ void main()
* direction over many rays. */
vec3 Ng = ray.direction;
LightProbeSample samp = lightprobe_load(ray.origin, Ng, V);
/* Clamp SH to have parity with forward evaluation. */
float clamp_indirect = uniform_buf.clamp.surface_indirect;
samp.volume_irradiance = spherical_harmonics_clamp(samp.volume_irradiance, clamp_indirect);
vec3 radiance = lightprobe_eval_direction(
samp, ray.origin, ray.direction, safe_rcp(ray_pdf_inv));
/* Set point really far for correct reprojection of background. */
float hit_time = 1000.0;
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.raytrace.brightness_clamp);
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.clamp.surface_indirect);
imageStore(ray_time_img, texel, vec4(hit_time));
imageStore(ray_radiance_img, texel, vec4(radiance, 0.0));

View File

@ -87,11 +87,6 @@ void main()
if (hit.valid) {
/* Evaluate radiance at hit-point. */
radiance = textureLod(planar_radiance_tx, vec3(hit.ss_hit_P.xy, planar_id), 0.0).rgb;
/* Transmit twice if thickness is set and ray is longer than thickness. */
// if (thickness > 0.0 && length(ray_data.xyz) > thickness) {
// ray_radiance.rgb *= color;
// }
}
else {
/* Using ray direction as geometric normal to bias the sampling position.
@ -105,7 +100,7 @@ void main()
hit.time = 10000.0;
}
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.raytrace.brightness_clamp);
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.clamp.surface_indirect);
imageStore(ray_time_img, texel, vec4(hit.time));
imageStore(ray_radiance_img, texel, vec4(radiance, 0.0));

View File

@ -13,6 +13,7 @@
#pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_ray_types_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_ray_trace_screen_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_spherical_harmonics_lib.glsl)
void main()
{
@ -131,12 +132,16 @@ void main()
vec3 Ng = ray.direction;
/* Fallback to nearest light-probe. */
LightProbeSample samp = lightprobe_load(ray.origin, Ng, V);
/* Clamp SH to have parity with forward evaluation. */
float clamp_indirect = uniform_buf.clamp.surface_indirect;
samp.volume_irradiance = spherical_harmonics_clamp(samp.volume_irradiance, clamp_indirect);
radiance = lightprobe_eval_direction(samp, ray.origin, ray.direction, safe_rcp(ray_pdf_inv));
/* Set point really far for correct reprojection of background. */
hit.time = 10000.0;
}
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.raytrace.brightness_clamp);
radiance = colorspace_brightness_clamp_max(radiance, uniform_buf.clamp.surface_indirect);
imageStore(ray_time_img, texel, vec4(hit.time));
imageStore(ray_radiance_img, texel, vec4(radiance, 0.0));

View File

@ -40,11 +40,11 @@ ReflectionProbeLowFreqLight reflection_probes_extract_low_freq(SphericalHarmonic
return result;
}
vec3 reflection_probes_normalization_eval(vec3 L,
ReflectionProbeLowFreqLight numerator,
ReflectionProbeLowFreqLight denominator)
float reflection_probes_normalization_eval(vec3 L,
ReflectionProbeLowFreqLight numerator,
ReflectionProbeLowFreqLight denominator)
{
/* TODO(fclem): Adjusting directionality is tricky.
* Needs to be revisited later on. For now only use the ambient term. */
return vec3(numerator.ambient * safe_rcp(denominator.ambient));
return (numerator.ambient * safe_rcp(denominator.ambient));
}

View File

@ -89,11 +89,12 @@ void main()
radiance.rgb = mix(world_radiance.rgb, radiance.rgb, opacity);
}
radiance = colorspace_brightness_clamp_max(radiance, probe_brightness_clamp);
if (!any(greaterThanEqual(local_texel, ivec2(write_coord.extent)))) {
float clamp_indirect = uniform_buf.clamp.surface_indirect;
vec3 out_radiance = colorspace_brightness_clamp_max(radiance, clamp_indirect);
ivec3 texel = ivec3(local_texel + write_coord.offset, write_coord.layer);
imageStore(atlas_img, texel, vec4(radiance, 1.0));
imageStore(atlas_img, texel, vec4(out_radiance, 1.0));
}
if (extract_sh) {

View File

@ -26,5 +26,8 @@ void main()
sh = lightprobe_irradiance_sample(probe_center);
}
float clamp_indirect_sh = uniform_buf.clamp.surface_indirect;
sh = spherical_harmonics_clamp(sh, clamp_indirect_sh);
reflection_probe_buf[idx].low_freq_light = reflection_probes_extract_low_freq(sh);
}

View File

@ -15,13 +15,13 @@
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
ivec2 tex_size = textureSize(depth_tx, 0).xy;
ivec2 tex_size = input_depth_extent;
if (!in_range_inclusive(texel, ivec2(0), ivec2(tex_size - 1))) {
return;
}
float depth = texelFetch(depth_tx, texel, 0).r;
float depth = texelFetch(hiz_tx, texel, 0).r;
if (depth == 1.0) {
return;
}

View File

@ -707,3 +707,29 @@ SphericalHarmonicL1 spherical_harmonics_decompress(SphericalHarmonicL1 sh)
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Clamping
*
* Clamp the total power of the SH function.
* \{ */
SphericalHarmonicL1 spherical_harmonics_clamp(SphericalHarmonicL1 sh, float clamp_value)
{
/* Convert coefficients to per channel column. */
mat4x4 per_channel = transpose(mat4x4(sh.L0.M0, sh.L1.Mn1, sh.L1.M0, sh.L1.Mp1));
/* Maximum per channel. */
vec3 max_L1 = vec3(reduce_max(abs(per_channel[0].yzw)),
reduce_max(abs(per_channel[1].yzw)),
reduce_max(abs(per_channel[2].yzw)));
/* Find maximum of the sh function over all chanels. */
vec3 max_sh = abs(sh.L0.M0.rgb) * 0.282094792 + max_L1 * 0.488602512;
float fac = clamp_value * safe_rcp(reduce_max(max_sh));
if (fac > 1.0) {
return sh;
}
return spherical_harmonics_mul(sh, fac);
}
/** \} */

View File

@ -21,8 +21,7 @@
#ifdef VOLUME_LIGHTING
vec3 volume_scatter_light_eval(
const bool is_directional, vec3 P, vec3 V, uint l_idx, float s_anisotropy)
vec3 volume_light_eval(const bool is_directional, vec3 P, vec3 V, uint l_idx, float s_anisotropy)
{
LightData light = light_buf[l_idx];
@ -48,10 +47,24 @@ vec3 volume_scatter_light_eval(
return vec3(0);
}
vec3 Li = volume_light(light, is_directional, lv) * visibility *
volume_shadow(light, is_directional, P, lv, extinction_tx);
vec3 Li = volume_light(light, is_directional, lv) * visibility;
return colorspace_brightness_clamp_max(Li, uniform_buf.volumes.light_clamp);
if (light.tilemap_index != LIGHT_NO_SHADOW) {
Li *= volume_shadow(light, is_directional, P, lv, extinction_tx);
}
return Li;
}
vec3 volume_lightprobe_eval(vec3 P, vec3 V, float s_anisotropy)
{
SphericalHarmonicL1 phase_sh = volume_phase_function_as_sh_L1(V, s_anisotropy);
SphericalHarmonicL1 volume_radiance_sh = lightprobe_irradiance_sample(P);
float clamp_indirect = uniform_buf.clamp.volume_indirect;
volume_radiance_sh = spherical_harmonics_clamp(volume_radiance_sh, clamp_indirect);
return spherical_harmonics_dot(volume_radiance_sh, phase_sh).xyz;
}
#endif
@ -81,25 +94,35 @@ void main()
float s_anisotropy = phase.x / max(1.0, phase.y);
#ifdef VOLUME_LIGHTING
SphericalHarmonicL1 phase_sh = volume_phase_function_as_sh_L1(V, s_anisotropy);
SphericalHarmonicL1 volume_radiance_sh = lightprobe_irradiance_sample(P);
vec3 direct_radiance = vec3(0.0);
vec3 light_scattering = spherical_harmonics_dot(volume_radiance_sh, phase_sh).xyz;
if (reduce_max(s_scattering) > 0.0) {
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
direct_radiance += volume_light_eval(true, P, V, l_idx, s_anisotropy);
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
light_scattering += volume_scatter_light_eval(true, P, V, l_idx, s_anisotropy);
vec2 pixel = ((vec2(froxel.xy) + 0.5) * uniform_buf.volumes.inv_tex_size.xy) *
uniform_buf.volumes.main_view_extent;
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx)
{
direct_radiance += volume_light_eval(false, P, V, l_idx, s_anisotropy);
}
LIGHT_FOREACH_END
}
LIGHT_FOREACH_END
vec2 pixel = ((vec2(froxel.xy) + 0.5) * uniform_buf.volumes.inv_tex_size.xy) *
uniform_buf.volumes.main_view_extent;
vec3 indirect_radiance = volume_lightprobe_eval(P, V, s_anisotropy).xyz;
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) {
light_scattering += volume_scatter_light_eval(false, P, V, l_idx, s_anisotropy);
}
LIGHT_FOREACH_END
direct_radiance *= s_scattering;
indirect_radiance *= s_scattering;
scattering += light_scattering * s_scattering;
float clamp_direct = uniform_buf.clamp.volume_direct;
float clamp_indirect = uniform_buf.clamp.volume_indirect;
direct_radiance = colorspace_brightness_clamp_max(direct_radiance, clamp_direct);
indirect_radiance = colorspace_brightness_clamp_max(indirect_radiance, clamp_indirect);
scattering += direct_radiance + indirect_radiance;
#endif
if (uniform_buf.volumes.history_opacity > 0.0) {

View File

@ -61,6 +61,11 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light)
.image_out(2, DEFERRED_RADIANCE_FORMAT, "direct_radiance_1_img")
.image_out(3, DEFERRED_RADIANCE_FORMAT, "direct_radiance_2_img")
.image_out(4, DEFERRED_RADIANCE_FORMAT, "direct_radiance_3_img")
/* Optimized out if use_split_indirect is false. */
.image_out(5, DEFERRED_RADIANCE_FORMAT, "indirect_radiance_1_img")
.image_out(6, DEFERRED_RADIANCE_FORMAT, "indirect_radiance_2_img")
.image_out(7, DEFERRED_RADIANCE_FORMAT, "indirect_radiance_3_img")
.specialization_constant(Type::BOOL, "use_split_indirect", false)
.specialization_constant(Type::BOOL, "use_lightprobe_eval", false)
.specialization_constant(Type::BOOL, "render_pass_shadow_enabled", true)
.define("SPECIALIZED_SHADOW_PARAMS")
@ -103,6 +108,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_combine)
.sampler(5, ImageType::FLOAT_2D, "indirect_radiance_1_tx")
.sampler(6, ImageType::FLOAT_2D, "indirect_radiance_2_tx")
.sampler(7, ImageType::FLOAT_2D, "indirect_radiance_3_tx")
.image(5, GPU_RGBA16F, Qualifier::READ_WRITE, ImageType::FLOAT_2D, "radiance_feedback_img")
.fragment_out(0, Type::VEC4, "out_combined")
.additional_info("eevee_shared",
"eevee_gbuffer_data",
@ -114,7 +120,8 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_combine)
.specialization_constant(Type::BOOL, "render_pass_diffuse_light_enabled", true)
.specialization_constant(Type::BOOL, "render_pass_specular_light_enabled", true)
.specialization_constant(Type::BOOL, "render_pass_normal_enabled", true)
.specialization_constant(Type::BOOL, "use_combined_lightprobe_eval", false)
.specialization_constant(Type::BOOL, "use_radiance_feedback", false)
.specialization_constant(Type::BOOL, "use_split_radiance", false)
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_deferred_capture_eval)

View File

@ -174,7 +174,7 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_world)
IRRADIANCE_GRID_BRICK_SIZE,
IRRADIANCE_GRID_BRICK_SIZE)
.define("IRRADIANCE_GRID_UPLOAD")
.additional_info("eevee_shared")
.additional_info("eevee_shared", "eevee_global_ubo")
.push_constant(Type::INT, "grid_index")
.storage_buf(0, Qualifier::READ, "uint", "bricks_infos_buf[]")
.storage_buf(1, Qualifier::READ, "SphereProbeHarmonic", "harmonic_buf")
@ -188,7 +188,7 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_load)
IRRADIANCE_GRID_BRICK_SIZE,
IRRADIANCE_GRID_BRICK_SIZE)
.define("IRRADIANCE_GRID_UPLOAD")
.additional_info("eevee_shared")
.additional_info("eevee_shared", "eevee_global_ubo")
.push_constant(Type::MAT4, "grid_local_to_world")
.push_constant(Type::INT, "grid_index")
.push_constant(Type::INT, "grid_start_index")

View File

@ -23,13 +23,12 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_remap)
.push_constant(Type::IVEC4, "probe_coord_packed")
.push_constant(Type::IVEC4, "write_coord_packed")
.push_constant(Type::IVEC4, "world_coord_packed")
.push_constant(Type::FLOAT, "probe_brightness_clamp")
.sampler(0, ImageType::FLOAT_CUBE, "cubemap_tx")
.sampler(1, ImageType::FLOAT_2D_ARRAY, "atlas_tx")
.storage_buf(0, Qualifier::WRITE, "SphereProbeHarmonic", "out_sh[SPHERE_PROBE_MAX_HARMONIC]")
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "atlas_img")
.compute_source("eevee_reflection_probe_remap_comp.glsl")
.additional_info("eevee_shared")
.additional_info("eevee_shared", "eevee_global_ubo")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_reflection_probe_irradiance)
@ -48,7 +47,10 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_select)
"SphereProbeData",
"reflection_probe_buf[SPHERE_PROBE_MAX]")
.push_constant(Type::INT, "reflection_probe_count")
.additional_info("eevee_shared", "eevee_sampling_data", "eevee_volume_probe_data")
.additional_info("eevee_shared",
"eevee_sampling_data",
"eevee_global_ubo",
"eevee_volume_probe_data")
.compute_source("eevee_reflection_probe_select_comp.glsl")
.do_static_compilation(true);

View File

@ -61,11 +61,12 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_update)
GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
.do_static_compilation(true)
.local_group_size(SHADOW_DEPTH_SCAN_GROUP_SIZE, SHADOW_DEPTH_SCAN_GROUP_SIZE)
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
.push_constant(Type::IVEC2, "input_depth_extent")
.push_constant(Type::FLOAT, "tilemap_proj_ratio")
.additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data")
.additional_info(
"eevee_shared", "draw_view", "draw_view_culling", "eevee_hiz_data", "eevee_light_data")
.compute_source("eevee_shadow_tag_usage_comp.glsl");
GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_surfels)

View File

@ -55,6 +55,7 @@ void OVERLAY_edit_curves_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_edit_particle_point();
grp = pd->edit_curves_points_grp[i] = DRW_shgroup_create(sh, psl->edit_curves_points_ps[i]);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "useWeight", false);
}
DRW_PASS_CREATE(psl->edit_curves_lines_ps[i], (state | pd->clipping_state));
sh = OVERLAY_shader_edit_particle_strand();

View File

@ -184,6 +184,7 @@ static void OVERLAY_cache_init(void *vedata)
case CTX_MODE_PAINT_GREASE_PENCIL:
case CTX_MODE_SCULPT_GREASE_PENCIL:
case CTX_MODE_EDIT_GREASE_PENCIL:
case CTX_MODE_WEIGHT_GREASE_PENCIL:
OVERLAY_edit_grease_pencil_cache_init(data);
break;
case CTX_MODE_PARTICLE:
@ -294,6 +295,14 @@ static bool overlay_object_is_edit_mode(const OVERLAY_PrivateData *pd, const Obj
return false;
}
static bool overlay_object_is_paint_mode(const DRWContextState *draw_ctx, const Object *ob)
{
if (ob->type == OB_GREASE_PENCIL && draw_ctx->object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) {
return true;
}
return (ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT);
}
static bool overlay_should_fade_object(Object *ob, Object *active_object)
{
if (!active_object || !ob) {
@ -336,8 +345,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
false;
const bool in_particle_edit_mode = (ob->mode == OB_MODE_PARTICLE_EDIT) &&
(pd->ctx_mode == CTX_MODE_PARTICLE);
const bool in_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
const bool in_paint_mode = overlay_object_is_paint_mode(draw_ctx, ob);
const bool in_sculpt_curve_mode = (ob == draw_ctx->obact ||
(is_preview && dupli_parent == draw_ctx->obact &&
ob->type == OB_CURVES)) &&
@ -464,6 +472,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
case OB_MODE_TEXTURE_PAINT:
OVERLAY_paint_texture_cache_populate(data, ob);
break;
case OB_MODE_WEIGHT_GPENCIL_LEGACY:
OVERLAY_weight_grease_pencil_cache_populate(data, ob);
break;
default:
break;
}
@ -750,6 +761,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_edit_curves_draw(data);
break;
case CTX_MODE_EDIT_GREASE_PENCIL:
case CTX_MODE_WEIGHT_GREASE_PENCIL:
OVERLAY_edit_grease_pencil_draw(data);
break;
default:

View File

@ -20,7 +20,7 @@ void OVERLAY_facing_cache_init(OVERLAY_Data *vedata)
for (int i = 0; i < 2; i++) {
/* Non Meshes Pass (Camera, empties, lights ...) */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->facing_ps[i], state | pd->clipping_state);
GPUShader *sh = OVERLAY_shader_facing();

View File

@ -23,7 +23,7 @@ void OVERLAY_fade_cache_init(OVERLAY_Data *vedata)
for (int i = 0; i < 2; i++) {
/* Non Meshes Pass (Camera, empties, lights ...) */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_BLEND_ALPHA;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->fade_ps[i], state | pd->clipping_state);
GPUShader *sh = OVERLAY_shader_uniform_color();

View File

@ -24,6 +24,7 @@ void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata)
const bke::AttrDomain selection_domain = ED_grease_pencil_selection_domain_get(
draw_ctx->scene->toolsettings);
const View3D *v3d = draw_ctx->v3d;
const bool use_weight = (draw_ctx->object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) != 0;
GPUShader *sh;
DRWShadingGroup *grp;
@ -32,19 +33,23 @@ void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata)
DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->edit_grease_pencil_ps, (state | pd->clipping_state));
const bool show_points = selection_domain == bke::AttrDomain::Point;
const bool show_points = (selection_domain == bke::AttrDomain::Point) || use_weight;
const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) != 0;
if (show_lines) {
sh = OVERLAY_shader_edit_particle_strand();
grp = pd->edit_grease_pencil_wires_grp = DRW_shgroup_create(sh, psl->edit_grease_pencil_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "useWeight", use_weight);
DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
}
if (show_points) {
sh = OVERLAY_shader_edit_particle_point();
grp = pd->edit_grease_pencil_points_grp = DRW_shgroup_create(sh, psl->edit_grease_pencil_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "useWeight", use_weight);
DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
}
}
@ -69,6 +74,28 @@ void OVERLAY_edit_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
}
}
void OVERLAY_weight_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
using namespace blender::draw;
OVERLAY_PrivateData *pd = vedata->stl->pd;
const DRWContextState *draw_ctx = DRW_context_state_get();
DRWShadingGroup *lines_grp = pd->edit_grease_pencil_wires_grp;
if (lines_grp) {
blender::gpu::Batch *geom_lines = DRW_cache_grease_pencil_weight_lines_get(draw_ctx->scene,
ob);
DRW_shgroup_call_no_cull(lines_grp, geom_lines, ob);
}
DRWShadingGroup *points_grp = pd->edit_grease_pencil_points_grp;
if (points_grp) {
blender::gpu::Batch *geom_points = DRW_cache_grease_pencil_weight_points_get(draw_ctx->scene,
ob);
DRW_shgroup_call_no_cull(points_grp, geom_points, ob);
}
}
void OVERLAY_edit_grease_pencil_draw(OVERLAY_Data *vedata)
{
OVERLAY_PassList *psl = vedata->psl;

View File

@ -249,16 +249,7 @@ void OVERLAY_paint_vertex_cache_populate(OVERLAY_Data *vedata, Object *ob)
void OVERLAY_paint_weight_cache_populate(OVERLAY_Data *vedata, Object *ob)
{
switch (ob->type) {
case OB_MESH:
OVERLAY_paint_vertex_cache_populate(vedata, ob);
break;
case OB_GREASE_PENCIL:
/* TODO */
break;
default:
BLI_assert_unreachable();
}
OVERLAY_paint_vertex_cache_populate(vedata, ob);
}
void OVERLAY_paint_draw(OVERLAY_Data *vedata)

View File

@ -46,6 +46,7 @@ void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata)
sh = OVERLAY_shader_edit_particle_point();
pd->edit_particle_point_grp = grp = DRW_shgroup_create(sh, psl->edit_particle_ps);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_bool_copy(grp, "useWeight", false);
}
void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob)

View File

@ -564,6 +564,7 @@ void OVERLAY_edit_gpencil_legacy_draw(OVERLAY_Data *vedata);
void OVERLAY_edit_grease_pencil_cache_init(OVERLAY_Data *vedata);
void OVERLAY_edit_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_weight_grease_pencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_grease_pencil_draw(OVERLAY_Data *vedata);
void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata);

View File

@ -571,6 +571,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_particle_point)
.vertex_in(0, Type::VEC3, "pos")
.vertex_in(1, Type::FLOAT, "selection")
.vertex_out(overlay_edit_flat_color_iface)
.sampler(0, ImageType::FLOAT_1D, "weightTex")
.push_constant(Type::BOOL, "useWeight")
.fragment_out(0, Type::VEC4, "fragColor")
.vertex_source("overlay_edit_particle_point_vert.glsl")
.fragment_source("overlay_point_varying_color_frag.glsl")

View File

@ -5,12 +5,34 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#define no_active_weight 666.0
vec3 weight_to_rgb(float t)
{
if (t == no_active_weight) {
/* No weight. */
return colorWire.rgb;
}
if (t > 1.0 || t < 0.0) {
/* Error color */
return vec3(1.0, 0.0, 1.0);
}
else {
return texture(weightTex, t).rgb;
}
}
void main()
{
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);
finalColor = mix(colorWire, colorVertexSelect, selection);
if (useWeight) {
finalColor = vec4(weight_to_rgb(selection), 1.0);
}
else {
finalColor = mix(colorWire, colorVertexSelect, selection);
}
gl_PointSize = sizeVertex * 2.0;

View File

@ -286,4 +286,6 @@ blender::gpu::Batch *DRW_cache_grease_pencil_edit_points_get(const Scene *scene,
blender::gpu::Batch *DRW_cache_grease_pencil_edit_lines_get(const Scene *scene, Object *ob);
gpu::VertBuf *DRW_cache_grease_pencil_position_buffer_get(const Scene *scene, Object *ob);
gpu::VertBuf *DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Object *ob);
blender::gpu::Batch *DRW_cache_grease_pencil_weight_points_get(const Scene *scene, Object *ob);
blender::gpu::Batch *DRW_cache_grease_pencil_weight_lines_get(const Scene *scene, Object *ob);
} // namespace blender::draw

View File

@ -310,7 +310,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
Mesh *mesh,
bool is_editmode,
bool is_paint_mode,
bool is_mode_active,
bool edit_mode_active,
const float4x4 &object_to_world,
bool do_final,
bool do_uvedit,

View File

@ -571,7 +571,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
const bool edit_mode_active,
const float4x4 &object_to_world,
const bool do_final,
const bool do_uvedit,
@ -698,7 +698,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
mesh,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
object_to_world,
do_final,
do_uvedit,

View File

@ -576,7 +576,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
Mesh *mesh,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
const bool edit_mode_active,
const float4x4 &object_to_world,
const bool do_final,
const bool do_uvedit,
@ -599,7 +599,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->bm = mesh->runtime->edit_mesh->bm;
mr->edit_bmesh = mesh->runtime->edit_mesh.get();
mr->mesh = (do_final) ? editmesh_eval_final : editmesh_eval_cage;
mr->edit_data = is_mode_active ? mr->mesh->runtime->edit_data.get() : nullptr;
mr->edit_data = edit_mode_active ? mr->mesh->runtime->edit_data.get() : nullptr;
/* If there is no distinct cage, hide unmapped edges that can't be selected. */
mr->hide_unmapped_edges = !do_final || editmesh_eval_final == editmesh_eval_cage;
@ -636,7 +636,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
/* Use bmesh directly when the object is in edit mode unchanged by any modifiers.
* For non-final UVs, always use original bmesh since the UV editor does not support
* using the cage mesh with deformed coordinates. */
if ((is_mode_active && mr->mesh->runtime->is_original_bmesh &&
if ((edit_mode_active && mr->mesh->runtime->is_original_bmesh &&
mr->mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) ||
(do_uvedit && !do_final))
{
@ -646,7 +646,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->extract_type = MR_EXTRACT_MESH;
/* Use mapping from final to original mesh when the object is in edit mode. */
if (is_mode_active && do_final) {
if (edit_mode_active && do_final) {
mr->v_origindex = static_cast<const int *>(
CustomData_get_layer(&mr->mesh->vert_data, CD_ORIGINDEX));
mr->e_origindex = static_cast<const int *>(
@ -709,7 +709,7 @@ MeshRenderData *mesh_render_data_create(Object *object,
mr->material_indices = *attributes.lookup<int>("material_index", bke::AttrDomain::Face);
if (is_mode_active || is_paint_mode) {
if (edit_mode_active || is_paint_mode) {
if (use_hide) {
mr->hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
mr->hide_edge = *attributes.lookup<bool>(".hide_edge", bke::AttrDomain::Edge);

View File

@ -10,6 +10,7 @@
#include "BKE_attribute.hh"
#include "BKE_curves.hh"
#include "BKE_deform.hh"
#include "BKE_grease_pencil.h"
#include "BKE_grease_pencil.hh"
@ -209,6 +210,189 @@ static void copy_transformed_positions(const Span<float3> src_positions,
}
}
static void grease_pencil_weight_batch_ensure(Object &object,
const GreasePencil &grease_pencil,
const Scene &scene)
{
using namespace blender::bke::greasepencil;
constexpr float no_active_weight = 666.0f;
BLI_assert(grease_pencil.runtime != nullptr);
GreasePencilBatchCache *cache = static_cast<GreasePencilBatchCache *>(
grease_pencil.runtime->batch_cache);
if (cache->edit_points_pos != nullptr) {
return;
}
/* Should be discarded together. */
BLI_assert(cache->edit_points_pos == nullptr && cache->edit_line_indices == nullptr &&
cache->edit_points_indices == nullptr);
BLI_assert(cache->edit_points == nullptr && cache->edit_lines == nullptr);
/* Get active vertex group. */
const bDeformGroup *active_defgroup = static_cast<bDeformGroup *>(BLI_findlink(
&grease_pencil.vertex_group_names, grease_pencil.vertex_group_active_index - 1));
const char *active_defgroup_name = (active_defgroup == nullptr) ? "" : active_defgroup->name;
/* Get the visible drawings. */
const Vector<ed::greasepencil::DrawingInfo> drawings =
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
const Span<const Layer *> layers = grease_pencil.layers();
static GPUVertFormat format_points_pos = {0};
if (format_points_pos.attr_len == 0) {
GPU_vertformat_attr_add(&format_points_pos, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
}
static GPUVertFormat format_points_weight = {0};
if (format_points_weight.attr_len == 0) {
GPU_vertformat_attr_add(&format_points_weight, "selection", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
GPUUsageType vbo_flag = GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
cache->edit_points_pos = GPU_vertbuf_create_with_format_ex(&format_points_pos, vbo_flag);
cache->edit_points_selection = GPU_vertbuf_create_with_format_ex(&format_points_weight,
vbo_flag);
int visible_points_num = 0;
int total_line_ids_num = 0;
int total_points_num = 0;
for (const ed::greasepencil::DrawingInfo &info : drawings) {
const bke::CurvesGeometry &curves = info.drawing.strokes();
total_points_num += curves.points_num();
}
GPU_vertbuf_data_alloc(cache->edit_points_pos, total_points_num);
GPU_vertbuf_data_alloc(cache->edit_points_selection, total_points_num);
MutableSpan<float3> points_pos = {
static_cast<float3 *>(GPU_vertbuf_get_data(cache->edit_points_pos)),
GPU_vertbuf_get_vertex_len(cache->edit_points_pos)};
MutableSpan<float> points_weight = {
static_cast<float *>(GPU_vertbuf_get_data(cache->edit_points_selection)),
GPU_vertbuf_get_vertex_len(cache->edit_points_selection)};
int drawing_start_offset = 0;
for (const ed::greasepencil::DrawingInfo &info : drawings) {
const Layer &layer = *layers[info.layer_index];
const float4x4 layer_space_to_object_space = layer.to_object_space(object);
const bke::CurvesGeometry &curves = info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
IndexMaskMemory memory;
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
object, info.drawing, memory);
const IndexRange points(drawing_start_offset, curves.points_num());
const Span<float3> positions = curves.positions();
MutableSpan<float3> positions_slice = points_pos.slice(points);
threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange range) {
copy_transformed_positions(positions, range, layer_space_to_object_space, positions_slice);
});
/* Get vertex weights of the active vertex group in this drawing. */
const VArray<float> weights = *curves.attributes().lookup_or_default<float>(
active_defgroup_name, bke::AttrDomain::Point, no_active_weight);
MutableSpan<float> weights_slice = points_weight.slice(points);
weights.materialize(weights_slice);
drawing_start_offset += curves.points_num();
/* Add one id for the restart after every curve. */
total_line_ids_num += visible_strokes.size();
Array<int> size_per_editable_stroke(visible_strokes.size());
offset_indices::gather_group_sizes(points_by_curve, visible_strokes, size_per_editable_stroke);
/* Add one id for every non-cyclic segment. */
total_line_ids_num += std::accumulate(
size_per_editable_stroke.begin(), size_per_editable_stroke.end(), 0);
/* Add one id for the last segment of every cyclic curve. */
total_line_ids_num += array_utils::count_booleans(curves.cyclic(), visible_strokes);
/* Do not show weights for locked layers. */
if (layer.is_locked()) {
continue;
}
visible_strokes.foreach_index([&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
visible_points_num += points.size();
});
}
GPUIndexBufBuilder elb;
GPU_indexbuf_init_ex(&elb,
GPU_PRIM_LINE_STRIP,
total_line_ids_num,
GPU_vertbuf_get_vertex_len(cache->edit_points_pos));
GPUIndexBufBuilder epb;
GPU_indexbuf_init_ex(&epb,
GPU_PRIM_POINTS,
visible_points_num,
GPU_vertbuf_get_vertex_len(cache->edit_points_pos));
/* Fill point index buffer with data. */
drawing_start_offset = 0;
for (const ed::greasepencil::DrawingInfo &info : drawings) {
const Layer *layer = layers[info.layer_index];
const bke::CurvesGeometry &curves = info.drawing.strokes();
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> cyclic = curves.cyclic();
IndexMaskMemory memory;
const IndexMask visible_strokes = ed::greasepencil::retrieve_visible_strokes(
object, info.drawing, memory);
/* Fill line indices. */
visible_strokes.foreach_index([&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
const bool is_cyclic = cyclic[curve_i];
for (const int point_i : points) {
GPU_indexbuf_add_generic_vert(&elb, point_i + drawing_start_offset);
}
if (is_cyclic) {
GPU_indexbuf_add_generic_vert(&elb, points.first() + drawing_start_offset);
}
GPU_indexbuf_add_primitive_restart(&elb);
});
/* Fill point indices. */
if (!layer->is_locked()) {
visible_strokes.foreach_index([&](const int curve_i) {
const IndexRange points = points_by_curve[curve_i];
for (const int point : points) {
GPU_indexbuf_add_generic_vert(&epb, point + drawing_start_offset);
}
});
}
drawing_start_offset += curves.points_num();
}
cache->edit_line_indices = GPU_indexbuf_build(&elb);
cache->edit_points_indices = GPU_indexbuf_build(&epb);
/* Create the batches. */
cache->edit_points = GPU_batch_create(
GPU_PRIM_POINTS, cache->edit_points_pos, cache->edit_points_indices);
GPU_batch_vertbuf_add(cache->edit_points, cache->edit_points_selection, false);
cache->edit_lines = GPU_batch_create(
GPU_PRIM_LINE_STRIP, cache->edit_points_pos, cache->edit_line_indices);
GPU_batch_vertbuf_add(cache->edit_lines, cache->edit_points_selection, false);
/* Allow creation of buffer texture. */
GPU_vertbuf_use(cache->edit_points_pos);
GPU_vertbuf_use(cache->edit_points_selection);
cache->is_dirty = false;
}
static void grease_pencil_edit_batch_ensure(Object &object,
const GreasePencil &grease_pencil,
const Scene &scene)
@ -752,4 +936,22 @@ gpu::VertBuf *DRW_cache_grease_pencil_color_buffer_get(const Scene *scene, Objec
return cache->vbo_col;
}
gpu::Batch *DRW_cache_grease_pencil_weight_points_get(const Scene *scene, Object *ob)
{
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
GreasePencilBatchCache *cache = grease_pencil_batch_cache_get(grease_pencil);
grease_pencil_weight_batch_ensure(*ob, grease_pencil, *scene);
return cache->edit_points;
}
gpu::Batch *DRW_cache_grease_pencil_weight_lines_get(const Scene *scene, Object *ob)
{
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
GreasePencilBatchCache *cache = grease_pencil_batch_cache_get(grease_pencil);
grease_pencil_weight_batch_ensure(*ob, grease_pencil, *scene);
return cache->edit_lines;
}
} // namespace blender::draw

View File

@ -1383,7 +1383,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
DRW_object_is_in_edit_mode(ob);
/* This could be set for paint mode too, currently it's only used for edit-mode. */
const bool is_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob);
const bool edit_mode_active = is_editmode && DRW_object_is_in_edit_mode(ob);
DRWBatchFlag batch_requested = cache.batch_requested;
cache.batch_requested = (DRWBatchFlag)0;
@ -1512,7 +1512,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
cache.batch_ready |= batch_requested;
bool do_cage = false, do_uvcage = false;
if (is_editmode && is_mode_active) {
if (is_editmode && edit_mode_active) {
const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob);
const Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob);
@ -1871,7 +1871,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
mesh,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
ob->object_to_world(),
false,
true,
@ -1888,7 +1888,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
mesh,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
ob->object_to_world(),
false,
false,
@ -1904,7 +1904,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
&cache.final,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
ob->object_to_world(),
true,
false,
@ -1925,7 +1925,7 @@ void DRW_mesh_batch_cache_create_requested(TaskGraph *task_graph,
mesh,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
ob->object_to_world(),
true,
false,

View File

@ -2094,7 +2094,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
MeshBufferCache &mbc,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
const bool edit_mode_active,
const float4x4 &object_to_world,
const bool do_final,
const bool do_uvedit,
@ -2172,7 +2172,7 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
mesh,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
object_to_world,
do_final,
do_uvedit,
@ -2319,7 +2319,7 @@ void DRW_create_subdivision(Object *ob,
MeshBufferCache *mbc,
const bool is_editmode,
const bool is_paint_mode,
const bool is_mode_active,
const bool edit_mode_active,
const float4x4 &object_to_world,
const bool do_final,
const bool do_uvedit,
@ -2343,7 +2343,7 @@ void DRW_create_subdivision(Object *ob,
*mbc,
is_editmode,
is_paint_mode,
is_mode_active,
edit_mode_active,
object_to_world,
do_final,
do_uvedit,

View File

@ -203,7 +203,7 @@ void DRW_create_subdivision(Object *ob,
MeshBufferCache *mbc,
bool is_editmode,
bool is_paint_mode,
bool is_mode_active,
bool edit_mode_active,
const float4x4 &object_to_world,
bool do_final,
bool do_uvedit,

View File

@ -228,16 +228,6 @@ void View::frustum_culling_sphere_calc(int view_id)
}
}
void View::disable(IndexRange range)
{
/* Set bounding sphere to -1.0f radius will bypass the culling test and treat every instance as
* invisible. */
range = IndexRange(view_len_).intersect(range);
for (auto view_id : range) {
reinterpret_cast<BoundSphere *>(&culling_[view_id].bound_sphere)->radius = -1.0f;
}
}
void View::bind()
{
if (dirty_ && !procedural_) {

View File

@ -73,9 +73,6 @@ class View {
/* For compatibility with old system. Will be removed at some point. */
void sync(const DRWView *view);
/** Disable a range in the multi-view array. Disabled view will not produce any instances. */
void disable(IndexRange range);
/** Enable or disable every visibility test (frustum culling, HiZ culling). */
void visibility_test(bool enable)
{

View File

@ -278,14 +278,14 @@ struct MeshExtract {
/* `draw_cache_extract_mesh_render_data.cc` */
/**
* \param is_mode_active: When true, use the modifiers from the edit-data,
* \param edit_mode_active: When true, use the modifiers from the edit-data,
* otherwise don't use modifiers as they are not from this object.
*/
MeshRenderData *mesh_render_data_create(Object *object,
Mesh *mesh,
bool is_editmode,
bool is_paint_mode,
bool is_mode_active,
bool edit_mode_active,
const float4x4 &object_to_world,
bool do_final,
bool do_uvedit,

View File

@ -962,6 +962,7 @@ void ANIM_OT_keyframe_delete_v3d(wmOperatorType *ot)
static int insert_key_button_exec(bContext *C, wmOperator *op)
{
using namespace blender::animrig;
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
@ -992,15 +993,14 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
if (fcu) {
changed = blender::animrig::insert_keyframe_direct(
op->reports,
ptr,
prop,
fcu,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
nullptr,
eInsertKeyFlags(0));
changed = insert_keyframe_direct(op->reports,
ptr,
prop,
fcu,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
nullptr,
eInsertKeyFlags(0));
}
else {
BKE_report(op->reports,
@ -1017,19 +1017,18 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
C, &ptr, prop, index, nullptr, nullptr, &driven, &special);
if (fcu && driven) {
const float driver_frame = blender::animrig::evaluate_driver_from_rna_pointer(
const float driver_frame = evaluate_driver_from_rna_pointer(
&anim_eval_context, &ptr, prop, fcu);
AnimationEvalContext remapped_context = BKE_animsys_eval_context_construct(
CTX_data_depsgraph_pointer(C), driver_frame);
changed = blender::animrig::insert_keyframe_direct(
op->reports,
ptr,
prop,
fcu,
&remapped_context,
eBezTriple_KeyframeType(ts->keyframe_type),
nullptr,
INSERTKEY_NOFLAGS);
changed = insert_keyframe_direct(op->reports,
ptr,
prop,
fcu,
&remapped_context,
eBezTriple_KeyframeType(ts->keyframe_type),
nullptr,
INSERTKEY_NOFLAGS);
}
}
else {
@ -1064,15 +1063,15 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
index = -1;
}
changed = (blender::animrig::insert_keyframe(bmain,
op->reports,
ptr.owner_id,
group,
path->c_str(),
index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag) != 0);
CombinedKeyingResult result = insert_keyframe(bmain,
*ptr.owner_id,
group,
path->c_str(),
index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
changed = result.get_count(SingleKeyingResult::SUCCESS) != 0;
}
else {
BKE_report(op->reports,

View File

@ -1020,6 +1020,7 @@ static int insert_key_to_keying_set_path(bContext *C,
const eModifyKey_Modes mode,
const float frame)
{
using namespace blender::animrig;
/* Since keying settings can be defined on the paths too,
* apply the settings for this path first. */
const eInsertKeyFlags path_insert_key_flags = keyingset_apply_keying_flags(
@ -1074,29 +1075,36 @@ static int insert_key_to_keying_set_path(bContext *C,
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
frame);
int keyed_channels = 0;
CombinedKeyingResult combined_result;
for (; array_index < array_length; array_index++) {
if (mode == MODIFYKEY_MODE_INSERT) {
keyed_channels += blender::animrig::insert_keyframe(bmain,
reports,
keyingset_path->id,
groupname,
keyingset_path->rna_path,
array_index,
&anim_eval_context,
keytype,
path_insert_key_flags);
CombinedKeyingResult result = insert_keyframe(bmain,
*keyingset_path->id,
groupname,
keyingset_path->rna_path,
array_index,
&anim_eval_context,
keytype,
path_insert_key_flags);
keyed_channels += result.get_count(SingleKeyingResult::SUCCESS);
combined_result.merge(result);
}
else if (mode == MODIFYKEY_MODE_DELETE) {
keyed_channels += blender::animrig::delete_keyframe(bmain,
reports,
keyingset_path->id,
nullptr,
keyingset_path->rna_path,
array_index,
frame);
keyed_channels += delete_keyframe(bmain,
reports,
keyingset_path->id,
nullptr,
keyingset_path->rna_path,
array_index,
frame);
}
}
if (combined_result.get_count(SingleKeyingResult::SUCCESS) == 0) {
combined_result.generate_reports(reports);
}
switch (GS(keyingset_path->id->name)) {
case ID_OB: /* Object (or Object-Related) Keyframes */
{

View File

@ -601,10 +601,10 @@ static bool gpencil_weightmode_toggle_poll(bContext *C)
{
/* if using gpencil object, use this gpd */
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
if ((ob) && (ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL))) {
return ob->data != nullptr;
}
return ED_gpencil_data_get_active(C) != nullptr;
return false;
}
static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
@ -615,36 +615,45 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
const bool back = RNA_boolean_get(op->ptr, "back");
wmMsgBus *mbus = CTX_wm_message_bus(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bool is_object = false;
short mode;
/* if using a gpencil object, use this datablock */
Object *ob = CTX_data_active_object(C);
const bool is_mode_set = (ob->mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) != 0;
if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
gpd = static_cast<bGPdata *>(ob->data);
bGPdata *gpd = static_cast<bGPdata *>(ob->data);
if (gpd == nullptr) {
return OPERATOR_CANCELLED;
}
is_object = true;
}
const int mode_flag = OB_MODE_WEIGHT_GPENCIL_LEGACY;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
if (gpd == nullptr) {
return OPERATOR_CANCELLED;
/* Just toggle weightmode flag... */
gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE;
/* set mode */
if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
mode = OB_MODE_WEIGHT_GPENCIL_LEGACY;
}
else {
mode = OB_MODE_OBJECT;
}
}
/* Just toggle weightmode flag... */
gpd->flag ^= GP_DATA_STROKE_WEIGHTMODE;
/* set mode */
if (gpd->flag & GP_DATA_STROKE_WEIGHTMODE) {
mode = OB_MODE_WEIGHT_GPENCIL_LEGACY;
}
else {
mode = OB_MODE_OBJECT;
else if ((ob) && (ob->type == OB_GREASE_PENCIL)) {
is_object = true;
if (!is_mode_set) {
mode = OB_MODE_WEIGHT_GPENCIL_LEGACY;
}
else {
mode = OB_MODE_OBJECT;
}
}
if (is_object) {
/* try to back previous mode */
if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) {
mode = ob->restore_mode;
if (ob->type == OB_GPENCIL_LEGACY) {
bGPdata *gpd = static_cast<bGPdata *>(ob->data);
if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && (back == 1)) {
mode = ob->restore_mode;
}
}
ob->restore_mode = ob->mode;
ob->mode = mode;
@ -664,9 +673,16 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
}
/* setup other modes */
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
if (ob->type == OB_GPENCIL_LEGACY) {
bGPdata *gpd = static_cast<bGPdata *>(ob->data);
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
else if (ob->type == OB_GREASE_PENCIL) {
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
DEG_id_tag_update(&grease_pencil->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);

View File

@ -548,11 +548,9 @@ static void init_brush_icons()
# define INIT_BRUSH_ICON(icon_id, name) \
{ \
uchar *rect = (uchar *)datatoc_##name##_png; \
const uchar *rect = (const uchar *)datatoc_##name##_png; \
const int size = datatoc_##name##_png_size; \
DrawInfo *di; \
\
di = def_internal_icon(nullptr, icon_id, 0, 0, w, ICON_TYPE_BUFFER, 0); \
DrawInfo *di = def_internal_icon(nullptr, icon_id, 0, 0, w, ICON_TYPE_BUFFER, 0); \
di->data.buffer.image->datatoc_rect = rect; \
di->data.buffer.image->datatoc_size = size; \
} \
@ -1616,8 +1614,8 @@ PreviewImage *UI_icon_to_preview(int icon_id)
}
if (di->type == ICON_TYPE_PREVIEW) {
PreviewImage *prv = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
static_cast<PreviewImage *>(icon->obj);
const PreviewImage *prv = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
static_cast<const PreviewImage *>(icon->obj);
if (prv) {
return BKE_previewimg_copy(prv);
@ -2483,7 +2481,7 @@ int UI_icon_from_rnaptr(const bContext *C, PointerRNA *ptr, int rnaicon, const b
return RNA_int_get(ptr, "icon");
}
else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) {
DynamicPaintSurface *surface = static_cast<DynamicPaintSurface *>(ptr->data);
const DynamicPaintSurface *surface = static_cast<const DynamicPaintSurface *>(ptr->data);
if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
return ICON_SHADING_TEXTURE;

View File

@ -148,8 +148,8 @@ bool mode_compat_test(const Object *ob, eObjectMode mode)
}
break;
case OB_GREASE_PENCIL:
if (mode & (OB_MODE_EDIT | OB_MODE_PAINT_GREASE_PENCIL | OB_MODE_WEIGHT_PAINT |
OB_MODE_SCULPT_GPENCIL_LEGACY))
if (mode & (OB_MODE_EDIT | OB_MODE_PAINT_GREASE_PENCIL | OB_MODE_SCULPT_GPENCIL_LEGACY |
OB_MODE_WEIGHT_GPENCIL_LEGACY))
{
return true;
}

View File

@ -409,7 +409,7 @@ void mode_exit_generic(Object *ob, const eObjectMode mode_flag)
bool mode_toggle_poll_test(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (ob == nullptr || !ELEM(ob->type, OB_MESH, OB_GREASE_PENCIL)) {
if (ob == nullptr || ob->type != OB_MESH) {
return false;
}
if (!ob->data || ID_IS_LINKED(ob->data)) {

View File

@ -1543,31 +1543,9 @@ static void wpaint_paint_leaves(bContext *C,
/** \name Enter Weight Paint Mode
* \{ */
static void grease_pencil_wpaintmode_enter(Main *bmain, Scene *scene, Object *ob)
{
const PaintMode paint_mode = PaintMode::Weight;
Paint *weight_paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
BKE_paint_ensure(bmain, scene->toolsettings, &weight_paint);
ob->mode |= OB_MODE_WEIGHT_PAINT;
/* Flush object mode. */
DEG_id_tag_update(&ob->id, ID_RECALC_SYNC_TO_EVAL);
}
void ED_object_wpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
switch (ob->type) {
case OB_MESH:
vwpaint::mode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_WEIGHT_PAINT);
break;
case OB_GREASE_PENCIL:
grease_pencil_wpaintmode_enter(bmain, scene, ob);
break;
default:
BLI_assert_unreachable();
break;
}
vwpaint::mode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_enter(bContext *C, Depsgraph *depsgraph)
{
@ -1584,18 +1562,7 @@ void ED_object_wpaintmode_enter(bContext *C, Depsgraph *depsgraph)
void ED_object_wpaintmode_exit_ex(Object *ob)
{
switch (ob->type) {
case OB_MESH:
vwpaint::mode_exit_generic(ob, OB_MODE_WEIGHT_PAINT);
break;
case OB_GREASE_PENCIL: {
ob->mode &= ~OB_MODE_WEIGHT_PAINT;
break;
}
default:
BLI_assert_unreachable();
break;
}
vwpaint::mode_exit_generic(ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_exit(bContext *C)
{
@ -1668,6 +1635,8 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
}
}
Mesh *mesh = BKE_mesh_from_object(ob);
if (is_mode_set) {
ED_object_wpaintmode_exit_ex(ob);
}
@ -1683,15 +1652,12 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
/* Prepare armature posemode. */
blender::ed::object::posemode_set_for_weight_paint(C, bmain, ob, is_mode_set);
if (ob->type == OB_MESH) {
/* Weight-paint works by overriding colors in mesh,
* so need to make sure we recalculate on enter and
* exit (exit needs doing regardless because we
* should re-deform).
*/
Mesh *mesh = BKE_mesh_from_object(ob);
DEG_id_tag_update(&mesh->id, 0);
}
/* Weight-paint works by overriding colors in mesh,
* so need to make sure we recalculate on enter and
* exit (exit needs doing regardless because we
* should re-deform).
*/
DEG_id_tag_update(&mesh->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);

View File

@ -853,15 +853,17 @@ static void insert_fcurve_key(bAnimContext *ac,
* (TODO: add the full-blown PointerRNA relative parsing case here...)
*/
if (ale->id && !ale->owner) {
insert_keyframe(ac->bmain,
reports,
ale->id,
((fcu->grp) ? (fcu->grp->name) : (nullptr)),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
CombinedKeyingResult result = insert_keyframe(ac->bmain,
*ale->id,
((fcu->grp) ? (fcu->grp->name) : (nullptr)),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
if (result.get_count(SingleKeyingResult::SUCCESS) == 0) {
result.generate_reports(reports);
}
}
else {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);

View File

@ -206,15 +206,17 @@ static void insert_graph_keys(bAnimContext *ac, eGraphKeys_InsertKey_Types mode)
* up adding the keyframes on a new F-Curve in the action data instead.
*/
if (ale->id && !ale->owner && !fcu->driver) {
insert_keyframe(ac->bmain,
reports,
ale->id,
((fcu->grp) ? (fcu->grp->name) : (nullptr)),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
CombinedKeyingResult result = insert_keyframe(ac->bmain,
*ale->id,
((fcu->grp) ? (fcu->grp->name) : (nullptr)),
fcu->rna_path,
fcu->array_index,
&anim_eval_context,
eBezTriple_KeyframeType(ts->keyframe_type),
flag);
if (result.get_count(SingleKeyingResult::SUCCESS) == 0) {
result.generate_reports(reports);
}
}
else {
AnimData *adt = ANIM_nla_mapping_get(ac, ale);

View File

@ -621,17 +621,18 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData *data, int offset)
{
char msg[UI_MAX_DRAW_STR];
if (area == nullptr) {
return;
}
if (area) {
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
SNPRINTF(msg, IFACE_("Slip offset: %s"), num_str);
}
else {
SNPRINTF(msg, IFACE_("Slip offset: %d"), offset);
}
char msg[UI_MAX_DRAW_STR];
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
SNPRINTF(msg, IFACE_("Slip offset: %s"), num_str);
}
else {
SNPRINTF(msg, IFACE_("Slip offset: %d"), offset);
}
ED_area_status_text(area, msg);

View File

@ -1714,6 +1714,9 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
case CTX_MODE_SCULPT_GREASE_PENCIL:
ARRAY_SET_ITEMS(contexts, ".paint_common", ".grease_pencil_sculpt");
break;
case CTX_MODE_WEIGHT_GREASE_PENCIL:
ARRAY_SET_ITEMS(contexts, ".grease_pencil_weight");
break;
case CTX_MODE_EDIT_POINT_CLOUD:
ARRAY_SET_ITEMS(contexts, ".point_cloud_edit");
break;

View File

@ -121,9 +121,6 @@ static void uiTemplatePaintModeSelection(uiLayout *layout, bContext *C)
ViewLayer *view_layer = CTX_data_view_layer(C);
BKE_view_layer_synced_ensure(scene, view_layer);
Object *ob = BKE_view_layer_active_object_get(view_layer);
if (ob->type != OB_MESH) {
return;
}
/* Gizmos aren't used in paint modes */
if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) {

View File

@ -152,7 +152,8 @@ static blender::VectorSet<Sequence *> query_snap_targets(Scene *scene,
return snap_targets;
}
static int seq_get_snap_target_points_count(short snap_mode,
static int seq_get_snap_target_points_count(const Scene *scene,
short snap_mode,
blender::Span<Sequence *> snap_targets)
{
int count = 2; /* Strip start and end are always used. */
@ -167,6 +168,10 @@ static int seq_get_snap_target_points_count(short snap_mode,
count++;
}
if (snap_mode & SEQ_SNAP_TO_MARKERS) {
count += BLI_listbase_count(&scene->markers);
}
return count;
}
@ -175,7 +180,8 @@ static bool seq_snap_target_points_build(Scene *scene,
TransSeqSnapData *snap_data,
blender::Span<Sequence *> snap_targets)
{
const size_t point_count_target = seq_get_snap_target_points_count(snap_mode, snap_targets);
const size_t point_count_target = seq_get_snap_target_points_count(
scene, snap_mode, snap_targets);
if (point_count_target == 0) {
return false;
}
@ -188,6 +194,13 @@ static bool seq_snap_target_points_build(Scene *scene,
i++;
}
if (snap_mode & SEQ_SNAP_TO_MARKERS) {
LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
snap_data->target_snap_points[i] = marker->frame;
i++;
}
}
for (Sequence *seq : snap_targets) {
snap_data->target_snap_points[i] = SEQ_time_left_handle_frame_get(scene, seq);
snap_data->target_snap_points[i + 1] = SEQ_time_right_handle_frame_get(scene, seq);

View File

@ -50,6 +50,7 @@ set(SRC
intern/trim_curves.cc
intern/uv_pack.cc
intern/uv_parametrizer.cc
intern/volume_grid_resample.cc
GEO_add_curves_on_mesh.hh
GEO_curve_constraints.hh

Some files were not shown because too many files have changed in this diff Show More