GPv3: Initial sculpt mode #119338
|
@ -176,7 +176,6 @@ def main() -> None:
|
|||
# Support version without a minor version "3" (add zero).
|
||||
tuple((0, 0, 0))
|
||||
)
|
||||
python_version_str = "%d.%d" % python_version_number[:2]
|
||||
|
||||
# Get Blender version.
|
||||
blender_version_str = str(make_utils.parse_blender_version())
|
||||
|
|
|
@ -9,4 +9,5 @@ requests==2.31.0
|
|||
|
||||
# Only needed to match the theme used for the official documentation.
|
||||
# Without this theme, the default theme will be used.
|
||||
sphinx_rtd_theme==1.3.0rc1
|
||||
furo==2024.1.29
|
||||
sphinx-basic-ng==1.0.0b2
|
||||
|
|
|
@ -1929,22 +1929,30 @@ def write_sphinx_conf_py(basepath):
|
|||
# The theme 'sphinx_rtd_theme' is no longer distributed with sphinx by default, only use when available.
|
||||
fw(r"""
|
||||
try:
|
||||
__import__('sphinx_rtd_theme')
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
import furo
|
||||
html_theme = "furo"
|
||||
del furo
|
||||
except ModuleNotFoundError:
|
||||
pass
|
||||
""")
|
||||
if html_theme == "furo":
|
||||
html_theme_options = {
|
||||
"light_css_variables": {
|
||||
"color-brand-primary": "#265787",
|
||||
"color-brand-content": "#265787",
|
||||
},
|
||||
}
|
||||
|
||||
fw("if html_theme == 'sphinx_rtd_theme':\n")
|
||||
fw(" html_theme_options = {\n")
|
||||
fw(" 'display_version': False,\n")
|
||||
# fw(" 'analytics_id': '',\n")
|
||||
# fw(" 'collapse_navigation': True,\n")
|
||||
fw(" 'sticky_navigation': False,\n")
|
||||
fw(" 'navigation_depth': 1,\n")
|
||||
fw(" 'includehidden': False,\n")
|
||||
# fw(" 'titles_only': False\n")
|
||||
fw(" }\n\n")
|
||||
html_sidebars = {
|
||||
"**": [
|
||||
"sidebar/brand.html",
|
||||
"sidebar/search.html",
|
||||
"sidebar/scroll-start.html",
|
||||
"sidebar/navigation.html",
|
||||
"sidebar/scroll-end.html",
|
||||
# "sidebar/variant-selector.html",
|
||||
]
|
||||
}
|
||||
""")
|
||||
|
||||
# not helpful since the source is generated, adds to upload size.
|
||||
fw("html_copy_source = False\n")
|
||||
|
@ -1961,7 +1969,7 @@ except ModuleNotFoundError:
|
|||
fw("html_logo = 'static/blender_logo.svg'\n")
|
||||
# Disable default `last_updated` value, since this is the date of doc generation, not the one of the source commit.
|
||||
fw("html_last_updated_fmt = None\n\n")
|
||||
fw("if html_theme == 'sphinx_rtd_theme':\n")
|
||||
fw("if html_theme == 'furo':\n")
|
||||
fw(" html_css_files = ['css/version_switch.css']\n")
|
||||
fw(" html_js_files = ['js/version_switch.js']\n")
|
||||
|
||||
|
|
|
@ -1,19 +1,323 @@
|
|||
/* Hide home icon in search area */
|
||||
.wy-side-nav-search > a:hover {background: none; opacity: 0.9}
|
||||
.wy-side-nav-search > a.icon::before {content: none}
|
||||
/*
|
||||
* This stylesheet is applied after the theme's default one,
|
||||
* and thus any overrides or additions can be added here.
|
||||
*
|
||||
* More info:
|
||||
* https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx.application.Sphinx.add_css_file
|
||||
*/
|
||||
|
||||
.wy-nav-content {
|
||||
max-width: 1000px !important;
|
||||
body {
|
||||
--sidebar-caption-font-size: var(--font-size--normal);
|
||||
--toc-title-font-size: var(--font-size--normal);
|
||||
--toc-font-size: var(--sidebar-item-font-size);
|
||||
--admonition-font-size: var(--font-size--normal);
|
||||
--admonition-title-font-size: var(--font-size--normal);
|
||||
--color-api-name: #e87d0d;
|
||||
}
|
||||
|
||||
/* Fix long titles on mobile */
|
||||
h1, h2, h3, h4, h5, h6 {word-break: break-all}
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
margin-top: 1.75rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Temp fix for https://github.com/readthedocs/sphinx_rtd_theme/pull/1109 */
|
||||
.hlist tr {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.hlist td {margin-right: auto}
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
.rubric {
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: 1.125em;
|
||||
}
|
||||
|
||||
/* Reduce the margins on top/bottom of horizontal lines. */
|
||||
hr.docutils {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
|
||||
/* Slightly decrease text to make the text fit on one line */
|
||||
.sidebar-brand-text {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.toctree-checkbox~label .icon svg {
|
||||
transition: transform 0.25s ease-out;
|
||||
}
|
||||
|
||||
/* Add more visual weight to definition terms */
|
||||
dl dt {
|
||||
font-weight: bold !important
|
||||
}
|
||||
|
||||
/* Fixes to field list, see #104636 */
|
||||
dl.field-list {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(80%, 95%);
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* TABLE & FIGURE */
|
||||
|
||||
/* Cell's vertical align. */
|
||||
/* use "valign" class for middle align */
|
||||
table.docutils:not(.valign) td {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Decrease whitespace above figure and add it below */
|
||||
figure {
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
figcaption {
|
||||
margin-bottom: 0.5rem !important;
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* End TABLE & FIGURE. */
|
||||
|
||||
/* Force admonition to span the full width if close to a figure */
|
||||
.admonition {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Use secondary font color for caption text */
|
||||
figcaption,
|
||||
caption {
|
||||
color: var(--color-foreground-secondary);
|
||||
font-size: var(--font-size--small)
|
||||
}
|
||||
|
||||
/* A bit hacky, revert the themes styling of kbd */
|
||||
kbd:not(.compound) {
|
||||
all: revert;
|
||||
}
|
||||
|
||||
/* Only style parent kbd elements instead of the individual children */
|
||||
:not(dl.option-list)> :not(kbd):not(kbd)>kbd,
|
||||
.menuselection {
|
||||
background-color: var(--color-background-secondary);
|
||||
border: 1px solid var(--color-foreground-border);
|
||||
border-radius: .2rem;
|
||||
box-shadow: 0 .0625rem 0 rgba(0, 0, 0, .2), inset 0 0 0 .125rem var(--color-background-secondary);
|
||||
color: var(--color-foreground-primary);
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 0 .2rem;
|
||||
}
|
||||
|
||||
.highlight .nc,
|
||||
.highlight .nn,
|
||||
.highlight .gu {
|
||||
text-decoration-line: none !important;
|
||||
}
|
||||
|
||||
.caption .menuselection {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Quotes for Fig. "link". */
|
||||
a[href^="#fig-"]::before {
|
||||
content: "\201c";
|
||||
}
|
||||
|
||||
a[href^="#fig-"]::after {
|
||||
content: "\201d";
|
||||
}
|
||||
|
||||
/* Mark external links. */
|
||||
a.external {
|
||||
filter: brightness(150%);
|
||||
}
|
||||
|
||||
/* List blender.org as internal. */
|
||||
.external[href^="https://www.blender.org"],
|
||||
.external[href^="https://docs.blender.org"],
|
||||
.external[href^="https://projects.blender.org"],
|
||||
.external[href^="https://builder.blender.org"],
|
||||
.external[href^="https://code.blender.org"],
|
||||
.external[href^="https://translate.blender.org"],
|
||||
.external[href^="https://fund.blender.org"],
|
||||
.external[href^="blender_manual_html.zip"],
|
||||
.external[href^="blender_manual_epub.zip"],
|
||||
.external[href^="https://archive.blender.org"] {
|
||||
filter: revert;
|
||||
}
|
||||
|
||||
/* ".. container::" lead, block text float around image. */
|
||||
.lead {
|
||||
clear: both;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Start reference admonition. */
|
||||
.admonition.refbox {
|
||||
border-color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
.admonition.refbox>.admonition-title {
|
||||
background-color: rgba(50, 50, 50, 0.2);
|
||||
border-color: rgb(50, 50, 50);
|
||||
}
|
||||
|
||||
.admonition.refbox>.admonition-title::before {
|
||||
background-color: var(--color-content-foreground);
|
||||
}
|
||||
|
||||
/* 'refbox' field. */
|
||||
.refbox .field-list .field-name,
|
||||
.refbox .field-list .field-body {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.refbox dl dt {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
/* End reference admonition. */
|
||||
|
||||
/* Applied on main index:sections. */
|
||||
|
||||
.global-index-toc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Start section cards. */
|
||||
.toc-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
grid-gap: 20px;
|
||||
list-style-type: none;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: .3em;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.card div.figure,
|
||||
.card figure {
|
||||
margin-bottom: 0px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card img {
|
||||
border-top-left-radius: .3em;
|
||||
border-top-right-radius: .3em;
|
||||
}
|
||||
|
||||
.card dl {
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
.card dl dt>a {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card dl dt a em,
|
||||
.card dl dt a span {
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.card dl dt {
|
||||
padding: 0px 15px 0px !important
|
||||
}
|
||||
|
||||
.card dl dd {
|
||||
padding: 0px 15px 5px 15px;
|
||||
font-style: normal;
|
||||
margin: 0px;
|
||||
color: var(--color-foreground-secondary);
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
#getting-started .card {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* End section cards. */
|
||||
|
||||
/* Start custom toctree. */
|
||||
/* Indent all lines following the first. */
|
||||
.toctree-wrapper * a {
|
||||
display: block;
|
||||
padding-top: 0.25em;
|
||||
}
|
||||
|
||||
.toctree-wrapper ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
/* Underline provided by nested ul (not li). */
|
||||
.toctree-wrapper * ul {
|
||||
margin-bottom: 1rem !important;
|
||||
border-top: solid var(--color-background-border) 1px;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
/* End custom toctree. */
|
||||
|
||||
/* Start footer contribute link */
|
||||
.footer-contribute {
|
||||
display: block;
|
||||
font-size: var(--font-size--small);
|
||||
}
|
||||
|
||||
.bottom-of-page {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.footer-contribute ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-bottom: 1rem
|
||||
}
|
||||
|
||||
.footer-contribute li {
|
||||
display: inline;
|
||||
list-style-type: none;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.footer-contribute {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* End footer contribute link */
|
|
@ -1,49 +1,35 @@
|
|||
/* Override RTD theme */
|
||||
.rst-versions {
|
||||
border-top: 0px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.version-btn.vdeact {
|
||||
cursor: default;
|
||||
color: dimgray;
|
||||
}
|
||||
|
||||
.version-btn.vdeact::after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
#versionwrap {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
padding-top: 2px;
|
||||
font-size: 90%;
|
||||
padding-left: 0;
|
||||
font-size: var(--sidebar-item-font-size);
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#versionwrap>ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
#versionwrap>li {
|
||||
display: flex;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.version-btn {
|
||||
display: inline-block;
|
||||
background-color: #272525;
|
||||
width: 140px;
|
||||
background-color: var(--color-sidebar-background);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 3px 10px;
|
||||
margin: 0px 5px 4px;
|
||||
vertical-align: middle;
|
||||
color: #27AE60;
|
||||
border: solid 1px #444444;
|
||||
color: var(--color-link);
|
||||
border: solid 1px var(--color-sidebar-background-border);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
z-index: 400;
|
||||
transition: border-color 0.4s;
|
||||
}
|
||||
|
||||
.version-btn::after {
|
||||
content: "\f0d8";
|
||||
display: inline;
|
||||
font: normal normal normal 16px/1 FontAwesome;
|
||||
color: #8d8c8c;
|
||||
vertical-align: top;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.version-btn-open::after {
|
||||
|
@ -57,7 +43,7 @@
|
|||
|
||||
.version-btn-open {
|
||||
color: gray;
|
||||
border: solid 1px gray;
|
||||
border: solid 1px var(--color-sidebar-background-border);
|
||||
}
|
||||
|
||||
.version-btn.wait {
|
||||
|
@ -73,32 +59,34 @@
|
|||
display: none;
|
||||
position: absolute;
|
||||
bottom: 28px;
|
||||
width: 140px;
|
||||
width: 50%;
|
||||
margin: 0 5px;
|
||||
padding-bottom: 4px;
|
||||
background-color: #0003;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 6px #000C;
|
||||
z-index: 999;
|
||||
max-height: calc(100vh - 30px);
|
||||
overflow-x: clip;
|
||||
overflow-y: auto;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.version-title {
|
||||
padding: 5px;
|
||||
color: black;
|
||||
color: var(--color-content-foreground);
|
||||
text-align: center;
|
||||
font-size: 102%;
|
||||
background-color: #27ae60;
|
||||
border-bottom: solid 1.5px #444;
|
||||
font-weight: 700;
|
||||
background-color: var(--color-brand-primary);
|
||||
border-bottom: solid 1.5px var(--color-sidebar-background-border);
|
||||
}
|
||||
|
||||
.version-list {
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 4px;
|
||||
text-align: center;
|
||||
background-color: #000C;
|
||||
border: solid 1px gray;
|
||||
border: solid 1px var(--color-sidebar-background-border);
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
}
|
||||
|
||||
|
@ -112,39 +100,21 @@
|
|||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 4px 0px;
|
||||
color: #404040;
|
||||
color: var(--color-sidebar-link-text);
|
||||
}
|
||||
|
||||
.version-list li {
|
||||
background-color: #ede9e9;
|
||||
color: #404040;
|
||||
background-color: var(--color-sidebar-background);
|
||||
color: var(--color-sidebar-link-text);
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.version-list li:hover,
|
||||
.version-list li a:focus {
|
||||
background-color: #b9cfda;
|
||||
background-color: var(--color-background-hover);
|
||||
}
|
||||
|
||||
.version-list li.selected,
|
||||
.version-list li.selected:hover {
|
||||
background-color: #8d8c8c;
|
||||
}
|
||||
|
||||
.version-list li.selected span {
|
||||
cursor: default;
|
||||
outline-color: red;
|
||||
}
|
||||
|
||||
.version-arrow {
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
left: 50%;
|
||||
bottom: 4px;
|
||||
margin-left: -4px;
|
||||
transform: rotate(225deg);
|
||||
background: #ede9e9;
|
||||
border: 1px solid gray;
|
||||
border-width: 1px 0 0 1px;
|
||||
.version-list li.selected {
|
||||
background: var(--color-sidebar-item-background--current);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{%- extends "!base.html" -%}
|
||||
|
||||
{%- block theme_scripts -%}
|
||||
{{ super() }}
|
||||
<script defer data-domain="docs.blender.org" src="https://analytics.blender.org/js/script.js"></script>
|
||||
{%- endblock -%}
|
|
@ -1,6 +1,3 @@
|
|||
{# For the "Report Issue" button on the bottom of pages. #}
|
||||
{%- extends "!footer.html" %}
|
||||
{%- block extrafooter %}
|
||||
{%- if not pagename in ("search", "404", "genindex") and hasdoc(pagename) %}
|
||||
<div class="footer-contribute">
|
||||
<ul>
|
||||
|
@ -13,10 +10,9 @@
|
|||
#}Permanent+Link%5D%28https%3A%2F%2Fdocs.blender.org%2F{#
|
||||
#}api%2F{{ version }}%2F{{ pagename }}{{ file_suffix }}%29%0D%0A%0D%0A%2A%2A{#
|
||||
#}Short+description+of+error%2A%2A%0D%0A%5B{#
|
||||
#}Please+fill+out+a+short+description+of+the+error+here%5D%0D%0A"
|
||||
class="fa fa-bug"> {{ _('Report issue on this page') }}</a>
|
||||
#}Please+fill+out+a+short+description+of+the+error+here%5D%0D%0A" class="fa fa-bug"> {{ _('Report issue
|
||||
on this page') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{%- endif %}
|
||||
{% endblock %}
|
||||
{%- endif %}
|
|
@ -0,0 +1,6 @@
|
|||
{%- extends "!page.html" -%}
|
||||
|
||||
{%- block footer -%}
|
||||
{{ super() }}
|
||||
{%- include "components/footer_contribute.html" -%}
|
||||
{%- endblock footer -%}
|
|
@ -6,7 +6,6 @@
|
|||
{{ release }}
|
||||
</span>
|
||||
<div class="version-dialog" aria-hidden="true">
|
||||
<div class="version-arrow" aria-hidden="true"></div>
|
||||
<div class="version-title">Versions</div>
|
||||
<ul id="version-vsnlist" class="version-list" role="menu" aria-labelledby="version-popover" aria-hidden="true">
|
||||
<li role="presentation">Loading...</li>
|
||||
|
@ -27,4 +26,4 @@
|
|||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
|
@ -119,7 +119,7 @@ BVHMetal::BVHMetal(const BVHParams ¶ms_,
|
|||
|
||||
BVHMetal::~BVHMetal()
|
||||
{
|
||||
/* Clear point used by enqueuing. */
|
||||
/* Clear point used by enqueueing. */
|
||||
device->release_bvh(this);
|
||||
|
||||
if (@available(macos 12.0, *)) {
|
||||
|
|
|
@ -341,7 +341,7 @@ string MetalDevice::preprocess_source(MetalPipelineType pso_type,
|
|||
}
|
||||
|
||||
# ifdef WITH_CYCLES_DEBUG
|
||||
global_defines += "#define __KERNEL_DEBUG__\n";
|
||||
global_defines += "#define WITH_CYCLES_DEBUG\n";
|
||||
# endif
|
||||
|
||||
switch (device_vendor) {
|
||||
|
|
|
@ -144,7 +144,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(__KERNEL_DEBUG__)
|
||||
#if defined(WITH_CYCLES_DEBUG)
|
||||
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
||||
isect->t = ray->tmax;
|
||||
isect->type = PRIMITIVE_NONE;
|
||||
|
@ -281,7 +281,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
|||
return false;
|
||||
}
|
||||
|
||||
# if defined(__KERNEL_DEBUG__)
|
||||
# if defined(WITH_CYCLES_DEBUG)
|
||||
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
||||
if (local_isect) {
|
||||
local_isect->num_hits = 0;
|
||||
|
@ -383,7 +383,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
|||
return false;
|
||||
}
|
||||
|
||||
# if defined(__KERNEL_DEBUG__)
|
||||
# if defined(WITH_CYCLES_DEBUG)
|
||||
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
||||
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
|
||||
return false;
|
||||
|
@ -446,7 +446,7 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
|||
return false;
|
||||
}
|
||||
|
||||
# if defined(__KERNEL_DEBUG__)
|
||||
# if defined(WITH_CYCLES_DEBUG)
|
||||
if (is_null_instance_acceleration_structure(metal_ancillaries->accel_struct)) {
|
||||
kernel_assert(!"Invalid metal_ancillaries->accel_struct pointer");
|
||||
return false;
|
||||
|
|
|
@ -212,7 +212,7 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
|
|||
/* BSDF */
|
||||
#ifdef WITH_CYCLES_DEBUG
|
||||
ccl_device_inline void surface_shader_validate_bsdf_sample(const KernelGlobals kg,
|
||||
const ShaderClosure *sc,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 wo,
|
||||
const int org_label,
|
||||
const float2 org_roughness,
|
||||
|
|
|
@ -319,14 +319,29 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
|
|||
is_extension = module_name.startswith(_ext_base_pkg_idname_with_dot)
|
||||
|
||||
if handle_error is None:
|
||||
def handle_error(_ex):
|
||||
def handle_error(ex):
|
||||
if isinstance(ex, ImportError):
|
||||
# NOTE: checking "Add-on " prefix is rather weak,
|
||||
# it's just a way to avoid the noise of a full trace-back when
|
||||
# an add-on is simply missing on the file-system.
|
||||
if (type(msg := ex.msg) is str) and msg.startswith("Add-on "):
|
||||
print(msg)
|
||||
return
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# reload if the mtime changes
|
||||
mod = sys.modules.get(module_name)
|
||||
# chances of the file _not_ existing are low, but it could be removed
|
||||
if mod and os.path.exists(mod.__file__):
|
||||
|
||||
# Set to `mod.__file__` or None.
|
||||
mod_file = None
|
||||
|
||||
if (
|
||||
(mod is not None) and
|
||||
(mod_file := mod.__file__) is not None and
|
||||
os.path.exists(mod_file)
|
||||
):
|
||||
|
||||
if getattr(mod, "__addon_enabled__", False):
|
||||
# This is an unlikely situation,
|
||||
|
@ -336,18 +351,15 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
|
|||
try:
|
||||
mod.unregister()
|
||||
except BaseException as ex:
|
||||
print(
|
||||
"Exception in module unregister():",
|
||||
repr(getattr(mod, "__file__", module_name)),
|
||||
)
|
||||
print("Exception in module unregister():", (mod_file or module_name))
|
||||
handle_error(ex)
|
||||
return None
|
||||
|
||||
mod.__addon_enabled__ = False
|
||||
mtime_orig = getattr(mod, "__time__", 0)
|
||||
mtime_new = os.path.getmtime(mod.__file__)
|
||||
mtime_new = os.path.getmtime(mod_file)
|
||||
if mtime_orig != mtime_new:
|
||||
print("module changed on disk:", repr(mod.__file__), "reloading...")
|
||||
print("module changed on disk:", repr(mod_file), "reloading...")
|
||||
|
||||
try:
|
||||
importlib.reload(mod)
|
||||
|
@ -374,11 +386,20 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
|
|||
# Use instead of `__import__` so that sub-modules can eventually be supported.
|
||||
# This is also documented to be the preferred way to import modules.
|
||||
mod = importlib.import_module(module_name)
|
||||
if mod.__file__ is None:
|
||||
# This can happen when the addon has been removed but there are
|
||||
# residual `.pyc` files left behind.
|
||||
raise ImportError(name=module_name)
|
||||
mod.__time__ = os.path.getmtime(mod.__file__)
|
||||
if (mod_file := mod.__file__) is None:
|
||||
# This can happen when:
|
||||
# - The add-on has been removed but there are residual `.pyc` files left behind.
|
||||
# - An extension is a directory that doesn't contain an `__init__.py` file.
|
||||
#
|
||||
# Include a message otherwise the "cause:" for failing to load the module is left blank.
|
||||
# Include the `__path__` when available so there is a reference to the location that failed to load.
|
||||
raise ImportError(
|
||||
"module loaded with no associated file, __path__=%r, aborting!" % (
|
||||
getattr(mod, "__path__", None)
|
||||
),
|
||||
name=module_name
|
||||
)
|
||||
mod.__time__ = os.path.getmtime(mod_file)
|
||||
mod.__addon_enabled__ = False
|
||||
except BaseException as ex:
|
||||
# If the add-on doesn't exist, don't print full trace-back because the back-trace is in this case
|
||||
|
@ -386,7 +407,7 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
|
|||
# Account for `ImportError` & `ModuleNotFoundError`.
|
||||
if isinstance(ex, ImportError):
|
||||
if ex.name == module_name:
|
||||
print("Add-on not loaded: \"%s\", cause: %s" % (module_name, str(ex)))
|
||||
ex.msg = "Add-on not loaded: \"%s\", cause: %s" % (module_name, str(ex))
|
||||
|
||||
# Issue with an add-on from an extension repository, report a useful message.
|
||||
elif is_extension and module_name.startswith(ex.name + "."):
|
||||
|
@ -396,22 +417,20 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
|
|||
None,
|
||||
)
|
||||
if repo is None:
|
||||
print(
|
||||
ex.msg = (
|
||||
"Add-on not loaded: \"%s\", cause: extension repository \"%s\" doesn't exist" %
|
||||
(module_name, repo_id)
|
||||
)
|
||||
elif not repo.enabled:
|
||||
print(
|
||||
ex.msg = (
|
||||
"Add-on not loaded: \"%s\", cause: extension repository \"%s\" is disabled" %
|
||||
(module_name, repo_id)
|
||||
)
|
||||
else:
|
||||
# The repository exists and is enabled, it should have imported.
|
||||
print("Add-on not loaded: \"%s\", cause: %s" % (module_name, str(ex)))
|
||||
else:
|
||||
handle_error(ex)
|
||||
else:
|
||||
handle_error(ex)
|
||||
ex.msg = "Add-on not loaded: \"%s\", cause: %s" % (module_name, str(ex))
|
||||
|
||||
handle_error(ex)
|
||||
|
||||
if default_set:
|
||||
_addon_remove(module_name)
|
||||
|
@ -446,10 +465,7 @@ def enable(module_name, *, default_set=False, persistent=False, handle_error=Non
|
|||
try:
|
||||
mod.register()
|
||||
except BaseException as ex:
|
||||
print(
|
||||
"Exception in module register():",
|
||||
getattr(mod, "__file__", module_name),
|
||||
)
|
||||
print("Exception in module register():", (mod_file or module_name))
|
||||
handle_error(ex)
|
||||
del sys.modules[module_name]
|
||||
if default_set:
|
||||
|
|
|
@ -181,7 +181,7 @@ def write_sysinfo(filepath):
|
|||
output.write("SDL: Blender was built without SDL support\n")
|
||||
|
||||
if bpy.app.background:
|
||||
output.write("\nOpenGL: missing, background mode\n")
|
||||
output.write("\nGPU: missing, background mode\n")
|
||||
else:
|
||||
output.write(title("GPU"))
|
||||
output.write("renderer:\t%r\n" % gpu.platform.renderer_get())
|
||||
|
|
|
@ -443,9 +443,13 @@ class PREFERENCES_OT_addon_enable(Operator):
|
|||
|
||||
def err_cb(ex):
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# The full trace-back in the UI is unwieldy and associated with unhandled exceptions.
|
||||
# Only show a single exception instead of the full trace-back,
|
||||
# developers can debug using information printed in the console.
|
||||
nonlocal err_str
|
||||
err_str = traceback.format_exc()
|
||||
print(err_str)
|
||||
err_str = str(ex)
|
||||
|
||||
mod = addon_utils.enable(self.module, default_set=True, handle_error=err_cb)
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ class DATA_PT_EEVEE_light(DataButtonsPanel, Panel):
|
|||
col.prop(light, "use_shadow", text="Cast Shadow")
|
||||
col.prop(light, "shadow_softness_factor", text="Shadow Softness")
|
||||
col.prop(light, "shadow_filter_radius", text="Filtering Radius")
|
||||
col.prop(light, "shadow_resolution_scale", text="Resolution Scale")
|
||||
|
||||
if light.type == 'SUN':
|
||||
col.prop(light, "shadow_trace_distance", text="Trace Distance")
|
||||
|
|
|
@ -155,6 +155,7 @@ class OBJECT_MT_modifier_add_generate(ModifierAddMenu, Menu):
|
|||
self.operator_modifier_add(layout, 'WIREFRAME')
|
||||
if ob_type == 'GREASEPENCIL':
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_ARRAY')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_BUILD')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_DASH')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_ENVELOPE')
|
||||
self.operator_modifier_add(layout, 'GREASE_PENCIL_LENGTH')
|
||||
|
|
|
@ -727,6 +727,9 @@ class RENDER_PT_eevee_next_shadows(RenderButtonsPanel, Panel):
|
|||
col = layout.column()
|
||||
col.prop(props, "shadow_normal_bias", text="Normal Bias")
|
||||
|
||||
col = layout.column()
|
||||
col.prop(props, "use_shadow_jittered_viewport", text="Jittered Transparency (Viewport)")
|
||||
|
||||
|
||||
class RENDER_PT_eevee_sampling(RenderButtonsPanel, Panel):
|
||||
bl_label = "Sampling"
|
||||
|
|
|
@ -2251,8 +2251,11 @@ class USERPREF_PT_addons(AddOnPanel, Panel):
|
|||
|
||||
prefs = context.preferences
|
||||
|
||||
use_extension_repos = prefs.experimental.use_extension_repos
|
||||
if use_extension_repos and self.is_extended():
|
||||
if (
|
||||
prefs.view.show_developer_ui and
|
||||
prefs.experimental.use_extension_repos and
|
||||
self.is_extended()
|
||||
):
|
||||
# Rely on the draw function being appended to by the extensions add-on.
|
||||
return
|
||||
|
||||
|
|
|
@ -2739,7 +2739,7 @@ class VIEW3D_MT_image_add(Menu):
|
|||
|
||||
def draw(self, _context):
|
||||
layout = self.layout
|
||||
# Expliclitly set background mode on/off as operator will try to
|
||||
# Explicitly set background mode on/off as operator will try to
|
||||
# auto detect which mode to use otherwise.
|
||||
layout.operator("object.empty_image_add", text="Reference", icon='IMAGE_REFERENCE').background = False
|
||||
layout.operator("object.empty_image_add", text="Background", icon='IMAGE_BACKGROUND').background = True
|
||||
|
|
|
@ -29,7 +29,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 10
|
||||
#define BLENDER_FILE_SUBVERSION 11
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
|
|
@ -110,6 +110,7 @@ enum eCbEvent {
|
|||
BKE_CB_EVT_EXTENSION_REPOS_UPDATE_POST,
|
||||
BKE_CB_EVT_EXTENSION_REPOS_SYNC,
|
||||
BKE_CB_EVT_EXTENSION_REPOS_UPGRADE,
|
||||
BKE_CB_EVT_EXTENSION_REPOS_FILES_CLEAR,
|
||||
BKE_CB_EVT_TOT,
|
||||
};
|
||||
|
||||
|
|
|
@ -86,11 +86,11 @@ char BKE_imtype_valid_depths(char imtype);
|
|||
|
||||
/**
|
||||
* String is from command line `--render-format` argument,
|
||||
* keep in sync with `creator_args.c` help info.
|
||||
* keep in sync with `creator_args.cc` help info.
|
||||
*/
|
||||
char BKE_imtype_from_arg(const char *imtype_arg);
|
||||
|
||||
/* Conversion between ImBuf settings. */
|
||||
/* Conversion between #ImBuf settings. */
|
||||
|
||||
void BKE_image_format_from_imbuf(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
|
||||
void BKE_image_format_to_imbuf(struct ImBuf *ibuf, const struct ImageFormatData *imf);
|
||||
|
|
|
@ -112,7 +112,7 @@ void BKE_scene_object_base_flag_sync_from_base(Base *base);
|
|||
*/
|
||||
void BKE_scene_set_background(Main *bmain, Scene *sce);
|
||||
/**
|
||||
* Called from `creator_args.c`.
|
||||
* Called from `creator_args.cc`.
|
||||
*/
|
||||
Scene *BKE_scene_set_name(Main *bmain, const char *name);
|
||||
|
||||
|
|
|
@ -1737,6 +1737,97 @@ static void legacy_object_modifier_weight_lineart(Object &object, GpencilModifie
|
|||
greasepencil::convert::lineart_wrap_v3(&legacy_md_lineart, &md_lineart);
|
||||
}
|
||||
|
||||
static void legacy_object_modifier_build(Object &object, GpencilModifierData &legacy_md)
|
||||
{
|
||||
ModifierData &md = legacy_object_modifier_common(
|
||||
object, eModifierType_GreasePencilBuild, legacy_md);
|
||||
auto &md_build = reinterpret_cast<GreasePencilBuildModifierData &>(md);
|
||||
auto &legacy_md_build = reinterpret_cast<BuildGpencilModifierData &>(legacy_md);
|
||||
|
||||
md_build.flag = 0;
|
||||
if (legacy_md_build.flag & GP_BUILD_RESTRICT_TIME) {
|
||||
md_build.flag |= MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME;
|
||||
}
|
||||
if (legacy_md_build.flag & GP_BUILD_USE_FADING) {
|
||||
md_build.flag |= MOD_GREASE_PENCIL_BUILD_USE_FADING;
|
||||
}
|
||||
|
||||
switch (legacy_md_build.mode) {
|
||||
case GP_BUILD_MODE_ADDITIVE:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE;
|
||||
break;
|
||||
case GP_BUILD_MODE_CONCURRENT:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT;
|
||||
break;
|
||||
case GP_BUILD_MODE_SEQUENTIAL:
|
||||
default:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (legacy_md_build.time_alignment) {
|
||||
default:
|
||||
case GP_BUILD_TIMEALIGN_START:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START;
|
||||
break;
|
||||
case GP_BUILD_TIMEALIGN_END:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (legacy_md_build.time_mode) {
|
||||
default:
|
||||
case GP_BUILD_TIMEMODE_FRAMES:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES;
|
||||
break;
|
||||
case GP_BUILD_TIMEMODE_PERCENTAGE:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE;
|
||||
break;
|
||||
case GP_BUILD_TIMEMODE_DRAWSPEED:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (legacy_md_build.transition) {
|
||||
default:
|
||||
case GP_BUILD_TRANSITION_GROW:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW;
|
||||
break;
|
||||
case GP_BUILD_TRANSITION_SHRINK:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK;
|
||||
break;
|
||||
case GP_BUILD_TRANSITION_VANISH:
|
||||
md_build.mode = MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||
break;
|
||||
}
|
||||
|
||||
md_build.start_frame = legacy_md_build.start_frame;
|
||||
md_build.end_frame = legacy_md_build.end_frame;
|
||||
md_build.start_delay = legacy_md_build.start_delay;
|
||||
md_build.length = legacy_md_build.length;
|
||||
md_build.fade_fac = legacy_md_build.fade_fac;
|
||||
md_build.fade_opacity_strength = legacy_md_build.fade_opacity_strength;
|
||||
md_build.fade_thickness_strength = legacy_md_build.fade_thickness_strength;
|
||||
md_build.percentage_fac = legacy_md_build.percentage_fac;
|
||||
md_build.speed_fac = legacy_md_build.speed_fac;
|
||||
md_build.speed_maxgap = legacy_md_build.speed_maxgap;
|
||||
STRNCPY(md_build.target_vgname, legacy_md_build.target_vgname);
|
||||
|
||||
legacy_object_modifier_influence(md_build.influence,
|
||||
legacy_md_build.layername,
|
||||
legacy_md_build.layer_pass,
|
||||
legacy_md_build.flag & GP_WEIGHT_INVERT_LAYER,
|
||||
legacy_md_build.flag & GP_WEIGHT_INVERT_LAYERPASS,
|
||||
&legacy_md_build.material,
|
||||
legacy_md_build.pass_index,
|
||||
legacy_md_build.flag & GP_WEIGHT_INVERT_MATERIAL,
|
||||
legacy_md_build.flag & GP_WEIGHT_INVERT_PASS,
|
||||
legacy_md_build.target_vgname,
|
||||
legacy_md_build.flag & GP_WEIGHT_INVERT_VGROUP,
|
||||
nullptr,
|
||||
false);
|
||||
}
|
||||
|
||||
static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
||||
{
|
||||
BLI_assert(BLI_listbase_is_empty(&object.modifiers));
|
||||
|
@ -1818,6 +1909,8 @@ static void legacy_object_modifiers(Main & /*bmain*/, Object &object)
|
|||
legacy_object_modifier_weight_lineart(object, *gpd_md);
|
||||
break;
|
||||
case eGpencilModifierType_Build:
|
||||
legacy_object_modifier_build(object, *gpd_md);
|
||||
break;
|
||||
case eGpencilModifierType_Simplify:
|
||||
case eGpencilModifierType_Texture:
|
||||
break;
|
||||
|
|
|
@ -298,7 +298,7 @@ void BKE_lattice_resize(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
|
|||
calc_lat_fudu(lt->flag, wNew, &fw, &dw);
|
||||
|
||||
/* If old size is different than resolution changed in interface,
|
||||
* try to do clever reinit of points. Pretty simply idea, we just
|
||||
* try to do clever reinitialize of points. Pretty simply idea, we just
|
||||
* deform new verts by old lattice, but scaling them to match old
|
||||
* size first.
|
||||
*/
|
||||
|
|
|
@ -2127,11 +2127,10 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
|
|||
}
|
||||
group->geometry_node_asset_traits->flag |= GEO_NODE_ASSET_MODIFIER;
|
||||
|
||||
group->tree_interface.add_socket(DATA_("Geometry"),
|
||||
"",
|
||||
"NodeSocketGeometry",
|
||||
NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT,
|
||||
nullptr);
|
||||
group->tree_interface.add_socket(
|
||||
DATA_("Geometry"), "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
|
||||
group->tree_interface.add_socket(
|
||||
DATA_("Geometry"), "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_INPUT, nullptr);
|
||||
bNodeTreeInterfaceSocket *angle_io_socket = group->tree_interface.add_socket(
|
||||
DATA_("Angle"), "", "NodeSocketFloat", NODE_INTERFACE_SOCKET_INPUT, nullptr);
|
||||
auto &angle_data = *static_cast<bNodeSocketValueFloat *>(angle_io_socket->socket_data);
|
||||
|
@ -2146,7 +2145,7 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
|
|||
group_input_angle->locx = -420.0f;
|
||||
group_input_angle->locy = -300.0f;
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_angle->outputs) {
|
||||
if (!STREQ(socket->identifier, "Socket_1")) {
|
||||
if (!STREQ(socket->identifier, "Socket_2")) {
|
||||
socket->flag |= SOCK_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
@ -2154,7 +2153,7 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
|
|||
group_input_mesh->locx = -60.0f;
|
||||
group_input_mesh->locy = -100.0f;
|
||||
LISTBASE_FOREACH (bNodeSocket *, socket, &group_input_mesh->outputs) {
|
||||
if (!STREQ(socket->identifier, "Socket_0")) {
|
||||
if (!STREQ(socket->identifier, "Socket_1")) {
|
||||
socket->flag |= SOCK_HIDDEN;
|
||||
}
|
||||
}
|
||||
|
@ -2197,7 +2196,7 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
|
|||
nodeFindSocket(group_output, SOCK_IN, "Socket_0"));
|
||||
nodeAddLink(group,
|
||||
group_input_angle,
|
||||
nodeFindSocket(group_input_angle, SOCK_OUT, "Socket_1"),
|
||||
nodeFindSocket(group_input_angle, SOCK_OUT, "Socket_2"),
|
||||
less_than_or_equal,
|
||||
nodeFindSocket(less_than_or_equal, SOCK_IN, "B"));
|
||||
nodeAddLink(group,
|
||||
|
@ -2212,7 +2211,7 @@ static bNodeTree *add_auto_smooth_node_tree(Main &bmain)
|
|||
nodeFindSocket(boolean_and, SOCK_IN, "Boolean_001"));
|
||||
nodeAddLink(group,
|
||||
group_input_mesh,
|
||||
nodeFindSocket(group_input_mesh, SOCK_OUT, "Socket_0"),
|
||||
nodeFindSocket(group_input_mesh, SOCK_OUT, "Socket_1"),
|
||||
shade_smooth_edge,
|
||||
nodeFindSocket(shade_smooth_edge, SOCK_IN, "Geometry"));
|
||||
nodeAddLink(group,
|
||||
|
@ -2336,14 +2335,14 @@ static ModifierData *create_auto_smooth_modifier(
|
|||
id_us_plus(&md->node_group->id);
|
||||
|
||||
md->settings.properties = idprop::create_group("Nodes Modifier Settings").release();
|
||||
IDProperty *angle_prop = idprop::create("Socket_1", angle).release();
|
||||
IDProperty *angle_prop = idprop::create("Socket_2", angle).release();
|
||||
auto *ui_data = reinterpret_cast<IDPropertyUIDataFloat *>(IDP_ui_data_ensure(angle_prop));
|
||||
ui_data->base.rna_subtype = PROP_ANGLE;
|
||||
ui_data->soft_min = 0.0f;
|
||||
ui_data->soft_max = DEG2RADF(180.0f);
|
||||
IDP_AddToGroup(md->settings.properties, angle_prop);
|
||||
IDP_AddToGroup(md->settings.properties, idprop::create("Socket_1_use_attribute", 0).release());
|
||||
IDP_AddToGroup(md->settings.properties, idprop::create("Socket_1_attribute_name", "").release());
|
||||
IDP_AddToGroup(md->settings.properties, idprop::create("Socket_2_use_attribute", 0).release());
|
||||
IDP_AddToGroup(md->settings.properties, idprop::create("Socket_2_attribute_name", "").release());
|
||||
|
||||
BKE_modifiers_persistent_uid_init(object, md->modifier);
|
||||
return &md->modifier;
|
||||
|
|
|
@ -1190,6 +1190,10 @@ bNodeTreeInterfaceSocket *bNodeTreeInterface::add_socket(const blender::StringRe
|
|||
const NodeTreeInterfaceSocketFlag flag,
|
||||
bNodeTreeInterfacePanel *parent)
|
||||
{
|
||||
/* Check that each interface socket is either an input or an output. Technically, it can be both
|
||||
* at the same time, but we don't want that for the time being. */
|
||||
BLI_assert(((NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT) & flag) !=
|
||||
(NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT));
|
||||
if (parent == nullptr) {
|
||||
parent = &root_panel;
|
||||
}
|
||||
|
|
|
@ -92,8 +92,19 @@ int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
|
|||
*/
|
||||
int BLI_rename_overwrite(const char *from, const char *to) ATTR_NONNULL();
|
||||
/**
|
||||
* Deletes the specified file or directory (depending on dir), optionally
|
||||
* doing recursive delete of directory contents.
|
||||
* Deletes the specified file or directory.
|
||||
*
|
||||
* \param dir: Delete an empty directory instead of a file.
|
||||
* The value is ignored when `recursive` is true but should true to make the intention clear.
|
||||
* If the directory is not empty, delete fails.
|
||||
* \param recursive: Recursively delete files including `path` which may be a directory of a file.
|
||||
*
|
||||
* \note Symbolic-Links for (UNIX) behave as follows:
|
||||
* - Never followed, treated as regular files.
|
||||
* - Links are removed, not the files/directories they references.
|
||||
* - When `path` itself links to another directory,
|
||||
* deleting `path` behaves as if a regular file is being deleted.
|
||||
* - If `dir` is true and `path` is a link, delete fails.
|
||||
*
|
||||
* \return zero on success (matching 'remove' behavior).
|
||||
*/
|
||||
|
|
|
@ -250,7 +250,7 @@ template<typename Function> inline void isolate_task(const Function &function)
|
|||
|
||||
/**
|
||||
* Should surround parallel code that is highly bandwidth intensive, e.g. it just fills a buffer
|
||||
* with no or just few additional operations. If the buffers are large, it's benefitial to limit
|
||||
* with no or just few additional operations. If the buffers are large, it's beneficial to limit
|
||||
* the number of threads doing the work because that just creates more overhead on the hardware
|
||||
* level and doesn't provide a notable performance benefit beyond a certain point.
|
||||
*/
|
||||
|
@ -261,7 +261,7 @@ inline void memory_bandwidth_bound_task(const int64_t approximate_bytes_touched,
|
|||
/* Don't limit threading when all touched memory can stay in the CPU cache, because there a much
|
||||
* higher memory bandwidth is available compared to accessing RAM. This value is supposed to be
|
||||
* on the order of the L3 cache size. Accessing that value is not quite straight forward and even
|
||||
* if it was, it's not clear if using the exact cache size would be benefitial because there is
|
||||
* if it was, it's not clear if using the exact cache size would be beneficial because there is
|
||||
* often more stuff going on on the CPU at the same time. */
|
||||
if (approximate_bytes_touched <= 8 * 1024 * 1024) {
|
||||
function();
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utils.hh"
|
||||
#include "BLI_sys_types.h" /* for intptr_t support */
|
||||
#include "BLI_sys_types.h" /* For `intptr_t` support. */
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
/** Sizes above this must be allocated. */
|
||||
|
@ -292,19 +292,19 @@ bool BLI_file_is_writable(const char *filepath)
|
|||
{
|
||||
bool writable;
|
||||
if (BLI_access(filepath, W_OK) == 0) {
|
||||
/* file exists and I can write to it */
|
||||
/* File exists and I can write to it. */
|
||||
writable = true;
|
||||
}
|
||||
else if (errno != ENOENT) {
|
||||
/* most likely file or containing directory cannot be accessed */
|
||||
/* Most likely file or containing directory cannot be accessed. */
|
||||
writable = false;
|
||||
}
|
||||
else {
|
||||
/* file doesn't exist -- check I can create it in parent directory */
|
||||
/* File doesn't exist -- check I can create it in parent directory. */
|
||||
char parent[FILE_MAX];
|
||||
BLI_path_split_dir_part(filepath, parent, sizeof(parent));
|
||||
#ifdef WIN32
|
||||
/* windows does not have X_OK */
|
||||
/* Windows does not have X_OK. */
|
||||
writable = BLI_access(parent, W_OK) == 0;
|
||||
#else
|
||||
writable = BLI_access(parent, X_OK | W_OK) == 0;
|
||||
|
@ -321,7 +321,7 @@ bool BLI_file_touch(const char *filepath)
|
|||
int c = getc(f);
|
||||
|
||||
if (c == EOF) {
|
||||
/* Empty file, reopen in truncate write mode... */
|
||||
/* Empty file, reopen in truncate write mode. */
|
||||
fclose(f);
|
||||
f = BLI_fopen(filepath, "w+b");
|
||||
}
|
||||
|
@ -734,6 +734,9 @@ int BLI_delete(const char *path, bool dir, bool recursive)
|
|||
|
||||
BLI_assert(!BLI_path_is_rel(path));
|
||||
|
||||
/* Not an error but avoid ambiguous arguments (recursive file deletion isn't meaningful). */
|
||||
BLI_assert(!(dir == false && recursive == true));
|
||||
|
||||
if (recursive) {
|
||||
err = delete_recursive(path);
|
||||
}
|
||||
|
@ -1089,6 +1092,9 @@ static int recursive_operation_impl(StrBuf *src_buf,
|
|||
* prefixing it with path_dst, recursively scanning subdirectories, and invoking the specified
|
||||
* callbacks for files and subdirectories found as appropriate.
|
||||
*
|
||||
* \note Symbolic links are *not* followed, even when `path_src` links to a directory,
|
||||
* it wont be recursed down. Support for this could be added.
|
||||
*
|
||||
* \param path_src: Top-level source path.
|
||||
* \param path_dst: Top-level destination path.
|
||||
* \param callback_dir_pre: Optional, to be invoked before entering a subdirectory,
|
||||
|
@ -1222,7 +1228,7 @@ static int delete_soft(const char *file, const char **error_message)
|
|||
int pid = fork();
|
||||
|
||||
if (pid != 0) {
|
||||
/* Parent process */
|
||||
/* Parent process. */
|
||||
int wstatus = 0;
|
||||
|
||||
waitpid(pid, &wstatus, 0);
|
||||
|
@ -1243,7 +1249,7 @@ static int delete_soft(const char *file, const char **error_message)
|
|||
execvp(args[0], (char **)args);
|
||||
|
||||
*error_message = "Forking process failed.";
|
||||
return -1; /* This should only be reached if execvp fails and stack isn't replaced. */
|
||||
return -1; /* This should only be reached if `execvp` fails and stack isn't replaced. */
|
||||
}
|
||||
# endif
|
||||
|
||||
|
@ -1278,6 +1284,8 @@ int BLI_access(const char *filepath, int mode)
|
|||
int BLI_delete(const char *path, bool dir, bool recursive)
|
||||
{
|
||||
BLI_assert(!BLI_path_is_rel(path));
|
||||
/* Not an error but avoid ambiguous arguments (recursive file deletion isn't meaningful). */
|
||||
BLI_assert(!(dir == false && recursive == true));
|
||||
|
||||
if (recursive) {
|
||||
return recursive_operation(path, nullptr, nullptr, delete_single_file, delete_callback_post);
|
||||
|
@ -1347,13 +1355,13 @@ static int copy_callback_pre(const char *from, const char *to)
|
|||
return RecursiveOp_Callback_Error;
|
||||
}
|
||||
|
||||
/* create a directory */
|
||||
/* Create a directory. */
|
||||
if (mkdir(to, st.st_mode)) {
|
||||
perror("mkdir");
|
||||
return RecursiveOp_Callback_Error;
|
||||
}
|
||||
|
||||
/* set proper owner and group on new directory */
|
||||
/* Set proper owner and group on new directory. */
|
||||
if (chown(to, st.st_uid, st.st_gid)) {
|
||||
perror("chown");
|
||||
return RecursiveOp_Callback_Error;
|
||||
|
@ -1380,12 +1388,12 @@ static int copy_single_file(const char *from, const char *to)
|
|||
}
|
||||
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
/* symbolic links should be copied in special way */
|
||||
/* Symbolic links should be copied in special way. */
|
||||
char *link_buffer;
|
||||
int need_free;
|
||||
int64_t link_len;
|
||||
|
||||
/* get large enough buffer to read link content */
|
||||
/* Get large enough buffer to read link content. */
|
||||
if ((st.st_size + 1) < sizeof(buf)) {
|
||||
link_buffer = buf;
|
||||
need_free = 0;
|
||||
|
@ -1423,7 +1431,7 @@ static int copy_single_file(const char *from, const char *to)
|
|||
return RecursiveOp_Callback_OK;
|
||||
}
|
||||
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode) || S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
|
||||
/* copy special type of file */
|
||||
/* Copy special type of file. */
|
||||
if (mknod(to, st.st_mode, st.st_rdev)) {
|
||||
perror("mknod");
|
||||
return RecursiveOp_Callback_Error;
|
||||
|
|
|
@ -467,10 +467,11 @@ static void evaluate_coarse_difference(const Span<DifferenceCourseBoundary> boun
|
|||
* #CoarseSegment::Type::Unknown. Those segments can be evaluated in more detail afterwards.
|
||||
*
|
||||
* \param root_expression: Expression to be evaluated.
|
||||
* \param eval_order: Pre-computed evaluation order. All children of a term must come before
|
||||
* the term itself.
|
||||
* \param eval_bounds: If given, the evaluation is restriced to those bounds. Otherwise, the full
|
||||
* referenced masks are used.
|
||||
* \param eval_order: Pre-computed evaluation order.
|
||||
* All children of a term must come before the term itself.
|
||||
* \param eval_bounds: If given, the evaluation is restricted to those bounds.
|
||||
* Otherwise, the full
|
||||
* referenced masks are used.
|
||||
*/
|
||||
static CoarseResult evaluate_coarse(const Expr &root_expression,
|
||||
const Span<const Expr *> eval_order,
|
||||
|
@ -1148,7 +1149,7 @@ static void evaluate_short_unknown_segments_exactly(
|
|||
}
|
||||
case ExactEvalMode::Indices: {
|
||||
/* #evaluate_exact_with_indices requires that all index masks have a single segment in the
|
||||
* provided bounds. So split up the range into subranges first if necessary. */
|
||||
* provided bounds. So split up the range into sub-ranges first if necessary. */
|
||||
Vector<int64_t, 16> split_indices;
|
||||
/* Always adding the beginning and end of the bounds simplifies the code below. */
|
||||
split_indices.extend({bounds.first(), bounds.one_after_last()});
|
||||
|
|
|
@ -4800,8 +4800,9 @@ void lookat_m4(
|
|||
|
||||
i_multmatrix(mat1, mat);
|
||||
|
||||
mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */
|
||||
mat1[1][2] = mat1[2][1] = 0.0f; /* those modified by the last */
|
||||
/* Be careful here to reinitialize those modified by the last. */
|
||||
mat1[1][1] = mat1[2][2] = 1.0f;
|
||||
mat1[1][2] = mat1[2][1] = 0.0f;
|
||||
|
||||
/* paragraph */
|
||||
if (hyp != 0.0f) { /* rotate Y */
|
||||
|
|
|
@ -228,7 +228,7 @@ void memory_bandwidth_bound_task_impl(const FunctionRef<void()> function)
|
|||
#ifdef WITH_TBB
|
||||
/* This is the maximum number of threads that may perform these memory bandwidth bound tasks at
|
||||
* the same time. Often fewer threads are already enough to use up the full bandwidth capacity.
|
||||
* Additional threads usually have a negilible benefit and can even make performance worse.
|
||||
* Additional threads usually have a negligible benefit and can even make performance worse.
|
||||
*
|
||||
* It's better to use fewer threads here so that the CPU cores can do other tasks at the same
|
||||
* time which may be more compute intensive. */
|
||||
|
|
|
@ -314,7 +314,7 @@ static void area_add_window_regions(ScrArea *area, SpaceLink *sl, ListBase *lb)
|
|||
case SPACE_ACTION: {
|
||||
SpaceAction *saction = (SpaceAction *)sl;
|
||||
|
||||
/* We totally reinit the view for the Action Editor,
|
||||
/* We totally reinitialize the view for the Action Editor,
|
||||
* as some old instances had some weird cruft set. */
|
||||
region->v2d.tot.xmin = -20.0f;
|
||||
region->v2d.tot.ymin = float(-area->winy) / 3.0f;
|
||||
|
|
|
@ -554,11 +554,10 @@ static bNodeTree *add_realize_node_tree(Main *bmain)
|
|||
{
|
||||
bNodeTree *node_tree = ntreeAddTree(bmain, "Realize Instances 2.93 Legacy", "GeometryNodeTree");
|
||||
|
||||
node_tree->tree_interface.add_socket("Geometry",
|
||||
"",
|
||||
"NodeSocketGeometry",
|
||||
NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT,
|
||||
nullptr);
|
||||
node_tree->tree_interface.add_socket(
|
||||
"Geometry", "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
|
||||
node_tree->tree_interface.add_socket(
|
||||
"Geometry", "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_INPUT, nullptr);
|
||||
|
||||
bNode *group_input = nodeAddStaticNode(nullptr, node_tree, NODE_GROUP_INPUT);
|
||||
group_input->locx = -400.0f;
|
||||
|
|
|
@ -3064,6 +3064,12 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 11)) {
|
||||
LISTBASE_FOREACH (Light *, light, &bmain->lights) {
|
||||
light->shadow_resolution_scale = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always bump subversion in BKE_blender_version.h when adding versioning
|
||||
* code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check.
|
||||
|
|
|
@ -299,7 +299,7 @@ void DEG_graph_tag_relations_update(Depsgraph *graph)
|
|||
graph_id_tag_update(deg_graph->bmain,
|
||||
deg_graph,
|
||||
°_graph->scene->id,
|
||||
ID_RECALC_BASE_FLAGS,
|
||||
ID_RECALC_BASE_FLAGS | ID_RECALC_HIERARCHY,
|
||||
deg::DEG_UPDATE_SOURCE_RELATIONS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,15 @@ void Light::sync(ShadowModule &shadows, const Object *ob, float threshold)
|
|||
|
||||
this->pcf_radius = la->shadow_filter_radius;
|
||||
|
||||
float resolution_scale = std::clamp(la->shadow_resolution_scale, 0.0f, 2.0f);
|
||||
if (resolution_scale < 1.0) {
|
||||
this->lod_bias = -log2(resolution_scale);
|
||||
}
|
||||
else {
|
||||
this->lod_bias = -(resolution_scale - 1.0f);
|
||||
}
|
||||
this->lod_bias += shadows.get_global_lod_bias();
|
||||
|
||||
eLightType new_type = to_light_type(la->type, la->area_shape, la->mode & LA_USE_SOFT_FALLOFF);
|
||||
if (assign_if_different(this->type, new_type)) {
|
||||
shadow_discard_safe(shadows);
|
||||
|
|
|
@ -356,6 +356,10 @@ Material &MaterialModule::material_sync(Object *ob,
|
|||
mat.is_alpha_blend_transparent = use_forward_pipeline &&
|
||||
GPU_material_flag_get(mat.shading.gpumat,
|
||||
GPU_MATFLAG_TRANSPARENT);
|
||||
mat.has_transparent_shadows = blender_mat->blend_flag & MA_BL_TRANSPARENT_SHADOW &&
|
||||
GPU_material_flag_get(mat.shading.gpumat,
|
||||
GPU_MATFLAG_TRANSPARENT);
|
||||
|
||||
return mat;
|
||||
});
|
||||
|
||||
|
|
|
@ -291,6 +291,7 @@ struct MaterialPass {
|
|||
|
||||
struct Material {
|
||||
bool is_alpha_blend_transparent;
|
||||
bool has_transparent_shadows;
|
||||
bool has_surface;
|
||||
bool has_volume;
|
||||
MaterialPass shadow;
|
||||
|
|
|
@ -797,8 +797,6 @@ struct LightData {
|
|||
float radius_squared;
|
||||
/** Spot angle tangent. */
|
||||
float spot_tan;
|
||||
/** Reuse for directional LOD bias. */
|
||||
#define _clipmap_lod_bias spot_tan
|
||||
|
||||
/** --- Shadow Data --- */
|
||||
/** Near clip distances. Float stored as int for atomic operations. */
|
||||
|
@ -821,7 +819,8 @@ struct LightData {
|
|||
float shadow_trace_distance;
|
||||
/* Radius in pixels for shadow filtering. */
|
||||
float pcf_radius;
|
||||
int _pad0;
|
||||
/* Shadow Map resolution bias. */
|
||||
float lod_bias;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(LightData, 16)
|
||||
|
||||
|
@ -1028,7 +1027,8 @@ struct ShadowSceneData {
|
|||
int step_count;
|
||||
/* Bias the shading point by using the normal to avoid self intersection. */
|
||||
float normal_bias;
|
||||
int _pad0;
|
||||
/* Ratio between tile-map pixel world "radius" and film pixel world "radius". */
|
||||
float tilemap_projection_ratio;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ShadowSceneData, 16)
|
||||
|
||||
|
|
|
@ -531,7 +531,7 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera
|
|||
/* The bias is applied in cascade_level_range().
|
||||
* Using clipmap_lod_min here simplify code in shadow_directional_level().
|
||||
* Minus 1 because of the ceil(). */
|
||||
light._clipmap_lod_bias = light.clipmap_lod_min - 1;
|
||||
light.lod_bias = light.clipmap_lod_min - 1;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
@ -621,7 +621,7 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light,
|
|||
light.clipmap_lod_min = levels_range.first();
|
||||
light.clipmap_lod_max = levels_range.last();
|
||||
|
||||
light._clipmap_lod_bias = lod_bias;
|
||||
light.lod_bias = lod_bias;
|
||||
}
|
||||
|
||||
void ShadowDirectional::sync(const float4x4 &object_mat,
|
||||
|
@ -742,6 +742,9 @@ void ShadowModule::init()
|
|||
}
|
||||
}
|
||||
|
||||
jittered_transparency_ = !inst_.is_viewport() ||
|
||||
scene.eevee.flag & SCE_EEVEE_SHADOW_JITTERED_VIEWPORT;
|
||||
|
||||
data_.ray_count = clamp_i(inst_.scene->eevee.shadow_ray_count, 1, SHADOW_MAX_RAY);
|
||||
data_.step_count = clamp_i(inst_.scene->eevee.shadow_step_count, 1, SHADOW_MAX_STEP);
|
||||
data_.normal_bias = max_ff(inst_.scene->eevee.shadow_normal_bias, 0.0f);
|
||||
|
@ -757,7 +760,7 @@ void ShadowModule::init()
|
|||
simplify_shadows = inst_.is_viewport() ? scene.r.simplify_shadows :
|
||||
scene.r.simplify_shadows_render;
|
||||
}
|
||||
lod_bias_ = math::interpolate(float(SHADOW_TILEMAP_LOD), 0.0f, simplify_shadows);
|
||||
lod_bias_ = -log2(simplify_shadows);
|
||||
|
||||
const int2 atlas_extent = shadow_page_size_ * int2(SHADOW_PAGE_PER_ROW);
|
||||
const int atlas_layers = divide_ceil_u(shadow_page_len_, SHADOW_PAGE_PER_LAYER);
|
||||
|
@ -824,6 +827,8 @@ void ShadowModule::begin_sync()
|
|||
past_casters_updated_.clear();
|
||||
curr_casters_updated_.clear();
|
||||
curr_casters_.clear();
|
||||
jittered_transparent_casters_.clear();
|
||||
update_casters_ = true;
|
||||
|
||||
{
|
||||
Manager &manager = *inst_.manager;
|
||||
|
@ -849,7 +854,7 @@ void ShadowModule::begin_sync()
|
|||
sub.bind_ssbo("surfel_buf", &surfels_buf);
|
||||
sub.bind_ssbo("capture_info_buf", &capture_info_buf);
|
||||
sub.push_constant("directional_level", directional_level);
|
||||
sub.push_constant("tilemap_projection_ratio", projection_ratio);
|
||||
sub.push_constant("tilemap_proj_ratio", projection_ratio);
|
||||
sub.bind_resources(inst_.lights);
|
||||
sub.dispatch(&inst_.volume_probes.bake.dispatch_per_surfel_);
|
||||
|
||||
|
@ -864,7 +869,7 @@ void ShadowModule::begin_sync()
|
|||
sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
|
||||
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
|
||||
sub.bind_texture("depth_tx", &src_depth_tx_);
|
||||
sub.push_constant("tilemap_projection_ratio", &tilemap_projection_ratio_);
|
||||
sub.push_constant("tilemap_proj_ratio", &data_.tilemap_projection_ratio);
|
||||
sub.bind_resources(inst_.lights);
|
||||
sub.dispatch(&dispatch_depth_scan_size_);
|
||||
}
|
||||
|
@ -880,7 +885,7 @@ void ShadowModule::begin_sync()
|
|||
sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
|
||||
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("tilemap_proj_ratio", &data_.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_);
|
||||
|
@ -897,7 +902,8 @@ void ShadowModule::begin_sync()
|
|||
void ShadowModule::sync_object(const Object *ob,
|
||||
const ObjectHandle &handle,
|
||||
const ResourceHandle &resource_handle,
|
||||
bool is_alpha_blend)
|
||||
bool is_alpha_blend,
|
||||
bool has_transparent_shadows)
|
||||
{
|
||||
bool is_shadow_caster = !(ob->visibility_flag & OB_HIDE_SHADOW);
|
||||
if (!is_shadow_caster && !is_alpha_blend) {
|
||||
|
@ -907,11 +913,18 @@ void ShadowModule::sync_object(const Object *ob,
|
|||
ShadowObject &shadow_ob = objects_.lookup_or_add_default(handle.object_key);
|
||||
shadow_ob.used = true;
|
||||
const bool is_initialized = shadow_ob.resource_handle.raw != 0;
|
||||
if ((handle.recalc != 0 || !is_initialized) && is_shadow_caster) {
|
||||
if (shadow_ob.resource_handle.raw != 0) {
|
||||
const bool has_jittered_transparency = has_transparent_shadows && jittered_transparency_;
|
||||
if (is_shadow_caster && (handle.recalc || !is_initialized || has_jittered_transparency)) {
|
||||
if (handle.recalc && is_initialized) {
|
||||
past_casters_updated_.append(shadow_ob.resource_handle.raw);
|
||||
}
|
||||
curr_casters_updated_.append(resource_handle.raw);
|
||||
|
||||
if (has_jittered_transparency) {
|
||||
jittered_transparent_casters_.append(resource_handle.raw);
|
||||
}
|
||||
else {
|
||||
curr_casters_updated_.append(resource_handle.raw);
|
||||
}
|
||||
}
|
||||
shadow_ob.resource_handle = resource_handle;
|
||||
|
||||
|
@ -932,7 +945,7 @@ void ShadowModule::end_sync()
|
|||
light.shadow_discard_safe(*this);
|
||||
}
|
||||
else if (light.directional != nullptr) {
|
||||
light.directional->release_excess_tilemaps(inst_.camera, lod_bias_);
|
||||
light.directional->release_excess_tilemaps(inst_.camera, light.lod_bias);
|
||||
}
|
||||
else if (light.punctual != nullptr) {
|
||||
light.punctual->release_excess_tilemaps();
|
||||
|
@ -946,10 +959,10 @@ void ShadowModule::end_sync()
|
|||
light.tilemap_index = LIGHT_NO_SHADOW;
|
||||
}
|
||||
else if (light.directional != nullptr) {
|
||||
light.directional->end_sync(light, inst_.camera, lod_bias_);
|
||||
light.directional->end_sync(light, inst_.camera, light.lod_bias);
|
||||
}
|
||||
else if (light.punctual != nullptr) {
|
||||
light.punctual->end_sync(light, lod_bias_);
|
||||
light.punctual->end_sync(light, light.lod_bias);
|
||||
}
|
||||
else {
|
||||
light.tilemap_index = LIGHT_NO_SHADOW;
|
||||
|
@ -973,6 +986,7 @@ void ShadowModule::end_sync()
|
|||
}
|
||||
past_casters_updated_.push_update();
|
||||
curr_casters_updated_.push_update();
|
||||
jittered_transparent_casters_.push_update();
|
||||
|
||||
curr_casters_.push_update();
|
||||
|
||||
|
@ -1080,6 +1094,22 @@ void ShadowModule::end_sync()
|
|||
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
}
|
||||
|
||||
{
|
||||
/* Mark for update all shadow pages touching a jittered transparency shadow caster. */
|
||||
PassSimple &pass = jittered_transparent_caster_update_ps_;
|
||||
pass.init();
|
||||
if (jittered_transparent_casters_.size() > 0) {
|
||||
pass.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_UPDATE));
|
||||
pass.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
|
||||
pass.bind_ssbo("tiles_buf", tilemap_pool.tiles_data);
|
||||
pass.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
|
||||
pass.bind_ssbo("resource_ids_buf", jittered_transparent_casters_);
|
||||
pass.dispatch(
|
||||
int3(jittered_transparent_casters_.size(), 1, tilemap_pool.tilemaps_data.size()));
|
||||
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Non volume usage tagging happens between these two steps.
|
||||
* (Setup at begin_sync) */
|
||||
|
||||
|
@ -1088,7 +1118,7 @@ void ShadowModule::end_sync()
|
|||
sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_VOLUME));
|
||||
sub.bind_ssbo("tilemaps_buf", &tilemap_pool.tilemaps_data);
|
||||
sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data);
|
||||
sub.push_constant("tilemap_projection_ratio", &tilemap_projection_ratio_);
|
||||
sub.push_constant("tilemap_proj_ratio", &data_.tilemap_projection_ratio);
|
||||
sub.bind_resources(inst_.uniform_data);
|
||||
sub.bind_resources(inst_.hiz_buffer.front);
|
||||
sub.bind_resources(inst_.sampling);
|
||||
|
@ -1310,7 +1340,8 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
|
|||
dispatch_depth_scan_size_ = math::divide_ceil(target_size, int3(SHADOW_DEPTH_SCAN_GROUP_SIZE));
|
||||
|
||||
pixel_world_radius_ = screen_pixel_radius(view, int2(target_size));
|
||||
tilemap_projection_ratio_ = tilemap_pixel_radius() / pixel_world_radius_;
|
||||
data_.tilemap_projection_ratio = tilemap_pixel_radius() / pixel_world_radius_;
|
||||
inst_.uniform_data.push_update();
|
||||
|
||||
usage_tag_fb_resolution_ = math::divide_ceil(int2(target_size),
|
||||
int2(std::exp2(usage_tag_fb_lod_)));
|
||||
|
@ -1338,7 +1369,7 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
|
|||
}
|
||||
|
||||
inst_.hiz_buffer.update();
|
||||
bool update_casters = true;
|
||||
bool first_loop = true;
|
||||
|
||||
do {
|
||||
DRW_stats_group_start("Shadow");
|
||||
|
@ -1346,12 +1377,15 @@ void ShadowModule::set_view(View &view, GPUTexture *depth_tx)
|
|||
GPU_uniformbuf_clear_to_zero(shadow_multi_view_.matrices_ubo_get());
|
||||
|
||||
inst_.manager->submit(tilemap_setup_ps_, view);
|
||||
if (assign_if_different(update_casters, false)) {
|
||||
if (assign_if_different(update_casters_, false)) {
|
||||
/* Run caster update only once. */
|
||||
/* TODO(fclem): There is an optimization opportunity here where we can
|
||||
* test casters only against the static tilemaps instead of all of them. */
|
||||
inst_.manager->submit(caster_update_ps_, view);
|
||||
}
|
||||
if (assign_if_different(first_loop, false)) {
|
||||
inst_.manager->submit(jittered_transparent_caster_update_ps_, view);
|
||||
}
|
||||
inst_.manager->submit(tilemap_usage_ps_, view);
|
||||
inst_.manager->submit(tilemap_update_ps_, view);
|
||||
|
||||
|
|
|
@ -213,6 +213,11 @@ class ShadowModule {
|
|||
/** Map of shadow casters to track deletion & update of intersected shadows. */
|
||||
Map<ObjectKey, ShadowObject> objects_;
|
||||
|
||||
/* Used to call caster_update_ps_ only once per sync (Initialized on begin_sync). */
|
||||
bool update_casters_ = false;
|
||||
|
||||
bool jittered_transparency_ = false;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Tile-map Management
|
||||
* \{ */
|
||||
|
@ -229,9 +234,11 @@ class ShadowModule {
|
|||
Framebuffer usage_tag_fb;
|
||||
|
||||
PassSimple caster_update_ps_ = {"CasterUpdate"};
|
||||
PassSimple jittered_transparent_caster_update_ps_ = {"TransparentCasterUpdate"};
|
||||
/** List of Resource IDs (to get bounds) for tagging passes. */
|
||||
StorageVectorBuffer<uint, 128> past_casters_updated_ = {"PastCastersUpdated"};
|
||||
StorageVectorBuffer<uint, 128> curr_casters_updated_ = {"CurrCastersUpdated"};
|
||||
StorageVectorBuffer<uint, 128> jittered_transparent_casters_ = {"JitteredTransparentCasters"};
|
||||
/** List of Resource IDs (to get bounds) for getting minimum clip-maps bounds. */
|
||||
StorageVectorBuffer<uint, 128> curr_casters_ = {"CurrCasters"};
|
||||
|
||||
|
@ -249,8 +256,6 @@ class ShadowModule {
|
|||
StorageArrayBuffer<uint, SHADOW_VIEW_MAX, true> viewport_index_buf_ = {"viewport_index_buf"};
|
||||
|
||||
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;
|
||||
|
@ -334,7 +339,8 @@ class ShadowModule {
|
|||
void sync_object(const Object *ob,
|
||||
const ObjectHandle &handle,
|
||||
const ResourceHandle &resource_handle,
|
||||
bool is_alpha_blend);
|
||||
bool is_alpha_blend,
|
||||
bool has_transparent_shadows);
|
||||
void end_sync();
|
||||
|
||||
void set_lights_data();
|
||||
|
@ -359,6 +365,11 @@ class ShadowModule {
|
|||
return data_;
|
||||
}
|
||||
|
||||
float get_global_lod_bias()
|
||||
{
|
||||
return lod_bias_;
|
||||
}
|
||||
|
||||
private:
|
||||
void remove_unused();
|
||||
void debug_page_map_call(DRWPass *pass);
|
||||
|
|
|
@ -114,6 +114,7 @@ void SyncModule::sync_mesh(Object *ob,
|
|||
}
|
||||
|
||||
bool is_alpha_blend = false;
|
||||
bool has_transparent_shadows = false;
|
||||
float inflate_bounds = 0.0f;
|
||||
for (auto i : material_array.gpu_materials.index_range()) {
|
||||
GPUBatch *geom = mat_geom[i];
|
||||
|
@ -147,6 +148,7 @@ void SyncModule::sync_mesh(Object *ob,
|
|||
geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle);
|
||||
|
||||
is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
|
||||
has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
|
||||
|
||||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
|
@ -162,7 +164,7 @@ void SyncModule::sync_mesh(Object *ob,
|
|||
|
||||
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
|
||||
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||
}
|
||||
|
||||
|
@ -192,6 +194,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
|||
MaterialArray &material_array = inst_.materials.material_array_get(ob, has_motion);
|
||||
|
||||
bool is_alpha_blend = false;
|
||||
bool has_transparent_shadows = false;
|
||||
float inflate_bounds = 0.0f;
|
||||
for (SculptBatch &batch :
|
||||
sculpt_batches_per_material_get(ob_ref.object, material_array.gpu_materials))
|
||||
|
@ -226,6 +229,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
|||
geometry_call(material.reflection_probe_shading.sub_pass, geom, res_handle);
|
||||
|
||||
is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent;
|
||||
has_transparent_shadows = has_transparent_shadows || material.has_transparent_shadows;
|
||||
|
||||
GPUMaterial *gpu_material = material_array.gpu_materials[batch.material_slot];
|
||||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
|
@ -245,7 +249,7 @@ bool SyncModule::sync_sculpt(Object *ob,
|
|||
|
||||
inst_.manager->extract_object_attributes(res_handle, ob_ref, material_array.gpu_materials);
|
||||
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||
inst_.cryptomatte.sync_object(ob, res_handle);
|
||||
|
||||
return true;
|
||||
|
@ -308,13 +312,15 @@ void SyncModule::sync_point_cloud(Object *ob,
|
|||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
|
||||
bool is_alpha_blend = material.is_alpha_blend_transparent;
|
||||
|
||||
if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
|
||||
inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
|
||||
}
|
||||
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
||||
inst_.shadows.sync_object(ob,
|
||||
ob_handle,
|
||||
res_handle,
|
||||
material.is_alpha_blend_transparent,
|
||||
material.has_transparent_shadows);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -485,8 +491,9 @@ void SyncModule::sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandl
|
|||
|
||||
gpencil_drawcall_flush(iter);
|
||||
|
||||
bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
||||
bool is_alpha_blend = true; /* TODO material.is_alpha_blend. */
|
||||
bool has_transparent_shadows = true; /* TODO material.has_transparent_shadows. */
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend, has_transparent_shadows);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -560,13 +567,15 @@ void SyncModule::sync_curves(Object *ob,
|
|||
::Material *mat = GPU_material_get_material(gpu_material);
|
||||
inst_.cryptomatte.sync_material(mat);
|
||||
|
||||
bool is_alpha_blend = material.is_alpha_blend_transparent;
|
||||
|
||||
if (GPU_material_has_displacement_output(gpu_material) && mat->inflate_bounds != 0.0f) {
|
||||
inst_.manager->update_handle_bounds(res_handle, ob_ref, mat->inflate_bounds);
|
||||
}
|
||||
|
||||
inst_.shadows.sync_object(ob, ob_handle, res_handle, is_alpha_blend);
|
||||
inst_.shadows.sync_object(ob,
|
||||
ob_handle,
|
||||
res_handle,
|
||||
material.is_alpha_blend_transparent,
|
||||
material.has_transparent_shadows);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -28,7 +28,7 @@ float octahedral_texel_solid_angle(ivec2 local_texel,
|
|||
/* Do not weight these border pixels that are redundant. */
|
||||
return 0.0;
|
||||
}
|
||||
/* Since we are puting texel centers on the edges of the octahedron, the shape of a texel can be
|
||||
/* Since we are pouting texel centers on the edges of the octahedron, the shape of a texel can be
|
||||
* anything from a simple quad (at the Z=0 poles), to a 4 pointed start (at the Z=+-1 poles)
|
||||
* passing by arrow tail shapes (at the X=0 and Y=0 edges). So while it would be more correct to
|
||||
* account for all these shapes (using 8 triangles), it proves to be quite involved with all the
|
||||
|
@ -54,7 +54,7 @@ float octahedral_texel_solid_angle(ivec2 local_texel,
|
|||
v02 = normalize(v02);
|
||||
v12 = normalize(v12);
|
||||
v22 = normalize(v22);
|
||||
#if 0 /* Has artifacts, is marginaly more correct. */
|
||||
#if 0 /* Has artifacts, is marginally more correct. */
|
||||
/* For some reason quad_solid_angle(v10, v20, v11, v21) gives some strange artifacts at Z=0. */
|
||||
return 0.25 * (quad_solid_angle(v00, v10, v01, v11) + quad_solid_angle(v10, v20, v11, v21) +
|
||||
quad_solid_angle(v01, v11, v02, v12) + quad_solid_angle(v11, v21, v12, v22));
|
||||
|
@ -132,7 +132,7 @@ void main()
|
|||
/* TODO(fclem): Cleanup: Should spherical_harmonics_encode_signal_sample return a new sh
|
||||
* instead of adding to it? */
|
||||
spherical_harmonics_encode_signal_sample(L, local_radiance[0], sh);
|
||||
/* Outputs one SH for each threadgroup. */
|
||||
/* Outputs one SH for each thread-group. */
|
||||
uint work_group_index = gl_NumWorkGroups.x * gl_WorkGroupID.y + gl_WorkGroupID.x;
|
||||
out_sh[work_group_index].L0_M0 = sh.L0.M0;
|
||||
out_sh[work_group_index].L1_Mn1 = sh.L1.Mn1;
|
||||
|
|
|
@ -110,22 +110,8 @@ void shadow_tag_usage_tilemap_punctual(
|
|||
/* TODO(fclem): 3D shift for jittered soft shadows. */
|
||||
lP += vec3(0.0, 0.0, -light.shadow_projection_shift);
|
||||
|
||||
/* 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;
|
||||
/* Take the frustum padding into account. */
|
||||
footprint_ratio *= light.clip_side / orderedIntBitsToFloat(light.clip_near);
|
||||
float footprint_ratio = shadow_punctual_footprint_ratio(
|
||||
light, P, drw_view_is_perspective(), dist_to_cam, tilemap_proj_ratio);
|
||||
|
||||
if (radius == 0) {
|
||||
int face_id = shadow_punctual_face_index_get(lP);
|
||||
|
|
|
@ -23,7 +23,7 @@ void main()
|
|||
light.type = LIGHT_SUN;
|
||||
light.clipmap_lod_min = -5;
|
||||
light.clipmap_lod_max = 8;
|
||||
light._clipmap_lod_bias = 0.0;
|
||||
light.lod_bias = 0.0;
|
||||
float fac = float(SHADOW_TILEMAP_RES - 1) / float(SHADOW_TILEMAP_RES);
|
||||
EXPECT_EQ(shadow_directional_level(light, vec3(fac * 0.0)), light.clipmap_lod_min);
|
||||
EXPECT_EQ(shadow_directional_level(light, vec3(fac * 0.49)), 1);
|
||||
|
@ -51,7 +51,7 @@ void main()
|
|||
light._clipmap_origin_x = 0.0;
|
||||
light._clipmap_origin_y = 0.0;
|
||||
float half_size = exp2(float(light.clipmap_lod_min - 1));
|
||||
light._clipmap_lod_bias = light.clipmap_lod_min - 1;
|
||||
light.lod_bias = light.clipmap_lod_min - 1;
|
||||
float fac = float(SHADOW_TILEMAP_RES - 1) / float(SHADOW_TILEMAP_RES);
|
||||
EXPECT_EQ(shadow_directional_level(light, vec3(fac * half_size * 0.0, 0.0, 0.0)), 2);
|
||||
EXPECT_EQ(shadow_directional_level(light, vec3(fac * half_size * 0.5, 0.0, 0.0)), 2);
|
||||
|
@ -76,7 +76,7 @@ void main()
|
|||
light._position = vec3(0.0);
|
||||
light._clipmap_origin_x = 0.0;
|
||||
light._clipmap_origin_y = 0.0;
|
||||
light._clipmap_lod_bias = 0;
|
||||
light.lod_bias = 0;
|
||||
|
||||
float lod_min_tile_size = exp2(float(light.clipmap_lod_min)) / float(SHADOW_TILEMAP_RES);
|
||||
float lod_max_half_size = exp2(float(light.clipmap_lod_max)) / 2.0;
|
||||
|
@ -189,7 +189,7 @@ void main()
|
|||
light.clipmap_lod_max = 2; /* 3 tile-maps. */
|
||||
light.tilemap_index = 1;
|
||||
light._position = vec3(0.0);
|
||||
light._clipmap_lod_bias = light.clipmap_lod_min - 1;
|
||||
light.lod_bias = light.clipmap_lod_min - 1;
|
||||
light._clipmap_origin_x = 0.0;
|
||||
light._clipmap_origin_y = 0.0;
|
||||
float lod_tile_size = exp2(float(light.clipmap_lod_min)) / float(SHADOW_TILEMAP_RES);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_shape_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl)
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Tile-map data
|
||||
|
@ -106,7 +107,8 @@ ShadowTileData shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilem
|
|||
* \a lP shading point position in light space, relative to the to camera position snapped to
|
||||
* the smallest clip-map level (`shadow_world_to_local(light, P) - light._position`).
|
||||
*/
|
||||
int shadow_directional_level(LightData light, vec3 lP)
|
||||
|
||||
float shadow_directional_level_fractional(LightData light, vec3 lP)
|
||||
{
|
||||
float lod;
|
||||
if (light.type == LIGHT_SUN) {
|
||||
|
@ -124,8 +126,39 @@ int shadow_directional_level(LightData light, vec3 lP)
|
|||
float lod_min_half_size = exp2(float(light.clipmap_lod_min - 1));
|
||||
lod = length(lP.xy) * narrowing / lod_min_half_size;
|
||||
}
|
||||
int clipmap_lod = int(ceil(lod + light._clipmap_lod_bias));
|
||||
return clamp(clipmap_lod, light.clipmap_lod_min, light.clipmap_lod_max);
|
||||
float clipmap_lod = lod + light.lod_bias;
|
||||
return clamp(clipmap_lod, float(light.clipmap_lod_min), float(light.clipmap_lod_max));
|
||||
}
|
||||
|
||||
int shadow_directional_level(LightData light, vec3 lP)
|
||||
{
|
||||
return int(ceil(shadow_directional_level_fractional(light, lP)));
|
||||
}
|
||||
|
||||
/* How much a tilemap pixel covers a final image pixel. */
|
||||
float shadow_punctual_footprint_ratio(LightData light,
|
||||
vec3 P,
|
||||
bool is_perspective,
|
||||
float dist_to_cam,
|
||||
float tilemap_projection_ratio)
|
||||
{
|
||||
/* 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 dist_to_light = distance(P, light._position);
|
||||
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. */
|
||||
if (is_perspective) {
|
||||
footprint_ratio /= dist_to_cam;
|
||||
}
|
||||
/* Apply resolution ratio. */
|
||||
footprint_ratio *= tilemap_projection_ratio;
|
||||
/* Take the frustum padding into account. */
|
||||
footprint_ratio *= light.clip_side / orderedIntBitsToFloat(light.clip_near);
|
||||
return footprint_ratio;
|
||||
}
|
||||
|
||||
struct ShadowCoordinates {
|
||||
|
|
|
@ -412,7 +412,7 @@ SHADOW_MAP_TRACE_FN(ShadowRayPunctual)
|
|||
|
||||
/* Compute the world space offset of the shading position required for
|
||||
* stochastic percentage closer filtering of shadow-maps. */
|
||||
vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3 Ng)
|
||||
vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3 Ng, vec2 random)
|
||||
{
|
||||
if (light.pcf_radius <= 0.001) {
|
||||
/* Early return. */
|
||||
|
@ -461,14 +461,27 @@ vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3
|
|||
|
||||
/* Compute the actual offset. */
|
||||
|
||||
vec2 rand = vec2(0.0);
|
||||
#ifdef EEVEE_SAMPLING_DATA
|
||||
rand = sampling_rng_2D_get(SAMPLING_SHADOW_V);
|
||||
#endif
|
||||
vec2 pcf_offset = interlieved_gradient_noise(UTIL_TEXEL, vec2(0.0), rand);
|
||||
pcf_offset = pcf_offset * 2.0 - 1.0;
|
||||
vec2 pcf_offset = random * 2.0 - 1.0;
|
||||
pcf_offset *= light.pcf_radius;
|
||||
|
||||
/* Scale the offset based on shadow LOD. */
|
||||
if (is_directional) {
|
||||
vec3 lP = light_world_to_local(light, P);
|
||||
float level = shadow_directional_level_fractional(light, lP - light._position);
|
||||
float pcf_scale = mix(0.5, 1.0, fract(level));
|
||||
pcf_offset *= pcf_scale;
|
||||
}
|
||||
else {
|
||||
bool is_perspective = drw_view_is_perspective();
|
||||
float dist_to_cam = distance(P, drw_view_position());
|
||||
float footprint_ratio = shadow_punctual_footprint_ratio(
|
||||
light, P, is_perspective, dist_to_cam, uniform_buf.shadow.tilemap_projection_ratio);
|
||||
float lod = -log2(footprint_ratio) + light.lod_bias;
|
||||
lod = clamp(lod, 0.0, float(SHADOW_TILEMAP_LOD));
|
||||
float pcf_scale = exp2(lod);
|
||||
pcf_offset *= pcf_scale;
|
||||
}
|
||||
|
||||
vec3 ws_offset = TBN * vec3(pcf_offset, 0.0);
|
||||
vec3 offset_P = P + ws_offset;
|
||||
|
||||
|
@ -515,17 +528,19 @@ ShadowEvalResult shadow_eval(LightData light,
|
|||
# elif defined(GPU_COMPUTE_SHADER)
|
||||
vec2 pixel = vec2(gl_GlobalInvocationID.xy);
|
||||
# endif
|
||||
vec3 random_shadow_3d = utility_tx_fetch(utility_tx, pixel, UTIL_BLUE_NOISE_LAYER).rgb;
|
||||
random_shadow_3d += sampling_rng_3D_get(SAMPLING_SHADOW_U);
|
||||
vec3 blue_noise_3d = utility_tx_fetch(utility_tx, pixel, UTIL_BLUE_NOISE_LAYER).rgb;
|
||||
vec3 random_shadow_3d = blue_noise_3d + sampling_rng_3D_get(SAMPLING_SHADOW_U);
|
||||
vec2 random_pcf_2d = fract(blue_noise_3d.xy + sampling_rng_2D_get(SAMPLING_SHADOW_X));
|
||||
float normal_offset = uniform_buf.shadow.normal_bias;
|
||||
#else
|
||||
/* Case of surfel light eval. */
|
||||
vec3 random_shadow_3d = vec3(0.5);
|
||||
vec2 random_pcf_2d = vec2(0.0);
|
||||
/* TODO(fclem): Parameter on irradiance volumes? */
|
||||
float normal_offset = 0.02;
|
||||
#endif
|
||||
|
||||
P += shadow_pcf_offset(light, is_directional, P, Ng);
|
||||
P += shadow_pcf_offset(light, is_directional, P, Ng, random_pcf_2d);
|
||||
|
||||
/* Avoid self intersection. */
|
||||
P = offset_ray(P, Ng);
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_transparency_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
|
||||
|
||||
vec4 closure_to_rgba(Closure cl)
|
||||
{
|
||||
|
@ -25,13 +25,15 @@ vec4 closure_to_rgba(Closure cl)
|
|||
|
||||
void main()
|
||||
{
|
||||
float f_depth = gl_FragCoord.z + fwidth(gl_FragCoord.z);
|
||||
|
||||
#ifdef MAT_TRANSPARENT
|
||||
init_globals();
|
||||
|
||||
nodetree_surface(0.0);
|
||||
|
||||
float noise_offset = sampling_rng_1D_get(SAMPLING_TRANSPARENCY);
|
||||
float random_threshold = transparency_hashed_alpha_threshold(1.0, noise_offset, g_data.P);
|
||||
float random_threshold = pcg4d(vec4(g_data.P, noise_offset)).x;
|
||||
|
||||
float transparency = average(g_transmittance);
|
||||
if (transparency > random_threshold) {
|
||||
|
@ -40,8 +42,6 @@ void main()
|
|||
}
|
||||
#endif
|
||||
|
||||
float f_depth = gl_FragCoord.z + fwidth(gl_FragCoord.z);
|
||||
|
||||
#ifdef SHADOW_UPDATE_ATOMIC_RASTER
|
||||
ivec2 texel_co = ivec2(gl_FragCoord.xy);
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ SphericalHarmonicL1 volume_phase_function_as_sh_L1(vec3 V, float g)
|
|||
/* Compute rotated zonal harmonic.
|
||||
* From Bartlomiej Wronsky
|
||||
* "Volumetric Fog: Unified compute shader based solution to atmospheric scattering" page 55
|
||||
* Siggraph 2014
|
||||
* SIGGRAPH 2014
|
||||
* https://bartwronski.files.wordpress.com/2014/08/bwronski_volumetric_fog_siggraph2014.pdf
|
||||
*/
|
||||
SphericalHarmonicL1 sh;
|
||||
|
|
|
@ -64,7 +64,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
|
|||
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.push_constant(Type::FLOAT, "tilemap_proj_ratio")
|
||||
.additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data")
|
||||
.compute_source("eevee_shadow_tag_usage_comp.glsl");
|
||||
|
||||
|
@ -75,7 +75,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_surfels)
|
|||
/* ShadowTileDataPacked is uint. But MSL translation need the real type. */
|
||||
.storage_buf(7, Qualifier::READ_WRITE, "uint", "tiles_buf[]")
|
||||
.push_constant(Type::INT, "directional_level")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.push_constant(Type::FLOAT, "tilemap_proj_ratio")
|
||||
.additional_info("eevee_shared",
|
||||
"draw_view",
|
||||
"draw_view_culling",
|
||||
|
@ -96,7 +96,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
|
|||
.storage_buf(4, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.push_constant(Type::FLOAT, "tilemap_proj_ratio")
|
||||
.push_constant(Type::FLOAT, "pixel_world_radius")
|
||||
.push_constant(Type::IVEC2, "fb_resolution")
|
||||
.push_constant(Type::INT, "fb_lod")
|
||||
|
@ -117,7 +117,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_volume)
|
|||
.local_group_size(VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE)
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.push_constant(Type::FLOAT, "tilemap_proj_ratio")
|
||||
.additional_info("eevee_volume_properties_data",
|
||||
"eevee_shared",
|
||||
"draw_view",
|
||||
|
|
|
@ -623,7 +623,7 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
|||
cols_slice[idx]);
|
||||
}
|
||||
|
||||
if (is_cyclic && points.size() >= 3) {
|
||||
if (is_cyclic) {
|
||||
const int idx = points.size() + 1;
|
||||
const float length = points.size() > 1 ? lengths[points.size() - 1] : 0.0f;
|
||||
populate_point(verts_range,
|
||||
|
|
|
@ -73,11 +73,10 @@ void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
|
|||
nmd.node_group = ntreeAddTree(bmain, DATA_("Surface Deform"), "GeometryNodeTree");
|
||||
|
||||
bNodeTree *ntree = nmd.node_group;
|
||||
ntree->tree_interface.add_socket("Geometry",
|
||||
"",
|
||||
"NodeSocketGeometry",
|
||||
NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT,
|
||||
nullptr);
|
||||
ntree->tree_interface.add_socket(
|
||||
"Geometry", "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
|
||||
ntree->tree_interface.add_socket(
|
||||
"Geometry", "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_INPUT, nullptr);
|
||||
bNode *group_input = nodeAddStaticNode(&C, ntree, NODE_GROUP_INPUT);
|
||||
bNode *group_output = nodeAddStaticNode(&C, ntree, NODE_GROUP_OUTPUT);
|
||||
bNode *deform_node = nodeAddStaticNode(&C, ntree, GEO_NODE_DEFORM_CURVES_ON_SURFACE);
|
||||
|
|
|
@ -1224,9 +1224,9 @@ void ED_view3d_grid_steps(const Scene *scene,
|
|||
* The actual code is seen in `object_grid_frag.glsl` (see `grid_res`).
|
||||
* Currently the simulation is only done when RV3D_VIEW_IS_AXIS.
|
||||
*/
|
||||
float ED_view3d_grid_view_scale(Scene *scene,
|
||||
View3D *v3d,
|
||||
ARegion *region,
|
||||
float ED_view3d_grid_view_scale(const Scene *scene,
|
||||
const View3D *v3d,
|
||||
const ARegion *region,
|
||||
const char **r_grid_unit);
|
||||
|
||||
/**
|
||||
|
@ -1287,8 +1287,8 @@ void ED_view3d_draw_bgpic_test(const Scene *scene,
|
|||
|
||||
/* view3d_gizmo_preselect_type.cc */
|
||||
|
||||
void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C,
|
||||
wmGizmo *gz,
|
||||
void ED_view3d_gizmo_mesh_preselect_get_active(const bContext *C,
|
||||
const wmGizmo *gz,
|
||||
Base **r_base,
|
||||
BMElem **r_ele);
|
||||
void ED_view3d_gizmo_mesh_preselect_clear(wmGizmo *gz);
|
||||
|
@ -1305,8 +1305,8 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
|
|||
* See if current UUID is valid, otherwise set a valid UUID to v3d,
|
||||
* Try to keep the same UUID previously used to allow users to quickly toggle back and forth.
|
||||
*/
|
||||
bool ED_view3d_local_collections_set(Main *bmain, View3D *v3d);
|
||||
void ED_view3d_local_collections_reset(bContext *C, bool reset_all);
|
||||
bool ED_view3d_local_collections_set(const Main *bmain, View3D *v3d);
|
||||
void ED_view3d_local_collections_reset(const bContext *C, bool reset_all);
|
||||
|
||||
#ifdef WITH_XR_OPENXR
|
||||
void ED_view3d_xr_mirror_update(const ScrArea *area, const View3D *v3d, bool enable);
|
||||
|
|
|
@ -214,7 +214,7 @@ class AbstractTreeViewItem : public AbstractViewItem, public TreeViewItemContain
|
|||
*/
|
||||
virtual bool set_collapsed(bool collapsed);
|
||||
/**
|
||||
* Make this item be uncollapsed on first draw (may later be overriden by
|
||||
* Make this item be uncollapsed on first draw (may later be overridden by
|
||||
* #should_be_collapsed()). Must only be done during tree building.
|
||||
*
|
||||
* \note this does not call #on_collapse_change() or #set_collapsed() overrides.
|
||||
|
|
|
@ -178,8 +178,8 @@ class LayerViewItem : public AbstractTreeViewItem {
|
|||
|
||||
bool supports_collapsing() const override
|
||||
{
|
||||
/* This is a bit redundant since `LayerViewItem` can't have children. But being expplicit might
|
||||
* catch errors. */
|
||||
/* This is a bit redundant since `LayerViewItem` can't have children.
|
||||
* But being explicit might catch errors. */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -342,7 +342,7 @@ static void update_affected_nodes_by_clip_planes(GestureData &gesture_data)
|
|||
case SelectionType::Outside:
|
||||
/* Certain degenerate cases of a lasso shape can cause the resulting
|
||||
* frustum planes to enclose a node's AABB, therefore we must submit it
|
||||
* to be more throughly evaluated. */
|
||||
* to be more thoroughly evaluated. */
|
||||
if (gesture_data.shape_type == ShapeType::Lasso) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -38,9 +38,12 @@ int /*eContextResult*/ file_context(const bContext *C,
|
|||
|
||||
#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X)
|
||||
|
||||
#define FILE_LAYOUT_COMPACT(_layout) ((_layout->width / UI_SCALE_FAC) < 500)
|
||||
#define FILE_LAYOUT_HIDE_DATE(_layout) ((_layout->width / UI_SCALE_FAC) < 250)
|
||||
#define FILE_LAYOUT_HIDE_SIZE(_layout) ((_layout->width / UI_SCALE_FAC) < 350)
|
||||
#define FILE_LAYOUT_COMPACT(_layout) \
|
||||
(_layout->flag & FILE_LAYOUT_VER && (_layout->width / UI_SCALE_FAC) < 500)
|
||||
#define FILE_LAYOUT_HIDE_DATE(_layout) \
|
||||
(_layout->flag & FILE_LAYOUT_VER && (_layout->width / UI_SCALE_FAC) < 250)
|
||||
#define FILE_LAYOUT_HIDE_SIZE(_layout) \
|
||||
(_layout->flag & FILE_LAYOUT_VER && (_layout->width / UI_SCALE_FAC) < 350)
|
||||
|
||||
void file_calc_previews(const bContext *C, ARegion *region);
|
||||
void file_draw_list(const bContext *C, ARegion *region);
|
||||
|
|
|
@ -2179,19 +2179,6 @@ static int graphkeys_select_key_handles_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void graphkeys_select_key_handles_ui(bContext * /*C*/, wmOperator *op)
|
||||
{
|
||||
uiLayout *layout = op->layout;
|
||||
uiLayout *row;
|
||||
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, op->ptr, "left_handle_action", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, op->ptr, "right_handle_action", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
row = uiLayoutRow(layout, false);
|
||||
uiItemR(row, op->ptr, "key_action", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
|
||||
void GRAPH_OT_select_key_handles(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
|
@ -2203,7 +2190,6 @@ void GRAPH_OT_select_key_handles(wmOperatorType *ot)
|
|||
/* callbacks */
|
||||
ot->poll = graphop_visible_keyframes_poll;
|
||||
ot->exec = graphkeys_select_key_handles_exec;
|
||||
ot->ui = graphkeys_select_key_handles_ui;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
|
||||
|
|
|
@ -404,7 +404,7 @@ static void stats_update(Depsgraph *depsgraph,
|
|||
|
||||
memset(stats, 0x0, sizeof(*stats));
|
||||
|
||||
if (obedit) {
|
||||
if (obedit && (ob->type != OB_GREASE_PENCIL)) {
|
||||
/* Edit Mode. */
|
||||
FOREACH_OBJECT_BEGIN (scene, view_layer, ob_iter) {
|
||||
if (ob_iter->base_flag & BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT) {
|
||||
|
@ -829,7 +829,26 @@ void ED_info_draw_stats(
|
|||
stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
|
||||
}
|
||||
|
||||
if (obedit) {
|
||||
if (!any_selected) {
|
||||
if (any_objects) {
|
||||
/* Show scene totals if nothing is selected. */
|
||||
stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height);
|
||||
stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height);
|
||||
stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height);
|
||||
stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
|
||||
}
|
||||
else {
|
||||
/* No objects in scene. */
|
||||
stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
|
||||
}
|
||||
}
|
||||
else if ((ob) && ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL)) {
|
||||
stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height);
|
||||
stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height);
|
||||
stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height);
|
||||
stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height);
|
||||
}
|
||||
else if (obedit) {
|
||||
if (obedit->type == OB_MESH) {
|
||||
stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
|
||||
stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
|
||||
|
@ -854,28 +873,9 @@ void ED_info_draw_stats(
|
|||
stats_row(col1, labels[FACES], col2, stats_fmt.totfacesculpt, nullptr, y, height);
|
||||
}
|
||||
}
|
||||
else if (!any_selected) {
|
||||
if (any_objects) {
|
||||
/* Show scene totals if nothing is selected. */
|
||||
stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height);
|
||||
stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height);
|
||||
stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height);
|
||||
stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height);
|
||||
}
|
||||
else {
|
||||
/* No objects in scene. */
|
||||
stats_row(col1, labels[OBJ], col2, stats_fmt.totobj, nullptr, y, height);
|
||||
}
|
||||
}
|
||||
else if (ob && (object_mode & OB_MODE_POSE)) {
|
||||
stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
|
||||
}
|
||||
else if ((ob) && ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL)) {
|
||||
stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height);
|
||||
stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height);
|
||||
stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height);
|
||||
stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height);
|
||||
}
|
||||
else if ((ob) && (ob->type == OB_LAMP)) {
|
||||
stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height);
|
||||
}
|
||||
|
|
|
@ -373,54 +373,7 @@ static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg,
|
|||
const SocketDeclaration &socket_decl = *socket_decl_ptr;
|
||||
NodeLinkItem item;
|
||||
item.socket_index = index++;
|
||||
if (dynamic_cast<const decl::Float *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_FLOAT;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Int *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_INT;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Bool *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_BOOLEAN;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Vector *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_VECTOR;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Color *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_RGBA;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Rotation *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_ROTATION;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Matrix *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_MATRIX;
|
||||
}
|
||||
else if (dynamic_cast<const decl::String *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_STRING;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Menu *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_MENU;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Image *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_IMAGE;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Texture *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_TEXTURE;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Material *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_MATERIAL;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Shader *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_SHADER;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Collection *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_COLLECTION;
|
||||
}
|
||||
else if (dynamic_cast<const decl::Object *>(&socket_decl)) {
|
||||
item.socket_type = SOCK_OBJECT;
|
||||
}
|
||||
else {
|
||||
item.socket_type = SOCK_CUSTOM;
|
||||
}
|
||||
item.socket_type = socket_decl.socket_type;
|
||||
item.socket_name = socket_decl.name.c_str();
|
||||
item.node_name = arg->node_type->ui_name;
|
||||
items.append(item);
|
||||
|
|
|
@ -578,10 +578,26 @@ static int preferences_extension_repo_remove_exec(bContext *C, wmOperator *op)
|
|||
char dirpath[FILE_MAX];
|
||||
BKE_preferences_extension_repo_dirpath_get(repo, dirpath, sizeof(dirpath));
|
||||
if (dirpath[0] && BLI_is_dir(dirpath)) {
|
||||
if (BLI_delete(dirpath, true, true) != 0) {
|
||||
|
||||
/* Removing custom directories has the potential to remove user data
|
||||
* if users accidentally point this to their home directory or similar.
|
||||
* Even though the UI shows a warning, we better prevent any accidents
|
||||
* caused by recursive removal, see #119481.
|
||||
* Only check custom directories because the non-custom directory is always
|
||||
* a specific location under Blender's local extensions directory. */
|
||||
const bool recursive = (repo->flag & USER_EXTENSION_REPO_FLAG_USE_CUSTOM_DIRECTORY) == 0;
|
||||
|
||||
/* Perform package manager specific clear operations,
|
||||
* needed when `recursive` is false so the empty directory can be removed.
|
||||
* If it's not empty there will be a warning that the directory couldn't be removed.
|
||||
* The user will have to do this manually which is good since unknown files
|
||||
* could be user data. */
|
||||
BKE_callback_exec_string(bmain, BKE_CB_EVT_EXTENSION_REPOS_FILES_CLEAR, dirpath);
|
||||
|
||||
if (BLI_delete(dirpath, true, recursive) != 0) {
|
||||
BKE_reportf(op->reports,
|
||||
RPT_ERROR,
|
||||
"Error removing directory: %s",
|
||||
RPT_WARNING,
|
||||
"Unable to remove directory: %s",
|
||||
errno ? strerror(errno) : "unknown");
|
||||
}
|
||||
}
|
||||
|
@ -688,9 +704,7 @@ static void PREFERENCES_OT_extension_repo_upgrade(wmOperatorType *ot)
|
|||
/** \name Drop Extension Operator
|
||||
* \{ */
|
||||
|
||||
static int preferences_extension_url_drop_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent * /*event*/)
|
||||
static int preferences_extension_url_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
char *url = RNA_string_get_alloc(op->ptr, "url", nullptr, 0, nullptr);
|
||||
const bool url_is_remote = STRPREFIX(url, "http://") || STRPREFIX(url, "https://") ||
|
||||
|
@ -705,7 +719,7 @@ static int preferences_extension_url_drop_invoke(bContext *C,
|
|||
PointerRNA props_ptr;
|
||||
WM_operator_properties_create_ptr(&props_ptr, ot);
|
||||
RNA_string_set(&props_ptr, "url", url);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
|
||||
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, event);
|
||||
WM_operator_properties_free(&props_ptr);
|
||||
retval = OPERATOR_FINISHED;
|
||||
}
|
||||
|
|
|
@ -914,9 +914,9 @@ void ED_view3d_grid_steps(const Scene *scene,
|
|||
view3d_grid_steps_ex(scene, v3d, rv3d, r_grid_steps, nullptr, nullptr);
|
||||
}
|
||||
|
||||
float ED_view3d_grid_view_scale(Scene *scene,
|
||||
View3D *v3d,
|
||||
ARegion *region,
|
||||
float ED_view3d_grid_view_scale(const Scene *scene,
|
||||
const View3D *v3d,
|
||||
const ARegion *region,
|
||||
const char **r_grid_unit)
|
||||
{
|
||||
float grid_scale;
|
||||
|
|
|
@ -493,8 +493,8 @@ void ED_gizmotypes_preselect_3d()
|
|||
* the information from this gizmo.
|
||||
* \{ */
|
||||
|
||||
void ED_view3d_gizmo_mesh_preselect_get_active(bContext *C,
|
||||
wmGizmo *gz,
|
||||
void ED_view3d_gizmo_mesh_preselect_get_active(const bContext *C,
|
||||
const wmGizmo *gz,
|
||||
Base **r_base,
|
||||
BMElem **r_ele)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "DNA_curve_types.h"
|
||||
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_rect.h"
|
||||
|
@ -224,6 +224,7 @@ void ViewOpsData::init_navigation(bContext *C,
|
|||
const float dyn_ofs_override[3],
|
||||
const bool use_cursor_init)
|
||||
{
|
||||
using namespace blender;
|
||||
this->nav_type = nav_type;
|
||||
eViewOpsFlag viewops_flag = nav_type->flag & viewops_flag_from_prefs();
|
||||
|
||||
|
@ -285,21 +286,18 @@ void ViewOpsData::init_navigation(bContext *C,
|
|||
float my_pivot[3]; /* View pivot. */
|
||||
float dvec[3];
|
||||
|
||||
/* locals for dist correction */
|
||||
float mat[3][3];
|
||||
float upvec[3];
|
||||
|
||||
negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */
|
||||
|
||||
/* Set the dist value to be the distance from this 3d point this means you'll
|
||||
* always be able to zoom into it and panning won't go bad when dist was zero. */
|
||||
|
||||
/* remove dist value */
|
||||
float3 upvec;
|
||||
upvec[0] = upvec[1] = 0;
|
||||
upvec[2] = rv3d->dist;
|
||||
copy_m3_m4(mat, rv3d->viewinv);
|
||||
float3x3 mat = float3x3(float4x4(rv3d->viewinv));
|
||||
|
||||
mul_m3_v3(mat, upvec);
|
||||
upvec = math::transform_point(mat, upvec);
|
||||
add_v3_v3v3(my_pivot, my_origin, upvec);
|
||||
|
||||
/* find a new ofs value that is along the view axis
|
||||
|
@ -778,7 +776,8 @@ void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat_new[4])
|
|||
|
||||
bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
|
||||
{
|
||||
static float lastofs[3] = {0, 0, 0};
|
||||
using namespace blender;
|
||||
static float3 lastofs = float3(0);
|
||||
bool is_set = false;
|
||||
|
||||
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
|
@ -801,41 +800,39 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
|
|||
Curve *cu = static_cast<Curve *>(ob_act_eval->data);
|
||||
EditFont *ef = cu->editfont;
|
||||
|
||||
zero_v3(lastofs);
|
||||
lastofs = float3(0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
add_v2_v2(lastofs, ef->textcurs[i]);
|
||||
lastofs += ef->textcurs[i];
|
||||
}
|
||||
mul_v2_fl(lastofs, 1.0f / 4.0f);
|
||||
lastofs *= 0.25f;
|
||||
|
||||
mul_m4_v3(ob_act_eval->object_to_world().ptr(), lastofs);
|
||||
lastofs = math::transform_point(ob_act_eval->object_to_world(), lastofs);
|
||||
|
||||
is_set = true;
|
||||
}
|
||||
else if (ob_act == nullptr || ob_act->mode == OB_MODE_OBJECT) {
|
||||
/* Object mode uses bounding-box centers. */
|
||||
uint tot = 0;
|
||||
float select_center[3];
|
||||
int total = 0;
|
||||
float3 select_center(0);
|
||||
|
||||
zero_v3(select_center);
|
||||
LISTBASE_FOREACH (Base *, base_eval, BKE_view_layer_object_bases_get(view_layer_eval)) {
|
||||
LISTBASE_FOREACH (const Base *, base_eval, BKE_view_layer_object_bases_get(view_layer_eval)) {
|
||||
if (BASE_SELECTED(v3d, base_eval)) {
|
||||
/* Use the bounding-box if we can. */
|
||||
Object *ob_eval = base_eval->object;
|
||||
const Object *ob_eval = base_eval->object;
|
||||
|
||||
if (ob_eval->runtime->bounds_eval) {
|
||||
blender::float3 cent = blender::math::midpoint(ob_eval->runtime->bounds_eval->min,
|
||||
ob_eval->runtime->bounds_eval->max);
|
||||
mul_m4_v3(ob_eval->object_to_world().ptr(), cent);
|
||||
add_v3_v3(select_center, cent);
|
||||
if (const std::optional<Bounds<float3>> bounds = BKE_object_boundbox_get(ob_eval)) {
|
||||
const float3 center = math::midpoint(bounds->min, bounds->max);
|
||||
select_center += math::transform_point(ob_eval->object_to_world(), center);
|
||||
}
|
||||
else {
|
||||
add_v3_v3(select_center, ob_eval->object_to_world().location());
|
||||
}
|
||||
tot++;
|
||||
total++;
|
||||
}
|
||||
}
|
||||
if (tot) {
|
||||
mul_v3_fl(select_center, 1.0f / float(tot));
|
||||
if (total) {
|
||||
mul_v3_fl(select_center, 1.0f / float(total));
|
||||
copy_v3_v3(lastofs, select_center);
|
||||
is_set = true;
|
||||
}
|
||||
|
|
|
@ -1147,7 +1147,9 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
|
|||
/** \name Local Collections
|
||||
* \{ */
|
||||
|
||||
static uint free_localcollection_bit(Main *bmain, ushort local_collections_uid, bool *r_reset)
|
||||
static uint free_localcollection_bit(const Main *bmain,
|
||||
ushort local_collections_uid,
|
||||
bool *r_reset)
|
||||
{
|
||||
ushort local_view_bits = 0;
|
||||
|
||||
|
@ -1196,7 +1198,7 @@ static void local_collections_reset_uuid(LayerCollection *layer_collection,
|
|||
}
|
||||
}
|
||||
|
||||
static void view3d_local_collections_reset(Main *bmain, const uint local_view_bit)
|
||||
static void view3d_local_collections_reset(const Main *bmain, const uint local_view_bit)
|
||||
{
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
|
||||
|
@ -1207,7 +1209,7 @@ static void view3d_local_collections_reset(Main *bmain, const uint local_view_bi
|
|||
}
|
||||
}
|
||||
|
||||
bool ED_view3d_local_collections_set(Main *bmain, View3D *v3d)
|
||||
bool ED_view3d_local_collections_set(const Main *bmain, View3D *v3d)
|
||||
{
|
||||
if ((v3d->flag & V3D_LOCAL_COLLECTIONS) == 0) {
|
||||
return true;
|
||||
|
@ -1231,7 +1233,7 @@ bool ED_view3d_local_collections_set(Main *bmain, View3D *v3d)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ED_view3d_local_collections_reset(bContext *C, const bool reset_all)
|
||||
void ED_view3d_local_collections_reset(const bContext *C, const bool reset_all)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
uint local_view_bit = ~(0);
|
||||
|
|
|
@ -1478,7 +1478,7 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
|
|||
}
|
||||
}
|
||||
|
||||
/* Aftertrans does insert keyframes, and clears base flags; doesn't read transdata. */
|
||||
/* Does insert keyframes, and clears base flags; doesn't read `transdata`. */
|
||||
special_aftertrans_update(C, t);
|
||||
|
||||
postTrans(C, t);
|
||||
|
@ -2221,7 +2221,7 @@ int transformEnd(bContext *C, TransInfo *t)
|
|||
exit_code = OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
/* Aftertrans does insert keyframes, and clears base flags; doesn't read transdata. */
|
||||
/* Does insert keyframes, and clears base flags; doesn't read `transdata`. */
|
||||
special_aftertrans_update(C, t);
|
||||
|
||||
/* Free data, also handles overlap [in freeTransCustomData()]. */
|
||||
|
|
|
@ -899,6 +899,12 @@ static eSnapMode snap_obj_fn(SnapObjectContext *sctx,
|
|||
}
|
||||
|
||||
if (GS(ob_data->name) == ID_ME) {
|
||||
if (ob_eval->type == OB_CURVES_LEGACY && BKE_object_is_in_editmode(ob_eval)) {
|
||||
/* Sometimes, such as when Mesh is generated by Geometry Nodes, a Curve object may have Mesh
|
||||
* instances.
|
||||
* In these cases, skip the snap to Mesh if the Curve is in edit mode. */
|
||||
return SCE_SNAP_TO_NONE;
|
||||
}
|
||||
return snap_object_mesh(sctx, ob_eval, ob_data, obmat, sctx->runtime.snap_to_flag, use_hide);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace blender::geometry::boolean {
|
|||
/** Specifies which solver to use. */
|
||||
enum class Solver {
|
||||
/**
|
||||
* The exact solver based on the Mesh Arrangments for Solid Geometry paper,
|
||||
* The exact solver based on the Mesh Arrangements for Solid Geometry paper,
|
||||
* by Zhou, Grinspun, Zorin, and Jacobson.
|
||||
*/
|
||||
MeshArr = 0,
|
||||
|
@ -54,9 +54,9 @@ struct BooleanOpParameters {
|
|||
* If there are more than two meshes, the first mesh is operand 0 and the rest of the
|
||||
* meshes are operand 1 (i.e., as if all of operands 1, ... are joined into one mesh.
|
||||
* The exact solvers assume that the meshes are PWN (piecewise winding number,
|
||||
* which approximately means that the meshes are enclosed watertight voluems,
|
||||
* which approximately means that the meshes are enclosed watertight volumes,
|
||||
* and all edges are manifold, though there are allowable exceptions to that last condition).
|
||||
* If the meshes don't sastisfy those conditions, all solvers will try to use ray-shooting
|
||||
* If the meshes don't satisfy those conditions, all solvers will try to use ray-shooting
|
||||
* to determine whether particular faces survive or not. This may or may not work
|
||||
* in the way the user hopes.
|
||||
*
|
||||
|
|
|
@ -1000,7 +1000,7 @@ static BMesh *mesh_bm_concat(Span<const Mesh *> meshes,
|
|||
*r_looptris = looptris;
|
||||
*r_looptris_tot = looptris_tot;
|
||||
|
||||
/* Tranform the vertices that into the desired target_transform space. */
|
||||
/* Transform the vertices that into the desired target_transform space. */
|
||||
BMIter iter;
|
||||
BMVert *eve;
|
||||
int i = 0;
|
||||
|
@ -1131,7 +1131,7 @@ static Mesh *mesh_boolean_float(Span<const Mesh *> meshes,
|
|||
BM_mesh_free(bm);
|
||||
if (prev_result_mesh != nullptr) {
|
||||
/* Except in the first iteration, two_meshes[0] holds the intermediate
|
||||
* mesh result from the previous iteraiton. */
|
||||
* mesh result from the previous iteration. */
|
||||
BKE_mesh_eval_delete(prev_result_mesh);
|
||||
}
|
||||
if (i < meshes.size() - 2) {
|
||||
|
|
|
@ -1691,7 +1691,7 @@ void gpu::MTLTexture::read_internal(int mip,
|
|||
|
||||
/** Determine source read texture handle. */
|
||||
id<MTLTexture> read_texture = texture_;
|
||||
/* Use textureview handle if reading from a GPU texture view. */
|
||||
/* Use texture-view handle if reading from a GPU texture view. */
|
||||
if (resource_mode_ == MTL_TEXTURE_MODE_TEXTURE_VIEW) {
|
||||
read_texture = this->get_metal_handle();
|
||||
}
|
||||
|
|
|
@ -174,7 +174,7 @@ void GLVaoCache::clear()
|
|||
if (context_) {
|
||||
context_->vao_cache_unregister(this);
|
||||
}
|
||||
/* Reinit. */
|
||||
/* Reinitialize. */
|
||||
this->init();
|
||||
}
|
||||
|
||||
|
|
|
@ -232,3 +232,67 @@ float wang_hash_noise(uint s)
|
|||
|
||||
return fract(float(s) / 4294967296.0);
|
||||
}
|
||||
|
||||
/* PCG */
|
||||
|
||||
/* https://www.pcg-random.org/ */
|
||||
uint pcg_uint(uint u)
|
||||
{
|
||||
uint state = u * 747796405u + 2891336453u;
|
||||
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||
return (word >> 22u) ^ word;
|
||||
}
|
||||
|
||||
float pcg(float v)
|
||||
{
|
||||
return pcg_uint(floatBitsToUint(v)) / float(0xffffffffU);
|
||||
}
|
||||
|
||||
float pcg(vec2 v)
|
||||
{
|
||||
/* Nested pcg (faster and better quality that pcg2d). */
|
||||
uvec2 u = floatBitsToUint(v);
|
||||
return pcg_uint(pcg_uint(u.x) + u.y) / float(0xffffffffU);
|
||||
}
|
||||
|
||||
/* http://www.jcgt.org/published/0009/03/02/ */
|
||||
vec3 pcg3d(vec3 v)
|
||||
{
|
||||
uvec3 u = floatBitsToUint(v);
|
||||
|
||||
u = u * 1664525u + 1013904223u;
|
||||
|
||||
u.x += u.y * u.z;
|
||||
u.y += u.z * u.x;
|
||||
u.z += u.x * u.y;
|
||||
|
||||
u ^= u >> 16u;
|
||||
|
||||
u.x += u.y * u.z;
|
||||
u.y += u.z * u.x;
|
||||
u.z += u.x * u.y;
|
||||
|
||||
return vec3(u) / float(0xffffffffU);
|
||||
}
|
||||
|
||||
/* http://www.jcgt.org/published/0009/03/02/ */
|
||||
vec4 pcg4d(vec4 v)
|
||||
{
|
||||
uvec4 u = floatBitsToUint(v);
|
||||
|
||||
u = u * 1664525u + 1013904223u;
|
||||
|
||||
u.x += u.y * u.w;
|
||||
u.y += u.z * u.x;
|
||||
u.z += u.x * u.y;
|
||||
u.w += u.y * u.z;
|
||||
|
||||
u ^= u >> 16u;
|
||||
|
||||
u.x += u.y * u.w;
|
||||
u.y += u.z * u.x;
|
||||
u.z += u.x * u.y;
|
||||
u.w += u.y * u.z;
|
||||
|
||||
return vec4(u) / float(0xffffffffU);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifdef USE_GEOMETRY_SHADER
|
||||
#if defined(USE_GEOMETRY_SHADER) || defined(USE_GEOMETRY_IFACE_COLOR)
|
||||
vec4 fragment_in_color()
|
||||
{
|
||||
return geometry_out.mColor;
|
||||
|
|
|
@ -97,13 +97,13 @@ bool is_equal(vec4 p1, vec4 p2)
|
|||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 + finalThickness[2] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
(sp1 + finalThickness[1] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V1_a \
|
||||
geometry_out.mTexCoord = vec2(0, 0); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 + finalThickness[2] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
(sp1 + finalThickness[1] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V2_a \
|
||||
geometry_out.mTexCoord = vec2(0, 0.5); \
|
||||
|
@ -114,12 +114,12 @@ bool is_equal(vec4 p1, vec4 p2)
|
|||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 - finalThickness[2] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
(sp1 - finalThickness[1] * n1) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
#define V1_b \
|
||||
geometry_out.mTexCoord = vec2(0, 1); \
|
||||
geometry_out.mColor = finalColor[1]; \
|
||||
gl_Position = vec4( \
|
||||
(sp1 - finalThickness[2] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
(sp1 - finalThickness[1] * n0) / gpencil_stroke_data.viewport, getZdepth(P1), 1.0);
|
||||
|
||||
#define V2_b \
|
||||
geometry_out.mTexCoord = vec2(0, 0.5); \
|
||||
|
@ -197,6 +197,11 @@ bool is_equal(vec4 p1, vec4 p2)
|
|||
vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; \
|
||||
gl_Position = vec4((sp2 + svn2) / gpencil_stroke_data.viewport, getZdepth(P2), 1.0);
|
||||
|
||||
vec4 uchar4_to_normalized_vec4(uchar4 udata)
|
||||
{
|
||||
return vec4(udata) / vec4(255.0f);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
/* Determine output geometry IDs. */
|
||||
|
@ -215,7 +220,9 @@ void main(void)
|
|||
for (int i = 0; i < 4; i++) {
|
||||
finalPos[i] = ModelViewProjectionMatrix *
|
||||
vec4(vertex_fetch_attribute(input_prim_id + i, pos, vec3).xyz, 1.0);
|
||||
finalColor[i] = vertex_fetch_attribute(input_prim_id + i, color, vec4);
|
||||
/* Color attribute uses GPU_FETCH_INT_TO_FLOAT_UNIT with GPU_COMP_U8. */
|
||||
finalColor[i] = uchar4_to_normalized_vec4(
|
||||
vertex_fetch_attribute(input_prim_id + i, color, uchar4));
|
||||
float in_thickness = vertex_fetch_attribute(input_prim_id + i, thickness, float);
|
||||
|
||||
if (gpencil_stroke_data.keep_size) {
|
||||
|
@ -223,7 +230,7 @@ void main(void)
|
|||
}
|
||||
else {
|
||||
float size = (ProjectionMatrix[3][3] == 0.0) ?
|
||||
(in_thickness / (gl_Position.z * defaultpixsize)) :
|
||||
(in_thickness / (finalPos[i].z * defaultpixsize)) :
|
||||
(in_thickness / defaultpixsize);
|
||||
finalThickness[i] = max(size * gpencil_stroke_data.objscale, 1.0);
|
||||
}
|
||||
|
@ -296,8 +303,14 @@ void main(void)
|
|||
}
|
||||
|
||||
/** Geometry output. */
|
||||
/* First triangle (T0). prevent excessively long miters at sharp
|
||||
* corners */
|
||||
|
||||
/* prevent excessively long miters at sharp corners */
|
||||
if (dot(v0, v1) < -MiterLimit) {
|
||||
miter_a = n1;
|
||||
length_a = finalThickness[1];
|
||||
}
|
||||
|
||||
/* First triangle (T0). */
|
||||
if (output_prim_triangle_id == 0) {
|
||||
if (dot(v0, v1) < -MiterLimit) {
|
||||
if (dot(v0, n1) > 0) {
|
||||
|
|
|
@ -39,6 +39,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke)
|
|||
|
||||
GPU_SHADER_CREATE_INFO(gpu_shader_gpencil_stroke_no_geom)
|
||||
.metal_backend_only(true)
|
||||
.define("USE_GEOMETRY_IFACE_COLOR")
|
||||
.additional_info("gpu_shader_gpencil_stroke_base")
|
||||
.vertex_out(gpencil_stroke_geom_iface)
|
||||
.vertex_source("gpu_shader_gpencil_stroke_vert_no_geom.glsl")
|
||||
|
|
|
@ -673,7 +673,7 @@ void colormanagement_init()
|
|||
}
|
||||
}
|
||||
|
||||
/* Then try bunded config file. */
|
||||
/* Then try bundled configuration file. */
|
||||
if (config == nullptr) {
|
||||
const std::optional<std::string> configdir = BKE_appdir_folder_id(BLENDER_DATAFILES,
|
||||
"colormanagement");
|
||||
|
@ -3952,6 +3952,19 @@ bool IMB_colormanagement_processor_is_noop(ColormanageProcessor *cm_processor)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!cm_processor->cpu_processor) {
|
||||
/* The CPU processor might have failed to be created, for example when the requested color
|
||||
* space does not exist in the configuration, or if there is a missing lookup table, or the
|
||||
* configuration is invalid due to other reasons.
|
||||
*
|
||||
* The actual processing checks for the cpu_processor not being null pointer, and it if is then
|
||||
* processing does not apply it. However, processing could still apply curve mapping.
|
||||
*
|
||||
* Hence a null-pointer here, which happens after the curve mapping check, but before accessing
|
||||
* cpu_processor. */
|
||||
return true;
|
||||
}
|
||||
|
||||
return OCIO_cpuProcessorIsNoOp(cm_processor->cpu_processor);
|
||||
}
|
||||
|
||||
|
|
|
@ -158,16 +158,17 @@ void USDPointInstancerReader::read_object_data(Main *bmain, const double motionS
|
|||
|
||||
ModifierData *md = BKE_modifier_new(eModifierType_Nodes);
|
||||
BLI_addtail(&object_->modifiers, md);
|
||||
BKE_modifiers_persistent_uid_init(*object_, *md);
|
||||
|
||||
NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
|
||||
nmd.node_group = ntreeAddTree(bmain, "Instances", "GeometryNodeTree");
|
||||
|
||||
bNodeTree *ntree = nmd.node_group;
|
||||
|
||||
ntree->tree_interface.add_socket("Geometry",
|
||||
"",
|
||||
"NodeSocketGeometry",
|
||||
NODE_INTERFACE_SOCKET_INPUT | NODE_INTERFACE_SOCKET_OUTPUT,
|
||||
nullptr);
|
||||
ntree->tree_interface.add_socket(
|
||||
"Geometry", "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_OUTPUT, nullptr);
|
||||
ntree->tree_interface.add_socket(
|
||||
"Geometry", "", "NodeSocketGeometry", NODE_INTERFACE_SOCKET_INPUT, nullptr);
|
||||
bNode *group_input = nodeAddStaticNode(nullptr, ntree, NODE_GROUP_INPUT);
|
||||
group_input->locx = -400.0f;
|
||||
bNode *group_output = nodeAddStaticNode(nullptr, ntree, NODE_GROUP_OUTPUT);
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
.shadow_softness_factor = 1.0f, \
|
||||
.shadow_trace_distance = 10.0f, \
|
||||
.shadow_filter_radius = 3.0f, \
|
||||
.shadow_resolution_scale = 1.0f, \
|
||||
.att_dist = 40.0f, \
|
||||
.sun_angle = DEG2RADF(0.526f), \
|
||||
.area_spread = DEG2RADF(180.0f), \
|
||||
|
|
|
@ -78,6 +78,9 @@ typedef struct Light {
|
|||
float shadow_softness_factor;
|
||||
float shadow_trace_distance;
|
||||
float shadow_filter_radius;
|
||||
float shadow_resolution_scale;
|
||||
|
||||
float _pad0;
|
||||
|
||||
/* Preview */
|
||||
struct PreviewImage *preview;
|
||||
|
|
|
@ -1019,7 +1019,7 @@
|
|||
.strength = 1.0f, \
|
||||
.skip = 0, \
|
||||
}
|
||||
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencilOutlineModifierData \
|
||||
{ \
|
||||
.flag = MOD_GREASE_PENCIL_OUTLINE_KEEP_SHAPE, \
|
||||
|
@ -1044,4 +1044,22 @@
|
|||
.smooth_step = 1, \
|
||||
}
|
||||
|
||||
/* Here we deliberately set effective range to the half the default
|
||||
* frame-range to have an immediate effect to suggest use-cases. */
|
||||
#define _DNA_DEFAULT_GreasePencilBuildModifierData \
|
||||
{ \
|
||||
.start_frame = 1, \
|
||||
.end_frame = 125, \
|
||||
.start_delay = 0.0f, \
|
||||
.length = 100.0f, \
|
||||
.flag = 0, \
|
||||
.mode = 0, \
|
||||
.transition = 0, \
|
||||
.time_alignment = 0, \
|
||||
.time_mode = 0, \
|
||||
.speed_fac = 1.2f, \
|
||||
.speed_maxgap = 0.5f, \
|
||||
.percentage_fac = 0.0f, \
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
|
|
|
@ -118,6 +118,7 @@ typedef enum ModifierType {
|
|||
eModifierType_GreasePencilEnvelope = 81,
|
||||
eModifierType_GreasePencilOutline = 82,
|
||||
eModifierType_GreasePencilShrinkwrap = 83,
|
||||
eModifierType_GreasePencilBuild = 84,
|
||||
NUM_MODIFIER_TYPES,
|
||||
} ModifierType;
|
||||
|
||||
|
@ -3310,3 +3311,96 @@ typedef struct GreasePencilShrinkwrapModifierData {
|
|||
/** Runtime only. */
|
||||
struct ShrinkwrapTreeData *cache_data;
|
||||
} GreasePencilShrinkwrapModifierData;
|
||||
|
||||
typedef struct GreasePencilBuildModifierData {
|
||||
ModifierData modifier;
|
||||
GreasePencilModifierInfluenceData influence;
|
||||
/**
|
||||
* If GP_BUILD_RESTRICT_TIME is set,
|
||||
* the defines the frame range where GP frames are considered.
|
||||
*/
|
||||
float start_frame;
|
||||
float end_frame;
|
||||
|
||||
/** Start time added on top of the drawing frame number */
|
||||
float start_delay;
|
||||
float length;
|
||||
|
||||
/** #GreasePencilBuildFlag. */
|
||||
short flag;
|
||||
|
||||
/** #GreasePencilBuildMode. */
|
||||
short mode;
|
||||
/** #GreasePencilBuildTransition. */
|
||||
short transition;
|
||||
|
||||
/**
|
||||
* #GreasePencilBuildTimeAlignment.
|
||||
* For the "Concurrent" mode, when should "shorter" strips start/end.
|
||||
*/
|
||||
short time_alignment;
|
||||
|
||||
/** Speed factor for #GP_BUILD_TIMEMODE_DRAWSPEED. */
|
||||
float speed_fac;
|
||||
/** Maximum time gap between strokes for #GP_BUILD_TIMEMODE_DRAWSPEED. */
|
||||
float speed_maxgap;
|
||||
/** GreasePencilBuildTimeMode. */
|
||||
short time_mode;
|
||||
char _pad[6];
|
||||
|
||||
/** Build origin control object. */
|
||||
struct Object *object;
|
||||
|
||||
/** Factor of the stroke (used instead of frame evaluation). */
|
||||
float percentage_fac;
|
||||
|
||||
/** Weight fading at the end of the stroke. */
|
||||
float fade_fac;
|
||||
/** Target vertex-group name, #MAX_VGROUP_NAME. */
|
||||
char target_vgname[64];
|
||||
/** Fading strength of opacity and thickness */
|
||||
float fade_opacity_strength;
|
||||
float fade_thickness_strength;
|
||||
} GreasePencilBuildModifierData;
|
||||
|
||||
typedef enum GreasePencilBuildMode {
|
||||
/* Strokes are shown one by one until all have appeared */
|
||||
MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL = 0,
|
||||
/* All strokes start at the same time */
|
||||
MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT = 1,
|
||||
/* Only the new strokes are built */
|
||||
MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE = 2,
|
||||
} GreasePencilBuildMode;
|
||||
|
||||
typedef enum GreasePencilBuildTransition {
|
||||
/* Show in forward order */
|
||||
MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW = 0,
|
||||
/* Hide in reverse order */
|
||||
MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK = 1,
|
||||
/* Hide in forward order */
|
||||
MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH = 2,
|
||||
} GreasePencilBuildTransition;
|
||||
|
||||
typedef enum GreasePencilBuildTimeAlignment {
|
||||
/* All strokes start at same time */
|
||||
MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START = 0,
|
||||
/* All strokes end at same time */
|
||||
MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END = 1,
|
||||
|
||||
/* TODO: Random Offsets, Stretch-to-Fill */
|
||||
} GreasePencilBuildTimeAlignment;
|
||||
|
||||
typedef enum GreasePencilBuildTimeMode {
|
||||
/** Use a number of frames build. */
|
||||
MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES = 0,
|
||||
/** Use manual percentage to build. */
|
||||
MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE = 1,
|
||||
/** Use factor of recorded speed to build. */
|
||||
MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED = 2,
|
||||
} GreasePencilBuildTimeMode;
|
||||
|
||||
typedef enum GreasePencilBuildFlag {
|
||||
/* Restrict modifier to only operating between the nominated frames */
|
||||
MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME = (1 << 0),
|
||||
MOD_GREASE_PENCIL_BUILD_USE_FADING = (1 << 14),
|
||||
} GreasePencilBuildFlag;
|
||||
|
|
|
@ -2887,6 +2887,7 @@ enum {
|
|||
SCE_EEVEE_DOF_JITTER = (1 << 23),
|
||||
SCE_EEVEE_SHADOW_ENABLED = (1 << 24),
|
||||
SCE_EEVEE_RAYTRACE_OPTIONS_SPLIT = (1 << 25),
|
||||
SCE_EEVEE_SHADOW_JITTERED_VIEWPORT = (1 << 26),
|
||||
};
|
||||
|
||||
typedef enum RaytraceEEVEE_Flag {
|
||||
|
|
|
@ -305,6 +305,7 @@ SDNA_DEFAULT_DECL_STRUCT(GreasePencilSubdivModifierData);
|
|||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilNoiseModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLengthModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLineartModifierData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilBuildModifierData);
|
||||
|
||||
/* Grease Pencil 3.0 modifiers. */
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencilSmoothModifierData);
|
||||
|
@ -581,6 +582,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
|||
SDNA_DEFAULT_DECL(GreasePencilLengthModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilHookModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilLineartModifierData),
|
||||
SDNA_DEFAULT_DECL(GreasePencilBuildModifierData),
|
||||
|
||||
/* Grease Pencil 3.0 defaults. */
|
||||
SDNA_DEFAULT_DECL(GreasePencilSmoothModifierData),
|
||||
|
|
|
@ -304,6 +304,17 @@ static void rna_def_light_shadow(StructRNA *srna, bool sun)
|
|||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_update(prop, 0, "rna_Light_update");
|
||||
|
||||
prop = RNA_def_property(srna, "shadow_resolution_scale", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_range(prop, 0.0f, 2.0f);
|
||||
RNA_def_property_ui_range(prop, 0.0f, 2.0f, 0.25f, 2);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Shadow Resolution Scale",
|
||||
"Scale the Shadow Map target resolution, where 1.0 tries to match shadow map and screen "
|
||||
"pixel density. (The scale is applied on top of the scene Simplify Shadow Resolution)");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY);
|
||||
RNA_def_property_update(prop, 0, "rna_Light_update");
|
||||
|
||||
if (sun) {
|
||||
prop = RNA_def_property(srna, "shadow_cascade_max_distance", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "cascade_max_dist");
|
||||
|
|
|
@ -234,6 +234,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
|
|||
ICON_MOD_ARRAY,
|
||||
"Array strokes",
|
||||
"Duplicate strokes into an array"},
|
||||
{eModifierType_GreasePencilBuild,
|
||||
"GREASE_PENCIL_BUILD",
|
||||
ICON_MOD_BUILD,
|
||||
"Build",
|
||||
"Grease Pencil build modifier"},
|
||||
{eModifierType_GreasePencilLength,
|
||||
"GREASE_PENCIL_LENGTH",
|
||||
ICON_MOD_LENGTH,
|
||||
|
@ -784,6 +789,25 @@ const EnumPropertyItem rna_enum_subdivision_boundary_smooth_items[] = {
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem grease_pencil_build_time_mode_items[] = {
|
||||
{MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED,
|
||||
"DRAWSPEED",
|
||||
0,
|
||||
"Natural Drawing Speed",
|
||||
"Use recorded speed multiplied by a factor"},
|
||||
{MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES,
|
||||
"FRAMES",
|
||||
0,
|
||||
"Number of Frames",
|
||||
"Set a fixed number of frames for all build animations"},
|
||||
{MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE,
|
||||
"PERCENTAGE",
|
||||
0,
|
||||
"Percentage Factor",
|
||||
"Set a manual percentage to build"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include <algorithm>
|
||||
|
@ -944,6 +968,7 @@ RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name);
|
|||
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightAngle, target_vgname);
|
||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilWeightProximity, target_vgname);
|
||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilLineart, vgname);
|
||||
RNA_MOD_VGROUP_NAME_SET(GreasePencilBuild, target_vgname);
|
||||
|
||||
static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
|
@ -1029,6 +1054,7 @@ RNA_MOD_OBJECT_SET(GreasePencilArmature, object, OB_ARMATURE);
|
|||
RNA_MOD_OBJECT_SET(GreasePencilOutline, object, OB_EMPTY);
|
||||
RNA_MOD_OBJECT_SET(GreasePencilShrinkwrap, target, OB_MESH);
|
||||
RNA_MOD_OBJECT_SET(GreasePencilShrinkwrap, aux_target, OB_MESH);
|
||||
RNA_MOD_OBJECT_SET(GreasePencilBuild, object, OB_EMPTY);
|
||||
|
||||
static void rna_HookModifier_object_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
|
@ -1969,6 +1995,7 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilHook);
|
|||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilEnvelope);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilOutline);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilShrinkwrap);
|
||||
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilBuild);
|
||||
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
|
||||
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
|
||||
|
@ -2089,6 +2116,35 @@ static void rna_GreasePencilDashModifier_segments_begin(CollectionPropertyIterat
|
|||
nullptr);
|
||||
}
|
||||
|
||||
const EnumPropertyItem *grease_pencil_build_time_mode_filter(bContext * /*C*/,
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA * /*prop*/,
|
||||
bool *r_free)
|
||||
{
|
||||
|
||||
auto *md = static_cast<ModifierData *>(ptr->data);
|
||||
auto *mmd = reinterpret_cast<BuildGpencilModifierData *>(md);
|
||||
const bool is_concurrent = (mmd->mode == MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT);
|
||||
|
||||
EnumPropertyItem *item_list = nullptr;
|
||||
int totitem = 0;
|
||||
|
||||
for (const EnumPropertyItem *item = grease_pencil_build_time_mode_items;
|
||||
item->identifier != nullptr;
|
||||
item++)
|
||||
{
|
||||
if (is_concurrent && (item->value == MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED)) {
|
||||
continue;
|
||||
}
|
||||
RNA_enum_item_add(&item_list, &totitem, item);
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&item_list, &totitem);
|
||||
*r_free = true;
|
||||
|
||||
return item_list;
|
||||
}
|
||||
|
||||
static const GreasePencilTimeModifierData *find_grease_pencil_time_modifier_of_segment(
|
||||
const Object &ob, const GreasePencilTimeModifierSegment &time_segment)
|
||||
{
|
||||
|
@ -10444,6 +10500,217 @@ static void rna_def_modifier_grease_pencil_shrinkwrap(BlenderRNA *brna)
|
|||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
static void rna_def_modifier_grease_pencil_build(BlenderRNA *brna)
|
||||
{
|
||||
static EnumPropertyItem prop_gpencil_build_mode_items[] = {
|
||||
{MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL,
|
||||
"SEQUENTIAL",
|
||||
0,
|
||||
"Sequential",
|
||||
"Strokes appear/disappear one after the other, but only a single one changes at a time"},
|
||||
{MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT,
|
||||
"CONCURRENT",
|
||||
0,
|
||||
"Concurrent",
|
||||
"Multiple strokes appear/disappear at once"},
|
||||
{MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE,
|
||||
"ADDITIVE",
|
||||
0,
|
||||
"Additive",
|
||||
"Builds only new strokes (assuming 'additive' drawing)"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static EnumPropertyItem prop_gpencil_build_transition_items[] = {
|
||||
{MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW,
|
||||
"GROW",
|
||||
0,
|
||||
"Grow",
|
||||
"Show points in the order they occur in each stroke "
|
||||
"(e.g. for animating lines being drawn)"},
|
||||
{MOD_GREASE_PENCIL_BUILD_TRANSITION_SHRINK,
|
||||
"SHRINK",
|
||||
0,
|
||||
"Shrink",
|
||||
"Hide points from the end of each stroke to the start "
|
||||
"(e.g. for animating lines being erased)"},
|
||||
{MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH,
|
||||
"FADE", /* "Fade" is the original id string kept for compatibility purpose. */
|
||||
0,
|
||||
"Vanish",
|
||||
"Hide points in the order they occur in each stroke "
|
||||
"(e.g. for animating ink fading or vanishing after getting drawn)"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static EnumPropertyItem prop_gpencil_build_time_align_items[] = {
|
||||
{MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START,
|
||||
"START",
|
||||
0,
|
||||
"Align Start",
|
||||
"All strokes start at same time (i.e. short strokes finish earlier)"},
|
||||
{MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END,
|
||||
"END",
|
||||
0,
|
||||
"Align End",
|
||||
"All strokes end at same time (i.e. short strokes start later)"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "GreasePencilBuildModifier", "Modifier");
|
||||
RNA_def_struct_ui_text(srna, "Build Modifier", "Animate strokes appearing and disappearing");
|
||||
RNA_def_struct_sdna(srna, "GreasePencilBuildModifierData");
|
||||
RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD);
|
||||
|
||||
rna_def_modifier_grease_pencil_layer_filter(srna);
|
||||
rna_def_modifier_grease_pencil_material_filter(
|
||||
srna, "rna_GreasePencilBuildModifier_material_filter_set");
|
||||
|
||||
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 0);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_frame_range_panel", 1);
|
||||
rna_def_modifier_panel_open_prop(srna, "open_fading_panel", 2);
|
||||
|
||||
RNA_define_lib_overridable(true);
|
||||
|
||||
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, prop_gpencil_build_mode_items);
|
||||
RNA_def_property_ui_text(prop, "Mode", "How strokes are being built");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "transition", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, prop_gpencil_build_transition_items);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Transition", "How are strokes animated (i.e. are they appearing or disappearing)");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "start_delay", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "start_delay");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Delay", "Number of frames after each GP keyframe before the modifier has any effect");
|
||||
RNA_def_property_range(prop, 0, MAXFRAMEF);
|
||||
RNA_def_property_ui_range(prop, 0, 200, 1, -1);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "length", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "length");
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Length",
|
||||
"Maximum number of frames that the build effect can run for "
|
||||
"(unless another GP keyframe occurs before this time has elapsed)");
|
||||
RNA_def_property_range(prop, 1, MAXFRAMEF);
|
||||
RNA_def_property_ui_range(prop, 1, 1000, 1, -1);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "concurrent_time_alignment", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "time_alignment");
|
||||
RNA_def_property_enum_items(prop, prop_gpencil_build_time_align_items);
|
||||
RNA_def_property_ui_text(prop, "Time Alignment", "How should strokes start to appear/disappear");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "time_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "time_mode");
|
||||
RNA_def_property_enum_items(prop, grease_pencil_build_time_mode_items);
|
||||
RNA_def_property_enum_funcs(prop, nullptr, nullptr, "grease_pencil_build_time_mode_filter");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Timing",
|
||||
"Use drawing speed, a number of frames, or a manual factor to build strokes");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
/* Speed factor for MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED. */
|
||||
/* Todo: Does it work? */
|
||||
prop = RNA_def_property(srna, "speed_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "speed_fac");
|
||||
RNA_def_property_ui_text(prop, "Speed Factor", "Multiply recorded drawing speed by a factor");
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_range(prop, 0, 5, 0.001, -1);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
/* Max gap in seconds between strokes for MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED. */
|
||||
prop = RNA_def_property(srna, "speed_maxgap", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "speed_maxgap");
|
||||
RNA_def_property_ui_text(prop, "Maximum Gap", "The maximum gap between strokes in seconds");
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_range(prop, 0, 4, 0.01, -1);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_restrict_frame_range", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Restrict Frame Range", "Only modify strokes during the specified frame range");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
/* Use percentage bool (used by sequential & concurrent modes) */
|
||||
prop = RNA_def_property(srna, "use_percentage", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "time_mode", MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Restrict Visible Points", "Use a percentage factor to determine the visible points");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
prop = RNA_def_property(srna, "percentage_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "percentage_fac");
|
||||
RNA_def_property_ui_text(prop, "Factor", "Defines how much of the stroke is visible");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "frame_start", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "start_frame");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Start Frame", "Start Frame (when Restrict Frame Range is enabled)");
|
||||
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "frame_end", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "end_frame");
|
||||
RNA_def_property_ui_text(prop, "End Frame", "End Frame (when Restrict Frame Range is enabled)");
|
||||
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_fading", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", MOD_GREASE_PENCIL_BUILD_USE_FADING);
|
||||
RNA_def_property_ui_text(prop, "Use Fading", "Fade out strokes instead of directly cutting off");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fade_factor", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "fade_fac");
|
||||
RNA_def_property_ui_text(prop, "Fade Factor", "Defines how much of the stroke is fading in/out");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "target_vertex_group", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_string_sdna(prop, nullptr, "target_vgname");
|
||||
RNA_def_property_ui_text(prop, "Vertex Group", "Output Vertex group");
|
||||
RNA_def_property_string_funcs(
|
||||
prop, nullptr, nullptr, "rna_GreasePencilBuildModifier_target_vgname_set");
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fade_opacity_strength", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "fade_opacity_strength");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Opacity Strength", "How much strength fading applies on top of stroke opacity");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "fade_thickness_strength", PROP_FLOAT, PROP_FACTOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "fade_thickness_strength");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Thickness Strength", "How much strength fading applies on top of stroke thickness");
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_update");
|
||||
|
||||
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Object", "Object used as build starting position");
|
||||
RNA_def_property_pointer_funcs(
|
||||
prop, nullptr, "rna_GreasePencilBuildModifier_object_set", nullptr, nullptr);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
|
||||
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
}
|
||||
|
||||
void RNA_def_modifier(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
|
@ -10636,6 +10903,7 @@ void RNA_def_modifier(BlenderRNA *brna)
|
|||
rna_def_modifier_grease_pencil_envelope(brna);
|
||||
rna_def_modifier_grease_pencil_outline(brna);
|
||||
rna_def_modifier_grease_pencil_shrinkwrap(brna);
|
||||
rna_def_modifier_grease_pencil_build(brna);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2071,6 +2071,10 @@ static void object_simplify_update(Scene *scene,
|
|||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
}
|
||||
|
||||
if (ob->type == OB_LAMP) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Scene_simplify_update_impl(Main *bmain,
|
||||
|
@ -8034,6 +8038,14 @@ static void rna_def_scene_eevee(BlenderRNA *brna)
|
|||
prop, "Tracing Method", "Select the tracing method used to find scene-ray intersections");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||
|
||||
prop = RNA_def_property(srna, "use_shadow_jittered_viewport", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "flag", SCE_EEVEE_SHADOW_JITTERED_VIEWPORT);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Jittered Shadows (Viewport)",
|
||||
"Enable jittered shadows on the viewport. (Jittered shadows are always "
|
||||
"enabled for final renders)");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, nullptr);
|
||||
|
||||
/* Volumetrics */
|
||||
prop = RNA_def_property(srna, "volumetric_start", PROP_FLOAT, PROP_DISTANCE);
|
||||
RNA_def_property_ui_text(prop, "Start", "Start distance of the volumetric effect");
|
||||
|
|
|
@ -1610,7 +1610,7 @@ static StructRNA *rna_Operator_register(Main *bmain,
|
|||
}
|
||||
|
||||
/* XXX, this doubles up with the operator name #29666.
|
||||
* for now just remove from dir(bpy.types) */
|
||||
* for now just remove from `dir(bpy.types)`. */
|
||||
|
||||
/* create a new operator type */
|
||||
dummy_ot.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummy_ot.idname, &RNA_Operator);
|
||||
|
@ -1783,7 +1783,7 @@ static StructRNA *rna_MacroOperator_register(Main *bmain,
|
|||
}
|
||||
|
||||
/* XXX, this doubles up with the operator name #29666.
|
||||
* for now just remove from dir(bpy.types) */
|
||||
* for now just remove from `dir(bpy.types)`. */
|
||||
|
||||
/* create a new operator type */
|
||||
dummy_ot.rna_ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummy_ot.idname, &RNA_Operator);
|
||||
|
|
|
@ -51,6 +51,7 @@ set(SRC
|
|||
intern/MOD_fluid.cc
|
||||
intern/MOD_grease_pencil_armature.cc
|
||||
intern/MOD_grease_pencil_array.cc
|
||||
intern/MOD_grease_pencil_build.cc
|
||||
intern/MOD_grease_pencil_color.cc
|
||||
intern/MOD_grease_pencil_dash.cc
|
||||
intern/MOD_grease_pencil_envelope.cc
|
||||
|
|
|
@ -96,6 +96,7 @@ extern ModifierTypeInfo modifierType_GreasePencilTime;
|
|||
extern ModifierTypeInfo modifierType_GreasePencilEnvelope;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilOutline;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilShrinkwrap;
|
||||
extern ModifierTypeInfo modifierType_GreasePencilBuild;
|
||||
|
||||
/* MOD_util.cc */
|
||||
|
||||
|
|
|
@ -0,0 +1,801 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup modifiers
|
||||
*/
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_sort.hh"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BLO_read_write.hh"
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_lib_query.hh"
|
||||
#include "BKE_modifier.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
#include "UI_resources.hh"
|
||||
|
||||
#include "MOD_grease_pencil_util.hh"
|
||||
#include "MOD_modifiertypes.hh"
|
||||
#include "MOD_ui_common.hh"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
|
||||
#include "GEO_reorder.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
static void init_data(ModifierData *md)
|
||||
{
|
||||
auto *gpmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||
|
||||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(GreasePencilBuildModifierData), modifier);
|
||||
modifier::greasepencil::init_influence_data(&gpmd->influence, false);
|
||||
}
|
||||
|
||||
static void copy_data(const ModifierData *md, ModifierData *target, int flags)
|
||||
{
|
||||
const auto *omd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
|
||||
auto *tomd = reinterpret_cast<GreasePencilBuildModifierData *>(target);
|
||||
|
||||
modifier::greasepencil::free_influence_data(&tomd->influence);
|
||||
|
||||
BKE_modifier_copydata_generic(md, target, flags);
|
||||
modifier::greasepencil::copy_influence_data(&omd->influence, &tomd->influence, flags);
|
||||
}
|
||||
|
||||
static void free_data(ModifierData *md)
|
||||
{
|
||||
auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||
modifier::greasepencil::free_influence_data(&omd->influence);
|
||||
}
|
||||
|
||||
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
|
||||
{
|
||||
auto *omd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||
modifier::greasepencil::foreach_influence_ID_link(&omd->influence, ob, walk, user_data);
|
||||
}
|
||||
|
||||
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||
if (mmd->object != nullptr) {
|
||||
DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
|
||||
}
|
||||
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Build Modifier");
|
||||
}
|
||||
|
||||
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
|
||||
{
|
||||
const auto *mmd = reinterpret_cast<const GreasePencilBuildModifierData *>(md);
|
||||
|
||||
BLO_write_struct(writer, GreasePencilBuildModifierData, mmd);
|
||||
modifier::greasepencil::write_influence_data(writer, &mmd->influence);
|
||||
}
|
||||
|
||||
static void blend_read(BlendDataReader *reader, ModifierData *md)
|
||||
{
|
||||
auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||
|
||||
modifier::greasepencil::read_influence_data(reader, &mmd->influence);
|
||||
}
|
||||
|
||||
static Array<int> point_counts_to_keep_concurrent(const bke::CurvesGeometry &curves,
|
||||
const IndexMask &selection,
|
||||
const int time_alignment,
|
||||
const int transition,
|
||||
const float factor,
|
||||
const bool clamp_points,
|
||||
int &r_curves_num,
|
||||
int &r_points_num)
|
||||
{
|
||||
const int stroke_count = curves.curves_num();
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
|
||||
curves.ensure_evaluated_lengths();
|
||||
float max_length = 0;
|
||||
for (const int stroke : curves.curves_range()) {
|
||||
const float len = curves.evaluated_length_total_for_curve(stroke, false);
|
||||
max_length = math::max(max_length, len);
|
||||
}
|
||||
|
||||
float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
|
||||
1.0f - factor;
|
||||
if (clamp_points) {
|
||||
r_curves_num = r_points_num = 0;
|
||||
factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
auto get_stroke_factor = [&](const float factor, const int index) {
|
||||
const float max_factor = max_length / curves.evaluated_length_total_for_curve(index, false);
|
||||
if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_START) {
|
||||
if (clamp_points) {
|
||||
return std::clamp(factor * max_factor, 0.0f, 1.0f);
|
||||
}
|
||||
return factor * max_factor;
|
||||
}
|
||||
if (time_alignment == MOD_GREASE_PENCIL_BUILD_TIMEALIGN_END) {
|
||||
const float min_factor = max_factor - 1.0f;
|
||||
const float use_factor = factor * max_factor;
|
||||
if (clamp_points) {
|
||||
return std::clamp(use_factor - min_factor, 0.0f, 1.0f);
|
||||
}
|
||||
return use_factor - min_factor;
|
||||
}
|
||||
return 0.0f;
|
||||
};
|
||||
|
||||
Array<bool> select(stroke_count);
|
||||
selection.to_bools(select.as_mutable_span());
|
||||
Array<int> result(stroke_count);
|
||||
for (const int curve : curves.curves_range()) {
|
||||
const float local_factor = select[curve] ? get_stroke_factor(factor_to_keep, curve) : 1.0f;
|
||||
const int num_points = points_by_curve[curve].size() * local_factor;
|
||||
result[curve] = num_points;
|
||||
if (clamp_points) {
|
||||
r_points_num += num_points;
|
||||
if (num_points > 0) {
|
||||
r_curves_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bke::CurvesGeometry build_concurrent(bke::greasepencil::Drawing &drawing,
|
||||
bke::CurvesGeometry &curves,
|
||||
const IndexMask &selection,
|
||||
const int time_alignment,
|
||||
const int transition,
|
||||
const float factor,
|
||||
const float factor_start,
|
||||
const float factor_opacity,
|
||||
const float factor_radii,
|
||||
StringRefNull target_vgname)
|
||||
{
|
||||
int dst_curves_num, dst_points_num;
|
||||
const bool has_fade = factor_start != factor;
|
||||
const Array<int> point_counts_to_keep = point_counts_to_keep_concurrent(
|
||||
curves, selection, time_alignment, transition, factor, true, dst_curves_num, dst_points_num);
|
||||
if (dst_curves_num == 0) {
|
||||
return {};
|
||||
}
|
||||
const Array<int> starts_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
|
||||
selection,
|
||||
time_alignment,
|
||||
transition,
|
||||
factor_start,
|
||||
false,
|
||||
dst_curves_num,
|
||||
dst_points_num) :
|
||||
Array<int>(0);
|
||||
const Array<int> ends_per_curve = has_fade ? point_counts_to_keep_concurrent(curves,
|
||||
selection,
|
||||
time_alignment,
|
||||
transition,
|
||||
factor,
|
||||
false,
|
||||
dst_curves_num,
|
||||
dst_points_num) :
|
||||
Array<int>(0);
|
||||
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float> opacities = drawing.opacities_for_write();
|
||||
MutableSpan<float> radii = drawing.radii_for_write();
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
|
||||
|
||||
const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||
|
||||
bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
|
||||
Array<int> dst_to_src_point(dst_points_num);
|
||||
Array<int> dst_to_src_curve(dst_curves_num);
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
dst_offsets[0] = 0;
|
||||
|
||||
int next_curve = 0;
|
||||
int next_point = 0;
|
||||
for (const int curve : curves.curves_range()) {
|
||||
if (!point_counts_to_keep[curve]) {
|
||||
continue;
|
||||
}
|
||||
const IndexRange points = points_by_curve[curve];
|
||||
dst_offsets[next_curve] = point_counts_to_keep[curve];
|
||||
const int curve_size = points.size();
|
||||
|
||||
auto get_fade_weight = [&](const int local_index) {
|
||||
const float fade_range = std::abs(ends_per_curve[curve] - starts_per_curve[curve]);
|
||||
if (is_vanishing) {
|
||||
const float factor_from_start = local_index - curve_size + ends_per_curve[curve];
|
||||
return 1.0f - std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
|
||||
}
|
||||
const float factor_from_start = local_index - starts_per_curve[curve];
|
||||
return std::clamp(factor_from_start / fade_range, 0.0f, 1.0f);
|
||||
};
|
||||
|
||||
const int extra_offset = is_vanishing ? points.size() - point_counts_to_keep[curve] : 0;
|
||||
for (const int stroke_point : IndexRange(point_counts_to_keep[curve])) {
|
||||
const int src_point_index = points.first() + extra_offset + stroke_point;
|
||||
if (has_fade) {
|
||||
const float fade_weight = get_fade_weight(extra_offset + stroke_point);
|
||||
opacities[src_point_index] = opacities[src_point_index] *
|
||||
(1.0f - fade_weight * factor_opacity);
|
||||
radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
|
||||
if (!weights.span.is_empty()) {
|
||||
weights.span[src_point_index] = fade_weight;
|
||||
}
|
||||
}
|
||||
dst_to_src_point[next_point] = src_point_index;
|
||||
next_point++;
|
||||
}
|
||||
dst_to_src_curve[next_curve] = curve;
|
||||
next_curve++;
|
||||
}
|
||||
weights.finish();
|
||||
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
|
||||
const bke::AttributeAccessor src_attributes = curves.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
|
||||
gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Point, {}, {}, dst_to_src_point, dst_attributes);
|
||||
gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Curve, {}, {}, dst_to_src_curve, dst_attributes);
|
||||
|
||||
dst_curves.update_curve_types();
|
||||
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
static void points_info_sequential(const bke::CurvesGeometry &curves,
|
||||
const IndexMask &selection,
|
||||
const int transition,
|
||||
const float factor,
|
||||
const bool clamp_points,
|
||||
int &r_curves_num,
|
||||
int &r_points_num)
|
||||
{
|
||||
const int stroke_count = curves.curves_num();
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
|
||||
float factor_to_keep = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ? factor :
|
||||
(1.0f - factor);
|
||||
if (clamp_points) {
|
||||
factor_to_keep = std::clamp(factor_to_keep, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||
|
||||
int effective_points_num = 0;
|
||||
selection.foreach_index(
|
||||
[&](const int index) { effective_points_num += points_by_curve[index].size(); });
|
||||
|
||||
const int untouched_points_num = points_by_curve.total_size() - effective_points_num;
|
||||
effective_points_num *= factor_to_keep;
|
||||
effective_points_num += untouched_points_num;
|
||||
|
||||
r_points_num = effective_points_num;
|
||||
r_curves_num = 0;
|
||||
|
||||
Array<bool> select(stroke_count);
|
||||
selection.to_bools(select.as_mutable_span());
|
||||
|
||||
int counted_points_num = 0;
|
||||
for (const int i : curves.curves_range()) {
|
||||
const int stroke = is_vanishing ? stroke_count - i - 1 : i;
|
||||
if (select[stroke] && counted_points_num >= effective_points_num) {
|
||||
continue;
|
||||
}
|
||||
counted_points_num += points_by_curve[stroke].size();
|
||||
r_curves_num++;
|
||||
}
|
||||
}
|
||||
|
||||
static bke::CurvesGeometry build_sequential(bke::greasepencil::Drawing &drawing,
|
||||
bke::CurvesGeometry &curves,
|
||||
const IndexMask &selection,
|
||||
const int transition,
|
||||
const float factor,
|
||||
const float factor_start,
|
||||
const float factor_opacity,
|
||||
const float factor_radii,
|
||||
StringRefNull target_vgname)
|
||||
{
|
||||
const bool has_fade = factor_start != factor;
|
||||
int dst_curves_num, dst_points_num;
|
||||
int start_points_num, end_points_num, dummy_curves_num;
|
||||
points_info_sequential(
|
||||
curves, selection, transition, factor, true, dst_curves_num, dst_points_num);
|
||||
|
||||
if (dst_curves_num == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
points_info_sequential(
|
||||
curves, selection, transition, factor_start, false, dummy_curves_num, start_points_num);
|
||||
points_info_sequential(
|
||||
curves, selection, transition, factor, false, dummy_curves_num, end_points_num);
|
||||
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
MutableSpan<float> opacities = drawing.opacities_for_write();
|
||||
MutableSpan<float> radii = drawing.radii_for_write();
|
||||
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
|
||||
bke::SpanAttributeWriter<float> weights = attributes.lookup_for_write_span<float>(target_vgname);
|
||||
|
||||
const bool is_vanishing = transition == MOD_GREASE_PENCIL_BUILD_TRANSITION_VANISH;
|
||||
|
||||
bke::CurvesGeometry dst_curves(dst_points_num, dst_curves_num);
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
Array<int> dst_to_src_point(dst_points_num);
|
||||
Array<int> dst_to_src_curve(dst_curves_num);
|
||||
|
||||
dst_offsets[0] = 0;
|
||||
|
||||
int next_curve = 1, next_point = 0;
|
||||
IndexMaskMemory memory;
|
||||
selection.complement(curves.curves_range(), memory).foreach_index([&](const int stroke) {
|
||||
for (const int point : points_by_curve[stroke]) {
|
||||
dst_to_src_point[next_point] = point;
|
||||
next_point++;
|
||||
}
|
||||
dst_offsets[next_curve] = next_point;
|
||||
next_curve++;
|
||||
});
|
||||
|
||||
const int stroke_count = curves.curves_num();
|
||||
bool done_scanning = false;
|
||||
selection.foreach_index([&](const int i) {
|
||||
const int stroke = is_vanishing ? stroke_count - i - 1 : i;
|
||||
if (done_scanning || next_point >= dst_points_num) {
|
||||
done_scanning = true;
|
||||
return;
|
||||
}
|
||||
|
||||
auto get_fade_weight = [&](const int next_point_count) {
|
||||
return std::clamp(float(next_point_count - start_points_num) /
|
||||
float(abs(end_points_num - start_points_num)),
|
||||
0.0f,
|
||||
1.0f);
|
||||
};
|
||||
|
||||
const IndexRange points = points_by_curve[stroke];
|
||||
for (const int point : points) {
|
||||
const int local_index = point - points.first();
|
||||
const int src_point_index = is_vanishing ? points.last() - local_index : point;
|
||||
dst_to_src_point[next_point] = src_point_index;
|
||||
|
||||
if (has_fade) {
|
||||
const float fade_weight = get_fade_weight(next_point);
|
||||
opacities[src_point_index] = opacities[src_point_index] *
|
||||
(1.0f - fade_weight * factor_opacity);
|
||||
radii[src_point_index] = radii[src_point_index] * (1.0f - fade_weight * factor_radii);
|
||||
if (!weights.span.is_empty()) {
|
||||
weights.span[src_point_index] = fade_weight;
|
||||
}
|
||||
}
|
||||
|
||||
next_point++;
|
||||
if (next_point >= dst_points_num) {
|
||||
done_scanning = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dst_offsets[next_curve] = next_point;
|
||||
dst_to_src_curve[next_curve - 1] = i;
|
||||
next_curve++;
|
||||
});
|
||||
weights.finish();
|
||||
|
||||
BLI_assert(next_curve == (dst_curves_num + 1));
|
||||
BLI_assert(next_point == dst_points_num);
|
||||
|
||||
const bke::AttributeAccessor src_attributes = curves.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
|
||||
gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Point, {}, {}, dst_to_src_point, dst_attributes);
|
||||
gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Curve, {}, {}, dst_to_src_curve, dst_attributes);
|
||||
|
||||
dst_curves.update_curve_types();
|
||||
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
static bke::CurvesGeometry reorder_strokes(const bke::CurvesGeometry &curves,
|
||||
const Span<bool> select,
|
||||
const Object &object,
|
||||
MutableSpan<bool> r_selection)
|
||||
{
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
const Span<float3> positions = curves.positions();
|
||||
const float3 center = object.object_to_world().location();
|
||||
|
||||
struct Pair {
|
||||
float value;
|
||||
int index;
|
||||
bool selected;
|
||||
};
|
||||
|
||||
Array<Pair> distances(curves.curves_num());
|
||||
for (const int stroke : curves.curves_range()) {
|
||||
const IndexRange points = points_by_curve[stroke];
|
||||
const float3 p1 = positions[points.first()];
|
||||
const float3 p2 = positions[points.last()];
|
||||
distances[stroke].value = math::max(math::distance(p1, center), math::distance(p2, center));
|
||||
distances[stroke].index = stroke;
|
||||
distances[stroke].selected = select[stroke];
|
||||
}
|
||||
|
||||
parallel_sort(
|
||||
distances.begin(), distances.end(), [](Pair &a, Pair &b) { return a.value < b.value; });
|
||||
|
||||
Array<int> new_order(curves.curves_num());
|
||||
for (const int i : curves.curves_range()) {
|
||||
new_order[i] = distances[i].index;
|
||||
r_selection[i] = distances[i].selected;
|
||||
}
|
||||
|
||||
return geometry::reorder_curves_geometry(curves, new_order.as_span(), {});
|
||||
}
|
||||
|
||||
static float get_factor_from_draw_speed(const bke::CurvesGeometry &curves,
|
||||
const float time_elapsed,
|
||||
const float speed_fac,
|
||||
const float max_gap)
|
||||
{
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
const VArray<float> init_times =
|
||||
attributes.lookup_or_default<float>("init_time", bke::AttrDomain::Curve, 0.0f).varray;
|
||||
const VArray<float> delta_times =
|
||||
attributes.lookup_or_default<float>("delta_time", bke::AttrDomain::Point, 0.0f).varray;
|
||||
|
||||
Array<float> times(curves.points_num());
|
||||
float current_time = 0;
|
||||
float previous_init_time = init_times[0];
|
||||
for (const int curve : curves.curves_range()) {
|
||||
if (curve > 0) {
|
||||
current_time += math::max(init_times[curve] - previous_init_time, max_gap);
|
||||
previous_init_time = init_times[curve];
|
||||
}
|
||||
for (const int point : points_by_curve[curve]) {
|
||||
current_time += delta_times[point];
|
||||
times[point] = current_time;
|
||||
}
|
||||
}
|
||||
for (const int point : curves.points_range()) {
|
||||
const float limit = time_elapsed * speed_fac;
|
||||
if (times[point] >= limit) {
|
||||
return math::clamp(float(point) / float(curves.points_num()), 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
static float get_build_factor(const GreasePencilBuildTimeMode time_mode,
|
||||
const int current_frame,
|
||||
const int start_frame,
|
||||
const int length,
|
||||
const float percentage,
|
||||
const bke::CurvesGeometry &curves,
|
||||
const float scene_fps,
|
||||
const float speed_fac,
|
||||
const float max_gap,
|
||||
const float fade)
|
||||
{
|
||||
switch (time_mode) {
|
||||
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES:
|
||||
return math::clamp(float(current_frame - start_frame) / length, 0.0f, 1.0f) * (1.0f + fade);
|
||||
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE:
|
||||
return percentage * (1.0f + fade);
|
||||
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED:
|
||||
return get_factor_from_draw_speed(
|
||||
curves, float(current_frame) / scene_fps, speed_fac, max_gap) *
|
||||
(1.0f + fade);
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static void build_drawing(const GreasePencilBuildModifierData &mmd,
|
||||
const Object &ob,
|
||||
bke::greasepencil::Drawing &drawing,
|
||||
const bke::greasepencil::Drawing *previous_drawing,
|
||||
const int current_time,
|
||||
const float scene_fps)
|
||||
{
|
||||
bke::CurvesGeometry &curves = drawing.strokes_for_write();
|
||||
|
||||
if (curves.points_num() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
IndexMaskMemory memory;
|
||||
IndexMask selection = modifier::greasepencil::get_filtered_stroke_mask(
|
||||
&ob, curves, mmd.influence, memory);
|
||||
|
||||
/* Remove a count of #prev_strokes. */
|
||||
if (mmd.mode == MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE && previous_drawing != nullptr) {
|
||||
const bke::CurvesGeometry &prev_curves = previous_drawing->strokes();
|
||||
const int prev_strokes = prev_curves.curves_num();
|
||||
const int added_strokes = curves.curves_num() - prev_strokes;
|
||||
if (added_strokes > 0) {
|
||||
Array<bool> work_on_select(curves.curves_num());
|
||||
selection.to_bools(work_on_select.as_mutable_span());
|
||||
work_on_select.as_mutable_span().take_front(prev_strokes).fill(false);
|
||||
selection = IndexMask::from_bools(work_on_select, memory);
|
||||
}
|
||||
}
|
||||
|
||||
if (mmd.object) {
|
||||
const int curves_num = curves.curves_num();
|
||||
Array<bool> select(curves_num), reordered_select(curves_num);
|
||||
selection.to_bools(select);
|
||||
curves = reorder_strokes(
|
||||
curves, select.as_span(), *mmd.object, reordered_select.as_mutable_span());
|
||||
selection = IndexMask::from_bools(reordered_select, memory);
|
||||
}
|
||||
|
||||
const float fade_factor = ((mmd.flag & MOD_GREASE_PENCIL_BUILD_USE_FADING) != 0) ? mmd.fade_fac :
|
||||
0.0f;
|
||||
float factor = get_build_factor(GreasePencilBuildTimeMode(mmd.time_mode),
|
||||
current_time,
|
||||
mmd.start_delay,
|
||||
mmd.length,
|
||||
mmd.percentage_fac,
|
||||
curves,
|
||||
scene_fps,
|
||||
mmd.speed_fac,
|
||||
mmd.speed_maxgap,
|
||||
fade_factor);
|
||||
float factor_start = factor - fade_factor;
|
||||
if (mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW) {
|
||||
std::swap(factor, factor_start);
|
||||
}
|
||||
|
||||
const float use_time_alignment = mmd.transition != MOD_GREASE_PENCIL_BUILD_TRANSITION_GROW ?
|
||||
!mmd.time_alignment :
|
||||
mmd.time_alignment;
|
||||
switch (mmd.mode) {
|
||||
default:
|
||||
case MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL:
|
||||
curves = build_sequential(drawing,
|
||||
curves,
|
||||
selection,
|
||||
mmd.transition,
|
||||
factor,
|
||||
factor_start,
|
||||
mmd.fade_opacity_strength,
|
||||
mmd.fade_thickness_strength,
|
||||
mmd.target_vgname);
|
||||
break;
|
||||
case MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT:
|
||||
curves = build_concurrent(drawing,
|
||||
curves,
|
||||
selection,
|
||||
use_time_alignment,
|
||||
mmd.transition,
|
||||
factor,
|
||||
factor_start,
|
||||
mmd.fade_opacity_strength,
|
||||
mmd.fade_thickness_strength,
|
||||
mmd.target_vgname);
|
||||
break;
|
||||
case MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE:
|
||||
curves = build_sequential(drawing,
|
||||
curves,
|
||||
selection,
|
||||
mmd.transition,
|
||||
factor,
|
||||
factor_start,
|
||||
mmd.fade_opacity_strength,
|
||||
mmd.fade_thickness_strength,
|
||||
mmd.target_vgname);
|
||||
break;
|
||||
}
|
||||
|
||||
drawing.tag_topology_changed();
|
||||
}
|
||||
|
||||
static void modify_geometry_set(ModifierData *md,
|
||||
const ModifierEvalContext *ctx,
|
||||
blender::bke::GeometrySet *geometry_set)
|
||||
{
|
||||
const auto *mmd = reinterpret_cast<GreasePencilBuildModifierData *>(md);
|
||||
|
||||
if (!geometry_set->has_grease_pencil()) {
|
||||
return;
|
||||
}
|
||||
|
||||
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
|
||||
const int eval_frame = grease_pencil.runtime->eval_frame;
|
||||
|
||||
IndexMaskMemory mask_memory;
|
||||
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
|
||||
grease_pencil, mmd->influence, mask_memory);
|
||||
const Vector<modifier::greasepencil::LayerDrawingInfo> drawing_infos =
|
||||
modifier::greasepencil::get_drawing_infos_by_layer(grease_pencil, layer_mask, eval_frame);
|
||||
|
||||
if (mmd->flag & MOD_GREASE_PENCIL_BUILD_RESTRICT_TIME) {
|
||||
if (eval_frame < mmd->start_frame || eval_frame > mmd->end_frame) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const Scene &scene = *DEG_get_evaluated_scene(ctx->depsgraph);
|
||||
const float scene_fps = float(scene.r.frs_sec) / scene.r.frs_sec_base;
|
||||
const Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
|
||||
|
||||
threading::parallel_for_each(
|
||||
drawing_infos, [&](modifier::greasepencil::LayerDrawingInfo drawing_info) {
|
||||
const bke::greasepencil::Drawing *prev_drawing = grease_pencil.get_drawing_at(
|
||||
*layers[drawing_info.layer_index], eval_frame - 1);
|
||||
build_drawing(
|
||||
*mmd, *ctx->object, *drawing_info.drawing, prev_drawing, eval_frame, scene_fps);
|
||||
});
|
||||
}
|
||||
|
||||
static void panel_draw(const bContext *C, Panel *panel)
|
||||
{
|
||||
uiLayout *layout = panel->layout;
|
||||
|
||||
PointerRNA ob_ptr;
|
||||
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
|
||||
|
||||
const GreasePencilBuildMode mode = GreasePencilBuildMode(RNA_enum_get(ptr, "mode"));
|
||||
GreasePencilBuildTimeMode time_mode = GreasePencilBuildTimeMode(RNA_enum_get(ptr, "time_mode"));
|
||||
|
||||
uiLayoutSetPropSep(layout, true);
|
||||
|
||||
/* First: Build mode and build settings. */
|
||||
uiItemR(layout, ptr, "mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
if (mode == MOD_GREASE_PENCIL_BUILD_MODE_SEQUENTIAL) {
|
||||
uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
if (mode == MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT) {
|
||||
/* Concurrent mode doesn't support MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED, so unset it. */
|
||||
if (time_mode == MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED) {
|
||||
RNA_enum_set(ptr, "time_mode", MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES);
|
||||
time_mode = MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES;
|
||||
}
|
||||
uiItemR(layout, ptr, "transition", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
uiItemS(layout);
|
||||
|
||||
/* Second: Time mode and time settings. */
|
||||
|
||||
uiItemR(layout, ptr, "time_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
if (mode == MOD_GREASE_PENCIL_BUILD_MODE_CONCURRENT) {
|
||||
uiItemR(layout, ptr, "concurrent_time_alignment", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
switch (time_mode) {
|
||||
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_DRAWSPEED:
|
||||
uiItemR(layout, ptr, "speed_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "speed_maxgap", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
break;
|
||||
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_FRAMES:
|
||||
uiItemR(layout, ptr, "length", UI_ITEM_NONE, IFACE_("Frames"), ICON_NONE);
|
||||
if (mode != MOD_GREASE_PENCIL_BUILD_MODE_ADDITIVE) {
|
||||
uiItemR(layout, ptr, "start_delay", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
}
|
||||
break;
|
||||
case MOD_GREASE_PENCIL_BUILD_TIMEMODE_PERCENTAGE:
|
||||
uiItemR(layout, ptr, "percentage_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
uiItemS(layout);
|
||||
uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
|
||||
|
||||
if (uiLayout *panel = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_frame_range_panel", "Effective Range"))
|
||||
{
|
||||
uiLayoutSetPropSep(panel, true);
|
||||
uiItemR(
|
||||
panel, ptr, "use_restrict_frame_range", UI_ITEM_NONE, IFACE_("Custom Range"), ICON_NONE);
|
||||
|
||||
const bool active = RNA_boolean_get(ptr, "use_restrict_frame_range");
|
||||
uiLayout *col = uiLayoutColumn(panel, false);
|
||||
uiLayoutSetActive(col, active);
|
||||
uiItemR(col, ptr, "frame_start", UI_ITEM_NONE, IFACE_("Start"), ICON_NONE);
|
||||
uiItemR(col, ptr, "frame_end", UI_ITEM_NONE, IFACE_("End"), ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *panel = uiLayoutPanelProp(C, layout, ptr, "open_fading_panel", "Fading")) {
|
||||
uiLayoutSetPropSep(panel, true);
|
||||
uiItemR(panel, ptr, "use_fading", UI_ITEM_NONE, IFACE_("Fade"), ICON_NONE);
|
||||
|
||||
const bool active = RNA_boolean_get(ptr, "use_fading");
|
||||
uiLayout *col = uiLayoutColumn(panel, false);
|
||||
uiLayoutSetActive(col, active);
|
||||
|
||||
uiItemR(col, ptr, "fade_factor", UI_ITEM_NONE, IFACE_("Factor"), ICON_NONE);
|
||||
|
||||
uiLayout *subcol = uiLayoutColumn(col, true);
|
||||
uiItemR(subcol, ptr, "fade_thickness_strength", UI_ITEM_NONE, IFACE_("Thickness"), ICON_NONE);
|
||||
uiItemR(subcol, ptr, "fade_opacity_strength", UI_ITEM_NONE, IFACE_("Opacity"), ICON_NONE);
|
||||
|
||||
uiItemPointerR(col,
|
||||
ptr,
|
||||
"target_vertex_group",
|
||||
&ob_ptr,
|
||||
"vertex_groups",
|
||||
IFACE_("Weight Output"),
|
||||
ICON_NONE);
|
||||
}
|
||||
|
||||
if (uiLayout *influence_panel = uiLayoutPanelProp(
|
||||
C, layout, ptr, "open_influence_panel", "Influence"))
|
||||
{
|
||||
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
|
||||
modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
|
||||
}
|
||||
|
||||
modifier_panel_end(layout, ptr);
|
||||
}
|
||||
|
||||
static void panel_register(ARegionType *region_type)
|
||||
{
|
||||
modifier_panel_register(region_type, eModifierType_GreasePencilBuild, panel_draw);
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
ModifierTypeInfo modifierType_GreasePencilBuild = {
|
||||
/*idname*/ "GreasePencilBuildModifier",
|
||||
/*name*/ N_("Build"),
|
||||
/*struct_name*/ "GreasePencilBuildModifierData",
|
||||
/*struct_size*/ sizeof(GreasePencilBuildModifierData),
|
||||
/*srna*/ &RNA_GreasePencilBuildModifier,
|
||||
/*type*/ ModifierTypeType::Nonconstructive,
|
||||
/*flags*/
|
||||
eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_EnableInEditmode |
|
||||
eModifierTypeFlag_SupportsEditmode,
|
||||
/*icon*/ ICON_MOD_LENGTH,
|
||||
|
||||
/*copy_data*/ blender::copy_data,
|
||||
|
||||
/*deform_verts*/ nullptr,
|
||||
/*deform_matrices*/ nullptr,
|
||||
/*deform_verts_EM*/ nullptr,
|
||||
/*deform_matrices_EM*/ nullptr,
|
||||
/*modify_mesh*/ nullptr,
|
||||
/*modify_geometry_set*/ blender::modify_geometry_set,
|
||||
|
||||
/*init_data*/ blender::init_data,
|
||||
/*required_data_mask*/ nullptr,
|
||||
/*free_data*/ blender::free_data,
|
||||
/*is_disabled*/ nullptr,
|
||||
/*update_depsgraph*/ blender::update_depsgraph,
|
||||
/*depends_on_time*/ nullptr,
|
||||
/*depends_on_normals*/ nullptr,
|
||||
/*foreach_ID_link*/ blender::foreach_ID_link,
|
||||
/*foreach_tex_link*/ nullptr,
|
||||
/*free_runtime_data*/ nullptr,
|
||||
/*panel_register*/ blender::panel_register,
|
||||
/*blend_write*/ blender::blend_write,
|
||||
/*blend_read*/ blender::blend_read,
|
||||
};
|
|
@ -287,5 +287,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
|
|||
INIT_TYPE(GreasePencilEnvelope);
|
||||
INIT_TYPE(GreasePencilOutline);
|
||||
INIT_TYPE(GreasePencilShrinkwrap);
|
||||
INIT_TYPE(GreasePencilBuild);
|
||||
#undef INIT_TYPE
|
||||
}
|
||||
|
|
|
@ -171,6 +171,8 @@ class SocketDeclaration : public ItemDeclaration {
|
|||
/** Defined by whether the socket is part of the node's input or
|
||||
* output socket declaration list. Included here for convenience. */
|
||||
eNodeSocketInOut in_out;
|
||||
/** Socket type that corresponds to this socket declaration. */
|
||||
eNodeSocketDatatype socket_type;
|
||||
bool hide_label = false;
|
||||
bool hide_value = false;
|
||||
bool compact = false;
|
||||
|
@ -682,6 +684,7 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
|
|||
socket_decl->name = name;
|
||||
socket_decl->identifier = identifier_in.is_empty() ? name : identifier_in;
|
||||
socket_decl->in_out = SOCK_IN;
|
||||
socket_decl->socket_type = DeclType::static_socket_type;
|
||||
socket_decl_builder->index_ = declaration_.inputs.append_and_get_index(socket_decl.get());
|
||||
declaration_.items.append(std::move(socket_decl));
|
||||
input_socket_builders_.append(&*socket_decl_builder);
|
||||
|
@ -693,6 +696,7 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef
|
|||
socket_decl->name = name;
|
||||
socket_decl->identifier = identifier_out.is_empty() ? name : identifier_out;
|
||||
socket_decl->in_out = SOCK_OUT;
|
||||
socket_decl->socket_type = DeclType::static_socket_type;
|
||||
socket_decl_builder->index_ = declaration_.outputs.append_and_get_index(socket_decl.get());
|
||||
declaration_.items.append(std::move(socket_decl));
|
||||
output_socket_builders_.append(&*socket_decl_builder);
|
||||
|
|
|
@ -30,5 +30,6 @@ namespace blender::nodes {
|
|||
|
||||
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node);
|
||||
bool socket_type_supports_fields(eNodeSocketDatatype socket_type);
|
||||
bool socket_type_supports_grids(eNodeSocketDatatype socket_type);
|
||||
|
||||
} // namespace blender::nodes
|
||||
|
|
|
@ -18,6 +18,8 @@ class FloatBuilder;
|
|||
|
||||
class Float : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_FLOAT;
|
||||
|
||||
float default_value = 0.0f;
|
||||
float soft_min_value = -FLT_MAX;
|
||||
float soft_max_value = FLT_MAX;
|
||||
|
@ -45,6 +47,8 @@ class IntBuilder;
|
|||
|
||||
class Int : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_INT;
|
||||
|
||||
int default_value = 0;
|
||||
int soft_min_value = INT32_MIN;
|
||||
int soft_max_value = INT32_MAX;
|
||||
|
@ -72,6 +76,8 @@ class VectorBuilder;
|
|||
|
||||
class Vector : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_VECTOR;
|
||||
|
||||
float3 default_value = {0, 0, 0};
|
||||
float soft_min_value = -FLT_MAX;
|
||||
float soft_max_value = FLT_MAX;
|
||||
|
@ -100,6 +106,8 @@ class BoolBuilder;
|
|||
|
||||
class Bool : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_BOOLEAN;
|
||||
|
||||
bool default_value = false;
|
||||
friend BoolBuilder;
|
||||
|
||||
|
@ -120,6 +128,8 @@ class ColorBuilder;
|
|||
|
||||
class Color : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_RGBA;
|
||||
|
||||
ColorGeometry4f default_value{0.8f, 0.8f, 0.8f, 1.0f};
|
||||
|
||||
friend ColorBuilder;
|
||||
|
@ -141,6 +151,8 @@ class RotationBuilder;
|
|||
|
||||
class Rotation : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_ROTATION;
|
||||
|
||||
math::EulerXYZ default_value;
|
||||
|
||||
friend RotationBuilder;
|
||||
|
@ -162,6 +174,8 @@ class MatrixBuilder;
|
|||
|
||||
class Matrix : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_MATRIX;
|
||||
|
||||
friend MatrixBuilder;
|
||||
|
||||
using Builder = MatrixBuilder;
|
||||
|
@ -178,6 +192,8 @@ class StringBuilder;
|
|||
|
||||
class String : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_STRING;
|
||||
|
||||
std::string default_value;
|
||||
|
||||
friend StringBuilder;
|
||||
|
@ -199,6 +215,8 @@ class MenuBuilder;
|
|||
|
||||
class Menu : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_MENU;
|
||||
|
||||
int32_t default_value;
|
||||
|
||||
friend MenuBuilder;
|
||||
|
@ -237,6 +255,8 @@ class IDSocketDeclaration : public SocketDeclaration {
|
|||
|
||||
class Object : public IDSocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_OBJECT;
|
||||
|
||||
using Builder = SocketDeclarationBuilder<Object>;
|
||||
|
||||
Object();
|
||||
|
@ -244,6 +264,8 @@ class Object : public IDSocketDeclaration {
|
|||
|
||||
class Material : public IDSocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_MATERIAL;
|
||||
|
||||
using Builder = SocketDeclarationBuilder<Material>;
|
||||
|
||||
Material();
|
||||
|
@ -251,6 +273,8 @@ class Material : public IDSocketDeclaration {
|
|||
|
||||
class Collection : public IDSocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_COLLECTION;
|
||||
|
||||
using Builder = SocketDeclarationBuilder<Collection>;
|
||||
|
||||
Collection();
|
||||
|
@ -258,6 +282,8 @@ class Collection : public IDSocketDeclaration {
|
|||
|
||||
class Texture : public IDSocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_TEXTURE;
|
||||
|
||||
using Builder = SocketDeclarationBuilder<Texture>;
|
||||
|
||||
Texture();
|
||||
|
@ -265,6 +291,8 @@ class Texture : public IDSocketDeclaration {
|
|||
|
||||
class Image : public IDSocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_IMAGE;
|
||||
|
||||
using Builder = SocketDeclarationBuilder<Image>;
|
||||
|
||||
Image();
|
||||
|
@ -274,6 +302,8 @@ class ShaderBuilder;
|
|||
|
||||
class Shader : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_SHADER;
|
||||
|
||||
friend ShaderBuilder;
|
||||
|
||||
using Builder = ShaderBuilder;
|
||||
|
@ -292,6 +322,8 @@ class Extend : public SocketDeclaration {
|
|||
friend ExtendBuilder;
|
||||
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_CUSTOM;
|
||||
|
||||
using Builder = ExtendBuilder;
|
||||
|
||||
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
|
||||
|
@ -304,6 +336,8 @@ class ExtendBuilder : public SocketDeclarationBuilder<Extend> {};
|
|||
|
||||
class Custom : public SocketDeclaration {
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_CUSTOM;
|
||||
|
||||
const char *idname_;
|
||||
std::function<void(bNode &node, bNodeSocket &socket, const char *data_path)> init_socket_fn;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ class Geometry : public SocketDeclaration {
|
|||
friend GeometryBuilder;
|
||||
|
||||
public:
|
||||
static constexpr eNodeSocketDatatype static_socket_type = SOCK_GEOMETRY;
|
||||
|
||||
using Builder = GeometryBuilder;
|
||||
|
||||
bNodeSocket &build(bNodeTree &ntree, bNode &node) const override;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "BKE_node.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
#include "NOD_socket.hh"
|
||||
#include "NOD_socket_search_link.hh"
|
||||
|
||||
#include "RNA_enum_types.hh"
|
||||
|
@ -100,17 +101,12 @@ const EnumPropertyItem *domain_without_corner_experimental_grease_pencil_version
|
|||
|
||||
} // namespace enums
|
||||
|
||||
bool grid_type_supported(const eCustomDataType data_type)
|
||||
bool custom_data_type_supports_grids(const eCustomDataType data_type)
|
||||
{
|
||||
return ELEM(data_type, CD_PROP_FLOAT, CD_PROP_FLOAT3);
|
||||
}
|
||||
|
||||
bool grid_type_supported(eNodeSocketDatatype socket_type)
|
||||
{
|
||||
if (const std::optional<eCustomDataType> data_type = bke::socket_type_to_custom_data_type(
|
||||
socket_type))
|
||||
if (const std::optional<eNodeSocketDatatype> socket_type = bke::custom_data_type_to_socket_type(
|
||||
data_type))
|
||||
{
|
||||
return grid_type_supported(*data_type);
|
||||
return socket_type_supports_grids(*socket_type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -123,7 +119,7 @@ const EnumPropertyItem *grid_custom_data_type_items_filter_fn(bContext * /*C*/,
|
|||
*r_free = true;
|
||||
return enum_items_filter(rna_enum_attribute_type_items,
|
||||
[](const EnumPropertyItem &item) -> bool {
|
||||
return grid_type_supported(eCustomDataType(item.value));
|
||||
return custom_data_type_supports_grids(eCustomDataType(item.value));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -135,7 +131,7 @@ const EnumPropertyItem *grid_socket_type_items_filter_fn(bContext * /*C*/,
|
|||
*r_free = true;
|
||||
return enum_items_filter(rna_enum_node_socket_data_type_items,
|
||||
[](const EnumPropertyItem &item) -> bool {
|
||||
return grid_type_supported(eNodeSocketDatatype(item.value));
|
||||
return socket_type_supports_grids(eNodeSocketDatatype(item.value));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue