Initial Grease Pencil 3.0 stage #106848

Merged
Falk David merged 224 commits from filedescriptor/blender:grease-pencil-v3 into main 2023-05-30 11:14:22 +02:00
201 changed files with 1920 additions and 1223 deletions
Showing only changes of commit db99c202b4 - Show all commits

View File

@ -893,6 +893,23 @@ static std::optional<BL::IntAttribute> find_material_index_attribute(BL::Mesh b_
return std::nullopt;
}
static std::optional<BL::BoolAttribute> find_sharp_face_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_BOOLEAN) {
continue;
}
if (b_attribute.name() != "sharp_face") {
continue;
}
return BL::BoolAttribute{b_attribute};
}
return std::nullopt;
}
static void create_mesh(Scene *scene,
Mesh *mesh,
BL::Mesh &b_mesh,
@ -983,16 +1000,22 @@ static void create_mesh(Scene *scene,
return 0;
};
std::optional<BL::BoolAttribute> sharp_faces = find_sharp_face_attribute(b_mesh);
auto get_face_sharp = [&](const int poly_index) -> bool {
if (sharp_faces) {
return sharp_faces->data[poly_index].value();
}
return false;
};
/* create faces */
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
if (!subdivision) {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
const int poly_index = t.polygon_index();
const MPoly &b_poly = polys[poly_index];
int3 vi = get_int3(t.vertices());
int shader = get_material_index(poly_index);
bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals;
bool smooth = !get_face_sharp(poly_index) || use_loop_normals;
if (use_loop_normals) {
BL::Array<float, 9> loop_normals = t.split_normals();
@ -1012,13 +1035,14 @@ static void create_mesh(Scene *scene,
else {
vector<int> vi;
const MPoly *polys = static_cast<const MPoly *>(b_mesh.polygons[0].ptr.data);
const MLoop *loops = static_cast<const MLoop *>(b_mesh.loops[0].ptr.data);
for (int i = 0; i < numfaces; i++) {
const MPoly &b_poly = polys[i];
int n = b_poly.totloop;
int shader = get_material_index(i);
bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals;
bool smooth = !get_face_sharp(i) || use_loop_normals;
vi.resize(n);
for (int i = 0; i < n; i++) {

View File

@ -81,7 +81,7 @@ class DeviceInfo {
bool has_gpu_queue; /* Device supports GPU queue. */
bool use_metalrt; /* Use MetalRT to accelerate ray queries (Metal only). */
KernelOptimizationLevel kernel_optimization_level; /* Optimization level applied to path tracing
kernels (Metal only). */
* kernels (Metal only). */
DenoiserTypeMask denoisers; /* Supported denoiser types. */
int cpu_threads;
vector<DeviceInfo> multi_devices;

View File

@ -278,7 +278,7 @@ int MetalDeviceQueue::num_concurrent_states(const size_t state_size) const
if (metal_device_->device_vendor == METAL_GPU_APPLE) {
result *= 4;
/* Increasing the state count doesn't notably benefit M1-family systems. */
/* Increasing the state count doesn't notably benefit M1-family systems. */
if (MetalInfo::get_apple_gpu_architecture(metal_device_->mtlDevice) != APPLE_M1) {
size_t system_ram = system_physical_ram();
size_t allocated_so_far = [metal_device_->mtlDevice currentAllocatedSize];

View File

@ -1343,7 +1343,7 @@ void PathTrace::guiding_prepare_structures()
* per update to be limited, for reproducible results and reasonable training size.
*
* Idea: we could stochastically discard samples with a probability of 1/num_samples_per_update
* we can then update only after the num_samples_per_update iterations are rendered. */
* we can then update only after the num_samples_per_update iterations are rendered. */
render_scheduler_.set_limit_samples_per_update(4);
}
else {

View File

@ -94,7 +94,7 @@ class PathTrace {
void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling);
/* Set the parameters for guiding.
* Use to setup the guiding structures before each rendering iteration.*/
* Use to setup the guiding structures before each rendering iteration. */
void set_guiding_params(const GuidingParams &params, const bool reset);
/* Sets output driver for render buffer output. */
@ -119,7 +119,7 @@ class PathTrace {
*/
void cancel();
/* Copy an entire render buffer to/from the path trace. */
/* Copy an entire render buffer to/from the path trace. */
/* Copy happens via CPU side buffer: data will be copied from every device of the path trace, and
* the data will be copied to the device of the given render buffers. */
@ -294,7 +294,7 @@ class PathTrace {
* rendering iteration. */
unique_ptr<openpgl::cpp::SampleStorage> guiding_sample_data_storage_;
/* The number of already performed training iterations for the guiding field.*/
/* The number of already performed training iterations for the guiding field. */
int guiding_update_count = 0;
#endif

View File

@ -202,7 +202,7 @@ ccl_device float2 direction_to_mirrorball(float3 dir)
}
/* Single face of a equiangular cube map projection as described in
https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */
* https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */
ccl_device float3 equiangular_cubemap_face_to_direction(float u, float v)
{
u = (1.0f - u);

View File

@ -136,7 +136,7 @@ ccl_device_forceinline float3 microfacet_beckmann_sample_vndf(const float3 wi,
/* Find root in a monotonic interval using newton method, under given precision and maximal
* iterations. Falls back to bisection if newton step produces results outside of the valid
* interval.*/
* interval. */
const float precision = 1e-6f;
const int max_iter = 3;
int iter = 0;

View File

@ -53,7 +53,7 @@ ccl_device_forceinline void guiding_record_surface_segment(KernelGlobals kg,
#endif
}
/* Records the surface scattering event at the current vertex position of the segment.*/
/* Records the surface scattering event at the current vertex position of the segment. */
ccl_device_forceinline void guiding_record_surface_bounce(KernelGlobals kg,
IntegratorState state,
ccl_private const ShaderData *sd,
@ -134,7 +134,7 @@ ccl_device_forceinline void guiding_record_bssrdf_segment(KernelGlobals kg,
}
/* Records the transmission of the path at the point of entry while passing
* the surface boundary.*/
* the surface boundary. */
ccl_device_forceinline void guiding_record_bssrdf_weight(KernelGlobals kg,
IntegratorState state,
const Spectrum weight,
@ -161,7 +161,7 @@ ccl_device_forceinline void guiding_record_bssrdf_weight(KernelGlobals kg,
/* Records the direction at the point of entry the path takes when sampling the SSS contribution.
* If not terminated this function is usually followed by a call of
* guiding_record_volume_transmission to record the transmittance between the point of entry and
* the point of exit.*/
* the point of exit. */
ccl_device_forceinline void guiding_record_bssrdf_bounce(KernelGlobals kg,
IntegratorState state,
const float pdf,
@ -216,7 +216,7 @@ ccl_device_forceinline void guiding_record_volume_segment(KernelGlobals kg,
#endif
}
/* Records the volume scattering event at the current vertex position of the segment.*/
/* Records the volume scattering event at the current vertex position of the segment. */
ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg,
IntegratorState state,
ccl_private const ShaderData *sd,
@ -247,7 +247,7 @@ ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg,
}
/* Records the transmission (a.k.a. transmittance weight) between the current path segment
* and the next one, when the path is inside or passes a volume.*/
* and the next one, when the path is inside or passes a volume. */
ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg,
IntegratorState state,
const float3 transmittance_weight)
@ -330,7 +330,7 @@ ccl_device_forceinline void guiding_record_light_surface_segment(
/* Records/Adds a final path segment when the path leaves the scene and
* intersects with a background light (e.g., background color,
* distant light, or env map). The vertex for this segment is placed along
* the current ray far out the scene.*/
* the current ray far out the scene. */
ccl_device_forceinline void guiding_record_background(KernelGlobals kg,
IntegratorState state,
const Spectrum L,
@ -359,7 +359,7 @@ ccl_device_forceinline void guiding_record_background(KernelGlobals kg,
/* Records the scattered contribution of a next event estimation
* (i.e., a direct light estimate scattered at the current path vertex
* towards the previous vertex).*/
* towards the previous vertex). */
ccl_device_forceinline void guiding_record_direct_light(KernelGlobals kg,
IntegratorShadowState state)
{
@ -397,7 +397,7 @@ ccl_device_forceinline void guiding_record_continuation_probability(
/* Path guiding debug render passes. */
/* Write a set of path guiding related debug information (e.g., guiding probability at first
* bounce) into separate rendering passes.*/
* bounce) into separate rendering passes. */
ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg,
IntegratorState state,
ccl_private const ShaderData *sd,

View File

@ -1019,7 +1019,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass);
# if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1
/* The current path throughput which is used later to calculate per-segment throughput.*/
/* The current path throughput which is used later to calculate per-segment throughput. */
const float3 initial_throughput = INTEGRATOR_STATE(state, path, throughput);
/* The path throughput used to calculate the throughput for direct light. */
float3 unlit_throughput = initial_throughput;
@ -1063,7 +1063,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) {
/* If the direct scatter event is generated using VOLUME_SAMPLE_DISTANCE the direct event
* will happen at the same position as the indirect event and the direct light contribution
* will contribute to the position of the next path segment.*/
* will contribute to the position of the next path segment. */
float3 transmittance_weight = spectrum_to_rgb(
safe_divide_color(result.indirect_throughput, initial_throughput));
guiding_record_volume_transmission(kg, state, transmittance_weight);
@ -1076,7 +1076,8 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
/* If the direct scatter event is generated using VOLUME_SAMPLE_EQUIANGULAR the direct
* event will happen at a separate position as the indirect event and the direct light
* contribution will contribute to the position of the current/previous path segment. The
* unlit_throughput has to be adjusted to include the scattering at the previous segment.*/
* unlit_throughput has to be adjusted to include the scattering at the previous segment.
*/
float3 scatterEval = one_float3();
if (state->guiding.path_segment) {
pgl_vec3f scatteringWeight = state->guiding.path_segment->scatteringWeight;

View File

@ -126,16 +126,16 @@ typedef struct IntegratorStateGPU {
/* Count number of kernels queued for specific shaders. */
ccl_global int *sort_key_counter[DEVICE_KERNEL_INTEGRATOR_NUM];
/* Index of shadow path which will be used by a next shadow path. */
/* Index of shadow path which will be used by a next shadow path. */
ccl_global int *next_shadow_path_index;
/* Index of main path which will be used by a next shadow catcher split. */
/* Index of main path which will be used by a next shadow catcher split. */
ccl_global int *next_main_path_index;
/* Partition/key offsets used when writing sorted active indices. */
ccl_global int *sort_partition_key_offsets;
/* Divisor used to partition active indices by locality when sorting by material. */
/* Divisor used to partition active indices by locality when sorting by material. */
uint sort_partition_divisor;
} IntegratorStateGPU;

View File

@ -38,7 +38,7 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg,
const float surface_guiding_probability = kernel_data.integrator.surface_guiding_probability;
float rand_bsdf_guiding = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_BSDF_GUIDING);
/* Compute proportion of diffuse BSDF and BSSRDFs .*/
/* Compute proportion of diffuse BSDF and BSSRDFs. */
float diffuse_sampling_fraction = 0.0f;
float bssrdf_sampling_fraction = 0.0f;
float bsdf_bssrdf_sampling_sum = 0.0f;

View File

@ -259,7 +259,7 @@ int LightTree::recursive_build(
bool should_split = false;
if (try_splitting) {
/* Find the best place to split the primitives into 2 nodes.
* If the best split cost is no better than making a leaf node, make a leaf instead.*/
* If the best split cost is no better than making a leaf node, make a leaf instead. */
float min_cost = min_split_saoh(
centroid_bounds, start, end, bbox, bcone, split_dim, split_bucket, num_left_prims, prims);
should_split = num_prims > max_lights_in_leaf_ || min_cost < energy_total;

View File

@ -351,7 +351,7 @@ class Scene : public NodeOwner {
/* Get maximum number of closures to be used in kernel. */
int get_max_closure_count();
/* Get size of a volume stack needed to render this scene. */
/* Get size of a volume stack needed to render this scene. */
int get_volume_stack_size() const;
template<typename T> void delete_node_impl(T *node)

View File

@ -507,7 +507,7 @@ void Session::do_delayed_reset()
params = delayed_reset_.session_params;
buffer_params_ = delayed_reset_.buffer_params;
/* Store parameters used for buffers access outside of scene graph. */
/* Store parameters used for buffers access outside of scene graph. */
buffer_params_.samples = params.samples;
buffer_params_.exposure = scene->film->get_exposure();
buffer_params_.use_approximate_shadow_catcher =

View File

@ -943,6 +943,11 @@ extern void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn);
*/
extern void GHOST_UseWindowFocus(bool use_focus);
/**
* Focus and raise windows on mouse hover.
*/
extern void GHOST_SetAutoFocus(bool auto_focus);
/**
* If window was opened using native pixel size, it returns scaling factor.
*/

View File

@ -332,6 +332,11 @@ class GHOST_ISystem {
*/
virtual void useWindowFocus(const bool use_focus) = 0;
/**
* Focus and raise windows on mouse hover.
*/
virtual void setAutoFocus(const bool auto_focus) = 0;
/**
* Get the Window under the cursor.
* \param x: The x-coordinate of the cursor.

View File

@ -918,6 +918,12 @@ void GHOST_UseWindowFocus(bool use_focus)
return system->useWindowFocus(use_focus);
}
void GHOST_SetAutoFocus(bool auto_focus)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
system->setAutoFocus(auto_focus);
}
float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;

View File

@ -878,7 +878,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
}
extensions_device.push_back("VK_KHR_dedicated_allocation");
extensions_device.push_back("VK_KHR_get_memory_requirements2");
/* Enable MoltenVK required instance extensions.*/
/* Enable MoltenVK required instance extensions. */
#ifdef VK_MVK_MOLTENVK_EXTENSION_NAME
requireExtension(
extensions_available, extensions_enabled, "VK_KHR_get_physical_device_properties2");

View File

@ -23,6 +23,7 @@
GHOST_System::GHOST_System()
: m_nativePixel(false),
m_windowFocus(true),
m_autoFocus(true),
m_displayManager(nullptr),
m_timerManager(nullptr),
m_windowManager(nullptr),
@ -412,6 +413,11 @@ void GHOST_System::useWindowFocus(const bool use_focus)
m_windowFocus = use_focus;
}
void GHOST_System::setAutoFocus(const bool auto_focus)
{
m_autoFocus = auto_focus;
}
bool GHOST_System::supportsCursorWarp()
{
return true;

View File

@ -160,6 +160,12 @@ class GHOST_System : public GHOST_ISystem {
bool m_windowFocus;
/**
* Focus and raise windows on mouse hover.
*/
void setAutoFocus(const bool auto_focus);
bool m_autoFocus;
/**
* Get the Window under the cursor.
* \param x: The x-coordinate of the cursor.

View File

@ -1828,10 +1828,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam,
if (!window->m_mousePresent) {
WINTAB_PRINTF("HWND %p mouse enter\n", window->getHWND());
TRACKMOUSEEVENT tme = {sizeof(tme)};
/* Request WM_MOUSELEAVE message when the cursor leaves the client area, and
* WM_MOUSEHOVER message after 50ms when in the client area. */
tme.dwFlags = TME_LEAVE | TME_HOVER;
tme.dwHoverTime = 50;
/* Request WM_MOUSELEAVE message when the cursor leaves the client area. */
tme.dwFlags = TME_LEAVE;
if (system->m_autoFocus) {
/* Request WM_MOUSEHOVER message after 100ms when in the client area. */
tme.dwFlags |= TME_HOVER;
tme.dwHoverTime = 100;
}
tme.hwndTrack = hwnd;
TrackMouseEvent(&tme);
window->m_mousePresent = true;

View File

@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel):
colliding_names = []
for collection in (
# Built-in names.
{"shade_smooth": None, "crease": None},
{"crease": None},
mesh.attributes,
None if ob is None else ob.vertex_groups,
):

View File

@ -60,7 +60,7 @@ static FT_Library ft_lib = NULL;
static FTC_Manager ftc_manager = NULL;
static FTC_CMapCache ftc_charmap_cache = NULL;
/* Lock for FreeType library, used around face creation and deletion. */
/* Lock for FreeType library, used around face creation and deletion. */
static ThreadMutex ft_lib_mutex;
/* May be set to #UI_widgetbase_draw_cache_flush. */
@ -1566,7 +1566,7 @@ FontBLF *blf_font_new_ex(const char *name,
}
}
/* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
/* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
if (font->unicode_ranges[0] == 0xffffffffU && font->unicode_ranges[1] == 0xffffffffU &&
font->unicode_ranges[2] == 0xffffffffU && font->unicode_ranges[3] >= 0x7FFFFFFU) {
font->flags |= BLF_LAST_RESORT;

View File

@ -300,7 +300,7 @@ typedef struct FontBLF {
/** Font size. */
float size;
/** Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */
/** Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */
FT_MM_Var *variations;
/** Character variation; 0=default, -1=min, +1=max. */

View File

@ -246,7 +246,7 @@ static const char32_t *blf_get_sample_text(FT_Face face)
return def;
}
/* Detect "Last resort" fonts. They have everything, except the last 5 bits. */
/* Detect "Last resort" fonts. They have everything, except the last 5 bits. */
if (os2_table->ulUnicodeRange1 == 0xffffffffU && os2_table->ulUnicodeRange2 == 0xffffffffU &&
os2_table->ulUnicodeRange3 == 0xffffffffU && os2_table->ulUnicodeRange4 >= 0x7FFFFFFU) {
return U"\xE000\xFFFF";

View File

@ -74,7 +74,7 @@ struct Scene;
/* keep in sync with MFace/MPoly types */
typedef struct DMFlagMat {
short mat_nr;
char flag;
bool sharp;
} DMFlagMat;
typedef enum DerivedMeshType {

View File

@ -83,8 +83,10 @@ typedef enum {
BKE_CB_EVT_RENDER_CANCEL,
BKE_CB_EVT_LOAD_PRE,
BKE_CB_EVT_LOAD_POST,
BKE_CB_EVT_LOAD_POST_FAIL,
BKE_CB_EVT_SAVE_PRE,
BKE_CB_EVT_SAVE_POST,
BKE_CB_EVT_SAVE_POST_FAIL,
BKE_CB_EVT_UNDO_PRE,
BKE_CB_EVT_UNDO_POST,
BKE_CB_EVT_REDO_PRE,
@ -123,6 +125,7 @@ void BKE_callback_exec_id_depsgraph(struct Main *bmain,
struct ID *id,
struct Depsgraph *depsgraph,
eCbEvent evt);
void BKE_callback_exec_string(struct Main *bmain, eCbEvent evt, const char *str);
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt);
void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt);

View File

@ -133,21 +133,26 @@ void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array
void BKE_curvemapping_get_range_minimums(const struct CurveMapping *curve_mapping,
float minimums[4]);
/** Get the reciprocal of the difference between the maximum and the minimum x value of each curve
/**
* Get the reciprocal of the difference between the maximum and the minimum x value of each curve
* map table. Evaluation parameters can be multiplied by this value to be normalized. If the
* difference is zero, 1^8 is returned. */
* difference is zero, 1^8 is returned.
*/
void BKE_curvemapping_compute_range_dividers(const struct CurveMapping *curve_mapping,
float dividers[4]);
/** Compute the slopes at the start and end points of each curve map. The slopes are multiplied by
/**
* Compute the slopes at the start and end points of each curve map. The slopes are multiplied by
* the range of the curve map to compensate for parameter normalization. If the slope is vertical,
* 1^8 is returned. */
* 1^8 is returned.
*/
void BKE_curvemapping_compute_slopes(const struct CurveMapping *curve_mapping,
float start_slopes[4],
float end_slopes[4]);
/** Check if the curve map at the index is identity, that is, does nothing. A curve map is said to
* be identity if:
/**
* Check if the curve map at the index is identity, that is, does nothing.
* A curve map is said to be identity if:
* - The curve mapping uses extrapolation.
* - Its range is 1.
* - The slope at its start point is 1.

View File

@ -139,11 +139,15 @@ enum {
/** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */
IDWALK_IGNORE_EMBEDDED_ID = (1 << 3),
/** Also process internal ID pointers like `ID.newid` or `ID.orig_id`.
* WARNING: Dangerous, use with caution. */
/**
* Also process internal ID pointers like `ID.newid` or `ID.orig_id`.
* WARNING: Dangerous, use with caution.
*/
IDWALK_DO_INTERNAL_RUNTIME_POINTERS = (1 << 9),
/** Also process the ID.lib pointer. It is an option because this pointer can usually be fully
ignored. */
/**
* Also process the ID.lib pointer. It is an option because this pointer can usually be fully
* ignored.
*/
IDWALK_DO_LIBRARY_POINTER = (1 << 10),
};

View File

@ -453,12 +453,15 @@ void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
*
* Used when defining an empty custom loop normals data layer,
* to keep same shading as with auto-smooth!
*
* \param sharp_faces: Optional array used to mark specific faces for sharp shading.
*/
void BKE_edges_sharp_from_angle_set(int numEdges,
const struct MLoop *mloops,
int numLoops,
const struct MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
int numPolys,
float split_angle,
bool *sharp_edges);
@ -574,6 +577,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space,
* (splitting edges).
*
* \param loop_to_poly_map: Optional pre-created map from loops to their polygon.
* \param sharp_faces: Optional array used to mark specific faces for sharp shading.
* \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on
* each side of the edge.
*/
@ -591,6 +595,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
bool use_split_normals,
float split_angle,
const bool *sharp_edges,
const bool *sharp_faces,
const int *loop_to_poly_map,
MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2]);
@ -605,6 +610,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
int numLoops,
const struct MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2]);
@ -618,6 +624,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
int numLoops,
const struct MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2]);

View File

@ -96,6 +96,9 @@ void BKE_mesh_legacy_convert_loose_edges_to_flag(struct Mesh *mesh);
void BKE_mesh_legacy_attribute_flags_to_strings(struct Mesh *mesh);
void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_faces_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_faces_from_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh);

View File

@ -324,6 +324,7 @@ int *BKE_mesh_calc_smoothgroups(int totedge,
const struct MLoop *mloop,
int totloop,
const bool *sharp_edges,
const bool *sharp_faces,
int *r_totgroup,
bool use_bitflags);

View File

@ -48,6 +48,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
const struct MLoop *mloop,
const struct MLoopTri *looptri,
uint looptri_len,
const bool *sharp_faces,
struct CustomData *loopdata,
bool calc_active_tangent,

View File

@ -76,6 +76,7 @@ typedef struct ShrinkwrapTreeData {
const struct MPoly *polys;
const float (*vert_normals)[3];
const float (*poly_normals)[3];
const bool *sharp_faces;
const float (*clnors)[3];
ShrinkwrapBoundaryData *boundary;
} ShrinkwrapTreeData;

View File

@ -63,6 +63,9 @@ bool allow_procedural_attribute_access(StringRef attribute_name)
if (attribute_name.startswith(".hide")) {
return false;
}
if (attribute_name.startswith(".uv")) {
return false;
}
if (attribute_name.startswith("." UV_VERTSEL_NAME ".")) {
return false;
}

View File

@ -506,7 +506,7 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath,
{
/* Don't print startup file loading. */
if (params->is_startup == false) {
printf("Read blend: %s\n", filepath);
printf("Read blend: \"%s\"\n", filepath);
}
BlendFileData *bfd = BLO_read_from_file(filepath, eBLOReadSkip(params->skip_flags), reports);
@ -518,7 +518,7 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath,
handle_subversion_warning(bfd->main, reports);
}
else {
BKE_reports_prependf(reports->reports, "Loading '%s' failed: ", filepath);
BKE_reports_prependf(reports->reports, "Loading \"%s\" failed: ", filepath);
}
return bfd;
}
@ -768,7 +768,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
bool ok_write;
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs: '%s' ", filepath);
printf("Writing userprefs: \"%s\" ", filepath);
if (use_template_userpref) {
ok_write = BKE_blendfile_userdef_write_app_template(filepath, reports);
}
@ -795,7 +795,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
/* Also save app-template prefs */
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE);
printf("Writing userprefs app-template: '%s' ", filepath);
printf("Writing userprefs app-template: \"%s\" ", filepath);
if (BKE_blendfile_userdef_write(filepath, reports) != 0) {
printf("ok\n");
}

View File

@ -69,6 +69,18 @@ void BKE_callback_exec_id_depsgraph(struct Main *bmain,
BKE_callback_exec(bmain, pointers, 2, evt);
}
void BKE_callback_exec_string(struct Main *bmain, eCbEvent evt, const char *str)
{
PointerRNA str_ptr;
PrimitiveStringRNA data = {};
data.value = str;
RNA_pointer_create(NULL, &RNA_PrimitiveString, &data, &str_ptr);
PointerRNA *pointers[1] = {&str_ptr};
BKE_callback_exec(bmain, pointers, 1, evt);
}
void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt)
{
ASSERT_CALLBACKS_INITIALIZED();

View File

@ -410,7 +410,7 @@ void BKE_curve_init(Curve *cu, const short curve_type)
}
cu->bevel_profile = nullptr;
/* Initialize the offset to 1.0, to compensate for it being set to -1.0
in the property getter. */
* in the property getter. */
cu->offset = 1.0f;
}

View File

@ -103,7 +103,6 @@ static void fill_mesh_topology(const int vert_offset,
MPoly &poly = polys[ring_poly_offset + i_profile];
poly.loopstart = ring_segment_loop_offset;
poly.totloop = 4;
poly.flag = ME_SMOOTH;
MLoop &loop_a = loops[ring_segment_loop_offset];
loop_a.v = ring_vert_offset + i_profile;
@ -674,6 +673,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
MutableSpan<MEdge> edges = mesh->edges_for_write();
MutableSpan<MPoly> polys = mesh->polys_for_write();
MutableSpan<MLoop> loops = mesh->loops_for_write();
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
fill_mesh_topology(info.vert_range.start(),
@ -690,6 +690,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
polys);
});
if (fill_caps) {
/* TODO: This is used to keep the tests passing after refactoring mesh shade smooth flags. It
* can be removed if the tests are updated and the final shading results will be the same. */
SpanAttributeWriter<bool> sharp_faces = mesh_attributes.lookup_or_add_for_write_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
const bool has_caps = fill_caps && !info.main_cyclic && info.profile_cyclic;
if (has_caps) {
const int poly_num = info.main_segment_num * info.profile_segment_num;
const int cap_poly_offset = info.poly_range.start() + poly_num;
sharp_faces.span[cap_poly_offset] = true;
sharp_faces.span[cap_poly_offset + 1] = true;
}
});
sharp_faces.finish();
}
const Span<float3> main_positions = main.evaluated_positions();
const Span<float3> tangents = main.evaluated_tangents();
const Span<float3> normals = main.evaluated_normals();
@ -721,8 +738,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
positions.slice(info.vert_range));
});
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
SpanAttributeWriter<bool> sharp_edges;
write_sharp_bezier_edges(curves_info, offsets, mesh_attributes, sharp_edges);
if (fill_caps) {

View File

@ -382,6 +382,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
if (dirty_nors_dst || do_loop_nors_dst) {
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face"));
BKE_mesh_normals_loop_split(positions_dst,
BKE_mesh_vert_normals_ensure(me_dst),
num_verts_dst,
@ -396,6 +398,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
use_split_nors_dst,
split_angle_dst,
sharp_edges,
sharp_faces,
nullptr,
nullptr,
custom_nors_dst);
@ -451,6 +454,8 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/,
loops_dst.size(),
polys_dst.data(),
poly_nors_dst,
static_cast<const bool *>(CustomData_get_layer_named(
&me_dst->pdata, CD_PROP_BOOL, "sharp_face")),
polys_dst.size(),
sharp_edges.span.data(),
custom_nors_dst);
@ -1109,26 +1114,21 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
return true;
}
if (r_map && cddata_type == CD_FAKE_SHARP) {
const size_t elem_size = sizeof(*((MPoly *)nullptr));
const size_t data_size = sizeof(((MPoly *)nullptr)->flag);
const size_t data_offset = offsetof(MPoly, flag);
const uint64_t data_flag = ME_SMOOTH;
data_transfer_layersmapping_add_item(r_map,
cddata_type,
mix_mode,
mix_factor,
mix_weights,
me_src->polys().data(),
me_dst->polys_for_write().data(),
me_src->totpoly,
me_dst->totpoly,
elem_size,
data_size,
data_offset,
data_flag,
nullptr,
interp_data);
if (!CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")) {
CustomData_add_layer_named(
&me_dst->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totpoly, "sharp_face");
}
data_transfer_layersmapping_add_item_cd(
r_map,
CD_PROP_BOOL,
mix_mode,
mix_factor,
mix_weights,
CustomData_get_layer_named(&me_src->pdata, CD_PROP_BOOL, "sharp_face"),
CustomData_get_layer_named_for_write(
&me_dst->pdata, CD_PROP_BOOL, "sharp_face", num_elem_dst),
interp,
interp_data);
return true;
}

View File

@ -589,7 +589,7 @@ static bool get_fcurve_end_keyframes(const FCurve *fcu,
}
/* The binary search returns an index where a keyframe would be inserted,
so it needs to be clamped to ensure it is in range of the array. */
* so it needs to be clamped to ensure it is in range of the array. */
first_index = clamp_i(first_index, 0, fcu->totvert - 1);
last_index = clamp_i(last_index - 1, 0, fcu->totvert - 1);
}

View File

@ -23,7 +23,7 @@
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_effect.h"
#include "BKE_fluid.h"
#include "BKE_global.h"
@ -3213,16 +3213,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
float size[3];
float cell_size_scaled[3];
/* Assign material + flags to new mesh.
* If there are no faces in original mesh, keep materials and flags unchanged. */
MPoly mp_example = {0};
if (MPoly *polys = BKE_mesh_polys_for_write(orgmesh)) {
mp_example = *polys;
}
const int *orig_material_indices = BKE_mesh_material_indices(orgmesh);
const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0;
const char mp_flag = mp_example.flag;
int i;
int num_verts, num_faces;
@ -3251,6 +3243,10 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
blender::MutableSpan<MPoly> polys = me->polys_for_write();
blender::MutableSpan<MLoop> loops = me->loops_for_write();
const bool is_sharp = orgmesh->attributes().lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false)[0];
BKE_mesh_smooth_flag_set(me, !is_sharp);
/* Get size (dimension) but considering scaling. */
copy_v3_v3(cell_size_scaled, fds->cell_size);
mul_v3_v3(cell_size_scaled, ob->scale);
@ -3338,7 +3334,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds,
for (const int i : polys.index_range()) {
/* Initialize from existing face. */
material_indices[i] = mp_mat_nr;
polys[i].flag = mp_flag;
polys[i].loopstart = i * 3;
polys[i].totloop = 3;

View File

@ -913,16 +913,6 @@ static void tag_component_positions_changed(void *owner)
}
}
static bool get_shade_smooth(const MPoly &poly)
{
return poly.flag & ME_SMOOTH;
}
static void set_shade_smooth(MPoly &poly, bool value)
{
SET_FLAG_FROM_TEST(poly.flag, value, ME_SMOOTH);
}
static float get_crease(const float &crease)
{
return crease;
@ -1217,17 +1207,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
nullptr,
AttributeValidator{&material_index_clamp});
static BuiltinCustomDataLayerProvider shade_smooth(
"shade_smooth",
ATTR_DOMAIN_FACE,
CD_PROP_BOOL,
CD_MPOLY,
BuiltinAttributeProvider::NonCreatable,
BuiltinAttributeProvider::NonDeletable,
face_access,
make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
nullptr);
static BuiltinCustomDataLayerProvider sharp_face("sharp_face",
ATTR_DOMAIN_FACE,
CD_PROP_BOOL,
CD_PROP_BOOL,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Deletable,
face_access,
make_array_read_attribute<bool>,
make_array_write_attribute<bool>,
nullptr);
static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge",
ATTR_DOMAIN_EDGE,
@ -1259,7 +1248,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access);
return ComponentAttributeProviders(
{&position, &id, &material_index, &shade_smooth, &sharp_edge, &crease},
{&position, &id, &material_index, &sharp_face, &sharp_edge, &crease},
{&corner_custom_data,
&vertex_groups,
&point_custom_data,

View File

@ -1275,9 +1275,8 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
gpl->actframe = gpf;
}
else if (addnew == GP_GETFRAME_ADD_COPY) {
/* The frame_addcopy function copies the active frame of gpl,
so we need to set the active frame before copying.
*/
/* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl,
* so we need to set the active frame before copying. */
gpl->actframe = gpf;
gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
}
@ -1306,9 +1305,8 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_
gpl->actframe = gpf;
}
else if (addnew == GP_GETFRAME_ADD_COPY) {
/* The frame_addcopy function copies the active frame of gpl;
so we need to set the active frame before copying.
*/
/* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl;
* so we need to set the active frame before copying. */
gpl->actframe = gpf;
gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe);
}

View File

@ -2281,6 +2281,8 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
&mesh->ldata, CD_CUSTOMLOOPNORMAL, loops.size())); /* May be nullptr. */
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
BKE_mesh_normals_loop_split(positions,
vert_normals,
mesh->totvert,
@ -2295,6 +2297,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
(mesh->flag & ME_AUTOSMOOTH) != 0,
mesh->smoothresh,
sharp_edges,
sharp_faces,
nullptr,
nullptr,
clnors);

View File

@ -1480,7 +1480,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
const int count = indices[2] != indices[3] ? 4 : 3;
polys[i].loopstart = loop_offset;
polys[i].totloop = count;
polys[i].flag = ME_SMOOTH;
mloop[loop_offset].v = uint32_t(indices[0]);
mloop[loop_offset + 1].v = uint32_t(indices[1]);

View File

@ -255,20 +255,24 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
Set<std::string> names_to_skip;
if (!BLO_write_is_undo(writer)) {
/* When converting to the old mesh format, don't save redundant attributes. */
names_to_skip.add_multiple_new({".hide_vert",
names_to_skip.add_multiple_new({"position",
".hide_vert",
".hide_edge",
".hide_poly",
"position",
"material_index",
".uv_seam",
".select_vert",
".select_edge",
".select_poly"});
".select_poly",
"material_index",
"sharp_face",
"sharp_edge"});
mesh->mvert = BKE_mesh_legacy_convert_positions_to_verts(
mesh, temp_arrays_for_legacy_format, vert_layers);
BKE_mesh_legacy_convert_hide_layers_to_flags(mesh);
BKE_mesh_legacy_convert_selection_layers_to_flags(mesh);
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh);
BKE_mesh_legacy_sharp_faces_to_flags(mesh);
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
BKE_mesh_legacy_edge_crease_from_layers(mesh);
BKE_mesh_legacy_sharp_edges_to_flags(mesh);
@ -1485,16 +1489,17 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth)
{
MutableSpan<MPoly> polys = me->polys_for_write();
using namespace blender;
using namespace blender::bke;
MutableAttributeAccessor attributes = me->attributes_for_write();
if (use_smooth) {
for (MPoly &poly : polys) {
poly.flag |= ME_SMOOTH;
}
attributes.remove("sharp_face");
}
else {
for (MPoly &poly : polys) {
poly.flag &= ~ME_SMOOTH;
}
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_only_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
sharp_faces.span.fill(true);
sharp_faces.finish();
}
}
@ -1842,7 +1847,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
&mesh->ldata, CD_CUSTOMLOOPNORMAL, mesh->totloop);
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
const Span<float3> positions = mesh->vert_positions();
const Span<MEdge> edges = mesh->edges();
const Span<MPoly> polys = mesh->polys();
@ -1862,6 +1868,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
use_split_normals,
split_angle,
sharp_edges,
sharp_faces,
nullptr,
r_lnors_spacearr,
clnors);

View File

@ -391,15 +391,12 @@ static void copy_vert_attributes(Mesh *dest_mesh,
/* Similar to copy_vert_attributes but for poly attributes. */
static void copy_poly_attributes(Mesh *dest_mesh,
MPoly *poly,
const MPoly *orig_poly,
const Mesh *orig_me,
int poly_index,
int index_in_orig_me,
Span<short> material_remap,
MutableSpan<int> dst_material_indices)
{
poly->flag = orig_poly->flag;
CustomData *target_cd = &dest_mesh->pdata;
const CustomData *source_cd = &orig_me->pdata;
for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) {
@ -751,8 +748,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
}
copy_poly_attributes(result,
poly,
orig_poly,
orig_me,
fi,
index_in_orig_me,

View File

@ -195,6 +195,9 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>(
"material_index", ATTR_DOMAIN_FACE);
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
blender::float2 *mloopuv = static_cast<blender::float2 *>(CustomData_add_layer_named(
&mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, DATA_("UVMap")));
@ -278,9 +281,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
}
}
if (is_smooth) {
polys[dst_poly].flag |= ME_SMOOTH;
}
sharp_faces.span[dst_poly] = !is_smooth;
dst_poly++;
dst_loop += 3;
index += 3;
@ -363,9 +364,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
}
}
if (is_smooth) {
polys[dst_poly].flag |= ME_SMOOTH;
}
sharp_faces.span[dst_poly] = !is_smooth;
dst_poly++;
dst_loop += 4;
@ -383,6 +382,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba
}
material_indices.finish();
sharp_faces.finish();
return mesh;
}

View File

@ -447,6 +447,12 @@ static void convert_mfaces_to_mpolys(ID *id,
material_indices = static_cast<int *>(CustomData_add_layer_named(
pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, totpoly, "material_index"));
}
bool *sharp_faces = static_cast<bool *>(
CustomData_get_layer_named_for_write(pdata, CD_PROP_BOOL, "sharp_face", totpoly));
if (!sharp_faces) {
sharp_faces = static_cast<bool *>(CustomData_add_layer_named(
pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, totpoly, "sharp_face"));
}
numTex = CustomData_number_of_layers(fdata, CD_MTFACE);
numCol = CustomData_number_of_layers(fdata, CD_MCOL);
@ -491,7 +497,7 @@ static void convert_mfaces_to_mpolys(ID *id,
poly->totloop = mf->v4 ? 4 : 3;
material_indices[i] = mf->mat_nr;
poly->flag = mf->flag;
sharp_faces[i] = (mf->flag & ME_SMOOTH) == 0;
#define ML(v1, v2) \
{ \
@ -975,6 +981,8 @@ static int mesh_tessface_calc(Mesh &mesh,
mloop = (const MLoop *)CustomData_get_layer(ldata, CD_MLOOP);
const int *material_indices = static_cast<const int *>(
CustomData_get_layer_named(pdata, CD_PROP_INT32, "material_index"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(pdata, CD_PROP_BOOL, "sharp_face"));
/* Allocate the length of `totfaces`, avoid many small reallocation's,
* if all faces are triangles it will be correct, `quads == 2x` allocations. */
@ -1014,7 +1022,7 @@ static int mesh_tessface_calc(Mesh &mesh,
lidx[2] = l3; \
lidx[3] = 0; \
mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \
mf->flag = poly->flag; \
mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \
mf->edcode = 0; \
(void)0
@ -1037,7 +1045,7 @@ static int mesh_tessface_calc(Mesh &mesh,
lidx[2] = l3; \
lidx[3] = l4; \
mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \
mf->flag = poly->flag; \
mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \
mf->edcode = TESSFACE_IS_QUAD; \
(void)0
@ -1123,7 +1131,6 @@ static int mesh_tessface_calc(Mesh &mesh,
lidx[3] = 0;
mf->mat_nr = material_indices ? material_indices[poly_index] : 0;
mf->flag = poly->flag;
mf->edcode = 0;
mface_index++;
@ -1214,6 +1221,57 @@ void BKE_mesh_tessface_ensure(struct Mesh *mesh)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Sharp Edge Conversion
* \{ */
void BKE_mesh_legacy_sharp_faces_to_flags(Mesh *mesh)
{
using namespace blender;
MutableSpan<MPoly> polys = mesh->polys_for_write();
if (const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"))) {
threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(polys[i].flag_legacy, !sharp_faces[i], ME_SMOOTH);
}
});
}
else {
for (const int i : polys.index_range()) {
polys[i].flag_legacy |= ME_SMOOTH;
}
}
}
void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
const Span<MPoly> polys = mesh->polys();
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (attributes.contains("sharp_face")) {
return;
}
if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) {
return !(poly.flag_legacy & ME_SMOOTH);
})) {
SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_only_span<bool>(
"sharp_face", ATTR_DOMAIN_FACE);
threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
sharp_faces.span[i] = !(polys[i].flag_legacy & ME_SMOOTH);
}
});
sharp_faces.finish();
}
else {
attributes.remove("sharp_face");
}
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face Set Conversion
* \{ */
@ -1496,7 +1554,7 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh)
".hide_poly", ATTR_DOMAIN_FACE, false);
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(polys[i].flag, hide_poly[i], ME_HIDE);
SET_FLAG_FROM_TEST(polys[i].flag_legacy, hide_poly[i], ME_HIDE);
}
});
}
@ -1539,13 +1597,14 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
}
const Span<MPoly> polys = mesh->polys();
if (std::any_of(
polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_HIDE; })) {
if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) {
return poly.flag_legacy & ME_HIDE;
})) {
SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>(
".hide_poly", ATTR_DOMAIN_FACE);
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
hide_poly.span[i] = polys[i].flag & ME_HIDE;
hide_poly.span[i] = polys[i].flag_legacy & ME_HIDE;
}
});
hide_poly.finish();
@ -1814,7 +1873,7 @@ void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh)
".select_poly", ATTR_DOMAIN_FACE, false);
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(polys[i].flag, select_poly[i], ME_FACE_SEL);
SET_FLAG_FROM_TEST(polys[i].flag_legacy, select_poly[i], ME_FACE_SEL);
}
});
}
@ -1858,13 +1917,14 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
}
const Span<MPoly> polys = mesh->polys();
if (std::any_of(
polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_FACE_SEL; })) {
if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) {
return poly.flag_legacy & ME_FACE_SEL;
})) {
SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>(
".select_poly", ATTR_DOMAIN_FACE);
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
select_poly.span[i] = polys[i].flag & ME_FACE_SEL;
select_poly.span[i] = polys[i].flag_legacy & ME_FACE_SEL;
}
});
select_poly.finish();

View File

@ -845,11 +845,14 @@ int *BKE_mesh_calc_smoothgroups(const int totedge,
const MLoop *mloop,
const int totloop,
const bool *sharp_edges,
const bool *sharp_faces,
int *r_totgroup,
const bool use_bitflags)
{
int *poly_groups = nullptr;
auto poly_is_smooth = [&](const int i) { return !(sharp_faces && sharp_faces[i]); };
auto poly_is_island_boundary_smooth = [&](const int poly_index,
const int /*loop_index*/,
const int edge_index,
@ -857,13 +860,13 @@ int *BKE_mesh_calc_smoothgroups(const int totedge,
const MeshElemMap &edge_poly_map_elem) {
/* Edge is sharp if one of its polys is flat, or edge itself is sharp,
* or edge is not used by exactly two polygons. */
if ((polys[poly_index].flag & ME_SMOOTH) && !(sharp_edges && sharp_edges[edge_index]) &&
if ((poly_is_smooth(poly_index)) && !(sharp_edges && sharp_edges[edge_index]) &&
(edge_user_count == 2)) {
/* In that case, edge appears to be smooth, but we need to check its other poly too. */
const int other_poly_index = (poly_index == edge_poly_map_elem.indices[0]) ?
edge_poly_map_elem.indices[1] :
edge_poly_map_elem.indices[0];
return (polys[other_poly_index].flag & ME_SMOOTH) == 0;
return !poly_is_smooth(other_poly_index);
}
return true;
};

View File

@ -63,7 +63,7 @@ static void merge_uvs_for_vertex(const Span<int> loops_for_vert, Span<float2 *>
if (loops_for_vert.size() <= 1) {
return;
}
/* Manipulate a copy of the loop indices, de-duplicating UVs per layer. */
/* Manipulate a copy of the loop indices, de-duplicating UVs per layer. */
Vector<int, 32> loops_merge;
loops_merge.reserve(loops_for_vert.size());
for (float2 *mloopuv : mloopuv_layers) {

View File

@ -389,6 +389,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&result->edata, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face"));
BKE_mesh_normals_loop_split(BKE_mesh_vert_positions(result),
BKE_mesh_vert_normals_ensure(result),
result->totvert,
@ -403,6 +405,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
true,
result->smoothresh,
sharp_edges,
sharp_faces,
nullptr,
&lnors_spacearr,
clnors);

View File

@ -786,6 +786,7 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
const Span<MLoop> loops,
const Span<int> loop_to_poly_map,
const Span<float3> poly_normals,
const Span<bool> sharp_faces,
const Span<bool> sharp_edges,
const bool check_angle,
const float split_angle,
@ -794,6 +795,9 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
{
using namespace blender;
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
auto poly_is_smooth = [&](const int poly_i) {
return sharp_faces.is_empty() || !sharp_faces[poly_i];
};
for (const int poly_i : polys.index_range()) {
const MPoly &poly = polys[poly_i];
@ -808,7 +812,7 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
/* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */
e2l[0] = loop_index;
/* We have to check this here too, else we might miss some flat faces!!! */
e2l[1] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID;
e2l[1] = (poly_is_smooth(poly_i)) ? INDEX_UNSET : INDEX_INVALID;
}
else if (e2l[1] == INDEX_UNSET) {
const bool is_angle_sharp = (check_angle &&
@ -820,7 +824,7 @@ static void mesh_edges_sharp_tag(const Span<MPoly> polys,
* or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the
* same vertex, or angle between both its polys' normals is above split_angle value.
*/
if (!(poly.flag & ME_SMOOTH) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
if (!poly_is_smooth(poly_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) ||
vert_i == loops[e2l[0]].v || is_angle_sharp) {
/* NOTE: we are sure that loop != 0 here ;). */
e2l[1] = INDEX_INVALID;
@ -855,6 +859,7 @@ void BKE_edges_sharp_from_angle_set(const int numEdges,
const int numLoops,
const MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
const int numPolys,
const float split_angle,
bool *sharp_edges)
@ -877,6 +882,7 @@ void BKE_edges_sharp_from_angle_set(const int numEdges,
{mloops, numLoops},
loop_to_poly,
{reinterpret_cast<const float3 *>(poly_normals), numPolys},
Span<bool>(sharp_faces, sharp_faces ? numPolys : 0),
Span<bool>(sharp_edges, numEdges),
true,
split_angle,
@ -1442,6 +1448,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
const bool use_split_normals,
const float split_angle,
const bool *sharp_edges,
const bool *sharp_faces,
const int *loop_to_poly_map,
MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2])
@ -1465,7 +1472,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
const MPoly &poly = polys[poly_index];
int ml_index = poly.loopstart;
const int ml_index_end = ml_index + poly.totloop;
const bool is_poly_flat = ((poly.flag & ME_SMOOTH) == 0);
const bool is_poly_flat = sharp_faces && sharp_faces[poly_index];
for (; ml_index < ml_index_end; ml_index++) {
if (is_poly_flat) {
@ -1555,6 +1562,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
loops,
loop_to_poly,
{reinterpret_cast<const float3 *>(poly_normals), numPolys},
Span<bool>(sharp_faces, sharp_faces ? numPolys : 0),
Span<bool>(sharp_edges, sharp_edges ? numEdges : 0),
check_angle,
split_angle,
@ -1605,6 +1613,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
const int numLoops,
const MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
const int numPolys,
MutableSpan<bool> sharp_edges,
short (*r_clnors_data)[2],
@ -1646,6 +1655,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
use_split_normals,
split_angle,
sharp_edges.data(),
sharp_faces,
loop_to_poly.data(),
&lnors_spacearr,
nullptr);
@ -1774,6 +1784,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
use_split_normals,
split_angle,
sharp_edges.data(),
sharp_faces,
loop_to_poly.data(),
&lnors_spacearr,
nullptr);
@ -1848,6 +1859,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
const int numLoops,
const MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
const int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2])
@ -1862,6 +1874,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
numLoops,
polys,
poly_normals,
sharp_faces,
numPolys,
{sharp_edges, numEdges},
r_clnors_data,
@ -1878,6 +1891,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
const int numLoops,
const MPoly *polys,
const float (*poly_normals)[3],
const bool *sharp_faces,
const int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2])
@ -1892,6 +1906,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
numLoops,
polys,
poly_normals,
sharp_faces,
numPolys,
{sharp_edges, numEdges},
r_clnors_data,
@ -1921,7 +1936,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
mesh_normals_loop_custom_set(reinterpret_cast<const float(*)[3]>(positions.data()),
BKE_mesh_vert_normals_ensure(mesh),
positions.size(),
@ -1932,6 +1948,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
loops.size(),
polys.data(),
BKE_mesh_poly_normals_ensure(mesh),
sharp_faces,
polys.size(),
sharp_edges.span,
clnors,

View File

@ -1361,6 +1361,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
if (dirty_nors_dst || do_loop_nors_dst) {
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh_dst->edata, CD_PROP_BOOL, "sharp_edge"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh_dst->pdata, CD_PROP_BOOL, "sharp_face"));
BKE_mesh_normals_loop_split(vert_positions_dst,
BKE_mesh_vert_normals_ensure(mesh_dst),
numverts_dst,
@ -1375,6 +1377,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
use_split_nors_dst,
split_angle_dst,
sharp_edges,
sharp_faces,
nullptr,
nullptr,
custom_nors_dst);

View File

@ -240,7 +240,7 @@ struct SGLSLMeshToTangent {
if (precomputedLoopNormals) {
return mikk::float3(precomputedLoopNormals[loop_index]);
}
if ((polys[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */
if (sharp_faces && sharp_faces[lt->poly]) { /* flat */
if (precomputedFaceNormals) {
return mikk::float3(precomputedFaceNormals[lt->poly]);
}
@ -285,6 +285,7 @@ struct SGLSLMeshToTangent {
const float (*vert_normals)[3];
const float (*orco)[3];
float (*tangent)[4]; /* destination */
const bool *sharp_faces;
int numTessFaces;
#ifdef USE_LOOPTRI_DETECT_QUADS
@ -394,6 +395,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
const MLoop *mloop,
const MLoopTri *looptri,
const uint looptri_len,
const bool *sharp_faces,
CustomData *loopdata,
bool calc_active_tangent,
@ -498,6 +500,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3],
mesh2tangent->polys = polys;
mesh2tangent->mloop = mloop;
mesh2tangent->looptri = looptri;
mesh2tangent->sharp_faces = sharp_faces;
/* NOTE: we assume we do have tessellated loop normals at this point
* (in case it is object-enabled), have to check this is valid. */
mesh2tangent->precomputedLoopNormals = loop_normals;
@ -583,6 +586,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval,
me_eval->loops().data(),
looptris.data(),
uint(looptris.size()),
static_cast<const bool *>(
CustomData_get_layer_named(&me_eval->pdata, CD_PROP_BOOL, "sharp_face")),
&me_eval->ldata,
calc_active_tangent,
tangent_names,

View File

@ -23,6 +23,11 @@ static const aal::RelationsInNode &get_relations_in_node(const bNode &node, Reso
{
if (node.is_group()) {
if (const bNodeTree *group = reinterpret_cast<const bNodeTree *>(node.id)) {
/* Undefined tree types have no relations. */
if (!ntreeIsRegistered(group)) {
return scope.construct<aal::RelationsInNode>();
}
BLI_assert(group->runtime->anonymous_attribute_relations);
return *group->runtime->anonymous_attribute_relations;
}

View File

@ -4090,7 +4090,7 @@ bool BKE_object_minmax_empty_drawtype(const struct Object *ob, float r_min[3], f
max[0] = radius + (ofs[0] * radius);
max[1] = radius + (ofs[1] * radius);
/* Since the image aspect can shrink the bounds towards the object origin,
* adjust the min/max to account for that. */
* adjust the min/max to account for that. */
for (int i = 0; i < 2; i++) {
CLAMP_MAX(min[i], 0.0f);
CLAMP_MIN(max[i], 0.0f);

View File

@ -2803,8 +2803,7 @@ static void sculpt_attribute_update_refs(Object *ob)
{
SculptSession *ss = ob->sculpt;
/* run twice, in case sculpt_attr_update had to recreate a layer and
messed up the bmesh offsets. */
/* Run twice, in case sculpt_attr_update had to recreate a layer and messed up #BMesh offsets. */
for (int i = 0; i < 2; i++) {
for (int j = 0; j < SCULPT_MAX_ATTRIBUTES; j++) {
SculptAttribute *attr = ss->temp_attributes + j;

View File

@ -151,19 +151,27 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node)
// BB_expand(&node->vb, co);
//}
static bool face_materials_match(const PBVH *pbvh, const int a, const int b)
static bool face_materials_match(const PBVH *pbvh,
const bool *sharp_faces,
const int a,
const int b)
{
if (pbvh->material_indices) {
if (pbvh->material_indices[a] != pbvh->material_indices[b]) {
return false;
}
}
return (pbvh->polys[a].flag & ME_SMOOTH) == (pbvh->polys[b].flag & ME_SMOOTH);
if (sharp_faces) {
if (sharp_faces[a] != sharp_faces[b]) {
return false;
}
}
return true;
}
static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2)
{
return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr));
return (f1->sharp == f2->sharp) && (f1->mat_nr == f2->mat_nr);
}
/* Adapted from BLI_kdopbvh.c */
@ -229,7 +237,7 @@ static int partition_indices_grids(int *prim_indices,
}
/* Returns the index of the first element on the right of the partition */
static int partition_indices_material(PBVH *pbvh, int lo, int hi)
static int partition_indices_material(PBVH *pbvh, const bool *sharp_faces, int lo, int hi)
{
const MLoopTri *looptri = pbvh->looptri;
const DMFlagMat *flagmats = pbvh->grid_flag_mats;
@ -239,10 +247,10 @@ static int partition_indices_material(PBVH *pbvh, int lo, int hi)
for (;;) {
if (pbvh->looptri) {
const int first = looptri[pbvh->prim_indices[lo]].poly;
for (; face_materials_match(pbvh, first, looptri[indices[i]].poly); i++) {
for (; face_materials_match(pbvh, sharp_faces, first, looptri[indices[i]].poly); i++) {
/* pass */
}
for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) {
for (; !face_materials_match(pbvh, sharp_faces, first, looptri[indices[j]].poly); j--) {
/* pass */
}
}
@ -450,7 +458,7 @@ static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, in
/* Return zero if all primitives in the node can be drawn with the
* same material (including flat/smooth shading), non-zero otherwise */
static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
static bool leaf_needs_material_split(PBVH *pbvh, const bool *sharp_faces, int offset, int count)
{
if (count <= 1) {
return false;
@ -460,7 +468,7 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count)
const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]];
for (int i = offset + count - 1; i > offset; i--) {
int prim = pbvh->prim_indices[i];
if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) {
if (!face_materials_match(pbvh, sharp_faces, first->poly, pbvh->looptri[prim].poly)) {
return true;
}
}
@ -539,6 +547,7 @@ static void test_face_boundaries(PBVH *pbvh)
*/
static void build_sub(PBVH *pbvh,
const bool *sharp_faces,
int node_index,
BB *cb,
BBC *prim_bbc,
@ -557,7 +566,7 @@ static void build_sub(PBVH *pbvh,
/* Decide whether this is a leaf or not */
const bool below_leaf_limit = count <= pbvh->leaf_limit || depth >= STACK_FIXED_DEPTH - 1;
if (below_leaf_limit) {
if (!leaf_needs_material_split(pbvh, offset, count)) {
if (!leaf_needs_material_split(pbvh, sharp_faces, offset, count)) {
build_leaf(pbvh, node_index, prim_bbc, offset, count);
if (node_index == 0) {
@ -610,11 +619,12 @@ static void build_sub(PBVH *pbvh,
}
else {
/* Partition primitives by material */
end = partition_indices_material(pbvh, offset, offset + count - 1);
end = partition_indices_material(pbvh, sharp_faces, offset, offset + count - 1);
}
/* Build children */
build_sub(pbvh,
sharp_faces,
pbvh->nodes[node_index].children_offset,
nullptr,
prim_bbc,
@ -623,6 +633,7 @@ static void build_sub(PBVH *pbvh,
prim_scratch,
depth + 1);
build_sub(pbvh,
sharp_faces,
pbvh->nodes[node_index].children_offset + 1,
nullptr,
prim_bbc,
@ -636,7 +647,7 @@ static void build_sub(PBVH *pbvh,
}
}
static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
static void pbvh_build(PBVH *pbvh, const bool *sharp_faces, BB *cb, BBC *prim_bbc, int totprim)
{
if (totprim != pbvh->totprim) {
pbvh->totprim = totprim;
@ -659,7 +670,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim)
}
pbvh->totnode = 1;
build_sub(pbvh, 0, cb, prim_bbc, 0, totprim, nullptr, 0);
build_sub(pbvh, sharp_faces, 0, cb, prim_bbc, 0, totprim, nullptr, 0);
}
static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node)
@ -881,7 +892,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
}
if (looptri_num) {
pbvh_build(pbvh, &cb, prim_bbc, looptri_num);
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, looptri_num);
#ifdef TEST_PBVH_FACE_SPLIT
test_face_boundaries(pbvh);
@ -968,7 +981,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
}
if (totgrid) {
pbvh_build(pbvh, &cb, prim_bbc, totgrid);
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
&me->pdata, CD_PROP_BOOL, "sharp_face");
pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, totgrid);
#ifdef TEST_PBVH_FACE_SPLIT
test_face_boundaries(pbvh);

View File

@ -116,6 +116,8 @@ bool BKE_shrinkwrap_init_tree(
data->mesh = mesh;
data->polys = mesh->polys().data();
data->vert_normals = BKE_mesh_vert_normals_ensure(mesh);
data->sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_face"));
if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) {
data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2);
@ -1175,7 +1177,7 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree,
const float(*vert_normals)[3] = tree->vert_normals;
/* Interpolate smooth normals if enabled. */
if ((tree->polys[tri->poly].flag & ME_SMOOTH) != 0) {
if (!(tree->sharp_faces && tree->sharp_faces[tri->poly])) {
const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v,
treeData->loop[tri->tri[1]].v,
treeData->loop[tri->tri[2]].v};

View File

@ -15,7 +15,7 @@
struct CCGMaterialFromMeshData {
const Mesh *mesh;
blender::Span<MPoly> polys;
const bool *sharp_faces;
const int *material_indices;
};
@ -24,9 +24,8 @@ static DMFlagMat subdiv_ccg_material_flags_eval(
{
CCGMaterialFromMeshData *data = (CCGMaterialFromMeshData *)material_flags_evaluator->user_data;
BLI_assert(coarse_face_index < data->mesh->totpoly);
const MPoly &poly = data->polys[coarse_face_index];
DMFlagMat material_flags;
material_flags.flag = poly.flag;
material_flags.sharp = data->sharp_faces && data->sharp_faces[coarse_face_index];
material_flags.mat_nr = data->material_indices ? data->material_indices[coarse_face_index] : 0;
return material_flags;
}
@ -45,7 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh(
data->mesh = mesh;
data->material_indices = (const int *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_INT32, "material_index");
data->polys = mesh->polys();
data->sharp_faces = (const bool *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_BOOL, "sharp_face");
material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval;
material_flags_evaluator->free = subdiv_ccg_material_flags_free;
material_flags_evaluator->user_data = data;

View File

@ -1068,20 +1068,17 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *polys)
int gridSize = ccgSubSurf_getGridSize(ss);
/* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */
int i = 0, k = 0;
DMFlagMat *faceFlags = ccgdm->faceFlags;
totface = ccgSubSurf_getNumFaces(ss);
for (index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
char flag = (faceFlags) ? faceFlags[index].flag : char(ME_SMOOTH);
for (S = 0; S < numVerts; S++) {
for (y = 0; y < gridSize - 1; y++) {
for (x = 0; x < gridSize - 1; x++) {
polys[i].loopstart = k;
polys[i].totloop = 4;
polys[i].flag = flag;
k += 4;
i++;
@ -1541,9 +1538,11 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
gridSideEdges = gridSize - 1;
gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
const MPoly *polys = static_cast<const MPoly *>(CustomData_get_layer(&dm->polyData, CD_MPOLY));
const int *material_indices = static_cast<const int *>(
CustomData_get_layer_named(&dm->polyData, CD_MPOLY, "material_index"));
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face"));
const int *base_polyOrigIndex = static_cast<const int *>(
CustomData_get_layer(&dm->polyData, CD_ORIGINDEX));
@ -1569,7 +1568,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm,
ccgdm->faceMap[index].startEdge = edgeNum;
ccgdm->faceMap[index].startFace = faceNum;
faceFlags->flag = polys ? polys[origIndex].flag : 0;
faceFlags->sharp = sharp_faces ? sharp_faces[origIndex] : false;
faceFlags->mat_nr = material_indices ? material_indices[origIndex] : 0;
faceFlags++;

View File

@ -180,6 +180,7 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid,
mesh->loops_for_write());
BKE_mesh_calc_edges(mesh, false, false);
BKE_mesh_smooth_flag_set(mesh, false);
return mesh;
}

View File

@ -586,7 +586,7 @@ static const AVCodec *get_av1_encoder(
}
else {
/* Is not a square num, set greater side based on longer side, or use a square if both
sides are equal. */
* sides are equal. */
int sqrt_p2 = power_of_2_min_i(threads_sqrt);
if (sqrt_p2 < 2) {
/* Ensure a default minimum. */

View File

@ -10,7 +10,7 @@
#ifdef __GNUC__
/* NOTE(@ideasman42): CLANG behaves slightly differently to GCC,
* these can be enabled but do so carefully as they can introduce build-errors. */
* these can be enabled but do so carefully as they can introduce build-errors. */
# if !defined(__clang__)
# pragma GCC diagnostic error "-Wsign-compare"
# pragma GCC diagnostic error "-Wconversion"

View File

@ -14,6 +14,7 @@
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_multi_value_map.hh"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
@ -940,6 +941,139 @@ static void version_geometry_nodes_primitive_uv_maps(bNodeTree &ntree)
}
}
/**
* When extruding from loose edges, the extrude geometry node used to create flat faces due to the
* default of the old "shade_smooth" attribute. Since the "false" value has changed with the
* "sharp_face" attribute, add nodes to propagate the new attribute in its inverted "smooth" form.
*/
static void version_geometry_nodes_extrude_smooth_propagation(bNodeTree &ntree)
{
using namespace blender;
Vector<bNode *> new_nodes;
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
if (node->idname != StringRef("GeometryNodeExtrudeMesh")) {
continue;
}
if (static_cast<const NodeGeometryExtrudeMesh *>(node->storage)->mode !=
GEO_NODE_EXTRUDE_MESH_EDGES) {
continue;
}
bNodeSocket *geometry_in_socket = nodeFindSocket(node, SOCK_IN, "Mesh");
bNodeSocket *geometry_out_socket = nodeFindSocket(node, SOCK_OUT, "Mesh");
Map<bNodeSocket *, bNodeLink *> in_links_per_socket;
MultiValueMap<bNodeSocket *, bNodeLink *> out_links_per_socket;
LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
in_links_per_socket.add(link->tosock, link);
out_links_per_socket.add(link->fromsock, link);
}
bNodeLink *geometry_in_link = in_links_per_socket.lookup_default(geometry_in_socket, nullptr);
Span<bNodeLink *> geometry_out_links = out_links_per_socket.lookup(geometry_out_socket);
if (!geometry_in_link || geometry_out_links.is_empty()) {
continue;
}
const bool versioning_already_done = [&]() {
if (geometry_in_link->fromnode->idname != StringRef("GeometryNodeCaptureAttribute")) {
return false;
}
bNode *capture_node = geometry_in_link->fromnode;
const NodeGeometryAttributeCapture &capture_storage =
*static_cast<const NodeGeometryAttributeCapture *>(capture_node->storage);
if (capture_storage.data_type != CD_PROP_BOOL ||
capture_storage.domain != ATTR_DOMAIN_FACE) {
return false;
}
bNodeSocket *capture_in_socket = nodeFindSocket(capture_node, SOCK_IN, "Value_003");
bNodeLink *capture_in_link = in_links_per_socket.lookup_default(capture_in_socket, nullptr);
if (!capture_in_link) {
return false;
}
if (capture_in_link->fromnode->idname != StringRef("GeometryNodeInputShadeSmooth")) {
return false;
}
if (geometry_out_links.size() != 1) {
return false;
}
bNodeLink *geometry_out_link = geometry_out_links.first();
if (geometry_out_link->tonode->idname != StringRef("GeometryNodeSetShadeSmooth")) {
return false;
}
bNode *set_smooth_node = geometry_out_link->tonode;
bNodeSocket *smooth_in_socket = nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth");
bNodeLink *connecting_link = in_links_per_socket.lookup_default(smooth_in_socket, nullptr);
if (!connecting_link) {
return false;
}
if (connecting_link->fromnode != capture_node) {
return false;
}
return true;
}();
if (versioning_already_done) {
continue;
}
bNode *capture_node = nodeAddNode(nullptr, &ntree, "GeometryNodeCaptureAttribute");
capture_node->parent = node->parent;
capture_node->locx = node->locx - 25;
capture_node->locy = node->locy;
new_nodes.append(capture_node);
static_cast<NodeGeometryAttributeCapture *>(capture_node->storage)->data_type = CD_PROP_BOOL;
static_cast<NodeGeometryAttributeCapture *>(capture_node->storage)->domain = ATTR_DOMAIN_FACE;
bNode *is_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeInputShadeSmooth");
is_smooth_node->parent = node->parent;
is_smooth_node->locx = capture_node->locx - 25;
is_smooth_node->locy = capture_node->locy;
new_nodes.append(is_smooth_node);
nodeAddLink(&ntree,
is_smooth_node,
nodeFindSocket(is_smooth_node, SOCK_OUT, "Smooth"),
capture_node,
nodeFindSocket(capture_node, SOCK_IN, "Value_003"));
nodeAddLink(&ntree,
capture_node,
nodeFindSocket(capture_node, SOCK_OUT, "Geometry"),
capture_node,
geometry_in_socket);
geometry_in_link->tonode = capture_node;
geometry_in_link->tosock = nodeFindSocket(capture_node, SOCK_IN, "Geometry");
bNode *set_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeSetShadeSmooth");
set_smooth_node->parent = node->parent;
set_smooth_node->locx = node->locx + 25;
set_smooth_node->locy = node->locy;
new_nodes.append(set_smooth_node);
nodeAddLink(&ntree,
node,
geometry_out_socket,
set_smooth_node,
nodeFindSocket(set_smooth_node, SOCK_IN, "Geometry"));
bNodeSocket *smooth_geometry_out = nodeFindSocket(set_smooth_node, SOCK_OUT, "Geometry");
for (bNodeLink *link : geometry_out_links) {
link->fromnode = set_smooth_node;
link->fromsock = smooth_geometry_out;
}
nodeAddLink(&ntree,
capture_node,
nodeFindSocket(capture_node, SOCK_OUT, "Attribute_003"),
set_smooth_node,
nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth"));
}
/* Move nodes to the front so that they are drawn behind existing nodes. */
for (bNode *node : new_nodes) {
BLI_remlink(&ntree.nodes, node);
BLI_addhead(&ntree.nodes, node);
}
if (!new_nodes.is_empty()) {
nodeRebuildIDVector(&ntree);
}
}
void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
{
if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@ -4047,5 +4181,10 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
}
}
/* Keep this block, even when empty. */
LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
if (ntree->type == NTREE_GEOMETRY) {
version_geometry_nodes_extrude_smooth_propagation(*ntree);
}
}
}
}

View File

@ -31,6 +31,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
BKE_mesh_legacy_convert_flags_to_hide_layers(&mesh);
BKE_mesh_legacy_convert_uvs_to_generic(&mesh);
BKE_mesh_legacy_convert_mpoly_to_material_indices(&mesh);
BKE_mesh_legacy_sharp_faces_from_flags(&mesh);
BKE_mesh_legacy_bevel_weight_to_layers(&mesh);
BKE_mesh_legacy_sharp_edges_from_flags(&mesh);
BKE_mesh_legacy_face_set_to_generic(&mesh);

View File

@ -113,18 +113,6 @@ using blender::Span;
using blender::StringRef;
using blender::Vector;
static char bm_face_flag_from_mflag(const char mflag)
{
return ((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0);
}
static char bm_face_flag_to_mflag(const BMFace *f)
{
const char hflag = f->head.hflag;
return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0);
}
bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
{
return ELEM(name,
@ -137,6 +125,7 @@ bool BM_attribute_stored_in_bmesh_builtin(const StringRef name)
".select_edge",
".select_poly",
"material_index",
"sharp_face",
"sharp_edge");
}
@ -426,6 +415,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
&me->pdata, CD_PROP_BOOL, ".hide_poly");
const int *material_indices = (const int *)CustomData_get_layer_named(
&me->pdata, CD_PROP_INT32, "material_index");
const bool *sharp_faces = (const bool *)CustomData_get_layer_named(
&me->pdata, CD_PROP_BOOL, "sharp_face");
const bool *sharp_edges = (const bool *)CustomData_get_layer_named(
&me->edata, CD_PROP_BOOL, "sharp_edge");
const bool *uv_seams = (const bool *)CustomData_get_layer_named(
@ -527,7 +518,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
BM_elem_index_set(f, bm->totface - 1); /* set_ok */
/* Transfer flag. */
f->head.hflag = bm_face_flag_from_mflag(polys[i].flag);
if (!(sharp_faces && sharp_faces[i])) {
BM_elem_flag_enable(f, BM_ELEM_SMOOTH);
}
if (hide_poly && hide_poly[i]) {
BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
}
@ -1252,6 +1245,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
bool need_hide_edge = false;
bool need_hide_poly = false;
bool need_material_index = false;
bool need_sharp_face = false;
bool need_sharp_edge = false;
bool need_uv_seam = false;
@ -1312,7 +1306,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (f->mat_nr != 0) {
need_material_index = true;
}
polys[i].flag = bm_face_flag_to_mflag(f);
if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
need_sharp_face = true;
}
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
need_hide_poly = true;
}
@ -1357,6 +1353,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH);
});
}
if (need_sharp_face) {
BM_mesh_elem_table_ensure(bm, BM_FACE);
write_fn_to_attribute<bool>(
me->attributes_for_write(), "sharp_face", ATTR_DOMAIN_FACE, [&](const int i) {
return !BM_elem_flag_test(BM_face_at_index(bm, i), BM_ELEM_SMOOTH);
});
}
if (need_uv_seam) {
BM_mesh_elem_table_ensure(bm, BM_EDGE);
write_fn_to_attribute<bool>(
@ -1524,6 +1527,7 @@ static void bm_face_loop_table_build(BMesh &bm,
MutableSpan<const BMLoop *> loop_table,
bool &need_select_poly,
bool &need_hide_poly,
bool &need_sharp_face,
bool &need_material_index)
{
char hflag = 0;
@ -1535,6 +1539,7 @@ static void bm_face_loop_table_build(BMesh &bm,
BM_elem_index_set(face, face_i); /* set_inline */
face_table[face_i] = face;
hflag |= face->head.hflag;
need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0;
need_material_index |= face->mat_nr != 0;
BMLoop *loop = BM_FACE_FIRST_LOOP(face);
@ -1622,6 +1627,7 @@ static void bm_to_mesh_faces(const BMesh &bm,
Mesh &mesh,
MutableSpan<bool> select_poly,
MutableSpan<bool> hide_poly,
MutableSpan<bool> sharp_faces,
MutableSpan<int> material_indices)
{
const Vector<BMeshToMeshLayerInfo> info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata);
@ -1632,7 +1638,6 @@ static void bm_to_mesh_faces(const BMesh &bm,
MPoly &dst_poly = dst_polys[face_i];
dst_poly.totloop = src_face.len;
dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face));
dst_poly.flag = bm_face_flag_to_mflag(&src_face);
bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data);
}
if (!select_poly.is_empty()) {
@ -1650,6 +1655,11 @@ static void bm_to_mesh_faces(const BMesh &bm,
material_indices[face_i] = bm_faces[face_i]->mat_nr;
}
}
if (!sharp_faces.is_empty()) {
for (const int face_i : range) {
sharp_faces[face_i] = !BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SMOOTH);
}
}
});
}
@ -1721,6 +1731,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
bool need_hide_poly = false;
bool need_material_index = false;
bool need_sharp_edge = false;
bool need_sharp_face = false;
bool need_uv_seams = false;
Array<const BMVert *> vert_table;
Array<const BMEdge *> edge_table;
@ -1740,8 +1751,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
[&]() {
face_table.reinitialize(bm->totface);
loop_table.reinitialize(bm->totloop);
bm_face_loop_table_build(
*bm, face_table, loop_table, need_select_poly, need_hide_poly, need_material_index);
bm_face_loop_table_build(*bm,
face_table,
loop_table,
need_select_poly,
need_hide_poly,
need_sharp_face,
need_material_index);
});
bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP);
@ -1756,6 +1772,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
bke::SpanAttributeWriter<bool> uv_seams;
bke::SpanAttributeWriter<bool> select_poly;
bke::SpanAttributeWriter<bool> hide_poly;
bke::SpanAttributeWriter<bool> sharp_face;
bke::SpanAttributeWriter<int> material_index;
if (need_select_vert) {
select_vert = attrs.lookup_or_add_for_write_only_span<bool>(".select_vert", ATTR_DOMAIN_POINT);
@ -1781,6 +1798,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
if (need_hide_poly) {
hide_poly = attrs.lookup_or_add_for_write_only_span<bool>(".hide_poly", ATTR_DOMAIN_FACE);
}
if (need_sharp_face) {
sharp_face = attrs.lookup_or_add_for_write_only_span<bool>("sharp_face", ATTR_DOMAIN_FACE);
}
if (need_material_index) {
material_index = attrs.lookup_or_add_for_write_only_span<int>("material_index",
ATTR_DOMAIN_FACE);
@ -1800,8 +1820,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
uv_seams.span);
},
[&]() {
bm_to_mesh_faces(
*bm, face_table, *me, select_poly.span, hide_poly.span, material_index.span);
bm_to_mesh_faces(*bm,
face_table,
*me,
select_poly.span,
hide_poly.span,
sharp_face.span,
material_index.span);
},
[&]() { bm_to_mesh_loops(*bm, loop_table, *me); });
@ -1813,5 +1838,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
uv_seams.finish();
select_poly.finish();
hide_poly.finish();
sharp_face.finish();
material_index.finish();
}

View File

@ -274,7 +274,7 @@ static BMOpDefine bmo_reverse_faces_def = {
* Flip Quad Tessellation
*
* Flip the tessellation direction of the selected quads.
*/
*/
static BMOpDefine bmo_flip_quad_tessellation_def = {
"flip_quad_tessellation",
/* slot_in */

View File

@ -30,7 +30,7 @@ namespace blender::compositor {
* - Distance between the center of the image and the pixel to be evaluated.
* - Distance between the center of the image and the outer-edge.
* - Distance between the center of the image and the inner-edge.
*
* With a simple compare it can be detected if the evaluated pixel is between the outer and inner
* edge.
*/

View File

@ -102,7 +102,7 @@ void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer *
const int coord_min = max_ii(coord - filtersize_, min_input_coord);
const int coord_max = min_ii(coord + filtersize_ + 1, max_input_coord);
/* *** This is the main part which is different to #GaussianBlurBaseOperation. *** */
/* *** This is the main part which is different to #GaussianBlurBaseOperation. *** */
/* Gauss. */
float alpha_accum = 0.0f;
float multiplier_accum = 0.0f;

View File

@ -155,7 +155,7 @@ struct PersistentOperationKey : public OperationKey {
component_name_storage_ = component_node->name;
name_storage_ = operation_node->name;
/* Assign fields used by the #OperationKey API. */
/* Assign fields used by the #OperationKey API. */
id = id_node->id_orig;
component_type = component_node->type;
component_name = component_name_storage_.c_str();

View File

@ -822,7 +822,6 @@ if(WITH_GTESTS)
tests/draw_pass_test.cc
tests/draw_testing.cc
tests/eevee_test.cc
tests/shaders_test.cc
tests/draw_testing.hh
)

View File

@ -227,7 +227,7 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_effect_reflection_resolve)
.auto_resource_location(true)
.do_static_compilation(true);
/* Split reflection resolve support for Intel-based MacBooks.*/
/* Split reflection resolve support for Intel-based MacBooks. */
GPU_SHADER_CREATE_INFO(eevee_legacy_effect_reflection_resolve_probe)
.define("RESOLVE_PROBE")
.additional_info("eevee_legacy_effect_reflection_resolve")

View File

@ -722,7 +722,7 @@ void ShadowModule::begin_sync()
PassMain::Sub &sub = pass.sub("Transparent");
/* WORKAROUND: The DRW_STATE_WRITE_STENCIL is here only to avoid enabling the rasterizer
* discard inside draw manager. */
sub.state_set(DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_STENCIL);
sub.state_set(DRW_STATE_CULL_FRONT | DRW_STATE_WRITE_STENCIL);
sub.state_stencil(0, 0, 0);
sub.framebuffer_set(&usage_tag_fb);
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT));
@ -730,6 +730,10 @@ void ShadowModule::begin_sync()
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
sub.push_constant("tilemap_projection_ratio", &tilemap_projection_ratio_);
sub.push_constant("pixel_world_radius", &pixel_world_radius_);
sub.push_constant("fb_resolution", &usage_tag_fb_resolution_);
sub.push_constant("fb_lod", &usage_tag_fb_lod_);
inst_.hiz_buffer.bind_resources(&sub);
inst_.lights.bind_resources(&sub);
box_batch_ = DRW_cache_cube_get();
@ -1092,12 +1096,17 @@ void ShadowModule::set_view(View &view)
int3 target_size = inst_.render_buffers.depth_tx.size();
dispatch_depth_scan_size_ = math::divide_ceil(target_size, int3(SHADOW_DEPTH_SCAN_GROUP_SIZE));
tilemap_projection_ratio_ = tilemap_pixel_radius() /
screen_pixel_radius(view, int2(target_size));
pixel_world_radius_ = screen_pixel_radius(view, int2(target_size));
tilemap_projection_ratio_ = tilemap_pixel_radius() / pixel_world_radius_;
usage_tag_fb_resolution_ = math::divide_ceil(int2(target_size),
int2(std::exp2(usage_tag_fb_lod_)));
usage_tag_fb.ensure(usage_tag_fb_resolution_);
usage_tag_fb.ensure(int2(target_size));
render_fb_.ensure(int2(SHADOW_TILEMAP_RES * shadow_page_size_));
inst_.hiz_buffer.update();
bool tile_update_remains = true;
while (tile_update_remains) {
DRW_stats_group_start("Shadow");

View File

@ -216,6 +216,9 @@ class ShadowModule {
int3 dispatch_depth_scan_size_;
/* Ratio between tile-map pixel world "radius" and film pixel world "radius". */
float tilemap_projection_ratio_;
float pixel_world_radius_;
int2 usage_tag_fb_resolution_;
int usage_tag_fb_lod_ = 5;
/* Statistics that are read back to CPU after a few frame (to avoid stall). */
SwapChain<ShadowStatisticsBuf, 5> statistics_buf_;

View File

@ -3,13 +3,120 @@
* Virtual shadowmapping: Usage tagging
*
* Shadow pages are only allocated if they are visible.
* This pass scan the depth buffer and tag all tiles that are needed for light shadowing as
* needed.
* This ray-marches the current fragment along the bounds depth and tags all the intersected shadow
* tiles.
*/
#pragma BLENDER_REQUIRE(eevee_shadow_tag_usage_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_debug_shape_lib.glsl)
float ray_aabb(vec3 ray_origin, vec3 ray_direction, vec3 aabb_min, vec3 aabb_max)
{
/* https://gdbooks.gitbooks.io/3dcollisions/content/Chapter3/raycast_aabb.html */
vec3 t_mins = (aabb_min - ray_origin) / ray_direction;
vec3 t_maxs = (aabb_max - ray_origin) / ray_direction;
float t_min = max_v3(min(t_mins, t_maxs));
float t_max = min_v3(max(t_mins, t_maxs));
/* AABB is in the opposite direction. */
if (t_max < 0.0) {
return -1.0;
}
/* No intersection. */
if (t_min > t_max) {
return -1.0;
}
/* The ray origin is inside the aabb. */
if (t_min < 0.0) {
/* For regular ray casting we would return t_max here,
* but we want to ray cast against the box volume, not just the surface. */
return 0.0;
}
return t_min;
}
float pixel_size_at(float linear_depth)
{
float pixel_size = pixel_world_radius;
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
if (is_persp) {
pixel_size *= max(0.01, linear_depth);
}
return pixel_size * exp2(fb_lod);
}
void step_bounding_sphere(vec3 vs_near_plane,
vec3 vs_view_direction,
float near_t,
float far_t,
out vec3 sphere_center,
out float sphere_radius)
{
float near_pixel_size = pixel_size_at(near_t);
vec3 near_center = vs_near_plane + vs_view_direction * near_t;
float far_pixel_size = pixel_size_at(far_t);
vec3 far_center = vs_near_plane + vs_view_direction * far_t;
sphere_center = mix(near_center, far_center, 0.5);
sphere_radius = 0;
for (int x = -1; x <= 1; x += 2) {
for (int y = -1; y <= 1; y += 2) {
vec3 near_corner = near_center + (near_pixel_size * 0.5 * vec3(x, y, 0));
sphere_radius = max(sphere_radius, len_squared(near_corner - sphere_center));
vec3 far_corner = far_center + (far_pixel_size * 0.5 * vec3(x, y, 0));
sphere_radius = max(sphere_radius, len_squared(far_corner - sphere_center));
}
}
sphere_center = point_view_to_world(sphere_center);
sphere_radius = sqrt(sphere_radius);
}
void main()
{
shadow_tag_usage(interp.vP, interp.P, gl_FragCoord.xy);
vec2 screen_uv = gl_FragCoord.xy / vec2(fb_resolution);
float opaque_depth = texelFetch(hiz_tx, int2(gl_FragCoord.xy), fb_lod).r;
vec3 ws_opaque = get_world_space_from_depth(screen_uv, opaque_depth);
vec3 ws_near_plane = get_world_space_from_depth(screen_uv, 0);
vec3 ws_view_direction = normalize(interp.P - ws_near_plane);
vec3 vs_near_plane = get_view_space_from_depth(screen_uv, 0);
vec3 vs_view_direction = normalize(interp.vP - vs_near_plane);
vec3 ls_near_plane = point_world_to_object(ws_near_plane);
vec3 ls_view_direction = normalize(point_world_to_object(interp.P) - ls_near_plane);
/* TODO (Miguel Pozo): We could try to ray-cast against the non-inflated bounds first,
* and fallback to the inflated ones if theres no hit.
* The inflated bounds can cause unnecesary extra steps. */
float ls_near_box_t = ray_aabb(
ls_near_plane, ls_view_direction, interp.ls_aabb_min, interp.ls_aabb_max);
vec3 ls_near_box = ls_near_plane + ls_view_direction * ls_near_box_t;
vec3 ws_near_box = point_object_to_world(ls_near_box);
float near_box_t = distance(ws_near_plane, ws_near_box);
float far_box_t = distance(ws_near_plane, interp.P);
/* Depth test. */
far_box_t = min(far_box_t, distance(ws_near_plane, ws_opaque));
/* Ray march from the front to the back of the bbox, and tag shadow usage along the way. */
float step_size;
for (float t = near_box_t; t <= far_box_t; t += step_size) {
/* Ensure we don't get past far_box_t. */
t = min(t, far_box_t);
step_size = pixel_size_at(t);
vec3 P = ws_near_plane + (ws_view_direction * t);
float step_radius;
step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
vec3 vP = point_world_to_view(P);
shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod));
}
}

View File

@ -3,8 +3,7 @@
* Virtual shadowmapping: Usage tagging
*
* Shadow pages are only allocated if they are visible.
* This pass scan the depth buffer and tag all tiles that are needed for light shadowing as
* needed.
* This contains the common logic used for tagging shadows for opaque and transparent receivers.
*/
#pragma BLENDER_REQUIRE(common_intersect_lib.glsl)
@ -14,7 +13,18 @@
#pragma BLENDER_REQUIRE(eevee_light_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_shadow_lib.glsl)
void shadow_tag_usage_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool is_directional)
void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_index)
{
if (tilemap_index > light_tilemap_max_get(light)) {
return;
}
tile_co >>= lod;
int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod);
atomicOr(tiles_buf[tile_index], SHADOW_IS_USED);
}
void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius)
{
LightData light = light_buf[l_idx];
@ -22,83 +32,141 @@ void shadow_tag_usage_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool
return;
}
int lod = 0;
ivec2 tile_co;
int tilemap_index = light.tilemap_index;
if (is_directional) {
vec3 lP = shadow_world_to_local(light, P);
vec3 lP = shadow_world_to_local(light, P);
if (radius == 0) {
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);
tile_co = coord.tile_coord;
tilemap_index = coord.tilemap_index;
shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index);
}
else {
vec3 lP = light_world_to_local(light, P - light._position);
float dist_to_light = length(lP);
if (dist_to_light > light.influence_radius_max) {
return;
}
if (light.type == LIGHT_SPOT) {
/* Early out if out of cone. */
float angle_tan = length(lP.xy / dist_to_light);
if (angle_tan > light.spot_tan) {
return;
vec3 start_lP = shadow_world_to_local(light, P - V * radius);
vec3 end_lP = shadow_world_to_local(light, P + V * radius);
int min_level = shadow_directional_level(light, start_lP - light._position);
int max_level = shadow_directional_level(light, end_lP - light._position);
for (int level = min_level; level <= max_level; level++) {
ShadowCoordinates coord_min = shadow_directional_coordinates_at_level(
light, lP - vec3(radius, radius, 0), level);
ShadowCoordinates coord_max = shadow_directional_coordinates_at_level(
light, lP + vec3(radius, radius, 0), level);
for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) {
for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) {
shadow_tag_usage_tile(light, ivec2(x, y), 0, coord_min.tilemap_index);
}
}
}
else if (is_area_light(light.type)) {
/* Early out if on the wrong side. */
if (lP.z > 0.0) {
return;
}
}
/* How much a shadow map pixel covers a final image pixel.
* We project a shadow map pixel (as a sphere for simplicity) to the receiver plane.
* We then reproject this sphere onto the camera screen and compare it to the film pixel size.
* This gives a good approximation of what LOD to select to get a somewhat uniform shadow map
* resolution in screen space. */
float footprint_ratio = dist_to_light;
/* Project the radius to the screen. 1 unit away from the camera the same way
* pixel_world_radius_inv was computed. Not needed in orthographic mode. */
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
if (is_persp) {
footprint_ratio /= dist_to_cam;
}
/* Apply resolution ratio. */
footprint_ratio *= tilemap_projection_ratio;
int face_id = shadow_punctual_face_index_get(lP);
lP = shadow_punctual_local_position_to_face_local(face_id, lP);
ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id);
tile_co = coord.tile_coord;
tilemap_index = coord.tilemap_index;
lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias));
lod = clamp(lod, 0, SHADOW_TILEMAP_LOD);
}
tile_co >>= lod;
}
if (tilemap_index > light_tilemap_max_get(light)) {
void shadow_tag_usage_tilemap_punctual(uint l_idx, vec3 P, vec3 V, float dist_to_cam, float radius)
{
LightData light = light_buf[l_idx];
if (light.tilemap_index == LIGHT_NO_SHADOW) {
return;
}
int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod);
atomicOr(tiles_buf[tile_index], SHADOW_IS_USED);
vec3 lP = light_world_to_local(light, P - light._position);
float dist_to_light = length(lP) - radius;
if (dist_to_light > light.influence_radius_max) {
return;
}
if (light.type == LIGHT_SPOT) {
/* Early out if out of cone. */
float angle_tan = length(lP.xy / dist_to_light);
if (angle_tan > light.spot_tan) {
return;
}
}
else if (is_area_light(light.type)) {
/* Early out if on the wrong side. */
if (lP.z - radius > 0.0) {
return;
}
}
/* How much a shadow map pixel covers a final image pixel.
* We project a shadow map pixel (as a sphere for simplicity) to the receiver plane.
* We then reproject this sphere onto the camera screen and compare it to the film pixel size.
* This gives a good approximation of what LOD to select to get a somewhat uniform shadow map
* resolution in screen space. */
float footprint_ratio = dist_to_light;
/* Project the radius to the screen. 1 unit away from the camera the same way
* pixel_world_radius_inv was computed. Not needed in orthographic mode. */
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
if (is_persp) {
footprint_ratio /= dist_to_cam;
}
/* Apply resolution ratio. */
footprint_ratio *= tilemap_projection_ratio;
if (radius == 0) {
int face_id = shadow_punctual_face_index_get(lP);
lP = shadow_punctual_local_position_to_face_local(face_id, lP);
ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id);
int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[coord.tilemap_index].lod_bias));
lod = clamp(lod, 0, SHADOW_TILEMAP_LOD);
shadow_tag_usage_tile(light, coord.tile_coord, lod, coord.tilemap_index);
}
else {
uint faces = 0u;
for (int x = -1; x <= 1; x += 2) {
for (int y = -1; y <= 1; y += 2) {
for (int z = -1; z <= 1; z += 2) {
vec3 _lP = lP + vec3(x, y, z) * radius;
faces |= 1u << shadow_punctual_face_index_get(_lP);
}
}
}
for (int face_id = 0; face_id < 6; face_id++) {
if ((faces & (1u << uint(face_id))) == 0u) {
continue;
}
int tilemap_index = light.tilemap_index + face_id;
int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias));
lod = clamp(lod, 0, SHADOW_TILEMAP_LOD);
vec3 _lP = shadow_punctual_local_position_to_face_local(face_id, lP);
vec3 offset = vec3(radius, radius, 0);
ShadowCoordinates coord_min = shadow_punctual_coordinates(light, _lP - offset, face_id);
ShadowCoordinates coord_max = shadow_punctual_coordinates(light, _lP + offset, face_id);
for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) {
for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) {
shadow_tag_usage_tile(light, ivec2(x, y), lod, tilemap_index);
}
}
}
}
}
/**
* \a radius Radius of the tagging area in world space.
* Used for downsampled/ray-marched tagging, so all the shadowmap texels covered get correctly
* tagged.
*/
void shadow_tag_usage(vec3 vP, vec3 P, vec3 V, float radius, float dist_to_cam, vec2 pixel)
{
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
shadow_tag_usage_tilemap_directional(l_idx, P, V, radius);
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) {
shadow_tag_usage_tilemap_punctual(l_idx, P, V, dist_to_cam, radius);
}
LIGHT_FOREACH_END
}
void shadow_tag_usage(vec3 vP, vec3 P, vec2 pixel)
{
float dist_to_cam = length(vP);
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, true);
}
LIGHT_FOREACH_END
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) {
shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, false);
}
LIGHT_FOREACH_END
shadow_tag_usage(vP, P, vec3(0), 0, dist_to_cam, pixel);
}

View File

@ -3,20 +3,89 @@
* Virtual shadowmapping: Usage tagging
*
* Shadow pages are only allocated if they are visible.
* This renders bounding boxes for transparent objects in order to tag the correct shadows.
* This renders the bounding boxes for transparent objects in order to tag the correct shadows.
*/
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(common_shape_lib.glsl)
#pragma BLENDER_REQUIRE(common_debug_shape_lib.glsl)
/* Inflate bounds by half a pixel as a conservative rasterization alternative,
* to ensure the tiles needed by all LOD0 pixels get tagged */
void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP)
{
vec3 vP = point_world_to_view(P);
float inflate_scale = pixel_world_radius * exp2(fb_lod);
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
if (is_persp) {
inflate_scale *= -vP.z;
}
/* Half-pixel. */
inflate_scale *= 0.5;
vec3 vs_inflate_vector = normal_object_to_view(sign(lP - ls_center));
vs_inflate_vector.z = 0;
/* Scale the vector so the largest axis length is 1 */
vs_inflate_vector /= max_v2(abs(vs_inflate_vector.xy));
vs_inflate_vector *= inflate_scale;
vP += vs_inflate_vector;
P = point_view_to_world(vP);
lP = point_world_to_object(P);
}
void main()
{
ObjectBounds bounds = bounds_buf[drw_ResourceID];
PASS_RESOURCE_ID
interp.P = bounds.bounding_corners[0].xyz;
interp.P += bounds.bounding_corners[1].xyz * pos.x;
interp.P += bounds.bounding_corners[2].xyz * pos.y;
interp.P += bounds.bounding_corners[3].xyz * pos.z;
const ObjectBounds bounds = bounds_buf[resource_id];
Box box = shape_box(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz,
bounds.bounding_corners[0].xyz + bounds.bounding_corners[2].xyz,
bounds.bounding_corners[0].xyz + bounds.bounding_corners[3].xyz);
vec3 ws_aabb_min = bounds.bounding_corners[0].xyz;
vec3 ws_aabb_max = bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz +
bounds.bounding_corners[2].xyz + bounds.bounding_corners[3].xyz;
vec3 ls_center = point_world_to_object((ws_aabb_min + ws_aabb_max) / 2.0);
vec3 ls_conservative_min = vec3(FLT_MAX);
vec3 ls_conservative_max = vec3(-FLT_MAX);
for (int i = 0; i < 8; i++) {
vec3 P = box.corners[i];
vec3 lP = point_world_to_object(P);
inflate_bounds(ls_center, P, lP);
ls_conservative_min = min(ls_conservative_min, lP);
ls_conservative_max = max(ls_conservative_max, lP);
}
interp.ls_aabb_min = ls_conservative_min;
interp.ls_aabb_max = ls_conservative_max;
vec3 lP = mix(ls_conservative_min, ls_conservative_max, max(vec3(0), pos));
interp.P = point_object_to_world(lP);
interp.vP = point_world_to_view(interp.P);
gl_Position = point_world_to_ndc(interp.P);
#if 0
if (gl_VertexID == 0) {
Box debug_box = shape_box(
ls_conservative_min,
ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(1, 0, 0),
ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(0, 1, 0),
ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(0, 0, 1));
for (int i = 0; i < 8; i++) {
debug_box.corners[i] = point_object_to_world(debug_box.corners[i]);
}
drw_debug(debug_box);
}
#endif
}

View File

@ -98,7 +98,12 @@ ShadowTileData shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilem
return shadow_tile_unpack(tile_data);
}
/* This function should be the inverse of ShadowDirectional::coverage_get(). */
/**
* This function should be the inverse of ShadowDirectional::coverage_get().
*
* \a lP shading point position in light space, relative to the to camera position snapped to
* the smallest clipmap level (`shadow_world_to_local(light, P) - light._position`).
*/
int shadow_directional_level(LightData light, vec3 lP)
{
float lod;
@ -144,14 +149,11 @@ ivec2 shadow_decompress_grid_offset(eLightType light_type, ivec2 offset, int lev
}
/**
* \a lP shading point position in light space (world unit) and translated to camera position
* snapped to smallest clipmap level.
* \a lP shading point position in light space (`shadow_world_to_local(light, P)`).
*/
ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3 lP, int level)
{
ShadowCoordinates ret;
int level = shadow_directional_level(light, lP - light._position);
/* This difference needs to be less than 32 for the later shift to be valid.
* This is ensured by ShadowDirectional::clipmap_level_range(). */
int level_relative = level - light.clipmap_lod_min;
@ -173,6 +175,15 @@ ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
return ret;
}
/**
* \a lP shading point position in light space (`shadow_world_to_local(light, P)`).
*/
ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP)
{
int level = shadow_directional_level(light, lP - light._position);
return shadow_directional_coordinates_at_level(light, lP, level);
}
/* Transform vector to face local coordinate. */
vec3 shadow_punctual_local_position_to_face_local(int face_id, vec3 lL)
{

View File

@ -54,7 +54,9 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
GPU_SHADER_INTERFACE_INFO(eevee_shadow_tag_transparent_iface, "interp")
.smooth(Type::VEC3, "P")
.smooth(Type::VEC3, "vP");
.smooth(Type::VEC3, "vP")
.flat(Type::VEC3, "ls_aabb_min")
.flat(Type::VEC3, "ls_aabb_max");
GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
.do_static_compilation(true)
@ -63,9 +65,17 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
.push_constant(Type::FLOAT, "pixel_world_radius")
.push_constant(Type::IVEC2, "fb_resolution")
.push_constant(Type::INT, "fb_lod")
.vertex_out(eevee_shadow_tag_transparent_iface)
.additional_info(
"eevee_shared", "draw_view", "draw_view_culling", "draw_modelmat_new", "eevee_light_data")
.additional_info("eevee_shared",
"draw_resource_id_varying",
"draw_view",
"draw_view_culling",
"draw_modelmat_new",
"eevee_hiz_data",
"eevee_light_data")
.vertex_source("eevee_shadow_tag_usage_vert.glsl")
.fragment_source("eevee_shadow_tag_usage_frag.glsl");

View File

@ -383,6 +383,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
is_auto_smooth,
split_angle,
sharp_edges,
mr->sharp_faces,
nullptr,
nullptr,
clnors);
@ -573,6 +574,9 @@ MeshRenderData *mesh_render_data_create(Object *object,
CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".select_edge"));
mr->select_poly = static_cast<const bool *>(
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".select_poly"));
mr->sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, "sharp_face"));
}
else {
/* #BMesh */

View File

@ -757,7 +757,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData *
const Span<MPoly> polys = mesh->polys();
for (const int i : polys.index_range()) {
uint32_t flag = 0;
if ((polys[i].flag & ME_SMOOTH) != 0) {
if (!(mr->sharp_faces && mr->sharp_faces[i])) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
if (mr->select_poly && mr->select_poly[i]) {
@ -786,7 +786,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh,
/* Selection and hiding from bmesh. */
uint32_t flag = (f) ? compute_coarse_face_flag_bm(f, mr->efa_act) : 0;
/* Smooth from mesh. */
if ((polys[i].flag & ME_SMOOTH) != 0) {
if (!(mr->sharp_faces && mr->sharp_faces[i])) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
flags_data[i] = uint(polys[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);

View File

@ -336,15 +336,17 @@ struct PBVHBatches {
float fno[3];
short no[3];
int last_poly = -1;
bool smooth = false;
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(args->pdata, CD_PROP_BOOL, "sharp_face"));
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri *tri) {
bool smooth = false;
if (tri->poly != last_poly) {
last_poly = tri->poly;
const MPoly &poly = args->polys[tri->poly];
if (!(poly.flag & ME_SMOOTH)) {
if (sharp_faces && sharp_faces[tri->poly]) {
smooth = true;
const MPoly &poly = args->polys[tri->poly];
BKE_mesh_calc_poly_normal(
&poly, args->mloop + poly.loopstart, args->vert_positions, fno);
normal_float_to_short_v3(no, fno);
@ -409,7 +411,7 @@ struct PBVHBatches {
foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) {
float3 no(0.0f, 0.0f, 0.0f);
const bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH;
const bool smooth = !args->grid_flag_mats[grid_index].sharp;
if (smooth) {
no = CCG_elem_no(&args->ccg_key, elems[0]);
@ -1085,7 +1087,7 @@ struct PBVHBatches {
for (int i : IndexRange(args->totprim)) {
int grid_index = args->grid_indices[i];
bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH;
bool smooth = !args->grid_flag_mats[grid_index].sharp;
BLI_bitmap *gh = args->grid_hidden[grid_index];
for (int y = 0; y < gridsize - 1; y += skip) {

View File

@ -209,10 +209,6 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, struct MeshBufferCac
void DRW_subdiv_cache_free(struct Subdiv *subdiv);
void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache,
struct MeshRenderData *mr,
const struct ToolSettings *toolsettings);
void draw_subdiv_init_origindex_buffer(struct GPUVertBuf *buffer,
int32_t *vert_origindex,
uint num_loops,

View File

@ -94,6 +94,7 @@ struct MeshRenderData {
const bool *select_vert;
const bool *select_edge;
const bool *select_poly;
const bool *sharp_faces;
float (*loop_normals)[3];
int *lverts, *ledges;

View File

@ -71,11 +71,11 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr,
if (mr->loop_normals) {
*lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]);
}
else if (poly->flag & ME_SMOOTH) {
*lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
else if (mr->sharp_faces && mr->sharp_faces[poly_index]) {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]);
}
else {
*lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]);
*lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]);
}
/* Flag for paint mode overlay.
@ -195,11 +195,11 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr,
if (mr->loop_normals) {
normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]);
}
else if (poly->flag & ME_SMOOTH) {
normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
else if (mr->sharp_faces && mr->sharp_faces[poly_index]) {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]);
}
else {
normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]);
normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]);
}
/* Flag for paint mode overlay.

View File

@ -120,6 +120,7 @@ static void extract_tan_init_common(const MeshRenderData *mr,
mr->loops.data(),
mr->looptris.data(),
mr->tri_len,
mr->sharp_faces,
cd_ldata,
calc_active_tangent,
r_tangent_names,

View File

@ -1,416 +0,0 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"
#include "draw_testing.hh"
#include "GPU_context.h"
#include "GPU_index_buffer.h"
#include "GPU_init_exit.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
#include "intern/draw_manager_testing.h"
#include "engines/basic/basic_private.h"
#include "engines/eevee/eevee_private.h"
#include "engines/gpencil/gpencil_engine.h"
#include "engines/image/image_private.hh"
#include "engines/overlay/overlay_private.hh"
#include "engines/workbench/workbench_private.h"
#include "intern/draw_shader.h"
namespace blender::draw {
using namespace blender::draw::image_engine;
static void test_workbench_glsl_shaders()
{
const int MAX_WPD = 6;
WORKBENCH_PrivateData wpds[MAX_WPD];
wpds[0].sh_cfg = GPU_SHADER_CFG_DEFAULT;
wpds[0].shading.light = V3D_LIGHTING_FLAT;
wpds[1].sh_cfg = GPU_SHADER_CFG_DEFAULT;
wpds[1].shading.light = V3D_LIGHTING_MATCAP;
wpds[2].sh_cfg = GPU_SHADER_CFG_DEFAULT;
wpds[2].shading.light = V3D_LIGHTING_STUDIO;
wpds[3].sh_cfg = GPU_SHADER_CFG_CLIPPED;
wpds[3].shading.light = V3D_LIGHTING_FLAT;
wpds[4].sh_cfg = GPU_SHADER_CFG_CLIPPED;
wpds[4].shading.light = V3D_LIGHTING_MATCAP;
wpds[5].sh_cfg = GPU_SHADER_CFG_CLIPPED;
wpds[5].shading.light = V3D_LIGHTING_STUDIO;
for (int wpd_index = 0; wpd_index < MAX_WPD; wpd_index++) {
WORKBENCH_PrivateData *wpd = &wpds[wpd_index];
EXPECT_NE(workbench_shader_opaque_get(wpd, WORKBENCH_DATATYPE_MESH), nullptr);
EXPECT_NE(workbench_shader_opaque_get(wpd, WORKBENCH_DATATYPE_HAIR), nullptr);
EXPECT_NE(workbench_shader_opaque_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD), nullptr);
EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_MESH, false), nullptr);
EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_MESH, true), nullptr);
EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_HAIR, false), nullptr);
EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_HAIR, true), nullptr);
EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, false),
nullptr);
EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, true),
nullptr);
EXPECT_NE(workbench_shader_composite_get(wpd), nullptr);
EXPECT_NE(workbench_shader_merge_infront_get(wpd), nullptr);
EXPECT_NE(workbench_shader_transparent_get(wpd, WORKBENCH_DATATYPE_MESH), nullptr);
EXPECT_NE(workbench_shader_transparent_get(wpd, WORKBENCH_DATATYPE_HAIR), nullptr);
EXPECT_NE(workbench_shader_transparent_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD), nullptr);
EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_MESH, false),
nullptr);
EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_MESH, true), nullptr);
EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_HAIR, false),
nullptr);
EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_HAIR, true), nullptr);
EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, false),
nullptr);
EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, true),
nullptr);
EXPECT_NE(workbench_shader_transparent_resolve_get(wpd), nullptr);
}
EXPECT_NE(workbench_shader_shadow_pass_get(false), nullptr);
EXPECT_NE(workbench_shader_shadow_pass_get(true), nullptr);
EXPECT_NE(workbench_shader_shadow_fail_get(false, false), nullptr);
EXPECT_NE(workbench_shader_shadow_fail_get(false, true), nullptr);
EXPECT_NE(workbench_shader_shadow_fail_get(true, false), nullptr);
EXPECT_NE(workbench_shader_shadow_fail_get(true, true), nullptr);
/* NOTE: workbench_shader_cavity_get(false, false) isn't a valid option. */
EXPECT_NE(workbench_shader_cavity_get(false, true), nullptr);
EXPECT_NE(workbench_shader_cavity_get(true, false), nullptr);
EXPECT_NE(workbench_shader_cavity_get(true, true), nullptr);
EXPECT_NE(workbench_shader_outline_get(), nullptr);
EXPECT_NE(workbench_shader_antialiasing_accumulation_get(), nullptr);
EXPECT_NE(workbench_shader_antialiasing_get(0), nullptr);
EXPECT_NE(workbench_shader_antialiasing_get(1), nullptr);
EXPECT_NE(workbench_shader_antialiasing_get(2), nullptr);
EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_LINEAR, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_LINEAR, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CUBIC, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CUBIC, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CLOSEST, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CLOSEST, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_LINEAR, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_LINEAR, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CUBIC, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CUBIC, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CLOSEST, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CLOSEST, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_LINEAR, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_LINEAR, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CUBIC, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CUBIC, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CLOSEST, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CLOSEST, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_LINEAR, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_LINEAR, true),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CUBIC, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CUBIC, true), nullptr);
EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CLOSEST, false),
nullptr);
EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CLOSEST, true),
nullptr);
GPUShader *dof_prepare_sh;
GPUShader *dof_downsample_sh;
GPUShader *dof_blur1_sh;
GPUShader *dof_blur2_sh;
GPUShader *dof_resolve_sh;
workbench_shader_depth_of_field_get(
&dof_prepare_sh, &dof_downsample_sh, &dof_blur1_sh, &dof_blur2_sh, &dof_resolve_sh);
EXPECT_NE(dof_prepare_sh, nullptr);
EXPECT_NE(dof_downsample_sh, nullptr);
EXPECT_NE(dof_blur1_sh, nullptr);
EXPECT_NE(dof_blur2_sh, nullptr);
EXPECT_NE(dof_resolve_sh, nullptr);
workbench_shader_free();
}
DRAW_TEST(workbench_glsl_shaders)
static void test_gpencil_glsl_shaders()
{
EXPECT_NE(GPENCIL_shader_antialiasing(0), nullptr);
EXPECT_NE(GPENCIL_shader_antialiasing(1), nullptr);
EXPECT_NE(GPENCIL_shader_antialiasing(2), nullptr);
EXPECT_NE(GPENCIL_shader_geometry_get(), nullptr);
EXPECT_NE(GPENCIL_shader_layer_blend_get(), nullptr);
EXPECT_NE(GPENCIL_shader_mask_invert_get(), nullptr);
EXPECT_NE(GPENCIL_shader_depth_merge_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_blur_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_colorize_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_composite_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_transform_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_glow_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_pixelize_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_rim_get(), nullptr);
EXPECT_NE(GPENCIL_shader_fx_shadow_get(), nullptr);
GPENCIL_shader_free();
}
DRAW_TEST(gpencil_glsl_shaders)
static void test_image_glsl_shaders()
{
EXPECT_NE(IMAGE_shader_image_get(), nullptr);
EXPECT_NE(IMAGE_shader_depth_get(), nullptr);
IMAGE_shader_free();
}
DRAW_TEST(image_glsl_shaders)
static void test_overlay_glsl_shaders()
{
for (int i = 0; i < 2; i++) {
eGPUShaderConfig sh_cfg = i == 0 ? GPU_SHADER_CFG_DEFAULT : GPU_SHADER_CFG_CLIPPED;
DRW_draw_state_init_gtests(sh_cfg);
EXPECT_NE(OVERLAY_shader_antialiasing(), nullptr);
EXPECT_NE(OVERLAY_shader_armature_degrees_of_freedom_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_armature_degrees_of_freedom_solid(), nullptr);
EXPECT_NE(OVERLAY_shader_armature_envelope(false), nullptr);
EXPECT_NE(OVERLAY_shader_armature_envelope(true), nullptr);
EXPECT_NE(OVERLAY_shader_armature_shape(false), nullptr);
EXPECT_NE(OVERLAY_shader_armature_shape(true), nullptr);
EXPECT_NE(OVERLAY_shader_armature_shape_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_armature_sphere(false), nullptr);
EXPECT_NE(OVERLAY_shader_armature_sphere(true), nullptr);
EXPECT_NE(OVERLAY_shader_armature_stick(), nullptr);
EXPECT_NE(OVERLAY_shader_armature_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_background(), nullptr);
EXPECT_NE(OVERLAY_shader_clipbound(), nullptr);
EXPECT_NE(OVERLAY_shader_depth_only(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_curve_handle(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_curve_point(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_curve_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_gpencil_guide_point(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_gpencil_point(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_gpencil_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_lattice_point(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_lattice_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_analysis(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_depth(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_edge(false), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_edge(true), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_face(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_facedot(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_normal(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_skin_root(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_mesh_vert(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_particle_strand(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_particle_point(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_edges_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_face_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_face_dots_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_verts_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_stretching_area_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_stretching_angle_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_tiled_image_borders_get(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_stencil_image(), nullptr);
EXPECT_NE(OVERLAY_shader_edit_uv_mask_image(), nullptr);
EXPECT_NE(OVERLAY_shader_extra(false), nullptr);
EXPECT_NE(OVERLAY_shader_extra(true), nullptr);
EXPECT_NE(OVERLAY_shader_extra_groundline(), nullptr);
EXPECT_NE(OVERLAY_shader_extra_wire(false, false), nullptr);
EXPECT_NE(OVERLAY_shader_extra_wire(false, true), nullptr);
EXPECT_NE(OVERLAY_shader_extra_wire(true, false), nullptr);
EXPECT_NE(OVERLAY_shader_extra_wire(true, true), nullptr);
EXPECT_NE(OVERLAY_shader_extra_loose_point(), nullptr);
EXPECT_NE(OVERLAY_shader_extra_point(), nullptr);
EXPECT_NE(OVERLAY_shader_facing(), nullptr);
EXPECT_NE(OVERLAY_shader_gpencil_canvas(), nullptr);
EXPECT_NE(OVERLAY_shader_grid(), nullptr);
EXPECT_NE(OVERLAY_shader_grid_image(), nullptr);
EXPECT_NE(OVERLAY_shader_image(), nullptr);
EXPECT_NE(OVERLAY_shader_motion_path_line(), nullptr);
EXPECT_NE(OVERLAY_shader_motion_path_vert(), nullptr);
EXPECT_NE(OVERLAY_shader_uniform_color(), nullptr);
EXPECT_NE(OVERLAY_shader_uniform_color_pointcloud(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass(false), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass(true), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass_curves(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass_gpencil(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_prepass_pointcloud(), nullptr);
EXPECT_NE(OVERLAY_shader_extra_grid(), nullptr);
EXPECT_NE(OVERLAY_shader_outline_detect(), nullptr);
EXPECT_NE(OVERLAY_shader_paint_face(), nullptr);
EXPECT_NE(OVERLAY_shader_paint_point(), nullptr);
EXPECT_NE(OVERLAY_shader_paint_texture(), nullptr);
EXPECT_NE(OVERLAY_shader_paint_vertcol(), nullptr);
EXPECT_NE(OVERLAY_shader_paint_weight(false), nullptr);
EXPECT_NE(OVERLAY_shader_paint_weight(true), nullptr);
EXPECT_NE(OVERLAY_shader_paint_wire(), nullptr);
EXPECT_NE(OVERLAY_shader_particle_dot(), nullptr);
EXPECT_NE(OVERLAY_shader_particle_shape(), nullptr);
EXPECT_NE(OVERLAY_shader_sculpt_mask(), nullptr);
EXPECT_NE(OVERLAY_shader_sculpt_curves_selection(), nullptr);
EXPECT_NE(OVERLAY_shader_viewer_attribute_curve(), nullptr);
EXPECT_NE(OVERLAY_shader_viewer_attribute_curves(), nullptr);
EXPECT_NE(OVERLAY_shader_viewer_attribute_mesh(), nullptr);
EXPECT_NE(OVERLAY_shader_viewer_attribute_pointcloud(), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(false, false), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(false, true), nullptr);
EXPECT_NE(OVERLAY_shader_volume_velocity(true, false), nullptr);
EXPECT_NE(OVERLAY_shader_wireframe(false), nullptr);
EXPECT_NE(OVERLAY_shader_wireframe(true), nullptr);
EXPECT_NE(OVERLAY_shader_wireframe_select(), nullptr);
EXPECT_NE(OVERLAY_shader_xray_fade(), nullptr);
}
OVERLAY_shader_free();
}
DRAW_TEST(overlay_glsl_shaders)
static void test_eevee_glsl_shaders_static()
{
EEVEE_shaders_material_shaders_init();
EXPECT_NE(EEVEE_shaders_bloom_blit_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_blit_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_downsample_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_downsample_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_upsample_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_upsample_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_resolve_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_bloom_resolve_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_bokeh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_setup_get(), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_flatten_tiles_get(), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_dilate_tiles_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_dilate_tiles_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_downsample_get(), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_reduce_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_reduce_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_FOREGROUND, false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_FOREGROUND, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_BACKGROUND, false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_BACKGROUND, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_HOLEFILL, false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_HOLEFILL, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_filter_get(), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(false, false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(false, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(true, false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(true, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(false, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(false, false), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(true, true), nullptr);
EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(true, false), nullptr);
EXPECT_NE(EEVEE_shaders_effect_downsample_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_downsample_cube_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_minz_downlevel_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_maxz_downlevel_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_minz_downdepth_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_maxz_downdepth_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_minz_downdepth_layer_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_minz_copydepth_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_maxz_copydepth_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_mist_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_motion_blur_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_motion_blur_object_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_motion_blur_hair_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_motion_blur_velocity_tiles_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_motion_blur_velocity_tiles_expand_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_ggx_lut_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_ggx_refraction_lut_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_filter_glossy_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_filter_diffuse_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_filter_visibility_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_grid_fill_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_planar_downsample_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_renderpasses_post_process_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_shadow_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_shadow_accum_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_subsurface_first_pass_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_subsurface_second_pass_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_clear_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_clear_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_scatter_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_scatter_with_lights_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_integration_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_resolve_sh_get(false), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_resolve_sh_get(true), nullptr);
EXPECT_NE(EEVEE_shaders_volumes_accum_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_studiolight_probe_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_studiolight_background_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_cube_display_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_grid_display_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_probe_planar_display_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_update_noise_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_velocity_resolve_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_taa_resolve_sh_get(EFFECT_TAA), nullptr);
EXPECT_NE(EEVEE_shaders_taa_resolve_sh_get(EFFECT_TAA_REPROJECT), nullptr);
EXPECT_NE(EEVEE_shaders_effect_reflection_trace_sh_get(), nullptr);
EXPECT_NE(EEVEE_shaders_effect_reflection_resolve_sh_get(), nullptr);
EEVEE_shaders_free();
}
DRAW_TEST(eevee_glsl_shaders_static)
static void test_draw_shaders(eParticleRefineShaderType sh_type)
{
DRW_shaders_free();
EXPECT_NE(DRW_shader_hair_refine_get(PART_REFINE_CATMULL_ROM, sh_type), nullptr);
DRW_shaders_free();
}
static void test_draw_glsl_shaders()
{
#ifndef __APPLE__
test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK);
test_draw_shaders(PART_REFINE_SHADER_COMPUTE);
#endif
test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND);
}
DRAW_TEST(draw_glsl_shaders)
static void test_basic_glsl_shaders()
{
for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) {
eGPUShaderConfig sh_cfg = static_cast<eGPUShaderConfig>(i);
BASIC_shaders_depth_sh_get(sh_cfg);
BASIC_shaders_pointcloud_depth_sh_get(sh_cfg);
BASIC_shaders_curves_depth_sh_get(sh_cfg);
BASIC_shaders_depth_conservative_sh_get(sh_cfg);
BASIC_shaders_pointcloud_depth_conservative_sh_get(sh_cfg);
}
BASIC_shaders_free();
}
DRAW_TEST(basic_glsl_shaders)
} // namespace blender::draw

View File

@ -345,7 +345,7 @@ void animviz_motionpath_compute_range(Object *ob, Scene *scene)
bAnimVizSettings *avs = ob->mode == OB_MODE_POSE ? &ob->pose->avs : &ob->avs;
if (avs->path_range == MOTIONPATH_RANGE_MANUAL) {
/* Don't touch manually-determined ranges. */
/* Don't touch manually-determined ranges. */
return;
}

View File

@ -41,7 +41,9 @@
#include "anim_intern.h"
/* ********************** frame change operator ***************************/
/* -------------------------------------------------------------------- */
/** \name Frame Change Operator
* \{ */
/* Check if the operator can be run from the current context */
static bool change_frame_poll(bContext *C)
@ -349,7 +351,11 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ****************** Start/End Frame Operators *******************************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Start/End Frame Operators
* \{ */
static bool anim_set_end_frames_poll(bContext *C)
{
@ -483,7 +489,11 @@ static void ANIM_OT_end_frame_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ****************** set preview range operator ****************************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Set Preview Range Operator
* \{ */
static int previewrange_define_exec(bContext *C, wmOperator *op)
{
@ -545,7 +555,11 @@ static void ANIM_OT_previewrange_set(wmOperatorType *ot)
WM_operator_properties_border(ot);
}
/* ****************** clear preview range operator ****************************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Clear Preview Range Operator
* \{ */
static int previewrange_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
@ -586,7 +600,11 @@ static void ANIM_OT_previewrange_clear(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ************************** registration **********************************/
/** \} */
/* -------------------------------------------------------------------- */
/** \name Registration
* \{ */
void ED_operatortypes_anim(void)
{
@ -632,3 +650,5 @@ void ED_keymap_anim(wmKeyConfig *keyconf)
{
WM_keymap_ensure(keyconf, "Animation", 0, 0);
}
/** \} */

View File

@ -798,7 +798,7 @@ static void gpencil_create_extensions_radius(tGPDfill *tgpf)
}
/* Don't check endpoint distances unless the bounding boxes of the strokes
are close enough together that they can plausibly be connected. */
* are close enough together that they can plausibly be connected. */
if (!extended_bbox_overlap(gps->boundbox_min,
gps->boundbox_max,
gps2->boundbox_min,

View File

@ -109,7 +109,7 @@ enum {
/* Display the hover region (edge or corner) of the underlying bounding box. */
ED_GIZMO_CAGE2D_STYLE_BOX = 0,
/* Display the bounding box plus dots on four corners while hovering, usually used for
transforming a 2D shape. */
* transforming a 2D shape. */
ED_GIZMO_CAGE2D_STYLE_BOX_TRANSFORM,
/* Display the bounding circle while hovering. */
ED_GIZMO_CAGE2D_STYLE_CIRCLE,

View File

@ -20,6 +20,7 @@ set(INC
../../python
../../render
../../windowmanager
../../../../intern/ghost
../../../../intern/guardedalloc
../../bmesh
# RNA_prototypes.h

View File

@ -47,6 +47,8 @@
#include "BKE_tracking.h"
#include "BKE_unit.h"
#include "GHOST_C-api.h"
#include "IMB_colormanagement.h"
#include "ED_screen.h"
@ -3459,6 +3461,9 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
/* Temporarily turn off window auto-focus on platforms that support it. */
GHOST_SetAutoFocus(false);
#ifdef WITH_INPUT_IME
if (!is_num_but) {
ui_textedit_ime_begin(win, but);
@ -3514,6 +3519,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_restore(win);
/* Turn back on the auto-focusing of windows. */
GHOST_SetAutoFocus(true);
/* Free text undo history text blocks. */
ui_textedit_undo_stack_destroy(data->undo_stack_text);
data->undo_stack_text = nullptr;

View File

@ -44,7 +44,6 @@ static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent *
return OPERATOR_RUNNING_MODAL;
}
/* function used for WM_OT_save_mainfile too */
static int wm_collada_export_exec(bContext *C, wmOperator *op)
{
char filepath[FILE_MAX];
@ -673,7 +672,6 @@ void WM_OT_collada_export(wmOperatorType *ot)
"Store Bindpose information in custom bone properties for later use during Collada export");
}
/* function used for WM_OT_save_mainfile too */
static int wm_collada_import_exec(bContext *C, wmOperator *op)
{
char filename[FILE_MAX];

View File

@ -800,11 +800,14 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
bke::MutableAttributeAccessor attributes = me->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, "sharp_face"));
BKE_edges_sharp_from_angle_set(me->totedge,
loops.data(),
loops.size(),
polys.data(),
BKE_mesh_poly_normals_ensure(me),
sharp_faces,
polys.size(),
me->smoothresh,
sharp_edges.span.data());
@ -1468,6 +1471,8 @@ void ED_mesh_split_faces(Mesh *mesh)
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> mesh_sharp_edges = attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
const bool *sharp_faces = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"));
Array<bool> sharp_edges(mesh->totedge);
mesh_sharp_edges.materialize(sharp_edges);
@ -1477,6 +1482,7 @@ void ED_mesh_split_faces(Mesh *mesh)
loops.size(),
polys.data(),
BKE_mesh_poly_normals_ensure(mesh),
sharp_faces,
polys.size(),
split_angle,
sharp_edges.data());
@ -1484,7 +1490,7 @@ void ED_mesh_split_faces(Mesh *mesh)
threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) {
for (const int poly_i : range) {
const MPoly &poly = polys[poly_i];
if (!(poly.flag & ME_SMOOTH)) {
if (sharp_faces && sharp_faces[poly_i]) {
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
sharp_edges[loop.e] = true;
}

View File

@ -25,6 +25,7 @@
#include "BLT_translation.h"
#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
@ -118,6 +119,7 @@ static bool object_remesh_poll(bContext *C)
static int voxel_remesh_exec(bContext *C, wmOperator *op)
{
using namespace blender;
Object *ob = CTX_data_active_object(C);
Mesh *mesh = static_cast<Mesh *>(ob->data);
@ -132,8 +134,10 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
}
/* Output mesh will be all smooth or all flat shading. */
const Span<MPoly> polys = mesh->polys();
const bool smooth_normals = polys.first().flag & ME_SMOOTH;
const bke::AttributeAccessor attributes = mesh->attributes();
const VArray<bool> sharp_faces = attributes.lookup_or_default<bool>(
"sharp_face", ATTR_DOMAIN_FACE, false);
const bool smooth_normals = !sharp_faces[0];
float isovalue = 0.0f;
if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
@ -176,9 +180,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob);
if (smooth_normals) {
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
}
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), smooth_normals);
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_end(ob);
@ -898,9 +900,7 @@ static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update,
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob);
if (qj->smooth_normals) {
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), true);
}
BKE_mesh_smooth_flag_set(static_cast<Mesh *>(ob->data), qj->smooth_normals);
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_end(ob);

View File

@ -377,7 +377,7 @@ static bool screen_areas_can_align(bScreen *screen, ScrArea *sa1, ScrArea *sa2,
return false;
}
/* Areas that are _smaller_ than minimum sizes, sharing an edge to be moved. See #100772. */
/* Areas that are _smaller_ than minimum sizes, sharing an edge to be moved. See #100772. */
if (SCREEN_DIR_IS_VERTICAL(dir)) {
const short xmin = MIN2(sa1->v1->vec.x, sa2->v1->vec.x);
const short xmax = MAX2(sa1->v3->vec.x, sa2->v3->vec.x);

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