Files
test/source/blender/blenloader/intern/versioning_defaults.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

828 lines
29 KiB
C++
Raw Normal View History

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup blenloader
*
* This file handles updating the `startup.blend`, this is used when reading old files.
*
* Unlike regular versioning this makes changes that ensure the startup file
* has brushes and other presets setup to take advantage of newer features.
*
* To update preference defaults see `userdef_default.c`.
*/
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
#define DNA_DEPRECATED_ALLOW
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
#include "BLI_string.h"
#include "BLI_system.h"
#include "BLI_utildefines.h"
#include "DNA_camera_types.h"
#include "DNA_curveprofile_types.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_light_types.h"
#include "DNA_mask_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "BKE_appdir.h"
#include "BKE_attribute.hh"
#include "BKE_brush.hh"
#include "BKE_colortools.h"
#include "BKE_curveprofile.h"
#include "BKE_customdata.h"
#include "BKE_gpencil_legacy.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_main_namemap.h"
#include "BKE_material.h"
#include "BKE_mesh.hh"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
Nodes: refactor node tree update handling Goals of this refactor: * More unified approach to updating everything that needs to be updated after a change in a node tree. * The updates should happen in the correct order and quadratic or worse algorithms should be avoided. * Improve detection of changes to the output to avoid tagging the depsgraph when it's not necessary. * Move towards a more declarative style of defining nodes by having a more centralized update procedure. The refactor consists of two main parts: * Node tree tagging and update refactor. * Generally, when changes are done to a node tree, it is tagged dirty until a global update function is called that updates everything in the correct order. * The tagging is more fine-grained compared to before, to allow for more precise depsgraph update tagging. * Depsgraph changes. * The shading specific depsgraph node for node trees as been removed. * Instead, there is a new `NTREE_OUTPUT` depsgrap node, which is only tagged when the output of the node tree changed (e.g. the Group Output or Material Output node). * The copy-on-write relation from node trees to the data block they are embedded in is now non-flushing. This avoids e.g. triggering a material update after the shader node tree changed in unrelated ways. Instead the material has a flushing relation to the new `NTREE_OUTPUT` node now. * The depsgraph no longer reports data block changes through to cycles through `Depsgraph.updates` when only the node tree changed in ways that do not affect the output. Avoiding unnecessary updates seems to work well for geometry nodes and cycles. The situation is a bit worse when there are drivers on the node tree, but that could potentially be improved separately in the future. Avoiding updates in eevee and the compositor is more tricky, but also less urgent. * Eevee updates are triggered by calling `DRW_notify_view_update` in `ED_render_view3d_update` indirectly from `DEG_editors_update`. * Compositor updates are triggered by `ED_node_composite_job` in `node_area_refresh`. This is triggered by calling `ED_area_tag_refresh` in `node_area_listener`. Removing updates always has the risk of breaking some dependency that no one was aware of. It's not unlikely that this will happen here as well. Adding back missing updates should be quite a bit easier than getting rid of unnecessary updates though. Differential Revision: https://developer.blender.org/D13246
2021-12-21 15:18:56 +01:00
#include "BKE_node_tree_update.h"
#include "BKE_paint.hh"
#include "BKE_screen.hh"
#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLT_translation.h"
#include "versioning_common.hh"
/* Make preferences read-only, use `versioning_userdef.cc`. */
#define U (*((const UserDef *)&U))
static bool blo_is_builtin_template(const char *app_template)
{
/* For all builtin templates shipped with Blender. */
2022-08-05 13:34:10 +10:00
return (
!app_template ||
STR_ELEM(app_template, N_("2D_Animation"), N_("Sculpting"), N_("VFX"), N_("Video_Editing")));
}
static void blo_update_defaults_screen(bScreen *screen,
const char *app_template,
const char *workspace_name)
{
/* For all app templates. */
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* Some toolbars have been saved as initialized,
* we don't want them to have odd zoom-level or scrolling set, see: #47047 */
if (ELEM(region->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
region->v2d.flag &= ~V2D_IS_INIT;
}
}
/* Set default folder. */
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_FILE) {
SpaceFile *sfile = (SpaceFile *)sl;
if (sfile->params) {
const char *dir_default = BKE_appdir_folder_default();
if (dir_default) {
STRNCPY(sfile->params->dir, dir_default);
sfile->params->file[0] = '\0';
}
}
}
}
}
/* For builtin templates only. */
if (!blo_is_builtin_template(app_template)) {
return;
}
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* Remove all stored panels, we want to use defaults
* (order, open/closed) as defined by UI code here! */
BKE_area_region_panels_free(&region->panels);
BLI_freelistN(&region->panels_category_active);
/* Reset size so it uses consistent defaults from the region types. */
region->sizex = 0;
region->sizey = 0;
}
if (area->spacetype == SPACE_IMAGE) {
if (STREQ(workspace_name, "UV Editing")) {
SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
if (sima->mode == SI_MODE_VIEW) {
sima->mode = SI_MODE_UV;
}
}
}
else if (area->spacetype == SPACE_ACTION) {
/* Show markers region, hide channels and collapse summary in timelines. */
SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first);
saction->flag |= SACTION_SHOW_MARKERS;
if (saction->mode == SACTCONT_TIMELINE) {
saction->ads.flag |= ADS_FLAG_SUMMARY_COLLAPSED;
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_CHANNELS) {
region->flag |= RGN_FLAG_HIDDEN;
}
}
}
else {
/* Open properties panel by default. */
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_UI) {
region->flag &= ~RGN_FLAG_HIDDEN;
}
}
}
}
else if (area->spacetype == SPACE_GRAPH) {
SpaceGraph *sipo = static_cast<SpaceGraph *>(area->spacedata.first);
sipo->flag |= SIPO_SHOW_MARKERS;
}
else if (area->spacetype == SPACE_NLA) {
SpaceNla *snla = static_cast<SpaceNla *>(area->spacedata.first);
snla->flag |= SNLA_SHOW_MARKERS;
}
else if (area->spacetype == SPACE_SEQ) {
SpaceSeq *seq = static_cast<SpaceSeq *>(area->spacedata.first);
seq->flag |= SEQ_SHOW_MARKERS | SEQ_ZOOM_TO_FIT | SEQ_USE_PROXIES | SEQ_SHOW_OVERLAY;
seq->render_size = SEQ_RENDER_SIZE_PROXY_100;
seq->timeline_overlay.flag |= SEQ_TIMELINE_SHOW_STRIP_SOURCE | SEQ_TIMELINE_SHOW_STRIP_NAME |
SEQ_TIMELINE_SHOW_STRIP_DURATION | SEQ_TIMELINE_SHOW_GRID |
VSE: Improve retiming UI Currently retiming is quite awkward, when you need to retime multiple strips strips in sync. It is possible to use meta strips, but this is still not great. This is resolved by implementing selection. General changes: Gizmos are removed, since they are designed to operate only on active strip and don't support selection. Transform operator code is implemented for retiming data, which allows more sophisticated manipulation. Instead of drawing marker-like symbols, keyframes are drawn to represent retiming data. Retiming handles are now called keys. To have consistent names, DNA structures have been renamed. Retiming data is drawn on strip as overlay. UI changes: Retiming tool is removed. To edit retiming data, press Ctrl + R, select a key and move it. When retiming is edited, retiming menu and context menu shows more relevant features, like making transitions. Strip and retiming key selection can not be combined. It is possible to use box select operator to select keys, if any key is selected. Otherwise strips are selected. Adding retiming keys is possible with I shortcut or from menu. Retiming keys are always drawn at strip left and right boundary. These keys do not really exist until they are selected. This is to simplify retiming of strips that are resized. These keys are called "fake keys" in code. API changes: Functions, properties and types related to retiming handles are renamed to retiming keys: retiming_handle_add() -> retiming_key_add() retiming_handle_move() -> retiming_key_move() retiming_handle_remove() -> retiming_key_remove() retiming_handles -> retiming_keys RetimingHandle -> RetimingKey Retiming editing "mode" is activated by setting `Sequence.show_retiming_keys`. Pull Request: https://projects.blender.org/blender/blender/pulls/109044
2023-09-27 01:45:59 +02:00
SEQ_TIMELINE_SHOW_STRIP_COLOR_TAG |
SEQ_TIMELINE_SHOW_STRIP_RETIMING;
seq->preview_overlay.flag |= SEQ_PREVIEW_SHOW_OUTLINE_SELECTED;
}
else if (area->spacetype == SPACE_TEXT) {
/* Show syntax and line numbers in Script workspace text editor. */
SpaceText *stext = static_cast<SpaceText *>(area->spacedata.first);
stext->showsyntax = true;
stext->showlinenrs = true;
}
else if (area->spacetype == SPACE_VIEW3D) {
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
/* Screen space cavity by default for faster performance. */
v3d->shading.cavity_type = V3D_SHADING_CAVITY_CURVATURE;
v3d->shading.flag |= V3D_SHADING_SPECULAR_HIGHLIGHT;
v3d->overlay.texture_paint_mode_opacity = 1.0f;
v3d->overlay.weight_paint_mode_opacity = 1.0f;
v3d->overlay.vertex_paint_mode_opacity = 1.0f;
/* Use dimmed selected edges. */
v3d->overlay.edit_flag &= ~V3D_OVERLAY_EDIT_EDGES;
/* grease pencil settings */
v3d->vertex_opacity = 1.0f;
v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
/* Remove dither pattern in wireframe mode. */
v3d->shading.xray_alpha_wire = 0.0f;
v3d->clip_start = 0.01f;
/* Skip startups that use the viewport color by default. */
if (v3d->shading.background_type != V3D_SHADING_BACKGROUND_VIEWPORT) {
copy_v3_fl(v3d->shading.background_color, 0.05f);
}
/* Disable Curve Normals. */
v3d->overlay.edit_flag &= ~V3D_OVERLAY_EDIT_CU_NORMALS;
v3d->overlay.normals_constant_screen_size = 7.0f;
}
else if (area->spacetype == SPACE_CLIP) {
SpaceClip *sclip = static_cast<SpaceClip *>(area->spacedata.first);
sclip->around = V3D_AROUND_CENTER_MEDIAN;
sclip->mask_info.blend_factor = 0.7f;
sclip->mask_info.draw_flag = MASK_DRAWFLAG_SPLINE;
}
}
/* Show tool-header by default (for most cases at least, hide for others). */
const bool hide_image_tool_header = STREQ(workspace_name, "Rendering");
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
ListBase *regionbase = (sl == static_cast<SpaceLink *>(area->spacedata.first)) ?
&area->regionbase :
&sl->regionbase;
LISTBASE_FOREACH (ARegion *, region, regionbase) {
if (region->regiontype == RGN_TYPE_TOOL_HEADER) {
if (((sl->spacetype == SPACE_IMAGE) && hide_image_tool_header) ||
sl->spacetype == SPACE_SEQ) {
region->flag |= RGN_FLAG_HIDDEN;
}
else {
region->flag &= ~(RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER);
}
}
}
}
}
/* 2D animation template. */
if (app_template && STREQ(app_template, "2D_Animation")) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (area->spacetype == SPACE_ACTION) {
SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first);
/* Enable Sliders. */
saction->flag |= SACTION_SLIDERS;
}
else if (area->spacetype == SPACE_VIEW3D) {
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
/* Set Material Color by default. */
v3d->shading.color_type = V3D_SHADING_MATERIAL_COLOR;
/* Enable Annotations. */
v3d->flag2 |= V3D_SHOW_ANNOTATION;
}
}
}
}
void BLO_update_defaults_workspace(WorkSpace *workspace, const char *app_template)
{
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
if (layout->screen) {
blo_update_defaults_screen(layout->screen, app_template, workspace->id.name + 2);
}
}
if (blo_is_builtin_template(app_template)) {
/* Clear all tools to use default options instead, ignore the tool saved in the file. */
while (!BLI_listbase_is_empty(&workspace->tools)) {
BKE_workspace_tool_remove(workspace, static_cast<bToolRef *>(workspace->tools.first));
}
/* For 2D animation template. */
if (STREQ(workspace->id.name + 2, "Drawing")) {
workspace->object_mode = OB_MODE_PAINT_GPENCIL_LEGACY;
}
/* For Sculpting template. */
if (STREQ(workspace->id.name + 2, "Sculpting")) {
LISTBASE_FOREACH (WorkSpaceLayout *, layout, &workspace->layouts) {
bScreen *screen = layout->screen;
if (screen) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (area->spacetype == SPACE_VIEW3D) {
View3D *v3d = static_cast<View3D *>(area->spacedata.first);
v3d->shading.flag &= ~V3D_SHADING_CAVITY;
copy_v3_fl(v3d->shading.single_color, 1.0f);
STRNCPY(v3d->shading.matcap, "basic_1");
}
}
}
}
}
}
}
}
static void blo_update_defaults_scene(Main *bmain, Scene *scene)
{
2023-05-09 12:50:37 +10:00
STRNCPY(scene->r.engine, RE_engine_id_BLENDER_EEVEE);
scene->r.cfra = 1.0f;
/* Don't enable compositing nodes. */
if (scene->nodetree) {
ntreeFreeEmbeddedTree(scene->nodetree);
MEM_freeN(scene->nodetree);
2022-11-19 11:51:42 +01:00
scene->nodetree = nullptr;
scene->use_nodes = false;
}
/* Rename render layers. */
BKE_view_layer_rename(
bmain, scene, static_cast<ViewLayer *>(scene->view_layers.first), "ViewLayer");
/* Disable Z pass by default. */
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
view_layer->passflag &= ~SCE_PASS_Z;
}
/* New EEVEE defaults. */
scene->eevee.bloom_intensity = 0.05f;
scene->eevee.bloom_clamp = 0.0f;
scene->eevee.motion_blur_shutter = 0.5f;
copy_v3_v3(scene->display.light_direction, blender::float3(M_SQRT1_3));
copy_v2_fl2(scene->safe_areas.title, 0.1f, 0.05f);
copy_v2_fl2(scene->safe_areas.action, 0.035f, 0.035f);
2020-07-15 13:11:22 +10:00
/* Change default cube-map quality. */
scene->eevee.gi_filter_quality = 3.0f;
/* Enable Soft Shadows by default. */
scene->eevee.flag |= SCE_EEVEE_SHADOW_SOFT;
2021-02-16 21:15:45 +11:00
/* Be sure `curfalloff` and primitive are initialized. */
ToolSettings *ts = scene->toolsettings;
2022-11-19 11:51:42 +01:00
if (ts->gp_sculpt.cur_falloff == nullptr) {
ts->gp_sculpt.cur_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
CurveMapping *gp_falloff_curve = ts->gp_sculpt.cur_falloff;
BKE_curvemapping_init(gp_falloff_curve);
BKE_curvemap_reset(gp_falloff_curve->cm,
&gp_falloff_curve->clipr,
CURVE_PRESET_GAUSS,
CURVEMAP_SLOPE_POSITIVE);
}
2022-11-19 11:51:42 +01:00
if (ts->gp_sculpt.cur_primitive == nullptr) {
ts->gp_sculpt.cur_primitive = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
CurveMapping *gp_primitive_curve = ts->gp_sculpt.cur_primitive;
BKE_curvemapping_init(gp_primitive_curve);
BKE_curvemap_reset(gp_primitive_curve->cm,
&gp_primitive_curve->clipr,
CURVE_PRESET_BELL,
CURVEMAP_SLOPE_POSITIVE);
}
if (ts->sculpt) {
ts->sculpt->flags = static_cast<const Sculpt *>(DNA_struct_default_get(Sculpt))->flags;
}
/* Correct default startup UVs. */
Mesh *me = static_cast<Mesh *>(BLI_findstring(&bmain->meshes, "Cube", offsetof(ID, name) + 2));
if (me && (me->totloop == 24) && CustomData_has_layer(&me->loop_data, CD_PROP_FLOAT2)) {
const float uv_values[24][2] = {
{0.625, 0.50}, {0.875, 0.50}, {0.875, 0.75}, {0.625, 0.75}, {0.375, 0.75}, {0.625, 0.75},
{0.625, 1.00}, {0.375, 1.00}, {0.375, 0.00}, {0.625, 0.00}, {0.625, 0.25}, {0.375, 0.25},
{0.125, 0.50}, {0.375, 0.50}, {0.375, 0.75}, {0.125, 0.75}, {0.375, 0.50}, {0.625, 0.50},
{0.625, 0.75}, {0.375, 0.75}, {0.375, 0.25}, {0.625, 0.25}, {0.625, 0.50}, {0.375, 0.50},
};
Mesh: Move UV layers to generic attributes Currently the `MLoopUV` struct stores UV coordinates and flags related to editing UV maps in the UV editor. This patch changes the coordinates to use the generic 2D vector type, and moves the flags into three separate boolean attributes. This follows the design in T95965, with the ultimate intention of simplifying code and improving performance. Importantly, the change allows exporters and renderers to use UVs "touched" by geometry nodes, which only creates generic attributes. It also allows geometry nodes to create "proper" UV maps from scratch, though only with the Store Named Attribute node for now. The new design considers any 2D vector attribute on the corner domain to be a UV map. In the future, they might be distinguished from regular 2D vectors with attribute metadata, which may be helpful because they are often interpolated differently. Most of the code changes deal with passing around UV BMesh custom data offsets and tracking the boolean "sublayers". The boolean layers are use the following prefixes for attribute names: vert selection: `.vs.`, edge selection: `.es.`, pinning: `.pn.`. Currently these are short to avoid using up the maximum length of attribute names. To accommodate for these 4 extra characters, the name length limit is enlarged to 68 bytes, while the maximum user settable name length is still 64 bytes. Unfortunately Python/RNA API access to the UV flag data becomes slower. Accessing the boolean layers directly is be better for performance in general. Like the other mesh SoA refactors, backward and forward compatibility aren't affected, and won't be changed until 4.0. We pay for that by making mesh reading and writing more expensive with conversions. Resolves T85962 Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
float(*mloopuv)[2] = static_cast<float(*)[2]>(
CustomData_get_layer_for_write(&me->loop_data, CD_PROP_FLOAT2, me->totloop));
Mesh: Move UV layers to generic attributes Currently the `MLoopUV` struct stores UV coordinates and flags related to editing UV maps in the UV editor. This patch changes the coordinates to use the generic 2D vector type, and moves the flags into three separate boolean attributes. This follows the design in T95965, with the ultimate intention of simplifying code and improving performance. Importantly, the change allows exporters and renderers to use UVs "touched" by geometry nodes, which only creates generic attributes. It also allows geometry nodes to create "proper" UV maps from scratch, though only with the Store Named Attribute node for now. The new design considers any 2D vector attribute on the corner domain to be a UV map. In the future, they might be distinguished from regular 2D vectors with attribute metadata, which may be helpful because they are often interpolated differently. Most of the code changes deal with passing around UV BMesh custom data offsets and tracking the boolean "sublayers". The boolean layers are use the following prefixes for attribute names: vert selection: `.vs.`, edge selection: `.es.`, pinning: `.pn.`. Currently these are short to avoid using up the maximum length of attribute names. To accommodate for these 4 extra characters, the name length limit is enlarged to 68 bytes, while the maximum user settable name length is still 64 bytes. Unfortunately Python/RNA API access to the UV flag data becomes slower. Accessing the boolean layers directly is be better for performance in general. Like the other mesh SoA refactors, backward and forward compatibility aren't affected, and won't be changed until 4.0. We pay for that by making mesh reading and writing more expensive with conversions. Resolves T85962 Differential Revision: https://developer.blender.org/D14365
2023-01-10 00:47:04 -05:00
memcpy(mloopuv, uv_values, sizeof(float[2]) * me->totloop);
}
/* Make sure that the curve profile is initialized */
2022-11-19 11:51:42 +01:00
if (ts->custom_bevel_profile_preset == nullptr) {
ts->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE);
}
/* Clear ID properties so Cycles gets defaults. */
IDProperty *idprop = IDP_GetProperties(&scene->id);
if (idprop) {
IDP_ClearProperty(idprop);
}
}
void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
{
/* For all app templates. */
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
BLO_update_defaults_workspace(workspace, app_template);
}
/* New grease pencil brushes and vertex paint setup. */
{
/* Update Grease Pencil brushes. */
Brush *brush;
/* Pencil brush. */
do_versions_rename_id(bmain, ID_BR, "Draw Pencil", "Pencil");
/* Pen brush. */
do_versions_rename_id(bmain, ID_BR, "Draw Pen", "Pen");
/* Pen Soft brush. */
brush = reinterpret_cast<Brush *>(
do_versions_rename_id(bmain, ID_BR, "Draw Soft", "Pencil Soft"));
if (brush) {
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_PEN;
}
/* Ink Pen brush. */
do_versions_rename_id(bmain, ID_BR, "Draw Ink", "Ink Pen");
/* Ink Pen Rough brush. */
do_versions_rename_id(bmain, ID_BR, "Draw Noise", "Ink Pen Rough");
/* Marker Bold brush. */
do_versions_rename_id(bmain, ID_BR, "Draw Marker", "Marker Bold");
/* Marker Chisel brush. */
do_versions_rename_id(bmain, ID_BR, "Draw Block", "Marker Chisel");
/* Remove useless Fill Area.001 brush. */
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, "Fill Area.001", offsetof(ID, name) + 2));
if (brush) {
BKE_id_delete(bmain, brush);
}
/* Rename and fix materials and enable default object lights on. */
if (app_template && STREQ(app_template, "2D_Animation")) {
2022-11-19 11:51:42 +01:00
Material *ma = nullptr;
do_versions_rename_id(bmain, ID_MA, "Black", "Solid Stroke");
do_versions_rename_id(bmain, ID_MA, "Red", "Squares Stroke");
do_versions_rename_id(bmain, ID_MA, "Grey", "Solid Fill");
do_versions_rename_id(bmain, ID_MA, "Black Dots", "Dots Stroke");
/* Dots Stroke. */
ma = static_cast<Material *>(
BLI_findstring(&bmain->materials, "Dots Stroke", offsetof(ID, name) + 2));
2022-11-19 11:51:42 +01:00
if (ma == nullptr) {
ma = BKE_gpencil_material_add(bmain, "Dots Stroke");
}
ma->gp_style->mode = GP_MATERIAL_MODE_DOT;
/* Squares Stroke. */
ma = static_cast<Material *>(
BLI_findstring(&bmain->materials, "Squares Stroke", offsetof(ID, name) + 2));
2022-11-19 11:51:42 +01:00
if (ma == nullptr) {
ma = BKE_gpencil_material_add(bmain, "Squares Stroke");
}
ma->gp_style->mode = GP_MATERIAL_MODE_SQUARE;
/* Change Solid Stroke settings. */
ma = static_cast<Material *>(
BLI_findstring(&bmain->materials, "Solid Stroke", offsetof(ID, name) + 2));
2022-11-19 11:51:42 +01:00
if (ma != nullptr) {
ma->gp_style->mix_rgba[3] = 1.0f;
ma->gp_style->texture_offset[0] = -0.5f;
ma->gp_style->mix_factor = 0.5f;
}
/* Change Solid Fill settings. */
ma = static_cast<Material *>(
BLI_findstring(&bmain->materials, "Solid Fill", offsetof(ID, name) + 2));
2022-11-19 11:51:42 +01:00
if (ma != nullptr) {
ma->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
ma->gp_style->mix_rgba[3] = 1.0f;
ma->gp_style->texture_offset[0] = -0.5f;
ma->gp_style->mix_factor = 0.5f;
}
Object *ob = static_cast<Object *>(
BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2));
if (ob && ob->type == OB_GPENCIL_LEGACY) {
ob->dtx |= OB_USE_GPENCIL_LIGHTS;
}
}
/* Reset all grease pencil brushes. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
ToolSettings *ts = scene->toolsettings;
if (ts->gp_paint) {
BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
if (ts->gp_sculptpaint) {
BKE_brush_gpencil_sculpt_presets(bmain, ts, true);
}
if (ts->gp_vertexpaint) {
BKE_brush_gpencil_vertex_presets(bmain, ts, true);
}
if (ts->gp_weightpaint) {
BKE_brush_gpencil_weight_presets(bmain, ts, true);
}
/* Ensure new Paint modes. */
BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_VERTEX_GPENCIL);
BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_SCULPT_GPENCIL);
BKE_paint_ensure_from_paintmode(scene, PAINT_MODE_WEIGHT_GPENCIL);
/* Enable cursor. */
if (ts->gp_paint) {
ts->gp_paint->paint.flags |= PAINT_SHOW_BRUSH;
}
/* Ensure Palette by default. */
if (ts->gp_paint) {
BKE_gpencil_palette_ensure(bmain, scene);
}
}
}
/* For builtin templates only. */
if (!blo_is_builtin_template(app_template)) {
return;
}
2023-01-16 13:57:10 +11:00
/* Work-spaces. */
LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
WorkSpaceLayout *layout = BKE_workspace_active_layout_for_workspace_get(
win->workspace_hook, workspace);
/* Name all screens by their workspaces (avoids 'Default.###' names). */
/* Default only has one window. */
if (layout->screen) {
bScreen *screen = layout->screen;
if (!STREQ(screen->id.name + 2, workspace->id.name + 2)) {
BKE_main_namemap_remove_name(bmain, &screen->id, screen->id.name + 2);
BLI_strncpy(screen->id.name + 2, workspace->id.name + 2, sizeof(screen->id.name) - 2);
BLI_libblock_ensure_unique_name(bmain, screen->id.name);
}
}
/* For some reason we have unused screens, needed until re-saving.
* Clear unused layouts because they're visible in the outliner & Python API. */
LISTBASE_FOREACH_MUTABLE (WorkSpaceLayout *, layout_iter, &workspace->layouts) {
if (layout != layout_iter) {
BKE_workspace_layout_remove(bmain, workspace, layout_iter);
}
}
}
}
}
/* Scenes */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
blo_update_defaults_scene(bmain, scene);
if (app_template &&
(STREQ(app_template, "Video_Editing") || STREQ(app_template, "2D_Animation"))) {
/* Filmic is too slow, use standard until it is optimized. */
STRNCPY(scene->view_settings.view_transform, "Standard");
STRNCPY(scene->view_settings.look, "None");
}
else {
/* Default to AgX view transform. */
STRNCPY(scene->view_settings.view_transform, "AgX");
}
if (app_template && STREQ(app_template, "Video_Editing")) {
/* Pass: no extra tweaks needed. Keep the view settings configured above, and rely on the
* default state of enabled AV sync. */
}
else {
/* AV Sync break physics sim caching, disable until that is fixed. */
scene->audio.flag &= ~AUDIO_SYNC;
scene->flag &= ~SCE_FRAME_DROP;
}
/* Change default selection mode for Grease Pencil. */
if (app_template && STREQ(app_template, "2D_Animation")) {
ToolSettings *ts = scene->toolsettings;
ts->gpencil_selectmode_edit = GP_SELECTMODE_STROKE;
}
2018-11-21 18:03:38 +01:00
}
/* Objects */
do_versions_rename_id(bmain, ID_OB, "Lamp", "Light");
do_versions_rename_id(bmain, ID_LA, "Lamp", "Light");
if (app_template && STREQ(app_template, "2D_Animation")) {
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
if (object->type == OB_GPENCIL_LEGACY) {
/* Set grease pencil object in drawing mode */
bGPdata *gpd = (bGPdata *)object->data;
object->mode = OB_MODE_PAINT_GPENCIL_LEGACY;
gpd->flag |= GP_DATA_STROKE_PAINTMODE;
break;
}
}
}
LISTBASE_FOREACH (Mesh *, mesh, &bmain->meshes) {
/* Match default for new meshes. */
Mesh: Replace auto smooth with node group Design task: #93551 This PR replaces the auto smooth option with a geometry nodes modifier that sets the sharp edge attribute. This solves a fair number of long- standing problems related to auto smooth, simplifies the process of normal computation, and allows Blender to automatically choose between face, vertex, and face corner normals based on the sharp edge and face attributes. Versioning adds a geometry node group to objects with meshes that had auto-smooth enabled. The modifier can be applied, which also improves performance. Auto smooth is now unnecessary to get a combination of sharp and smooth edges. In general workflows are changed a bit. Separate procedural and destructive workflows are available. Custom normals can be used immediately without turning on the removed auto smooth option. **Procedural** The node group asset "Smooth by Angle" is the main way to set sharp normals based on the edge angle. It can be accessed directly in the add modifier menu. Of course the modifier can be reordered, muted, or applied like any other, or changed internally like any geometry nodes modifier. **Destructive** Often the sharp edges don't need to be dynamic. This can give better performance since edge angles don't need to be recalculated. In edit mode the two operators "Select Sharp Edges" and "Mark Sharp" can be used. In other modes, the "Shade Smooth by Angle" controls the edge sharpness directly. ### Breaking API Changes - `use_auto_smooth` is removed. Face corner normals are now used automatically if there are mixed smooth vs. not smooth tags. Meshes now always use custom normals if they exist. - In Cycles, the lack of the separate auto smooth state makes normals look triangulated when all faces are shaded smooth. - `auto_smooth_angle` is removed. Replaced by a modifier (or operator) controlling the sharp edge attribute. This means the mesh itself (without an object) doesn't know anything about automatically smoothing by angle anymore. - `create_normals_split`, `calc_normals_split`, and `free_normals_split` are removed, and are replaced by the simpler `Mesh.corner_normals` collection property. Since it gives access to the normals cache, it is automatically updated when relevant data changes. Addons are updated here: https://projects.blender.org/blender/blender-addons/pulls/104609 ### Tests - `geo_node_curves_test_deform_curves_on_surface` has slightly different results because face corner normals are used instead of interpolated vertex normals. - `bf_wavefront_obj_tests` has different export results for one file which mixed sharp and smooth faces without turning on auto smooth. - `cycles_mesh_cpu` has one object which is completely flat shaded. Previously every edge was split before rendering, now it looks triangulated. Pull Request: https://projects.blender.org/blender/blender/pulls/108014
2023-10-20 16:54:08 +02:00
mesh->smoothresh_legacy = DEG2RADF(30);
/* Match voxel remesher options for all existing meshes in templates. */
2022-04-13 12:30:29 +02:00
mesh->flag |= ME_REMESH_REPROJECT_VOLUME | ME_REMESH_REPROJECT_PAINT_MASK |
ME_REMESH_REPROJECT_SCULPT_FACE_SETS | ME_REMESH_REPROJECT_VERTEX_COLORS;
/* For Sculpting template. */
if (app_template && STREQ(app_template, "Sculpting")) {
mesh->remesh_voxel_size = 0.035f;
BKE_mesh_smooth_flag_set(mesh, false);
}
else {
/* Remove sculpt-mask data in default mesh objects for all non-sculpt templates. */
CustomData_free_layers(&mesh->vert_data, CD_PAINT_MASK, mesh->totvert);
CustomData_free_layers(&mesh->loop_data, CD_GRID_PAINT_MASK, mesh->totloop);
}
mesh->attributes_for_write().remove(".sculpt_face_set");
}
LISTBASE_FOREACH (Camera *, camera, &bmain->cameras) {
/* Initialize to a useful value. */
camera->dof.focus_distance = 10.0f;
camera->dof.aperture_fstop = 2.8f;
}
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
/* Fix lights defaults. */
light->clipsta = 0.05f;
light->att_dist = 40.0f;
}
/* Materials */
LISTBASE_FOREACH (Material *, ma, &bmain->materials) {
/* Update default material to be a bit more rough. */
ma->roughness = 0.5f;
if (ma->nodetree) {
for (bNode *node : ma->nodetree->all_nodes()) {
if (node->type == SH_NODE_BSDF_PRINCIPLED) {
bNodeSocket *roughness_socket = nodeFindSocket(node, SOCK_IN, "Roughness");
*version_cycles_node_socket_float_value(roughness_socket) = 0.5f;
bNodeSocket *emission = nodeFindSocket(node, SOCK_IN, "Emission Color");
copy_v4_fl(version_cycles_node_socket_rgba_value(emission), 1.0f);
bNodeSocket *emission_strength = nodeFindSocket(node, SOCK_IN, "Emission Strength");
*version_cycles_node_socket_float_value(emission_strength) = 0.0f;
node->custom1 = SHD_GLOSSY_MULTI_GGX;
node->custom2 = SHD_SUBSURFACE_RANDOM_WALK;
Nodes: refactor node tree update handling Goals of this refactor: * More unified approach to updating everything that needs to be updated after a change in a node tree. * The updates should happen in the correct order and quadratic or worse algorithms should be avoided. * Improve detection of changes to the output to avoid tagging the depsgraph when it's not necessary. * Move towards a more declarative style of defining nodes by having a more centralized update procedure. The refactor consists of two main parts: * Node tree tagging and update refactor. * Generally, when changes are done to a node tree, it is tagged dirty until a global update function is called that updates everything in the correct order. * The tagging is more fine-grained compared to before, to allow for more precise depsgraph update tagging. * Depsgraph changes. * The shading specific depsgraph node for node trees as been removed. * Instead, there is a new `NTREE_OUTPUT` depsgrap node, which is only tagged when the output of the node tree changed (e.g. the Group Output or Material Output node). * The copy-on-write relation from node trees to the data block they are embedded in is now non-flushing. This avoids e.g. triggering a material update after the shader node tree changed in unrelated ways. Instead the material has a flushing relation to the new `NTREE_OUTPUT` node now. * The depsgraph no longer reports data block changes through to cycles through `Depsgraph.updates` when only the node tree changed in ways that do not affect the output. Avoiding unnecessary updates seems to work well for geometry nodes and cycles. The situation is a bit worse when there are drivers on the node tree, but that could potentially be improved separately in the future. Avoiding updates in eevee and the compositor is more tricky, but also less urgent. * Eevee updates are triggered by calling `DRW_notify_view_update` in `ED_render_view3d_update` indirectly from `DEG_editors_update`. * Compositor updates are triggered by `ED_node_composite_job` in `node_area_refresh`. This is triggered by calling `ED_area_tag_refresh` in `node_area_listener`. Removing updates always has the risk of breaking some dependency that no one was aware of. It's not unlikely that this will happen here as well. Adding back missing updates should be quite a bit easier than getting rid of unnecessary updates though. Differential Revision: https://developer.blender.org/D13246
2021-12-21 15:18:56 +01:00
BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
else if (node->type == SH_NODE_SUBSURFACE_SCATTERING) {
node->custom1 = SHD_SUBSURFACE_RANDOM_WALK;
Nodes: refactor node tree update handling Goals of this refactor: * More unified approach to updating everything that needs to be updated after a change in a node tree. * The updates should happen in the correct order and quadratic or worse algorithms should be avoided. * Improve detection of changes to the output to avoid tagging the depsgraph when it's not necessary. * Move towards a more declarative style of defining nodes by having a more centralized update procedure. The refactor consists of two main parts: * Node tree tagging and update refactor. * Generally, when changes are done to a node tree, it is tagged dirty until a global update function is called that updates everything in the correct order. * The tagging is more fine-grained compared to before, to allow for more precise depsgraph update tagging. * Depsgraph changes. * The shading specific depsgraph node for node trees as been removed. * Instead, there is a new `NTREE_OUTPUT` depsgrap node, which is only tagged when the output of the node tree changed (e.g. the Group Output or Material Output node). * The copy-on-write relation from node trees to the data block they are embedded in is now non-flushing. This avoids e.g. triggering a material update after the shader node tree changed in unrelated ways. Instead the material has a flushing relation to the new `NTREE_OUTPUT` node now. * The depsgraph no longer reports data block changes through to cycles through `Depsgraph.updates` when only the node tree changed in ways that do not affect the output. Avoiding unnecessary updates seems to work well for geometry nodes and cycles. The situation is a bit worse when there are drivers on the node tree, but that could potentially be improved separately in the future. Avoiding updates in eevee and the compositor is more tricky, but also less urgent. * Eevee updates are triggered by calling `DRW_notify_view_update` in `ED_render_view3d_update` indirectly from `DEG_editors_update`. * Compositor updates are triggered by `ED_node_composite_job` in `node_area_refresh`. This is triggered by calling `ED_area_tag_refresh` in `node_area_listener`. Removing updates always has the risk of breaking some dependency that no one was aware of. It's not unlikely that this will happen here as well. Adding back missing updates should be quite a bit easier than getting rid of unnecessary updates though. Differential Revision: https://developer.blender.org/D13246
2021-12-21 15:18:56 +01:00
BKE_ntree_update_tag_node_property(ma->nodetree, node);
}
}
}
}
/* Brushes */
{
/* Enable for UV sculpt (other brush types will be created as needed),
* without this the grab brush will be active but not selectable from the list. */
const char *brush_name = "Grab";
Brush *brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (brush) {
brush->ob_mode |= OB_MODE_EDIT;
}
}
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
brush->blur_kernel_radius = 2;
/* Use full strength for all non-sculpt brushes,
* when painting we want to use full color/weight always.
*
* Note that sculpt is an exception,
* its values are overwritten by #BKE_brush_sculpt_reset below. */
brush->alpha = 1.0;
/* Enable anti-aliasing by default. */
brush->sampling_flag |= BRUSH_PAINT_ANTIALIASING;
}
{
/* Change the spacing of the Smear brush to 3.0% */
const char *brush_name;
Brush *brush;
brush_name = "Smear";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (brush) {
brush->spacing = 3.0;
}
brush_name = "Draw Sharp";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_DRAW_SHARP;
}
brush_name = "Elastic Deform";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_ELASTIC_DEFORM;
}
brush_name = "Pose";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_POSE;
}
brush_name = "Multi-plane Scrape";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_MULTIPLANE_SCRAPE;
}
brush_name = "Clay Thumb";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_CLAY_THUMB;
}
brush_name = "Cloth";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_CLOTH;
}
brush_name = "Slide Relax";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_SLIDE_RELAX;
}
brush_name = "Paint";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_PAINT;
}
brush_name = "Smear";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_SMEAR;
}
Sculpt: Boundary Brush This brush includes a set of deformation modes designed to deform and control the shape of the mesh boundaries, which are really hard to do with regular sculpt brushes (and even in edit mode). This is useful for creating cloth assets and hard surface base meshes. The brush detects the mesh boundary closest to the active vertex and propagates the deformation using the brush falloff into the mesh. It includes bend, expand, inflate, grab and twist deform modes. The main use cases of this brush are the Bend and Expand deformation modes, which depend on a grid topology to create the best results. In order to do further adjustments and tweaks to the result of these deformation modes, the brush also includes the Inflate, Grab and Twist deformation modes, which do not depend that much on the topology. Grab and Inflate are the same operation that is implemented in the Grab and Inflate tools, they are also available in the boundary brush as producing deformations with regular brushes in these areas is very hard to control. Even if this brush can produce deformations in triangle meshes and meshes with a non-regular quad grid, the more regular and clean the topology is, the better. Most of the assets this brush is intended to deform are always created from a cylindrical or plane quad grid, so it should be fine. Also, its algorithms can be improved in future versions to handle more corner cases and topology patterns. Reviewed By: sergey Differential Revision: https://developer.blender.org/D8356
2020-08-10 17:57:01 +02:00
brush_name = "Boundary";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
Sculpt: Boundary Brush This brush includes a set of deformation modes designed to deform and control the shape of the mesh boundaries, which are really hard to do with regular sculpt brushes (and even in edit mode). This is useful for creating cloth assets and hard surface base meshes. The brush detects the mesh boundary closest to the active vertex and propagates the deformation using the brush falloff into the mesh. It includes bend, expand, inflate, grab and twist deform modes. The main use cases of this brush are the Bend and Expand deformation modes, which depend on a grid topology to create the best results. In order to do further adjustments and tweaks to the result of these deformation modes, the brush also includes the Inflate, Grab and Twist deformation modes, which do not depend that much on the topology. Grab and Inflate are the same operation that is implemented in the Grab and Inflate tools, they are also available in the boundary brush as producing deformations with regular brushes in these areas is very hard to control. Even if this brush can produce deformations in triangle meshes and meshes with a non-regular quad grid, the more regular and clean the topology is, the better. Most of the assets this brush is intended to deform are always created from a cylindrical or plane quad grid, so it should be fine. Also, its algorithms can be improved in future versions to handle more corner cases and topology patterns. Reviewed By: sergey Differential Revision: https://developer.blender.org/D8356
2020-08-10 17:57:01 +02:00
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_BOUNDARY;
}
brush_name = "Simplify";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_SIMPLIFY;
}
brush_name = "Draw Face Sets";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_DRAW_FACE_SETS;
}
brush_name = "Multires Displacement Eraser";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER;
}
brush_name = "Multires Displacement Smear";
brush = static_cast<Brush *>(
BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2));
if (!brush) {
brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT);
id_us_min(&brush->id);
brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_SMEAR;
}
2023-09-21 20:12:28 +10:00
}
2023-09-21 20:12:28 +10:00
{
/* Use the same tool icon color in the brush cursor */
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (brush->ob_mode & OB_MODE_SCULPT) {
BLI_assert(brush->sculpt_tool != 0);
BKE_brush_sculpt_reset(brush);
}
}
}
}