UI: Asset Shelf (Experimental Feature) #104831

Closed
Julian Eisel wants to merge 399 commits from asset-shelf into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
123 changed files with 6407 additions and 5319 deletions
Showing only changes of commit 1bacc69871 - Show all commits

View File

@ -106,7 +106,8 @@ ExternalProject_Add(external_openimageio
CMAKE_GENERATOR ${PLATFORM_ALT_GENERATOR}
PREFIX ${BUILD_DIR}/openimageio
PATCH_COMMAND ${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/openimageio.diff &&
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_3832.diff &&
${PATCH_CMD} -p 1 -N -d ${BUILD_DIR}/openimageio/src/external_openimageio/ < ${PATCH_DIR}/oiio_deadlock.diff
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openimageio ${DEFAULT_CMAKE_FLAGS} ${OPENIMAGEIO_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/openimageio
)

View File

@ -0,0 +1,62 @@
diff -Naur orig/src/idiff/idiff.cpp external_openimageio/src/idiff/idiff.cpp
--- orig/src/idiff/idiff.cpp 2023-06-07 07:47:42 -0600
+++ external_openimageio/src/idiff/idiff.cpp 2023-06-07 09:46:47 -0600
@@ -399,5 +399,6 @@
imagecache->invalidate_all(true);
ImageCache::destroy(imagecache);
+ default_thread_pool()->resize(0);
return ret;
}
diff -Naur orig/src/libutil/thread.cpp external_openimageio/src/libutil/thread.cpp
--- orig/src/libutil/thread.cpp 2023-06-07 07:47:42 -0600
+++ external_openimageio/src/libutil/thread.cpp 2023-06-07 09:45:39 -0600
@@ -151,9 +151,10 @@
this->set_thread(i);
}
} else { // the number of threads is decreased
+ std::vector<std::unique_ptr<std::thread>> terminating_threads;
for (int i = oldNThreads - 1; i >= nThreads; --i) {
*this->flags[i] = true; // this thread will finish
- this->terminating_threads.push_back(
+ terminating_threads.push_back(
std::move(this->threads[i]));
this->threads.erase(this->threads.begin() + i);
}
@@ -162,6 +163,11 @@
std::unique_lock<std::mutex> lock(this->mutex);
this->cv.notify_all();
}
+ // wait for the terminated threads to finish
+ for (auto& thread : terminating_threads) {
+ if (thread->joinable())
+ thread->join();
+ }
this->threads.resize(
nThreads); // safe to delete because the threads are detached
this->flags.resize(
@@ -238,16 +244,10 @@
if (thread->joinable())
thread->join();
}
- // wait for the terminated threads to finish
- for (auto& thread : this->terminating_threads) {
- if (thread->joinable())
- thread->join();
- }
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
// therefore delete them here
this->clear_queue();
this->threads.clear();
- this->terminating_threads.clear();
this->flags.clear();
}
@@ -349,7 +349,6 @@
}
std::vector<std::unique_ptr<std::thread>> threads;
- std::vector<std::unique_ptr<std::thread>> terminating_threads;
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
mutable pvt::ThreadsafeQueue<std::function<void(int id)>*> q;
std::atomic<bool> isDone;

View File

@ -873,6 +873,7 @@ static ShaderNode *add_node(Scene *scene,
voronoi->set_dimensions(b_voronoi_node.voronoi_dimensions());
voronoi->set_feature((NodeVoronoiFeature)b_voronoi_node.feature());
voronoi->set_metric((NodeVoronoiDistanceMetric)b_voronoi_node.distance());
voronoi->set_normalize(b_voronoi_node.normalize());
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(voronoi, b_texture_mapping);
node = voronoi;

View File

@ -307,7 +307,12 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg,
case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: {
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
*roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y);
*eta = CLOSURE_IS_REFRACTIVE(bsdf->type) ? 1.0f / bsdf->ior : bsdf->ior;
if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) {
*eta = 1.0f / bsdf->ior;
}
else {
*eta = bsdf->ior;
}
break;
}
case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: {
@ -594,7 +599,9 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float
}
ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
ccl_private const ShaderClosure *sc)
ccl_private const ShaderClosure *sc,
const bool reflection,
const bool transmission)
{
Spectrum albedo = sc->weight;
/* Some closures include additional components such as Fresnel terms that cause their albedo to
@ -608,12 +615,16 @@ ccl_device_inline Spectrum bsdf_albedo(ccl_private const ShaderData *sd,
* extra overhead though. */
#if defined(__SVM__) || defined(__OSL__)
if (CLOSURE_IS_BSDF_MICROFACET(sc->type)) {
albedo *= bsdf_microfacet_estimate_fresnel(sd, (ccl_private const MicrofacetBsdf *)sc);
albedo *= bsdf_microfacet_estimate_fresnel(
sd, (ccl_private const MicrofacetBsdf *)sc, reflection, transmission);
}
else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) {
kernel_assert(reflection);
albedo *= ((ccl_private const PrincipledSheenBsdf *)sc)->avg_value;
}
else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) {
/* TODO(lukas): Principled Hair could also be split into a glossy and a transmission component,
* similar to Glass BSDFs. */
albedo *= bsdf_principled_hair_albedo(sd, sc);
}
#endif

View File

@ -338,17 +338,20 @@ ccl_device_inline void microfacet_ggx_preserve_energy(KernelGlobals kg,
* For better results, we'd be blending between this and Fss based on roughness, but that
* would involve storing or recomputing Fss, which is probably not worth it. */
ccl_device Spectrum bsdf_microfacet_estimate_fresnel(ccl_private const ShaderData *sd,
ccl_private const MicrofacetBsdf *bsdf)
ccl_private const MicrofacetBsdf *bsdf,
const bool reflection,
const bool transmission)
{
const bool is_glass = CLOSURE_IS_GLASS(bsdf->type);
const bool is_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
const bool m_reflection = !(m_refraction || m_glass);
Spectrum albedo = zero_spectrum();
if (!is_refractive || is_glass) {
if (reflection && (m_reflection || m_glass)) {
/* BSDF has a reflective lobe. */
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, false);
}
if (is_refractive) {
if (transmission && (m_refraction || m_glass)) {
/* BSDF has a refractive lobe (unless there's TIR). */
albedo += microfacet_fresnel(bsdf, sd->wi, bsdf->N, true);
}
@ -455,8 +458,12 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
}
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
const bool m_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
/* Refraction: Only consider BTDF
* Glass: Consider both BRDF and BTDF, mix based on Fresnel
* Reflection: Only consider BRDF */
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
const bool m_reflection = !(m_refraction || m_glass);
const float3 N = bsdf->N;
const float cos_NI = dot(N, wi);
@ -466,7 +473,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
const float alpha_x = bsdf->alpha_x;
const float alpha_y = bsdf->alpha_y;
const bool is_refraction = (cos_NO < 0.0f);
const bool is_transmission = (cos_NO < 0.0f);
/* Check whether the pair of directions is valid for evaluation:
* - Incoming direction has to be in the upper hemisphere (Cycles convention)
@ -475,15 +482,15 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
* - Purely reflective closures can't have refraction.
* - Purely refractive closures can't have reflection.
*/
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_refraction) ||
(is_refraction && !m_refractive) || (!is_refraction && m_refractive && !m_glass))
if ((cos_NI <= 0) || (alpha_x * alpha_y <= 5e-7f) || ((cos_NgO < 0.0f) != is_transmission) ||
(is_transmission && m_reflection) || (!is_transmission && m_refraction))
{
*pdf = 0.0f;
return zero_spectrum();
}
/* Compute half vector. */
float3 H = is_refraction ? -(bsdf->ior * wo + wi) : (wi + wo);
float3 H = is_transmission ? -(bsdf->ior * wo + wi) : (wi + wo);
const float inv_len_H = 1.0f / len(H);
H *= inv_len_H;
@ -491,7 +498,7 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
float D, lambdaI, lambdaO;
/* TODO: add support for anisotropic transmission. */
if (alpha_x == alpha_y || is_refraction) { /* Isotropic. */
if (alpha_x == alpha_y || is_transmission) { /* Isotropic. */
float alpha2 = alpha_x * alpha_y;
if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) {
@ -523,19 +530,19 @@ ccl_device Spectrum bsdf_microfacet_eval(ccl_private const ShaderClosure *sc,
}
float common = D / cos_NI *
(is_refraction ? sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
0.25f);
(is_transmission ? sqr(bsdf->ior * inv_len_H) * fabsf(dot(H, wi) * dot(H, wo)) :
0.25f);
float lobe_pdf = 1.0f;
if (m_glass) {
float fresnel = fresnel_dielectric_cos(dot(H, wi), bsdf->ior);
float reflect_pdf = (fresnel == 1.0f) ? 1.0f : clamp(fresnel, 0.125f, 0.875f);
lobe_pdf = is_refraction ? (1.0f - reflect_pdf) : reflect_pdf;
lobe_pdf = is_transmission ? (1.0f - reflect_pdf) : reflect_pdf;
}
*pdf = common * lobe_pdf / (1.0f + lambdaI);
const Spectrum F = microfacet_fresnel(bsdf, wi, H, is_refraction);
const Spectrum F = microfacet_fresnel(bsdf, wi, H, is_transmission);
return F * common / (1.0f + lambdaO + lambdaI);
}
@ -554,7 +561,9 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
const float m_eta = bsdf->ior;
const bool m_refractive = CLOSURE_IS_REFRACTIVE(bsdf->type);
const bool m_refraction = CLOSURE_IS_REFRACTION(bsdf->type);
const bool m_glass = CLOSURE_IS_GLASS(bsdf->type);
const bool m_reflection = !(m_refraction || m_glass);
const float alpha_x = bsdf->alpha_x;
const float alpha_y = bsdf->alpha_y;
bool m_singular = (m_type == MicrofacetType::SHARP) || (alpha_x * alpha_y <= 5e-7f);
@ -564,7 +573,7 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
if (cos_NI <= 0) {
*eval = zero_spectrum();
*pdf = 0.0f;
return (m_refractive ? LABEL_TRANSMIT : LABEL_REFLECT) |
return (m_reflection ? LABEL_REFLECT : LABEL_TRANSMIT) |
(m_singular ? LABEL_SINGULAR : LABEL_GLOSSY);
}
@ -603,13 +612,13 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc,
bool valid;
bool do_refract;
float lobe_pdf;
if (m_refractive) {
if (m_refraction || m_glass) {
bool inside;
float fresnel = fresnel_dielectric(m_eta, H, wi, wo, &inside);
valid = !inside;
/* For glass closures, we decide between reflection and refraction here. */
if (CLOSURE_IS_GLASS(bsdf->type)) {
if (m_glass) {
if (fresnel == 1.0f) {
/* TIR, reflection is the only option. */
do_refract = false;
@ -725,7 +734,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_conductor(KernelGlobals kg,
{
bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
bsdf->fresnel = fresnel;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
if (preserve_energy) {
/* In order to estimate Fss of the conductor, we fit the F82-tint model to it based on the
@ -748,7 +757,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(
{
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
bsdf->fresnel = fresnel;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
if (preserve_energy) {
/* Assume that the transmissive tint makes up most of the overall color. */
@ -765,7 +774,7 @@ ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(
{
bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
bsdf->fresnel = fresnel;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
if (preserve_energy) {
Spectrum Fss = one_spectrum();
@ -852,7 +861,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b
bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
bsdf->energy_scale = 1.0f;
bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID;
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf));
bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf, true, true));
return SD_BSDF | SD_BSDF_HAS_EVAL;
}

View File

@ -67,7 +67,7 @@ ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals
}
}
Spectrum closure_albedo = bsdf_albedo(sd, sc);
Spectrum closure_albedo = bsdf_albedo(sd, sc, true, true);
if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) {
diffuse_albedo += closure_albedo;
sum_nonspecular_weight += sc->sample_weight;

View File

@ -20,36 +20,61 @@ CCL_NAMESPACE_BEGIN
* them separately. */
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval,
const ClosureType closure_type,
ccl_private const ShaderClosure *sc,
const float3 wo,
Spectrum value)
{
eval->diffuse = zero_spectrum();
eval->glossy = zero_spectrum();
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
eval->diffuse = value;
}
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
else if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) {
eval->glossy = value;
}
else if (CLOSURE_IS_GLASS(sc->type)) {
/* Glass can count as glossy or transmission, depending on which side we end up on. */
if (dot(sc->N, wo) > 0.0f) {
eval->glossy = value;
}
}
eval->sum = value;
}
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval, Spectrum value)
{
eval->diffuse = zero_spectrum();
eval->glossy = zero_spectrum();
eval->sum = value;
}
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
const ClosureType closure_type,
ccl_private const ShaderClosure *sc,
const float3 wo,
Spectrum value)
{
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
eval->diffuse += value;
}
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
else if (CLOSURE_IS_BSDF_GLOSSY(sc->type)) {
eval->glossy += value;
}
else if (CLOSURE_IS_GLASS(sc->type)) {
if (dot(sc->N, wo) > 0.0f) {
eval->glossy += value;
}
}
eval->sum += value;
}
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval, Spectrum value)
{
eval->sum += value;
}
ccl_device_inline bool bsdf_eval_is_zero(ccl_private BsdfEval *eval)
{
return is_zero(eval->sum);

View File

@ -979,7 +979,7 @@ ccl_device_forceinline int kernel_path_mnee_sample(KernelGlobals kg,
bool found_refractive_microfacet_bsdf = false;
for (int ci = 0; ci < sd_mnee->num_closure; ci++) {
ccl_private ShaderClosure *bsdf = &sd_mnee->closure[ci];
if (CLOSURE_IS_REFRACTIVE(bsdf->type)) {
if (CLOSURE_IS_REFRACTION(bsdf->type) || CLOSURE_IS_GLASS(bsdf->type)) {
/* Note that Glass closures are treated as refractive further below. */
found_refractive_microfacet_bsdf = true;

View File

@ -140,11 +140,12 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
{
/* Filter out closures. */
if (kernel_data.integrator.filter_closures) {
if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_EMISSION) {
const int filter_closures = kernel_data.integrator.filter_closures;
if (filter_closures & FILTER_CLOSURE_EMISSION) {
sd->closure_emission_background = zero_spectrum();
}
if (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
if (filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) {
sd->flag &= ~SD_BSDF_HAS_EVAL;
}
@ -152,19 +153,20 @@ ccl_device_inline void surface_shader_prepare_closures(KernelGlobals kg,
for (int i = 0; i < sd->num_closure; i++) {
ccl_private ShaderClosure *sc = &sd->closure[i];
if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) &&
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIFFUSE)) ||
(CLOSURE_IS_BSDF_GLOSSY(sc->type) &&
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_GLOSSY)) ||
(CLOSURE_IS_BSDF_TRANSMISSION(sc->type) &&
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSMISSION)))
const bool filter_diffuse = (filter_closures & FILTER_CLOSURE_DIFFUSE);
const bool filter_glossy = (filter_closures & FILTER_CLOSURE_GLOSSY);
const bool filter_transmission = (filter_closures & FILTER_CLOSURE_TRANSMISSION);
const bool filter_glass = filter_glossy && filter_transmission;
if ((CLOSURE_IS_BSDF_DIFFUSE(sc->type) && filter_diffuse) ||
(CLOSURE_IS_BSDF_GLOSSY(sc->type) && filter_glossy) ||
(CLOSURE_IS_BSDF_TRANSMISSION(sc->type) && filter_transmission) ||
(CLOSURE_IS_GLASS(sc->type) && filter_glass))
{
sc->type = CLOSURE_NONE_ID;
sc->sample_weight = 0.0f;
}
else if ((CLOSURE_IS_BSDF_TRANSPARENT(sc->type) &&
(kernel_data.integrator.filter_closures & FILTER_CLOSURE_TRANSPARENT)))
{
(filter_closures & FILTER_CLOSURE_TRANSPARENT))) {
sc->type = CLOSURE_HOLDOUT_ID;
sc->sample_weight = 0.0f;
sd->flag |= SD_HOLDOUT;
@ -268,6 +270,13 @@ ccl_device_forceinline bool _surface_shader_exclude(ClosureType type, uint light
return true;
}
}
/* Glass closures are both glossy and transmissive, so only exclude them if both are filtered. */
const uint exclude_glass = SHADER_EXCLUDE_TRANSMIT | SHADER_EXCLUDE_GLOSSY;
if ((light_shader_flags & exclude_glass) == exclude_glass) {
if (CLOSURE_IS_GLASS(type)) {
return true;
}
}
return false;
}
@ -295,7 +304,7 @@ ccl_device_inline float _surface_shader_bsdf_eval_mis(KernelGlobals kg,
Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf);
if (bsdf_pdf != 0.0f) {
bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
bsdf_eval_accum(result_eval, sc, wo, eval * sc->weight);
sum_pdf += bsdf_pdf * sc->sample_weight;
}
}
@ -318,7 +327,7 @@ ccl_device_inline float surface_shader_bsdf_eval_pdfs(const KernelGlobals kg,
* factors drop out when using balance heuristic weighting. */
float sum_pdf = 0.0f;
float sum_sample_weight = 0.0f;
bsdf_eval_init(result_eval, CLOSURE_NONE_ID, zero_spectrum());
bsdf_eval_init(result_eval, zero_spectrum());
for (int i = 0; i < sd->num_closure; i++) {
ccl_private const ShaderClosure *sc = &sd->closure[i];
@ -328,7 +337,7 @@ ccl_device_inline float surface_shader_bsdf_eval_pdfs(const KernelGlobals kg,
Spectrum eval = bsdf_eval(kg, sd, sc, wo, &bsdf_pdf);
kernel_assert(bsdf_pdf >= 0.0f);
if (bsdf_pdf != 0.0f) {
bsdf_eval_accum(result_eval, sc->type, eval * sc->weight);
bsdf_eval_accum(result_eval, sc, wo, eval * sc->weight);
sum_pdf += bsdf_pdf * sc->sample_weight;
kernel_assert(bsdf_pdf * sc->sample_weight >= 0.0f);
pdfs[i] = bsdf_pdf * sc->sample_weight;
@ -369,7 +378,7 @@ ccl_device_inline
ccl_private BsdfEval *bsdf_eval,
const uint light_shader_flags)
{
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, zero_spectrum());
bsdf_eval_init(bsdf_eval, zero_spectrum());
float pdf = _surface_shader_bsdf_eval_mis(
kg, sd, wo, NULL, bsdf_eval, 0.0f, 0.0f, light_shader_flags);
@ -499,7 +508,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
/* Initialize to zero. */
int label = LABEL_NONE;
Spectrum eval = zero_spectrum();
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
bsdf_eval_init(bsdf_eval, eval);
*unguided_bsdf_pdf = 0.0f;
float guide_pdf = 0.0f;
@ -570,7 +579,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_mis(KernelGlobals kg,
# endif
if (*unguided_bsdf_pdf != 0.0f) {
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
@ -622,7 +631,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
/* Initialize to zero. */
int label = LABEL_NONE;
Spectrum eval = zero_spectrum();
bsdf_eval_init(bsdf_eval, CLOSURE_NONE_ID, eval);
bsdf_eval_init(bsdf_eval, eval);
*unguided_bsdf_pdf = 0.0f;
float guide_pdf = 0.0f;
@ -652,7 +661,8 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
&ris_samples[0].sampled_roughness,
&ris_samples[0].eta);
bsdf_eval_init(&ris_samples[0].bsdf_eval, sc->type, ris_samples[0].eval * sc->weight);
bsdf_eval_init(
&ris_samples[0].bsdf_eval, sc, ris_samples[0].wo, ris_samples[0].eval * sc->weight);
if (ris_samples[0].bsdf_pdf > 0.0f) {
if (sd->num_closure > 1) {
float sweight = sc->sample_weight;
@ -679,7 +689,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
// generate the second RIS candidate using a sample from the guiding distribution
// ------------------------------------------------------------------------------
float unguided_bsdf_pdfs[MAX_CLOSURE];
bsdf_eval_init(&ris_samples[1].bsdf_eval, CLOSURE_NONE_ID, eval);
bsdf_eval_init(&ris_samples[1].bsdf_eval, eval);
ris_samples[1].guide_pdf = guiding_bsdf_sample(
kg, state, float3_to_float2(ris_samples[1].rand), &ris_samples[1].wo);
ris_samples[1].guide_pdf *= (1.0f - bssrdf_sampling_prob);
@ -812,7 +822,7 @@ ccl_device int surface_shader_bsdf_guided_sample_closure_ris(KernelGlobals kg,
# endif
if (*unguided_bsdf_pdf != 0.0f) {
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
kernel_assert(reduce_min(bsdf_eval_sum(bsdf_eval)) >= 0.0f);
@ -914,7 +924,7 @@ ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg,
label = bsdf_sample(kg, sd, sc, path_flag, rand_bsdf, &eval, wo, pdf, sampled_roughness, eta);
if (*pdf != 0.0f) {
bsdf_eval_init(bsdf_eval, sc->type, eval * sc->weight);
bsdf_eval_init(bsdf_eval, sc, *wo, eval * sc->weight);
if (sd->num_closure > 1) {
float sweight = sc->sample_weight;
@ -922,7 +932,7 @@ ccl_device int surface_shader_bsdf_sample_closure(KernelGlobals kg,
}
}
else {
bsdf_eval_init(bsdf_eval, sc->type, zero_spectrum());
bsdf_eval_init(bsdf_eval, zero_spectrum());
}
return label;
@ -994,7 +1004,7 @@ ccl_device Spectrum surface_shader_diffuse(KernelGlobals kg, ccl_private const S
ccl_private const ShaderClosure *sc = &sd->closure[i];
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type) || CLOSURE_IS_BSSRDF(sc->type))
eval += bsdf_albedo(sd, sc);
eval += bsdf_albedo(sd, sc, true, true);
}
return eval;
@ -1007,8 +1017,8 @@ ccl_device Spectrum surface_shader_glossy(KernelGlobals kg, ccl_private const Sh
for (int i = 0; i < sd->num_closure; i++) {
ccl_private const ShaderClosure *sc = &sd->closure[i];
if (CLOSURE_IS_BSDF_GLOSSY(sc->type))
eval += bsdf_albedo(sd, sc);
if (CLOSURE_IS_BSDF_GLOSSY(sc->type) || CLOSURE_IS_GLASS(sc->type))
eval += bsdf_albedo(sd, sc, true, false);
}
return eval;
@ -1021,8 +1031,8 @@ ccl_device Spectrum surface_shader_transmission(KernelGlobals kg, ccl_private co
for (int i = 0; i < sd->num_closure; i++) {
ccl_private const ShaderClosure *sc = &sd->closure[i];
if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type))
eval += bsdf_albedo(sd, sc);
if (CLOSURE_IS_BSDF_TRANSMISSION(sc->type) || CLOSURE_IS_GLASS(sc->type))
eval += bsdf_albedo(sd, sc, false, true);
}
return eval;

View File

@ -217,7 +217,7 @@ ccl_device_inline float _volume_shader_phase_eval_mis(ccl_private const ShaderDa
Spectrum eval = volume_phase_eval(sd, svc, wo, &phase_pdf);
if (phase_pdf != 0.0f) {
bsdf_eval_accum(result_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
bsdf_eval_accum(result_eval, eval);
sum_pdf += phase_pdf * svc->sample_weight;
}
@ -237,7 +237,7 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
Spectrum eval = volume_phase_eval(sd, svc, wo, &phase_pdf);
if (phase_pdf != 0.0f) {
bsdf_eval_accum(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
bsdf_eval_accum(phase_eval, eval);
}
return phase_pdf;
@ -250,7 +250,7 @@ ccl_device float volume_shader_phase_eval(KernelGlobals kg,
const float3 wo,
ccl_private BsdfEval *phase_eval)
{
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
bsdf_eval_init(phase_eval, zero_spectrum());
float pdf = _volume_shader_phase_eval_mis(sd, phases, wo, -1, phase_eval, 0.0f, 0.0f);
@ -300,7 +300,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
float guide_pdf = 0.0f;
*sampled_roughness = 1.0f - fabsf(svc->g);
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
bsdf_eval_init(phase_eval, zero_spectrum());
if (sample_guiding) {
/* Sample guiding distribution. */
@ -320,7 +320,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
label = volume_phase_sample(sd, svc, rand_phase, &eval, wo, unguided_phase_pdf);
if (*unguided_phase_pdf != 0.0f) {
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
bsdf_eval_init(phase_eval, eval);
*phase_pdf = *unguided_phase_pdf;
if (use_volume_guiding) {
@ -332,7 +332,7 @@ ccl_device int volume_shader_phase_guided_sample(KernelGlobals kg,
kernel_assert(reduce_min(bsdf_eval_sum(phase_eval)) >= 0.0f);
}
else {
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, zero_spectrum());
bsdf_eval_init(phase_eval, zero_spectrum());
}
kernel_assert(reduce_min(bsdf_eval_sum(phase_eval)) >= 0.0f);
@ -359,7 +359,7 @@ ccl_device int volume_shader_phase_sample(KernelGlobals kg,
int label = volume_phase_sample(sd, svc, rand_phase, &eval, wo, pdf);
if (*pdf != 0.0f) {
bsdf_eval_init(phase_eval, CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID, eval);
bsdf_eval_init(phase_eval, eval);
}
return label;

View File

@ -316,7 +316,7 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
return;
}
point_to_centroid = -bcone.axis;
cos_theta_u = fast_cosf(bcone.theta_o);
cos_theta_u = fast_cosf(bcone.theta_o + bcone.theta_e);
distance = 1.0f;
}
else {

View File

@ -113,11 +113,13 @@ file(GLOB SRC_OSL_HEADER_DIST ${OSL_SHADER_DIR}/*.h)
set(SRC_OSL_HEADERS
node_color.h
node_color_blend.h
node_fractal_voronoi.h
node_fresnel.h
node_hash.h
node_math.h
node_noise.h
node_ramp_util.h
node_voronoi.h
stdcycles.h
${SRC_OSL_HEADER_DIST}
)

View File

@ -0,0 +1,137 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "node_voronoi.h"
#include "stdcycles.h"
#include "vector2.h"
#include "vector4.h"
#define vector3 point
#define FRACTAL_VORONOI_X_FX(T) \
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
{ \
float amplitude = 1.0; \
float max_amplitude = 0.0; \
float scale = 1.0; \
\
VoronoiOutput Output; \
Output.Distance = 0.0; \
Output.Color = color(0.0, 0.0, 0.0); \
Output.Position = vector4(0.0, 0.0, 0.0, 0.0); \
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
VoronoiOutput octave; \
if (params.feature == "f1") { \
octave = voronoi_f1(params, coord * scale); \
} \
else if (params.feature == "smooth_f1") { \
octave = voronoi_smooth_f1(params, coord * scale); \
} \
else { \
octave = voronoi_f2(params, coord * scale); \
} \
\
if (zero_input) { \
max_amplitude = 1.0; \
Output = octave; \
break; \
} \
else if (i <= params.detail) { \
max_amplitude += amplitude; \
Output.Distance += octave.Distance * amplitude; \
Output.Color += octave.Color * amplitude; \
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
scale *= params.lacunarity; \
amplitude *= params.roughness; \
} \
else { \
float remainder = params.detail - floor(params.detail); \
if (remainder != 0.0) { \
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
Output.Distance = mix( \
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
Output.Position = mix(Output.Position, \
mix(Output.Position, octave.Position / scale, amplitude), \
remainder); \
} \
} \
} \
\
if (params.normalize) { \
Output.Distance /= max_amplitude * params.max_distance; \
Output.Color /= max_amplitude; \
} \
\
Output.Position = safe_divide(Output.Position, params.scale); \
\
return Output; \
}
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
{ \
float amplitude = 1.0; \
float max_amplitude = 0.5 + 0.5 * params.randomness; \
float scale = 1.0; \
float distance = 8.0; \
\
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
\
if (zero_input) { \
distance = octave_distance; \
break; \
} \
else if (i <= params.detail) { \
max_amplitude = mix(max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
scale *= params.lacunarity; \
amplitude *= params.roughness; \
} \
else { \
float remainder = params.detail - floor(params.detail); \
if (remainder != 0.0) { \
float lerp_amplitude = mix( \
max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
distance = mix(distance, min(distance, lerp_distance), remainder); \
} \
} \
} \
\
if (params.normalize) { \
distance /= max_amplitude; \
} \
\
return distance; \
}
/* **** 1D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(float)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
/* **** 2D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(vector2)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector2)
/* **** 3D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(vector3)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector3)
/* **** 4D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(vector4)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector4)

View File

@ -0,0 +1,920 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include "node_hash.h"
#include "stdcycles.h"
#include "vector2.h"
#include "vector4.h"
#define vector3 point
struct VoronoiParams {
float scale;
float detail;
float roughness;
float lacunarity;
float smoothness;
float exponent;
float randomness;
float max_distance;
int normalize;
string feature;
string metric;
};
struct VoronoiOutput {
float Distance;
color Color;
vector4 Position;
};
/* **** Distance Functions **** */
float distance(float a, float b)
{
return abs(a - b);
}
float distance(vector2 a, vector2 b)
{
return length(a - b);
}
float distance(vector4 a, vector4 b)
{
return length(a - b);
}
float voronoi_distance(float a, float b)
{
return abs(a - b);
}
float voronoi_distance(vector2 a, vector2 b, VoronoiParams params)
{
if (params.metric == "euclidean") {
return distance(a, b);
}
else if (params.metric == "manhattan") {
return abs(a.x - b.x) + abs(a.y - b.y);
}
else if (params.metric == "chebychev") {
return max(abs(a.x - b.x), abs(a.y - b.y));
}
else if (params.metric == "minkowski") {
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent),
1.0 / params.exponent);
}
else {
return 0.0;
}
}
float voronoi_distance(vector3 a, vector3 b, VoronoiParams params)
{
if (params.metric == "euclidean") {
return distance(a, b);
}
else if (params.metric == "manhattan") {
return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
}
else if (params.metric == "chebychev") {
return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
}
else if (params.metric == "minkowski") {
return pow(pow(abs(a[0] - b[0]), params.exponent) + pow(abs(a[1] - b[1]), params.exponent) +
pow(abs(a[2] - b[2]), params.exponent),
1.0 / params.exponent);
}
else {
return 0.0;
}
}
float voronoi_distance(vector4 a, vector4 b, VoronoiParams params)
{
if (params.metric == "euclidean") {
return distance(a, b);
}
else if (params.metric == "manhattan") {
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
}
else if (params.metric == "chebychev") {
return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
}
else if (params.metric == "minkowski") {
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
pow(abs(a.z - b.z), params.exponent) + pow(abs(a.w - b.w), params.exponent),
1.0 / params.exponent);
}
else {
return 0.0;
}
}
/* **** Safe Division **** */
vector2 safe_divide(vector2 a, float b)
{
return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
}
vector4 safe_divide(vector4 a, float b)
{
return vector4((b != 0.0) ? a.x / b : 0.0,
(b != 0.0) ? a.y / b : 0.0,
(b != 0.0) ? a.z / b : 0.0,
(b != 0.0) ? a.w / b : 0.0);
}
/*
* SPDX-License-Identifier: MIT
* Original code is copyright (c) 2013 Inigo Quilez.
*
* Smooth Voronoi:
* - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
*
* Distance To Edge based on:
*
* - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
* - https://www.shadertoy.com/view/ldl3W8
*
* With optimization to change -2..2 scan window to -1..1 for better performance,
* as explained in https://www.shadertoy.com/view/llG3zy.
*/
/* **** 1D Voronoi **** */
vector4 voronoi_position(float coord)
{
return vector4(0.0, 0.0, 0.0, coord);
}
VoronoiOutput voronoi_f1(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float minDistance = 8.0;
float targetOffset = 0.0;
float targetPosition = 0.0;
for (int i = -1; i <= 1; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_float_to_color(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float smoothDistance = 8.0;
float smoothPosition = 0.0;
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
for (int i = -2; i <= 2; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
color cellColor = hash_float_to_color(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
float offsetF1 = 0.0;
float positionF1 = 0.0;
float offsetF2 = 0.0;
float positionF2 = 0.0;
for (int i = -1; i <= 1; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_float_to_color(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * params.randomness;
float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * params.randomness;
float distanceToMidLeft = abs((midPointPosition + leftPointPosition) / 2.0 - localPosition);
float distanceToMidRight = abs((midPointPosition + rightPointPosition) / 2.0 - localPosition);
return min(distanceToMidLeft, distanceToMidRight);
}
float voronoi_n_sphere_radius(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float closestPoint = 0.0;
float closestPointOffset = 0.0;
float minDistance = 8.0;
for (int i = -1; i <= 1; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = abs(pointPosition - localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
minDistance = 8.0;
float closestPointToClosestPoint = 0.0;
for (int i = -1; i <= 1; i++) {
if (i == 0) {
continue;
}
float cellOffset = i + closestPointOffset;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = abs(closestPoint - pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
return abs(closestPointToClosestPoint - closestPoint) / 2.0;
}
/* **** 2D Voronoi **** */
vector4 voronoi_position(vector2 coord)
{
return vector4(coord.x, coord.y, 0.0, 0.0);
}
VoronoiOutput voronoi_f1(VoronoiParams params, vector2 coord)
{
vector2 cellPosition = floor(coord);
vector2 localPosition = coord - cellPosition;
float minDistance = 8.0;
vector2 targetOffset = vector2(0.0, 0.0);
vector2 targetPosition = vector2(0.0, 0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector2 cellOffset = vector2(i, j);
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_vector2_to_color(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector2 coord)
{
vector2 cellPosition = floor(coord);
vector2 localPosition = coord - cellPosition;
float smoothDistance = 8.0;
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
vector2 smoothPosition = vector2(0.0, 0.0);
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
vector2 cellOffset = vector2(i, j);
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
color cellColor = hash_vector2_to_color(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vector2 coord)
{
vector2 cellPosition = floor(coord);
vector2 localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
vector2 offsetF1 = vector2(0.0, 0.0);
vector2 positionF1 = vector2(0.0, 0.0);
vector2 offsetF2 = vector2(0.0, 0.0);
vector2 positionF2 = vector2(0.0, 0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector2 cellOffset = vector2(i, j);
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_vector2_to_color(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vector2 coord)
{
vector2 cellPosition = floor(coord);
vector2 localPosition = coord - cellPosition;
vector2 vectorToClosest = vector2(0.0, 0.0);
float minDistance = 8.0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector2 cellOffset = vector2(i, j);
vector2 vectorToPoint = cellOffset +
hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
minDistance = 8.0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector2 cellOffset = vector2(i, j);
vector2 vectorToPoint = cellOffset +
hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness -
localPosition;
vector2 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
normalize(perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
}
return minDistance;
}
float voronoi_n_sphere_radius(VoronoiParams params, vector2 coord)
{
vector2 cellPosition = floor(coord);
vector2 localPosition = coord - cellPosition;
vector2 closestPoint = vector2(0.0, 0.0);
vector2 closestPointOffset = vector2(0.0, 0.0);
float minDistance = 8.0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector2 cellOffset = vector2(i, j);
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
minDistance = 8.0;
vector2 closestPointToClosestPoint = vector2(0.0, 0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0) {
continue;
}
vector2 cellOffset = vector2(i, j) + closestPointOffset;
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
/* **** 3D Voronoi **** */
vector4 voronoi_position(vector3 coord)
{
return vector4(coord.x, coord.y, coord.z, 0.0);
}
VoronoiOutput voronoi_f1(VoronoiParams params, vector3 coord)
{
vector3 cellPosition = floor(coord);
vector3 localPosition = coord - cellPosition;
float minDistance = 8.0;
vector3 targetOffset = vector3(0.0, 0.0, 0.0);
vector3 targetPosition = vector3(0.0, 0.0, 0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector3 cellOffset = vector3(i, j, k);
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_vector3_to_color(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector3 coord)
{
vector3 cellPosition = floor(coord);
vector3 localPosition = coord - cellPosition;
float smoothDistance = 8.0;
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
vector3 smoothPosition = vector3(0.0, 0.0, 0.0);
for (int k = -2; k <= 2; k++) {
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
vector3 cellOffset = vector3(i, j, k);
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
color cellColor = hash_vector3_to_color(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vector3 coord)
{
vector3 cellPosition = floor(coord);
vector3 localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
vector3 offsetF1 = vector3(0.0, 0.0, 0.0);
vector3 positionF1 = vector3(0.0, 0.0, 0.0);
vector3 offsetF2 = vector3(0.0, 0.0, 0.0);
vector3 positionF2 = vector3(0.0, 0.0, 0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector3 cellOffset = vector3(i, j, k);
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_vector3_to_color(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vector3 coord)
{
vector3 cellPosition = floor(coord);
vector3 localPosition = coord - cellPosition;
vector3 vectorToClosest = vector3(0.0, 0.0, 0.0);
float minDistance = 8.0;
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector3 cellOffset = vector3(i, j, k);
vector3 vectorToPoint = cellOffset +
hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
}
minDistance = 8.0;
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector3 cellOffset = vector3(i, j, k);
vector3 vectorToPoint = cellOffset +
hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness -
localPosition;
vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
normalize((vector)perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
}
}
return minDistance;
}
float voronoi_n_sphere_radius(VoronoiParams params, vector3 coord)
{
vector3 cellPosition = floor(coord);
vector3 localPosition = coord - cellPosition;
vector3 closestPoint = vector3(0.0, 0.0, 0.0);
vector3 closestPointOffset = vector3(0.0, 0.0, 0.0);
float minDistance = 8.0;
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector3 cellOffset = vector3(i, j, k);
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
}
minDistance = 8.0;
vector3 closestPointToClosestPoint = vector3(0.0, 0.0, 0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0 && k == 0) {
continue;
}
vector3 cellOffset = vector3(i, j, k) + closestPointOffset;
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
/* **** 4D Voronoi **** */
vector4 voronoi_position(vector4 coord)
{
return coord;
}
VoronoiOutput voronoi_f1(VoronoiParams params, vector4 coord)
{
vector4 cellPosition = floor(coord);
vector4 localPosition = coord - cellPosition;
float minDistance = 8.0;
vector4 targetOffset = vector4(0.0, 0.0, 0.0, 0.0);
vector4 targetPosition = vector4(0.0, 0.0, 0.0, 0.0);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector4 cellOffset = vector4(i, j, k, u);
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
}
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_vector4_to_color(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector4 coord)
{
vector4 cellPosition = floor(coord);
vector4 localPosition = coord - cellPosition;
float smoothDistance = 8.0;
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0);
for (int u = -2; u <= 2; u++) {
for (int k = -2; k <= 2; k++) {
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
vector4 cellOffset = vector4(i, j, k, u);
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
color cellColor = hash_vector4_to_color(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
}
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vector4 coord)
{
vector4 cellPosition = floor(coord);
vector4 localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0);
vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0);
vector4 offsetF2 = vector4(0.0, 0.0, 0.0, 0.0);
vector4 positionF2 = vector4(0.0, 0.0, 0.0, 0.0);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector4 cellOffset = vector4(i, j, k, u);
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
}
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_vector4_to_color(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vector4 coord)
{
vector4 cellPosition = floor(coord);
vector4 localPosition = coord - cellPosition;
vector4 vectorToClosest = vector4(0.0, 0.0, 0.0, 0.0);
float minDistance = 8.0;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector4 cellOffset = vector4(i, j, k, u);
vector4 vectorToPoint = cellOffset +
hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
}
}
minDistance = 8.0;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector4 cellOffset = vector4(i, j, k, u);
vector4 vectorToPoint = cellOffset +
hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness -
localPosition;
vector4 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
normalize(perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
}
}
}
return minDistance;
}
float voronoi_n_sphere_radius(VoronoiParams params, vector4 coord)
{
vector4 cellPosition = floor(coord);
vector4 localPosition = coord - cellPosition;
vector4 closestPoint = vector4(0.0, 0.0, 0.0, 0.0);
vector4 closestPointOffset = vector4(0.0, 0.0, 0.0, 0.0);
float minDistance = 8.0;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vector4 cellOffset = vector4(i, j, k, u);
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
}
}
minDistance = 8.0;
vector4 closestPointToClosestPoint = vector4(0.0, 0.0, 0.0, 0.0);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0 && k == 0 && u == 0) {
continue;
}
vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset;
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}

File diff suppressed because it is too large Load Diff

View File

@ -434,12 +434,14 @@ typedef enum ClosureType {
CLOSURE_BSDF_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
/* Glass */
CLOSURE_BSDF_SHARP_GLASS_ID,
CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID,
CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID,
CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */
CLOSURE_BSDF_HAIR_PRINCIPLED_ID,
CLOSURE_BSDF_HAIR_TRANSMISSION_ID,
/* Special cases */
CLOSURE_BSDF_TRANSPARENT_ID,
@ -473,15 +475,15 @@ typedef enum ClosureType {
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_SINGULAR(type) \
(type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \
type == CLOSURE_BSDF_TRANSPARENT_ID)
type == CLOSURE_BSDF_TRANSPARENT_ID || type == CLOSURE_BSDF_SHARP_GLASS_ID)
#define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID)
#define CLOSURE_IS_BSDF_MULTISCATTER(type) \
(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \
type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_BSDF_MICROFACET(type) \
((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
(type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \
type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) || \
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID))
#define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
#define CLOSURE_IS_BSSRDF(type) \
(type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID)
@ -491,8 +493,8 @@ typedef enum ClosureType {
#define CLOSURE_IS_VOLUME_ABSORPTION(type) (type == CLOSURE_VOLUME_ABSORPTION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
#define CLOSURE_IS_PHASE(type) (type == CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
#define CLOSURE_IS_REFRACTIVE(type) \
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_REFRACTION(type) \
(type >= CLOSURE_BSDF_REFRACTION_ID && type <= CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID)
#define CLOSURE_IS_GLASS(type) \
(type >= CLOSURE_BSDF_SHARP_GLASS_ID && type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
#define CLOSURE_IS_PRINCIPLED(type) (type == CLOSURE_BSDF_PRINCIPLED_ID)

File diff suppressed because it is too large Load Diff

View File

@ -1207,9 +1207,14 @@ NODE_DEFINE(VoronoiTextureNode)
feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
SOCKET_BOOLEAN(normalize, "Normalize", false);
SOCKET_IN_POINT(vector, "Vector", zero_float3(), SocketType::LINK_TEXTURE_GENERATED);
SOCKET_IN_FLOAT(w, "W", 0.0f);
SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
SOCKET_IN_FLOAT(detail, "Detail", 0.0f);
SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
@ -1230,6 +1235,9 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
ShaderInput *vector_in = input("Vector");
ShaderInput *w_in = input("W");
ShaderInput *scale_in = input("Scale");
ShaderInput *detail_in = input("Detail");
ShaderInput *roughness_in = input("Roughness");
ShaderInput *lacunarity_in = input("Lacunarity");
ShaderInput *smoothness_in = input("Smoothness");
ShaderInput *exponent_in = input("Exponent");
ShaderInput *randomness_in = input("Randomness");
@ -1243,6 +1251,9 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
@ -1255,19 +1266,21 @@ void VoronoiTextureNode::compile(SVMCompiler &compiler)
compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
compiler.add_node(
compiler.encode_uchar4(
vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
compiler.encode_uchar4(exponent_stack_offset,
randomness_stack_offset,
distance_stack_offset,
color_stack_offset),
compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
__float_as_int(w));
vector_stack_offset, w_in_stack_offset, scale_stack_offset, detail_stack_offset),
compiler.encode_uchar4(roughness_stack_offset,
lacunarity_stack_offset,
smoothness_stack_offset,
exponent_stack_offset),
compiler.encode_uchar4(
randomness_stack_offset, normalize, distance_stack_offset, color_stack_offset),
compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset));
compiler.add_node(__float_as_int(scale),
compiler.add_node(
__float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
compiler.add_node(__float_as_int(lacunarity),
__float_as_int(smoothness),
__float_as_int(exponent),
__float_as_int(randomness));
tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
}
@ -1278,6 +1291,7 @@ void VoronoiTextureNode::compile(OSLCompiler &compiler)
compiler.parameter(this, "dimensions");
compiler.parameter(this, "feature");
compiler.parameter(this, "metric");
compiler.parameter(this, "normalize");
compiler.add(this, "node_voronoi_texture");
}

View File

@ -254,8 +254,12 @@ class VoronoiTextureNode : public TextureNode {
NODE_SOCKET_API(int, dimensions)
NODE_SOCKET_API(NodeVoronoiDistanceMetric, metric)
NODE_SOCKET_API(NodeVoronoiFeature, feature)
NODE_SOCKET_API(bool, normalize)
NODE_SOCKET_API(float, w)
NODE_SOCKET_API(float, scale)
NODE_SOCKET_API(float, detail)
NODE_SOCKET_API(float, roughness)
NODE_SOCKET_API(float, lacunarity)
NODE_SOCKET_API(float, exponent)
NODE_SOCKET_API(float, smoothness)
NODE_SOCKET_API(float, randomness)

View File

@ -224,6 +224,12 @@ ccl_device_inline float2 floor(const float2 a)
#endif /* !__KERNEL_METAL__ */
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
ccl_device_inline float2 power(float2 v, float e)
{
return make_float2(powf(v.x, e), powf(v.y, e));
}
ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
{
return (b != 0.0f) ? a / b : zero_float2();

View File

@ -469,7 +469,8 @@ ccl_device_inline bool isequal(const float3 a, const float3 b)
#endif
}
ccl_device_inline float3 pow(float3 v, float e)
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
ccl_device_inline float3 power(float3 v, float e)
{
return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e));
}

View File

@ -593,7 +593,8 @@ ccl_device_inline float4 ensure_finite(float4 v)
return v;
}
ccl_device_inline float4 pow(float4 v, float e)
/* Consistent name for this would be pow, but HIP compiler crashes in name mangling. */
ccl_device_inline float4 power(float4 v, float e)
{
return make_float4(powf(v.x, e), powf(v.y, e), powf(v.z, e), powf(v.w, e));
}

View File

@ -44,10 +44,9 @@ def geometry_modifier_poll(context):
def get_context_modifier(context):
# Context only has a 'modifier' attribute in the modifier extra operators dropdown.
if hasattr(context, 'modifier'):
modifier = context.modifier
else:
# Context only has a "modifier" attribute in the modifier extra operators drop-down.
modifier = getattr(context, "modifier", ...)
if modifier is ...:
ob = context.object
if ob is None:
return False

View File

@ -2037,6 +2037,15 @@ class VIEW3D_MT_select_edit_gpencil(Menu):
layout.separator()
op = layout.operator("grease_pencil.select_ends", text="First")
op.amount_start = 1
op.amount_end = 0
op = layout.operator("grease_pencil.select_ends", text="Last")
op.amount_start = 0
op.amount_end = 1
layout.separator()
layout.operator("grease_pencil.select_more")
layout.operator("grease_pencil.select_less")

View File

@ -9,7 +9,9 @@
#include "BLI_cpp_type.hh"
#include "BLI_generic_span.hh"
#include "BLI_generic_virtual_array.hh"
#include "BLI_math_axis_angle.hh"
#include "BLI_math_color.hh"
#include "BLI_math_quaternion.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
@ -31,7 +33,8 @@ inline void convert_to_static_type(const CPPType &cpp_type, const Func &func)
bool,
int8_t,
ColorGeometry4f,
ColorGeometry4b>([&](auto type_tag) {
ColorGeometry4b,
math::Quaternion>([&](auto type_tag) {
using T = typename decltype(type_tag)::type;
if constexpr (std::is_same_v<T, void>) {
/* It's expected that the given cpp type is one of the supported ones. */
@ -400,7 +403,10 @@ class BooleanPropagationMixer {
* This mixer accumulates values in a type that is different from the one that is mixed.
* Some types cannot encode the floating point weights in their values (e.g. int and bool).
*/
template<typename T, typename AccumulationT, T (*ConvertToT)(const AccumulationT &value)>
template<typename T,
typename AccumulationT,
AccumulationT (*ValueToAccumulate)(const T &value),
T (*AccumulateToValue)(const AccumulationT &value)>
class SimpleMixerWithAccumulationType {
private:
struct Item {
@ -432,7 +438,7 @@ class SimpleMixerWithAccumulationType {
void set(const int64_t index, const T &value, const float weight = 1.0f)
{
const AccumulationT converted_value = static_cast<AccumulationT>(value);
const AccumulationT converted_value = ValueToAccumulate(value);
Item &item = accumulation_buffer_[index];
item.value = converted_value * weight;
item.weight = weight;
@ -440,7 +446,7 @@ class SimpleMixerWithAccumulationType {
void mix_in(const int64_t index, const T &value, const float weight = 1.0f)
{
const AccumulationT converted_value = static_cast<AccumulationT>(value);
const AccumulationT converted_value = ValueToAccumulate(value);
Item &item = accumulation_buffer_[index];
item.value += converted_value * weight;
item.weight += weight;
@ -457,7 +463,7 @@ class SimpleMixerWithAccumulationType {
const Item &item = accumulation_buffer_[i];
if (item.weight > 0.0f) {
const float weight_inv = 1.0f / item.weight;
const T converted_value = ConvertToT(item.value * weight_inv);
const T converted_value = AccumulateToValue(item.value * weight_inv);
buffer_[i] = converted_value;
}
else {
@ -532,40 +538,68 @@ template<> struct DefaultMixerStruct<ColorGeometry4b> {
using type = ColorGeometry4bMixer;
};
template<> struct DefaultMixerStruct<int> {
static double int_to_double(const int &value)
{
return double(value);
}
static int double_to_int(const double &value)
{
return int(std::round(value));
}
/* Store interpolated ints in a double temporarily, so that weights are handled correctly. It
* uses double instead of float so that it is accurate for all 32 bit integers. */
using type = SimpleMixerWithAccumulationType<int, double, double_to_int>;
using type = SimpleMixerWithAccumulationType<int, double, int_to_double, double_to_int>;
};
template<> struct DefaultMixerStruct<int2> {
static double2 int_to_double(const int2 &value)
{
return double2(value);
}
static int2 double_to_int(const double2 &value)
{
return int2(math::round(value));
}
/* Store interpolated ints in a double temporarily, so that weights are handled correctly. It
* uses double instead of float so that it is accurate for all 32 bit integers. */
using type = SimpleMixerWithAccumulationType<int2, double2, double_to_int>;
using type = SimpleMixerWithAccumulationType<int2, double2, int_to_double, double_to_int>;
};
template<> struct DefaultMixerStruct<bool> {
static float bool_to_float(const bool &value)
{
return value ? 1.0f : 0.0f;
}
static bool float_to_bool(const float &value)
{
return value >= 0.5f;
}
/* Store interpolated booleans in a float temporary.
* Otherwise information provided by weights is easily rounded away. */
using type = SimpleMixerWithAccumulationType<bool, float, float_to_bool>;
using type = SimpleMixerWithAccumulationType<bool, float, bool_to_float, float_to_bool>;
};
template<> struct DefaultMixerStruct<int8_t> {
static float int8_t_to_float(const int8_t &value)
{
return float(value);
}
static int8_t float_to_int8_t(const float &value)
{
return int8_t(std::round(value));
}
/* Store interpolated 8 bit integers in a float temporarily to increase accuracy. */
using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>;
using type = SimpleMixerWithAccumulationType<int8_t, float, int8_t_to_float, float_to_int8_t>;
};
template<> struct DefaultMixerStruct<math::Quaternion> {
static float3 quat_to_expmap(const math::Quaternion &value)
{
return value.expmap();
}
static math::Quaternion expmap_to_quat(const float3 &value)
{
return math::Quaternion::expmap(value);
}
using type =
SimpleMixerWithAccumulationType<math::Quaternion, float3, quat_to_expmap, expmap_to_quat>;
};
template<typename T> struct DefaultPropagationMixerStruct {

View File

@ -30,7 +30,7 @@ bool BKE_curves_attribute_required(const struct Curves *curves, const char *name
/* Depsgraph */
struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src);
struct Curves *BKE_curves_copy_for_eval(const struct Curves *curves_src);
void BKE_curves_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,

View File

@ -80,7 +80,7 @@ bool BKE_pointcloud_attribute_required(const struct PointCloud *pointcloud, cons
/* Dependency Graph */
struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src);
struct PointCloud *BKE_pointcloud_copy_for_eval(const struct PointCloud *pointcloud_src);
void BKE_pointcloud_data_update(struct Depsgraph *depsgraph,
struct Scene *scene,

View File

@ -48,7 +48,7 @@ struct wmWindow;
struct wmWindowManager;
/* spacetype has everything stored to get an editor working, it gets initialized via
* #ED_spacetypes_init() in `editors/space_api/spacetypes.c` */
* #ED_spacetypes_init() in `editors/space_api/spacetypes.cc` */
/* an editor in Blender is a combined ScrArea + SpaceType + SpaceData */
#define BKE_ST_MAXNAME 64

View File

@ -132,7 +132,7 @@ void BKE_volume_grid_transform_matrix_set(const struct Volume *volume,
* file path. Grids are shared with the source data-block, not copied. */
struct Volume *BKE_volume_new_for_eval(const struct Volume *volume_src);
struct Volume *BKE_volume_copy_for_eval(struct Volume *volume_src);
struct Volume *BKE_volume_copy_for_eval(const struct Volume *volume_src);
struct VolumeGrid *BKE_volume_grid_add(struct Volume *volume,
const char *name,

View File

@ -107,11 +107,13 @@ static int attribute_data_type_complexity(const eCustomDataType data_type)
return 6;
case CD_PROP_BYTE_COLOR:
return 7;
case CD_PROP_COLOR:
case CD_PROP_QUATERNION:
return 8;
case CD_PROP_COLOR:
return 9;
#if 0 /* These attribute types are not supported yet. */
case CD_PROP_STRING:
return 9;
return 10;
#endif
default:
/* Only accept "generic" custom data types used by the attribute system. */

View File

@ -3,11 +3,39 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array_utils.hh"
#include "BLI_math_quaternion.hh"
#include "BKE_attribute_math.hh"
namespace blender::bke::attribute_math {
template<>
math::Quaternion mix2(const float factor, const math::Quaternion &a, const math::Quaternion &b)
{
return math::interpolate(a, b, factor);
}
template<>
math::Quaternion mix3(const float3 &weights,
const math::Quaternion &v0,
const math::Quaternion &v1,
const math::Quaternion &v2)
{
const float3 expmap_mixed = mix3(weights, v0.expmap(), v1.expmap(), v2.expmap());
return math::Quaternion::expmap(expmap_mixed);
}
template<>
math::Quaternion mix4(const float4 &weights,
const math::Quaternion &v0,
const math::Quaternion &v1,
const math::Quaternion &v2,
const math::Quaternion &v3)
{
const float3 expmap_mixed = mix4(weights, v0.expmap(), v1.expmap(), v2.expmap(), v3.expmap());
return math::Quaternion::expmap(expmap_mixed);
}
ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer,
ColorGeometry4f default_color)
: ColorGeometry4fMixer(buffer, buffer.index_range(), default_color)

View File

@ -222,7 +222,7 @@ bool BKE_curves_attribute_required(const Curves * /*curves*/, const char *name)
return STREQ(name, ATTR_POSITION);
}
Curves *BKE_curves_copy_for_eval(Curves *curves_src)
Curves *BKE_curves_copy_for_eval(const Curves *curves_src)
{
return reinterpret_cast<Curves *>(
BKE_id_copy_ex(nullptr, &curves_src->id, nullptr, LIB_ID_COPY_LOCALIZE));

View File

@ -24,6 +24,7 @@
#include "BLI_index_range.hh"
#include "BLI_math.h"
#include "BLI_math_color_blend.h"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector.hh"
#include "BLI_mempool.h"
#include "BLI_path_util.h"
@ -1542,6 +1543,20 @@ static void layerInterp_propbool(const void **sources,
*(bool *)dest = result;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Callbacks for (#math::Quaternion, #CD_PROP_QUATERNION)
* \{ */
static void layerDefault_propquaternion(void *data, const int count)
{
using namespace blender;
MutableSpan(static_cast<math::Quaternion *>(data), count).fill(math::Quaternion::identity());
}
/** \} */
static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0: CD_MVERT */ /* DEPRECATED */
{sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
@ -1933,6 +1948,16 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
nullptr},
/* 51: CD_HAIRLENGTH */
{sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 52: CD_PROP_QUATERNION */
{sizeof(float[4]),
"vec4f",
1,
N_("Quaternion"),
nullptr,
nullptr,
nullptr,
nullptr,
layerDefault_propquaternion},
};
static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@ -1990,6 +2015,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDPropFloat2",
"CDPropBoolean",
"CDHairLength",
"CDPropQuaternion",
};
const CustomData_MeshMasks CD_MASK_BAREMESH = {
@ -5354,6 +5380,8 @@ const blender::CPPType *custom_data_type_to_cpp_type(const eCustomDataType type)
return &CPPType::get<int8_t>();
case CD_PROP_BYTE_COLOR:
return &CPPType::get<ColorGeometry4b>();
case CD_PROP_QUATERNION:
return &CPPType::get<math::Quaternion>();
case CD_PROP_STRING:
return &CPPType::get<MStringProperty>();
default:
@ -5390,6 +5418,9 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
if (type.is<ColorGeometry4b>()) {
return CD_PROP_BYTE_COLOR;
}
if (type.is<math::Quaternion>()) {
return CD_PROP_QUATERNION;
}
if (type.is<MStringProperty>()) {
return CD_PROP_STRING;
}

View File

@ -661,6 +661,26 @@ static int customdata_compare(
}
break;
}
case CD_PROP_QUATERNION: {
const float(*l1_data)[4] = (float(*)[4])l1->data;
const float(*l2_data)[4] = (float(*)[4])l2->data;
for (int i = 0; i < total_length; i++) {
if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
}
if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
}
if (compare_threshold_relative(l1_data[i][2], l2_data[i][2], thresh)) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
}
if (compare_threshold_relative(l1_data[i][3], l2_data[i][3], thresh)) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
}
}
break;
}
case CD_PROP_INT32: {
const int *l1_data = (int *)l1->data;
const int *l2_data = (int *)l2->data;

View File

@ -11,6 +11,7 @@
#include "DNA_object_types.h"
#include "BLI_map.hh"
#include "BLI_ordered_edge.hh"
#include "BLI_task.hh"
#include "BLI_threads.h"
#include "BLI_timeit.hh"
@ -21,43 +22,14 @@
namespace blender::bke::calc_edges {
/** This is used to uniquely identify edges in a hash map. */
struct OrderedEdge {
int v_low, v_high;
OrderedEdge(const int v1, const int v2)
{
if (v1 < v2) {
v_low = v1;
v_high = v2;
}
else {
v_low = v2;
v_high = v1;
}
}
OrderedEdge(const uint v1, const uint v2) : OrderedEdge(int(v1), int(v2)) {}
uint64_t hash() const
{
return (this->v_low << 8) ^ this->v_high;
}
/** Return a hash value that is likely to be different in the low bits from the normal `hash()`
* function. This is necessary to avoid collisions in #BKE_mesh_calc_edges. */
uint64_t hash2() const
{
return this->v_low;
}
friend bool operator==(const OrderedEdge &e1, const OrderedEdge &e2)
{
BLI_assert(e1.v_low < e1.v_high);
BLI_assert(e2.v_low < e2.v_high);
return e1.v_low == e2.v_low && e1.v_high == e2.v_high;
}
};
/**
* Return a hash value that is likely to be different in the low bits from the normal `hash()`
* function. This is necessary to avoid collisions in #BKE_mesh_calc_edges.
*/
static uint64_t edge_hash_2(const OrderedEdge &edge)
{
return edge.v_low;
}
/* The map first contains an edge pointer and later an index. */
union OrigEdgeOrIndex {
@ -86,7 +58,7 @@ static void add_existing_edges_to_hash_maps(Mesh *mesh,
for (const int2 &edge : edges) {
OrderedEdge ordered_edge{edge[0], edge[1]};
/* Only add the edge when it belongs into this map. */
if (task_index == (parallel_mask & ordered_edge.hash2())) {
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
edge_map.add_new(ordered_edge, {&edge});
}
}
@ -109,7 +81,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
if (vert_prev != vert) {
OrderedEdge ordered_edge{vert_prev, vert};
/* Only add the edge when it belongs into this map. */
if (task_index == (parallel_mask & ordered_edge.hash2())) {
if (task_index == (parallel_mask & edge_hash_2(ordered_edge))) {
edge_map.lookup_or_add(ordered_edge, {nullptr});
}
}
@ -171,7 +143,7 @@ static void update_edge_indices_in_poly_loops(const OffsetIndices<int> polys,
if (vert_prev != vert) {
OrderedEdge ordered_edge{vert_prev, vert};
/* Double lookup: First find the map that contains the edge, then lookup the edge. */
const EdgeMap &edge_map = edge_maps[parallel_mask & ordered_edge.hash2()];
const EdgeMap &edge_map = edge_maps[parallel_mask & edge_hash_2(ordered_edge)];
edge_index = edge_map.lookup(ordered_edge).index;
}
else {

View File

@ -320,7 +320,7 @@ bool BKE_pointcloud_attribute_required(const PointCloud * /*pointcloud*/, const
/* Dependency Graph */
PointCloud *BKE_pointcloud_copy_for_eval(PointCloud *pointcloud_src)
PointCloud *BKE_pointcloud_copy_for_eval(const PointCloud *pointcloud_src)
{
return reinterpret_cast<PointCloud *>(
BKE_id_copy_ex(nullptr, &pointcloud_src->id, nullptr, LIB_ID_COPY_LOCALIZE));

View File

@ -2684,7 +2684,8 @@ void BKE_scene_update_sound(Depsgraph *depsgraph, Main *bmain)
BKE_sound_set_scene_volume(scene, scene->audio.volume);
}
if (recalc & ID_RECALC_AUDIO_MUTE) {
const bool is_mute = (scene->audio.flag & AUDIO_MUTE);
const bool is_mute = (DEG_get_mode(depsgraph) == DAG_EVAL_VIEWPORT) &&
(scene->audio.flag & AUDIO_MUTE);
BKE_sound_mute_scene(scene, is_mute);
}
if (recalc & ID_RECALC_AUDIO_LISTENER) {

View File

@ -18,6 +18,7 @@
#include "BLI_endian_switch.h"
#include "BLI_fileops.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_path_util.h"
#include "RNA_access.h"
@ -778,6 +779,10 @@ static std::shared_ptr<io::serialize::Value> serialize_primitive_value(
const ColorGeometry4f value = *static_cast<const ColorGeometry4f *>(value_ptr);
return serialize_float_array({&value.r, 4});
}
case CD_PROP_QUATERNION: {
const math::Quaternion value = *static_cast<const math::Quaternion *>(value_ptr);
return serialize_float_array({&value.x, 4});
}
default:
break;
}
@ -966,6 +971,9 @@ template<typename T>
case CD_PROP_COLOR: {
return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
}
case CD_PROP_QUATERNION: {
return deserialize_float_array(io_value, {static_cast<float *>(r_value), 4});
}
default:
break;
}

View File

@ -1530,7 +1530,7 @@ Volume *BKE_volume_new_for_eval(const Volume *volume_src)
return volume_dst;
}
Volume *BKE_volume_copy_for_eval(Volume *volume_src)
Volume *BKE_volume_copy_for_eval(const Volume *volume_src)
{
return reinterpret_cast<Volume *>(
BKE_id_copy_ex(nullptr, &volume_src->id, nullptr, LIB_ID_COPY_LOCALIZE));

View File

@ -11,6 +11,7 @@
#include "BLI_index_mask.hh"
#include "BLI_math_base.hh"
#include "BLI_math_color.hh"
#include "BLI_math_quaternion.hh"
#include "BLI_math_vector.hh"
namespace blender::length_parameterize {

View File

@ -306,87 +306,85 @@ float musgrave_hetero_terrain(
/** \name Voronoi Noise
* \{ */
void voronoi_f1(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
void voronoi_smooth_f1(
float w, float smoothness, float randomness, float *r_distance, float3 *r_color, float *r_w);
void voronoi_f2(float w, float randomness, float *r_distance, float3 *r_color, float *r_w);
void voronoi_distance_to_edge(float w, float randomness, float *r_distance);
void voronoi_n_sphere_radius(float w, float randomness, float *r_radius);
struct VoronoiParams {
float scale;
float detail;
float roughness;
float lacunarity;
float smoothness;
float exponent;
float randomness;
float max_distance;
bool normalize;
int feature;
int metric;
};
void voronoi_f1(const float2 coord,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float2 *r_position);
void voronoi_smooth_f1(const float2 coord,
float smoothness,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float2 *r_position);
void voronoi_f2(const float2 coord,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float2 *r_position);
void voronoi_distance_to_edge(const float2 coord, float randomness, float *r_distance);
void voronoi_n_sphere_radius(const float2 coord, float randomness, float *r_radius);
struct VoronoiOutput {
float distance = 0.0f;
float3 color{0.0f, 0.0f, 0.0f};
float4 position{0.0f, 0.0f, 0.0f, 0.0f};
};
void voronoi_f1(const float3 coord,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float3 *r_position);
void voronoi_smooth_f1(const float3 coord,
float smoothness,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float3 *r_position);
void voronoi_f2(const float3 coord,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float3 *r_position);
void voronoi_distance_to_edge(const float3 coord, float randomness, float *r_distance);
void voronoi_n_sphere_radius(const float3 coord, float randomness, float *r_radius);
/* ***** Distances ***** */
void voronoi_f1(const float4 coord,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float4 *r_position);
void voronoi_smooth_f1(const float4 coord,
float smoothness,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float4 *r_position);
void voronoi_f2(const float4 coord,
float exponent,
float randomness,
int metric,
float *r_distance,
float3 *r_color,
float4 *r_position);
void voronoi_distance_to_edge(const float4 coord, float randomness, float *r_distance);
void voronoi_n_sphere_radius(const float4 coord, float randomness, float *r_radius);
float voronoi_distance(const float a, const float b);
float voronoi_distance(const float2 a, const float2 b, const VoronoiParams &params);
float voronoi_distance(const float3 a, const float3 b, const VoronoiParams &params);
float voronoi_distance(const float4 a, const float4 b, const VoronoiParams &params);
/* **** 1D Voronoi **** */
float4 voronoi_position(const float coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float coord);
/* **** 2D Voronoi **** */
float4 voronoi_position(const float2 coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float2 coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float2 coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float2 coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float2 coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float2 coord);
/* **** 3D Voronoi **** */
float4 voronoi_position(const float3 coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float3 coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float3 coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float3 coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float3 coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float3 coord);
/* **** 4D Voronoi **** */
float4 voronoi_position(const float4 coord);
VoronoiOutput voronoi_f1(const VoronoiParams &params, const float4 coord);
VoronoiOutput voronoi_smooth_f1(const VoronoiParams &params,
const float4 coord,
const bool calc_color);
VoronoiOutput voronoi_f2(const VoronoiParams &params, const float4 coord);
float voronoi_distance_to_edge(const VoronoiParams &params, const float4 coord);
float voronoi_n_sphere_radius(const VoronoiParams &params, const float4 coord);
/* Fractal Voronoi Noise */
template<typename T>
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams &params,
const T coord,
const bool calc_color);
template<typename T>
float fractal_voronoi_distance_to_edge(const VoronoiParams &params, const T coord);
/** \} */

View File

@ -32,7 +32,7 @@ template<typename T> class OffsetIndices {
OffsetIndices() = default;
OffsetIndices(const Span<T> offsets) : offsets_(offsets)
{
BLI_assert(std::is_sorted(offsets_.begin(), offsets_.end()));
BLI_assert(offsets_.size() < 2 || std::is_sorted(offsets_.begin(), offsets_.end()));
}
/** Return the total number of elements in the referenced arrays. */

View File

@ -0,0 +1,47 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_assert.h"
#include "BLI_math_vector_types.hh"
namespace blender {
/**
* A version of `int2` used as a key for hash-maps, agnostic of the arbitrary order of the two
* vertices in a mesh edge.
*/
struct OrderedEdge {
int v_low;
int v_high;
OrderedEdge(const int v1, const int v2)
{
if (v1 < v2) {
v_low = v1;
v_high = v2;
}
else {
v_low = v2;
v_high = v1;
}
}
OrderedEdge(const int2 edge) : OrderedEdge(edge[0], edge[1]) {}
OrderedEdge(const uint v1, const uint v2) : OrderedEdge(int(v1), int(v2)) {}
uint64_t hash() const
{
return (this->v_low << 8) ^ this->v_high;
}
friend bool operator==(const OrderedEdge &e1, const OrderedEdge &e2)
{
BLI_assert(e1.v_low < e1.v_high);
BLI_assert(e2.v_low < e2.v_high);
return e1.v_low == e2.v_low && e1.v_high == e2.v_high;
}
};
} // namespace blender

View File

@ -265,6 +265,10 @@ int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1);
* Removes the last slash and everything after it to the end of path, if there is one.
*/
void BLI_path_slash_rstrip(char *path) ATTR_NONNULL(1);
/**
* \return the next non-slash character or the null byte (when `path` only contains slashes).
*/
const char *BLI_path_slash_skip(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/**
* Changes to the path separators to the native ones for this OS.
*/

View File

@ -320,6 +320,7 @@ set(SRC
BLI_noise.hh
BLI_offset_indices.hh
BLI_offset_span.hh
BLI_ordered_edge.hh
BLI_parameter_pack_utils.hh
BLI_path_util.h
BLI_polyfill_2d.h

View File

@ -6,6 +6,7 @@
#include "BLI_cpp_type_make.hh"
#include "BLI_cpp_types_make.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh"
namespace blender {
@ -65,6 +66,8 @@ BLI_CPP_TYPE_MAKE(uint64_t, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::ColorGeometry4f, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::ColorGeometry4b, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(blender::math::Quaternion, CPPTypeFlags::BasicType)
BLI_CPP_TYPE_MAKE(std::string, CPPTypeFlags::BasicType)
BLI_VECTOR_CPP_TYPE_MAKE(std::string)
@ -94,6 +97,8 @@ void register_cpp_types()
BLI_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
BLI_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
BLI_CPP_TYPE_REGISTER(math::Quaternion);
BLI_CPP_TYPE_REGISTER(std::string);
BLI_VECTOR_CPP_TYPE_REGISTER(std::string);

File diff suppressed because it is too large Load Diff

View File

@ -1118,9 +1118,7 @@ bool BLI_path_abs(char path[FILE_MAX], const char *basepath)
BLI_assert(strlen(tmp) == root_dir_len);
/* Step over the slashes at the beginning of the path. */
while (BLI_path_slash_is_native_compat(*p)) {
p++;
}
p = (char *)BLI_path_slash_skip(p);
BLI_strncpy(tmp + root_dir_len, p, sizeof(tmp) - root_dir_len);
}
else {
@ -1958,6 +1956,15 @@ void BLI_path_slash_rstrip(char *path)
}
}
const char *BLI_path_slash_skip(const char *path)
{
/* This accounts for a null byte too. */
while (BLI_path_slash_is_native_compat(*path)) {
path++;
}
return path;
}
void BLI_path_slash_native(char *path)
{
#ifdef WIN32

View File

@ -42,7 +42,7 @@ set(SRC
intern/undofile.cc
intern/versioning_250.c
intern/versioning_260.c
intern/versioning_270.c
intern/versioning_270.cc
intern/versioning_280.cc
intern/versioning_290.cc
intern/versioning_300.cc

View File

@ -329,7 +329,9 @@ static void do_version_scene_collection_convert(
BLI_ghash_insert(collection_map, collection, sc);
}
LISTBASE_FOREACH (SceneCollection *, nsc, &sc->scene_collections) {
for (SceneCollection *nsc = static_cast<SceneCollection *>(sc->scene_collections.first);
nsc != nullptr;)
{
SceneCollection *nsc_next = nsc->next;
Collection *ncollection = BKE_collection_add(bmain, collection, nsc->name);
ncollection->id.lib = id->lib;

View File

@ -298,3 +298,6 @@ if(WITH_OPENCOLORIO)
endif()
blender_add_lib(bf_realtime_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
# Needed so we can use dna_type_offsets.h
add_dependencies(bf_realtime_compositor bf_dna)

View File

@ -211,6 +211,9 @@ ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph)
Object *DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
{
if (object == nullptr) {
return nullptr;
}
return (Object *)DEG_get_evaluated_id(depsgraph, &object->id);
}

View File

@ -127,7 +127,7 @@ void deg_graph_flush_visibility_flags(Depsgraph *graph)
op_node->custom_flags = 0;
op_node->num_links_pending = 0;
for (Relation *rel : op_node->outlinks) {
if ((rel->from->type == NodeType::OPERATION) && (rel->flag & RELATION_FLAG_CYCLIC) == 0) {
if ((rel->to->type == NodeType::OPERATION) && (rel->flag & RELATION_FLAG_CYCLIC) == 0) {
++op_node->num_links_pending;
}
}

View File

@ -246,7 +246,7 @@ void output_renderpass_color(int id, vec4 color)
imageStore(rp_color_img, ivec3(texel, id), color);
}
#endif
};
}
void output_renderpass_value(int id, float value)
{
@ -256,7 +256,7 @@ void output_renderpass_value(int id, float value)
imageStore(rp_value_img, ivec3(texel, id), vec4(value));
}
#endif
};
}
void clear_aovs()
{

View File

@ -83,7 +83,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
int *r_layer_index,
eCustomDataType *r_type)
{
const eCustomDataType possible_attribute_types[9] = {
const eCustomDataType possible_attribute_types[10] = {
CD_PROP_BOOL,
CD_PROP_INT8,
CD_PROP_INT32_2D,
@ -92,6 +92,7 @@ bool drw_custom_data_match_attribute(const CustomData *custom_data,
CD_PROP_FLOAT2,
CD_PROP_FLOAT3,
CD_PROP_COLOR,
CD_PROP_QUATERNION,
CD_PROP_BYTE_COLOR,
};

View File

@ -392,6 +392,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object,
}
case CD_PROP_BYTE_COLOR:
case CD_PROP_COLOR:
case CD_PROP_QUATERNION:
case CD_PROP_FLOAT3:
case CD_PROP_BOOL:
case CD_PROP_INT8:

View File

@ -107,6 +107,7 @@ static uint gpu_component_size_for_attribute_type(eCustomDataType type)
return 3;
case CD_PROP_COLOR:
case CD_PROP_BYTE_COLOR:
case CD_PROP_QUATERNION:
return 4;
default:
return 0;
@ -315,6 +316,7 @@ static void extract_attr(const MeshRenderData *mr,
case CD_PROP_FLOAT3:
extract_attr_generic<float3>(mr, vbo, request);
break;
case CD_PROP_QUATERNION:
case CD_PROP_COLOR:
extract_attr_generic<float4>(mr, vbo, request);
break;

View File

@ -172,6 +172,58 @@ static void GREASE_PENCIL_OT_select_linked(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int select_ends_exec(bContext *C, wmOperator *op)
{
const int amount_start = RNA_int_get(op->ptr, "amount_start");
const int amount_end = RNA_int_get(op->ptr, "amount_end");
Scene *scene = CTX_data_scene(C);
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int /*drawing_index*/, GreasePencilDrawing &drawing) {
blender::ed::curves::select_ends(drawing.geometry.wrap(), amount_start, amount_end);
});
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
* attribute for now. */
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, &grease_pencil);
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_select_ends(wmOperatorType *ot)
{
ot->name = "Select Ends";
ot->idname = "GREASE_PENCIL_OT_select_ends";
ot->description = "Select end points of strokes";
ot->exec = select_ends_exec;
ot->poll = editable_grease_pencil_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
"amount_start",
0,
0,
INT32_MAX,
"Amount Start",
"Number of points to select from the start",
0,
INT32_MAX);
RNA_def_int(ot->srna,
"amount_end",
1,
0,
INT32_MAX,
"Amount End",
"Number of points to select from the end",
0,
INT32_MAX);
}
static void keymap_grease_pencil_editing(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Edit Mode", 0, 0);
@ -187,6 +239,7 @@ void ED_operatortypes_grease_pencil(void)
WM_operatortype_append(GREASE_PENCIL_OT_select_more);
WM_operatortype_append(GREASE_PENCIL_OT_select_less);
WM_operatortype_append(GREASE_PENCIL_OT_select_linked);
WM_operatortype_append(GREASE_PENCIL_OT_select_ends);
}
void ED_keymap_grease_pencil(wmKeyConfig *keyconf)

View File

@ -10,16 +10,16 @@
#include "BLI_compiler_attrs.h"
#include "BKE_scene.h"
#ifdef __cplusplus
extern "C" {
#endif
enum eSceneCopyMethod;
struct Scene *ED_scene_add(struct Main *bmain,
struct bContext *C,
struct wmWindow *win,
enum eSceneCopyMethod method) ATTR_NONNULL();
eSceneCopyMethod method) ATTR_NONNULL();
/**
* Add a new scene in the sequence editor.
*
@ -27,8 +27,8 @@ struct Scene *ED_scene_add(struct Main *bmain,
*/
struct Scene *ED_scene_sequencer_add(struct Main *bmain,
struct bContext *C,
enum eSceneCopyMethod method,
const bool assign_strip);
eSceneCopyMethod method,
bool assign_strip);
/**
* \note Only call outside of area/region loops.
* \return true if successful.

View File

@ -497,9 +497,9 @@ bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm);
bScreen *ED_screen_animation_no_scrub(const struct wmWindowManager *wm);
/* screen keymaps */
/* called in spacetypes.c */
/* called in spacetypes.cc */
void ED_operatortypes_screen(void);
/* called in spacetypes.c */
/* called in spacetypes.cc */
void ED_keymap_screen(struct wmKeyConfig *keyconf);
/**
* Workspace key-maps.

View File

@ -45,7 +45,7 @@ set(SRC
io_collada.hh
io_gpencil.hh
io_obj.hh
io_ops.h
io_ops.hh
io_ply_ops.hh
io_stl_ops.hh
io_usd.hh

View File

@ -6,7 +6,7 @@
* \ingroup collada
*/
#include "io_ops.h" /* own include */
#include "io_ops.hh" /* own include */
#include "WM_api.h"
@ -28,7 +28,7 @@
#include "io_ply_ops.hh"
#include "io_stl_ops.hh"
void ED_operatortypes_io(void)
void ED_operatortypes_io()
{
#ifdef WITH_COLLADA
/* Collada operators: */

View File

@ -8,12 +8,4 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
void ED_operatortypes_io(void);
#ifdef __cplusplus
}
#endif
void ED_operatortypes_io();

View File

@ -8,6 +8,7 @@
#include "BLI_color.hh"
#include "BLI_generic_pointer.hh"
#include "BLI_math_quaternion.hh"
#include "BKE_attribute.h"
#include "BKE_context.h"
@ -106,6 +107,8 @@ static StringRefNull rna_property_name_for_type(const eCustomDataType type)
return "value_int";
case CD_PROP_INT32_2D:
return "value_int_vector_2d";
case CD_PROP_QUATERNION:
return "value_quat";
default:
BLI_assert_unreachable();
return "";
@ -198,6 +201,12 @@ static int mesh_set_attribute_exec(bContext *C, wmOperator *op)
case CD_PROP_COLOR:
RNA_float_get_array(op->ptr, prop_name.c_str(), static_cast<float *>(buffer));
break;
case CD_PROP_QUATERNION: {
float4 value;
RNA_float_get_array(op->ptr, prop_name.c_str(), value);
*static_cast<math::Quaternion *>(buffer) = math::normalize(math::Quaternion(value));
break;
}
case CD_PROP_BYTE_COLOR:
ColorGeometry4f value;
RNA_float_get_array(op->ptr, prop_name.c_str(), value);
@ -330,6 +339,11 @@ static int mesh_set_attribute_invoke(bContext *C, wmOperator *op, const wmEvent
case CD_PROP_INT32_2D:
RNA_property_int_set_array(op->ptr, prop, *active_value.get<int2>());
break;
case CD_PROP_QUATERNION: {
const math::Quaternion value = math::normalize(*active_value.get<math::Quaternion>());
RNA_property_float_set_array(op->ptr, prop, float4(value));
break;
}
default:
BLI_assert_unreachable();
}
@ -408,6 +422,16 @@ void MESH_OT_attribute_set(wmOperatorType *ot)
RNA_def_float_color(
ot->srna, "value_color", 4, color_default, -FLT_MAX, FLT_MAX, "Value", "", 0.0f, 1.0f);
RNA_def_boolean(ot->srna, "value_bool", false, "Value", "");
RNA_def_float_array(ot->srna,
"value_quat",
4,
rna_default_quaternion,
-FLT_MAX,
FLT_MAX,
"Value",
"",
FLT_MAX,
FLT_MAX);
}
/** \} */

View File

@ -5,6 +5,7 @@
set(INC
../include
../io
../../asset_system
../../blenkernel
../../blenlib
../../gpu
@ -19,7 +20,7 @@ set(INC_SYS
)
set(SRC
spacetypes.c
spacetypes.cc
)
set(LIB

View File

@ -6,7 +6,7 @@
* \ingroup spapi
*/
#include <stdlib.h>
#include <cstdlib>
#include "MEM_guardedalloc.h"
@ -58,9 +58,9 @@
#include "ED_util.h"
#include "ED_uvedit.h"
#include "io_ops.h"
#include "io_ops.hh"
void ED_spacetypes_init(void)
void ED_spacetypes_init()
{
/* UI unit is a variable, may be used in some space type initialization. */
U.widget_unit = 20;
@ -149,7 +149,7 @@ void ED_spacetypes_init(void)
}
}
void ED_spacemacros_init(void)
void ED_spacemacros_init()
{
/* Macros must go last since they reference other operators.
* They need to be registered after python operators too. */
@ -221,22 +221,21 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf)
/* ********************** Custom Draw Call API ***************** */
typedef struct RegionDrawCB {
struct RegionDrawCB {
struct RegionDrawCB *next, *prev;
void (*draw)(const bContext *, ARegion *, void *);
void *customdata;
int type;
} RegionDrawCB;
};
void *ED_region_draw_cb_activate(ARegionType *art,
void (*draw)(const bContext *, ARegion *, void *),
void *customdata,
int type)
{
RegionDrawCB *rdc = MEM_callocN(sizeof(RegionDrawCB), "RegionDrawCB");
RegionDrawCB *rdc = MEM_cnew<RegionDrawCB>(__func__);
BLI_addtail(&art->drawcalls, rdc);
rdc->draw = draw;
@ -277,7 +276,7 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
void ED_region_surface_draw_cb_draw(ARegionType *art, int type)
{
ed_region_draw_cb_draw(NULL, NULL, art, type);
ed_region_draw_cb_draw(nullptr, nullptr, art, type);
}
void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*free)(void *))
@ -295,19 +294,19 @@ void ED_region_draw_cb_remove_by_type(ARegionType *art, void *draw_fn, void (*fr
/* ********************* space template *********************** */
/* forward declare */
void ED_spacetype_xxx(void);
void ED_spacetype_xxx();
/* allocate and init some vars */
static SpaceLink *xxx_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
static SpaceLink *xxx_create(const ScrArea * /*area*/, const Scene * /*scene*/)
{
return NULL;
return nullptr;
}
/* Doesn't free the space-link itself. */
static void xxx_free(SpaceLink *UNUSED(sl)) {}
static void xxx_free(SpaceLink * /*sl*/) {}
/* spacetype; init callback for usage, should be re-doable. */
static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
static void xxx_init(wmWindowManager * /*wm*/, ScrArea * /*area*/)
{
/* link area to SpaceXXX struct */
@ -317,24 +316,23 @@ static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
/* add types to regions */
}
static SpaceLink *xxx_duplicate(SpaceLink *UNUSED(sl))
static SpaceLink *xxx_duplicate(SpaceLink * /*sl*/)
{
return NULL;
return nullptr;
}
static void xxx_operatortypes(void)
static void xxx_operatortypes()
{
/* register operator types for this space */
}
static void xxx_keymap(wmKeyConfig *UNUSED(keyconf))
static void xxx_keymap(wmKeyConfig * /*keyconf*/)
{
/* add default items to keymap */
}
/* only called once, from screen/spacetypes.c */
void ED_spacetype_xxx(void)
/* only called once, from screen/spacetypes.cc */
void ED_spacetype_xxx()
{
static SpaceType st;

View File

@ -405,8 +405,8 @@ std::string AssetCatalogDropTarget::drop_tooltip_asset_catalog(const wmDrag &dra
const AssetCatalog *src_catalog = get_drag_catalog(drag, get_asset_library());
return fmt::format(TIP_("Move catalog {} into {}"),
(std::string_view)src_catalog->path.name(),
(std::string_view)catalog_item_.get_name());
std::string_view(src_catalog->path.name()),
std::string_view(catalog_item_.get_name()));
}
std::string AssetCatalogDropTarget::drop_tooltip_asset_list(const wmDrag &drag) const
@ -620,7 +620,7 @@ std::string AssetCatalogTreeViewAllItem::DropTarget::drop_tooltip(const wmDrag &
drag, *get_view<AssetCatalogTreeView>().asset_library_);
return fmt::format(TIP_("Move catalog {} to the top level of the tree"),
(std::string_view)drag_catalog->path.name());
std::string_view(drag_catalog->path.name()));
}
bool AssetCatalogTreeViewAllItem::DropTarget::on_drop(bContext * /*C*/, const wmDrag &drag) const

View File

@ -247,6 +247,13 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
{
bNode *new_node = bke::node_copy_with_mapping(
&tree, node, LIB_ID_COPY_DEFAULT, true, socket_map);
/* Reset socket shape in case a node is copied to a different tree type. */
LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->inputs) {
socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
}
LISTBASE_FOREACH (bNodeSocket *, socket, &new_node->outputs) {
socket->display_shape = SOCK_DISPLAY_SHAPE_CIRCLE;
}
node_map.add_new(&node, new_node);
}
else {

View File

@ -58,7 +58,9 @@ set(SRC
tree/tree_element_gpencil_layer.cc
tree/tree_element_id.cc
tree/tree_element_id_curve.cc
tree/tree_element_id_gpencil_legacy.cc
tree/tree_element_id_library.cc
tree/tree_element_id_linestyle.cc
tree/tree_element_id_mesh.cc
tree/tree_element_id_metaball.cc
tree/tree_element_id_scene.cc
@ -82,7 +84,9 @@ set(SRC
tree/tree_element_gpencil_layer.hh
tree/tree_element_id.hh
tree/tree_element_id_curve.hh
tree/tree_element_id_gpencil_legacy.hh
tree/tree_element_id_library.hh
tree/tree_element_id_linestyle.hh
tree/tree_element_id_mesh.hh
tree/tree_element_id_metaball.hh
tree/tree_element_id_scene.hh

View File

@ -555,6 +555,8 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
case ID_CU_LEGACY:
case ID_MB:
case ID_TE:
case ID_LS:
case ID_GD_LEGACY:
BLI_assert_msg(0, "ID type expected to be expanded through new tree-element design");
break;
case ID_OB: {
@ -672,35 +674,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner,
}
break;
}
case ID_LS: {
FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id;
if (outliner_animdata_test(linestyle->adt)) {
outliner_add_element(space_outliner, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0);
}
for (int a = 0; a < MAX_MTEX; a++) {
if (linestyle->mtex[a]) {
outliner_add_element(space_outliner, &te->subtree, linestyle->mtex[a]->tex, te, 0, a);
}
}
break;
}
case ID_GD_LEGACY: {
bGPdata *gpd = (bGPdata *)id;
if (outliner_animdata_test(gpd->adt)) {
outliner_add_element(space_outliner, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
}
/* TODO: base element for layers? */
int index = 0;
LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl, &gpd->layers) {
outliner_add_element(space_outliner, &te->subtree, gpl, te, TSE_GP_LAYER, index);
index++;
}
break;
}
case ID_GR: {
/* Don't expand for instances, creates too many elements. */
if (!(te->parent && te->parent->idcode == ID_OB)) {

View File

@ -21,7 +21,9 @@
#include "../outliner_intern.hh"
#include "common.hh"
#include "tree_element_id_curve.hh"
#include "tree_element_id_gpencil_legacy.hh"
#include "tree_element_id_library.hh"
#include "tree_element_id_linestyle.hh"
#include "tree_element_id_mesh.hh"
#include "tree_element_id_metaball.hh"
#include "tree_element_id_scene.hh"
@ -51,6 +53,10 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
return std::make_unique<TreeElementIDMetaBall>(legacy_te, (MetaBall &)id);
case ID_TE:
return std::make_unique<TreeElementIDTexture>(legacy_te, (Tex &)id);
case ID_LS:
return std::make_unique<TreeElementIDLineStyle>(legacy_te, (FreestyleLineStyle &)id);
case ID_GD_LEGACY:
return std::make_unique<TreeElementIDGPLegacy>(legacy_te, (bGPdata &)id);
case ID_OB:
case ID_MA:
case ID_LT:
@ -66,9 +72,7 @@ std::unique_ptr<TreeElementID> TreeElementID::createFromID(TreeElement &legacy_t
case ID_PA:
case ID_MC:
case ID_MSK:
case ID_LS:
case ID_LP:
case ID_GD_LEGACY:
case ID_WS:
case ID_CV:
case ID_PT:

View File

@ -0,0 +1,49 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#include "DNA_ID.h"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_listBase.h"
#include "DNA_outliner_types.h"
#include "BLI_listbase.h"
#include "../outliner_intern.hh"
#include "tree_element_id_gpencil_legacy.hh"
namespace blender::ed::outliner {
TreeElementIDGPLegacy::TreeElementIDGPLegacy(TreeElement &legacy_te, bGPdata &gpd)
: TreeElementID(legacy_te, gpd.id), gpd_(gpd)
{
}
void TreeElementIDGPLegacy::expand(SpaceOutliner &space_outliner) const
{
expand_animation_data(space_outliner, gpd_.adt);
expandLayers(space_outliner);
}
bool TreeElementIDGPLegacy::isExpandValid() const
{
return true;
}
void TreeElementIDGPLegacy::expandLayers(SpaceOutliner &space_outliner) const
{
int index = 0;
LISTBASE_FOREACH_BACKWARD (bGPDlayer *, gpl, &gpd_.layers) {
outliner_add_element(
&space_outliner, &legacy_te_.subtree, gpl, &legacy_te_, TSE_GP_LAYER, index);
index++;
}
}
} // namespace blender::ed::outliner

View File

@ -0,0 +1,28 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#pragma once
#include "tree_element_id.hh"
namespace blender::ed::outliner {
class TreeElementIDGPLegacy final : public TreeElementID {
bGPdata &gpd_;
public:
TreeElementIDGPLegacy(TreeElement &legacy_te, bGPdata &gpd);
void expand(SpaceOutliner &) const override;
bool isExpandValid() const override;
private:
void expandLayers(SpaceOutliner &) const;
};
} // namespace blender::ed::outliner

View File

@ -0,0 +1,53 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#include "DNA_ID.h"
#include "DNA_linestyle_types.h"
#include "DNA_listBase.h"
#include "DNA_outliner_types.h"
#include "DNA_texture_types.h"
#include "../outliner_intern.hh"
#include "tree_element_id_linestyle.hh"
namespace blender::ed::outliner {
TreeElementIDLineStyle::TreeElementIDLineStyle(TreeElement &legacy_te,
FreestyleLineStyle &linestyle)
: TreeElementID(legacy_te, linestyle.id), linestyle_(linestyle)
{
}
void TreeElementIDLineStyle::expand(SpaceOutliner &space_outliner) const
{
expand_animation_data(space_outliner, linestyle_.adt);
expandTextures(space_outliner);
}
bool TreeElementIDLineStyle::isExpandValid() const
{
return true;
}
void TreeElementIDLineStyle::expandTextures(SpaceOutliner &space_outliner) const
{
for (int a = 0; a < MAX_MTEX; a++) {
if (linestyle_.mtex[a]) {
outliner_add_element(&space_outliner,
&legacy_te_.subtree,
(linestyle_.mtex[a])->tex,
&legacy_te_,
TSE_SOME_ID,
a);
}
}
}
} // namespace blender::ed::outliner

View File

@ -0,0 +1,30 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup spoutliner
*/
#pragma once
#include "tree_element_id.hh"
struct FreestyleLineStyle;
namespace blender::ed::outliner {
class TreeElementIDLineStyle final : public TreeElementID {
FreestyleLineStyle &linestyle_;
public:
TreeElementIDLineStyle(TreeElement &legacy_te, FreestyleLineStyle &linestyle);
void expand(SpaceOutliner &) const override;
bool isExpandValid() const override;
private:
void expandTextures(SpaceOutliner &) const;
};
} // namespace blender::ed::outliner

View File

@ -549,7 +549,7 @@ void SEQUENCER_OT_retiming_segment_speed_set(wmOperatorType *ot)
"Speed",
"New speed of retimed segment",
0.1f,
INT_MAX);
FLT_MAX);
}
/** \} */

View File

@ -346,6 +346,7 @@ static float get_default_column_width(const ColumnValues &values)
return 3.0f * float_width;
case SPREADSHEET_VALUE_TYPE_COLOR:
case SPREADSHEET_VALUE_TYPE_BYTE_COLOR:
case SPREADSHEET_VALUE_TYPE_QUATERNION:
return 4.0f * float_width;
case SPREADSHEET_VALUE_TYPE_INSTANCES:
return 8.0f;

View File

@ -9,6 +9,7 @@
#include "BLI_color.hh"
#include "BLI_cpp_type.hh"
#include "BLI_hash.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
@ -56,6 +57,9 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const CPPType &type)
if (type.is<ColorGeometry4b>()) {
return SPREADSHEET_VALUE_TYPE_BYTE_COLOR;
}
if (type.is<math::Quaternion>()) {
return SPREADSHEET_VALUE_TYPE_QUATERNION;
}
return SPREADSHEET_VALUE_TYPE_UNKNOWN;
}

View File

@ -5,6 +5,7 @@
#include <iomanip>
#include <sstream>
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh"
#include "BKE_geometry_set.hh"
@ -204,6 +205,10 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
const ColorGeometry4b value = data.get<ColorGeometry4b>(real_index);
this->draw_byte_color(params, value);
}
else if (data.type().is<math::Quaternion>()) {
const float4 value = float4(data.get<math::Quaternion>(real_index));
this->draw_float_vector(params, Span(&value.x, 4));
}
else if (data.type().is<bke::InstanceReference>()) {
const bke::InstanceReference value = data.get<bke::InstanceReference>(real_index);
switch (value.type()) {

View File

@ -107,6 +107,7 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter,
}
case SPREADSHEET_VALUE_TYPE_STRING:
return row_filter.value_string;
case SPREADSHEET_VALUE_TYPE_QUATERNION:
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
return "";
}
@ -250,7 +251,8 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel)
uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE);
break;
case SPREADSHEET_VALUE_TYPE_UNKNOWN:
uiItemL(layout, IFACE_("Unknown column type"), ICON_ERROR);
case SPREADSHEET_VALUE_TYPE_QUATERNION:
uiItemL(layout, IFACE_("Unsupported column type"), ICON_ERROR);
break;
}
}

View File

@ -101,6 +101,8 @@ static eV3D_OpEvent view3d_navigate_event(ViewOpsData *vod, const wmEvent *event
{
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CANCEL:
return VIEW_CANCEL;
case VIEW_MODAL_CONFIRM:
return VIEW_CONFIRM;
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:

View File

@ -6,6 +6,7 @@
#include "BLI_cpp_type_make.hh"
#include "BLI_cpp_types_make.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh"
#include "FN_field_cpp_type_make.hh"
@ -16,6 +17,7 @@ FN_FIELD_CPP_TYPE_MAKE(blender::float2);
FN_FIELD_CPP_TYPE_MAKE(blender::float3);
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4f);
FN_FIELD_CPP_TYPE_MAKE(blender::ColorGeometry4b);
FN_FIELD_CPP_TYPE_MAKE(blender::math::Quaternion);
FN_FIELD_CPP_TYPE_MAKE(bool);
FN_FIELD_CPP_TYPE_MAKE(int8_t);
FN_FIELD_CPP_TYPE_MAKE(int32_t);
@ -31,6 +33,7 @@ void FN_register_cpp_types()
FN_FIELD_CPP_TYPE_REGISTER(blender::float3);
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4f);
FN_FIELD_CPP_TYPE_REGISTER(blender::ColorGeometry4b);
FN_FIELD_CPP_TYPE_REGISTER(blender::math::Quaternion);
FN_FIELD_CPP_TYPE_REGISTER(bool);
FN_FIELD_CPP_TYPE_REGISTER(int8_t);
FN_FIELD_CPP_TYPE_REGISTER(int32_t);

View File

@ -1457,6 +1457,8 @@ static void customdata_weld(
int src_i, dest_i;
int j;
int vs_flag = 0;
/* interpolates a layer at a time */
dest_i = 0;
for (src_i = 0; src_i < source->totlayer; src_i++) {
@ -1477,7 +1479,21 @@ static void customdata_weld(
/* if we found a matching layer, add the data */
if (dest->layers[dest_i].type == type) {
void *src_data = source->layers[src_i].data;
if (CustomData_layer_has_interp(dest, dest_i)) {
if (type == CD_MVERT_SKIN) {
/* The `typeInfo->interp` of #CD_MVERT_SKIN does not include the flags, so #MVERT_SKIN_ROOT
* and #MVERT_SKIN_LOOSE are lost after the interpolation.
*
* This behavior is not incorrect. Ideally, islands should be checked to avoid repeated
* roots.
*
* However, for now, to prevent the loss of flags, they are simply re-added if any of the
* merged vertices have them. */
for (j = 0; j < count; j++) {
MVertSkin *vs = &((MVertSkin *)src_data)[src_indices[j]];
vs_flag |= vs->flag;
}
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
/* Already calculated.
* TODO: Optimize by exposing `typeInfo->interp`. */
}
@ -1507,7 +1523,11 @@ static void customdata_weld(
for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
CustomDataLayer *layer_dst = &dest->layers[dest_i];
const eCustomDataType type = eCustomDataType(layer_dst->type);
if (CustomData_layer_has_interp(dest, dest_i)) {
if (type == CD_MVERT_SKIN) {
MVertSkin *vs = &((MVertSkin *)layer_dst->data)[dest_index];
vs->flag = vs_flag;
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
/* Already calculated. */
}
else if (CustomData_layer_has_math(dest, dest_i)) {

View File

@ -4,6 +4,8 @@
#include "BLI_array_utils.hh"
#include "BLI_index_mask.hh"
#include "BLI_ordered_edge.hh"
#include "BLI_vector_set.hh"
#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
@ -14,12 +16,6 @@
namespace blender::geometry {
/* Naively checks if the first vertices and the second vertices are the same. */
static inline bool naive_edges_equal(const int2 &edge1, const int2 &edge2)
{
return edge1 == edge2;
}
static void add_new_vertices(Mesh &mesh, const Span<int> new_to_old_verts_map)
{
/* These types aren't supported for interpolation below. */
@ -154,70 +150,6 @@ static void add_new_edges(Mesh &mesh,
}
}
/**
* Merge the new_edge into the original edge.
*
* NOTE: This function is very specific to the situation and makes a lot of assumptions.
*/
static void merge_edges(const int orig_edge_i,
const int new_edge_i,
MutableSpan<int> new_corner_edges,
Vector<Vector<int>> &edge_to_loop_map,
Vector<int2> &new_edges,
Vector<int> &new_to_old_edges_map)
{
/* Merge back into the original edge by undoing the topology changes. */
BLI_assert(edge_to_loop_map[new_edge_i].size() == 1);
const int loop_i = edge_to_loop_map[new_edge_i][0];
new_corner_edges[loop_i] = orig_edge_i;
/* We are putting the last edge in the location of new_edge in all the maps, to remove
* new_edge efficiently. We have to update the topology information for this last edge
* though. Essentially we are replacing every instance of last_edge_i with new_edge_i. */
const int last_edge_i = new_edges.size() - 1;
if (last_edge_i != new_edge_i) {
BLI_assert(edge_to_loop_map[last_edge_i].size() == 1);
const int last_edge_loop_i = edge_to_loop_map[last_edge_i][0];
new_corner_edges[last_edge_loop_i] = new_edge_i;
}
/* We can now safely swap-remove. */
new_edges.remove_and_reorder(new_edge_i);
edge_to_loop_map.remove_and_reorder(new_edge_i);
new_to_old_edges_map.remove_and_reorder(new_edge_i);
}
/**
* Replace the vertex of an edge with a new one, and update the connected loops.
*
* NOTE: This only updates the loops containing the edge and the old vertex. It should therefore
* also be called on the adjacent edge.
*/
static void swap_vertex_of_edge(int2 &edge,
const int old_vert,
const int new_vert,
MutableSpan<int> corner_verts,
const Span<int> connected_loops)
{
if (edge[0] == old_vert) {
edge[0] = new_vert;
}
else if (edge[1] == old_vert) {
edge[1] = new_vert;
}
else {
BLI_assert_unreachable();
}
for (const int loop_i : connected_loops) {
if (corner_verts[loop_i] == old_vert) {
corner_verts[loop_i] = new_vert;
}
/* The old vertex is on the loop containing the adjacent edge. Since this function is also
* called on the adjacent edge, we don't replace it here. */
}
}
/** Split the vertex into duplicates so that each fan has a different vertex. */
static void split_vertex_per_fan(const int vertex,
const int start_offset,
@ -225,7 +157,6 @@ static void split_vertex_per_fan(const int vertex,
const Span<int> fans,
const Span<int> fan_sizes,
const Span<Vector<int>> edge_to_loop_map,
MutableSpan<int2> new_edges,
MutableSpan<int> corner_verts,
MutableSpan<int> new_to_old_verts_map)
{
@ -237,8 +168,13 @@ static void split_vertex_per_fan(const int vertex,
new_to_old_verts_map[new_vert_i - orig_verts_num] = vertex;
for (const int edge_i : fans.slice(fan_start, fan_sizes[i])) {
swap_vertex_of_edge(
new_edges[edge_i], vertex, new_vert_i, corner_verts, edge_to_loop_map[edge_i]);
for (const int loop_i : edge_to_loop_map[edge_i]) {
if (corner_verts[loop_i] == vertex) {
corner_verts[loop_i] = new_vert_i;
}
/* The old vertex is on the loop containing the adjacent edge. Since this function is also
* called on the adjacent edge, we don't replace it here. */
}
}
fan_start += fan_sizes[i];
}
@ -267,7 +203,7 @@ static int adjacent_edge(const Span<int> corner_verts,
* be used to retrieve the fans from connected_edges.
*/
static void calc_vertex_fans(const int vertex,
const Span<int> new_corner_verts,
const Span<int> corner_verts,
const Span<int> new_corner_edges,
const OffsetIndices<int> polys,
const Span<Vector<int>> edge_to_loop_map,
@ -298,7 +234,7 @@ static void calc_vertex_fans(const int vertex,
/* Add adjacent edges to search stack. */
for (const int loop_i : edge_to_loop_map[curr_edge_i]) {
const int adjacent_edge_i = adjacent_edge(
new_corner_verts, new_corner_edges, loop_i, polys[loop_to_poly_map[loop_i]], vertex);
corner_verts, new_corner_edges, loop_i, polys[loop_to_poly_map[loop_i]], vertex);
/* Find out if this edge was visited already. */
int i = curr_i + 1;
@ -340,18 +276,13 @@ static void calc_vertex_fans(const int vertex,
static void split_edge_per_poly(const int edge_i,
const int new_edge_start,
MutableSpan<Vector<int>> edge_to_loop_map,
MutableSpan<int> corner_edges,
MutableSpan<int2> new_edges,
MutableSpan<int> new_to_old_edges_map)
MutableSpan<int> corner_edges)
{
if (edge_to_loop_map[edge_i].size() <= 1) {
return;
}
int new_edge_index = new_edge_start;
for (const int loop_i : edge_to_loop_map[edge_i].as_span().drop_front(1)) {
const int2 &new_edge(new_edges[edge_i]);
new_edges[new_edge_index] = new_edge;
new_to_old_edges_map[new_edge_index] = edge_i;
edge_to_loop_map[new_edge_index].append({loop_i});
corner_edges[loop_i] = new_edge_index;
new_edge_index++;
@ -401,11 +332,11 @@ void split_edges(Mesh &mesh,
});
const OffsetIndices polys = mesh.polys();
const Array<int> orig_corner_edges = mesh.corner_edges();
IndexMaskMemory memory;
const IndexMask loose_edges = IndexMask::from_bits(mesh.loose_edges().is_loose_bits, memory);
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
MutableSpan<int> corner_edges = mesh.corner_edges_for_write();
Vector<int2> new_edges(new_edges_size);
new_edges.as_mutable_span().take_front(edges.size()).copy_from(edges);
Vector<Vector<int>> edge_to_loop_map(new_edges_size);
threading::parallel_for(edges.index_range(), 512, [&](const IndexRange range) {
@ -414,19 +345,18 @@ void split_edges(Mesh &mesh,
}
});
/* Used for transferring attributes. */
Vector<int> new_to_old_edges_map(new_edges.size());
std::iota(new_to_old_edges_map.begin(), new_to_old_edges_map.end(), 0);
/* Step 1: Split the edges. */
threading::parallel_for(mask.index_range(), 512, [&](IndexRange range) {
for (const int mask_i : range) {
const int edge_i = mask[mask_i];
split_edge_per_poly(edge_i, edge_offsets[edge_i], edge_to_loop_map, corner_edges);
}
});
/* Step 1: Split the edges. */
mask.foreach_index(GrainSize(512), [&](const int edge_i) {
split_edge_per_poly(edge_i,
edge_offsets[edge_i],
edge_to_loop_map,
corner_edges,
new_edges,
new_to_old_edges_map);
mask.foreach_index([&](const int edge_i) {
split_edge_per_poly(edge_i, edge_offsets[edge_i], edge_to_loop_map, corner_edges);
});
/* Step 1.5: Update topology information (can't parallelize). */
@ -438,6 +368,8 @@ void split_edges(Mesh &mesh,
}
});
MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
/* Step 2: Calculate vertex fans. */
Array<Vector<int>> vertex_fan_sizes(mesh.totvert);
threading::parallel_for(IndexRange(mesh.totvert), 512, [&](IndexRange range) {
@ -483,39 +415,43 @@ void split_edges(Mesh &mesh,
vert_to_edge_map[vert],
vertex_fan_sizes[vert],
edge_to_loop_map,
new_edges,
corner_verts,
new_to_old_verts_map);
}
});
/* Step 4: Deduplicate edges. We loop backwards so we can use remove_and_reorder. Although this
* does look bad (3 nested loops), in practice the inner loops are very small. For most meshes,
* there are at most 2 polygons connected to each edge, and hence you'll only get at most 1
* duplicate per edge. */
for (int mask_i = mask.size() - 1; mask_i >= 0; mask_i--) {
const int edge = mask[mask_i];
int start_of_duplicates = edge_offsets[edge];
int end_of_duplicates = start_of_duplicates + num_edge_duplicates[edge] - 1;
for (int duplicate = end_of_duplicates; duplicate >= start_of_duplicates; duplicate--) {
if (naive_edges_equal(new_edges[edge], new_edges[duplicate])) {
merge_edges(
edge, duplicate, corner_edges, edge_to_loop_map, new_edges, new_to_old_edges_map);
break;
}
for (int other = start_of_duplicates; other < duplicate; other++) {
if (naive_edges_equal(new_edges[other], new_edges[duplicate])) {
merge_edges(
other, duplicate, corner_edges, edge_to_loop_map, new_edges, new_to_old_edges_map);
break;
}
}
VectorSet<OrderedEdge> new_edges;
new_edges.reserve(new_edges_size + loose_edges.size());
for (const int i : polys.index_range()) {
const IndexRange poly = polys[i];
for (const int corner : poly) {
const int vert_1 = corner_verts[corner];
const int vert_2 = corner_verts[bke::mesh::poly_corner_next(poly, corner)];
corner_edges[corner] = new_edges.index_of_or_add_as(OrderedEdge(vert_1, vert_2));
}
}
loose_edges.foreach_index([&](const int64_t i) { new_edges.add(OrderedEdge(edges[i])); });
Array<int> new_to_old_edges_map(new_edges.size());
auto index_mask_to_indices = [&](const IndexMask &mask, MutableSpan<int> indices) {
for (const int i : mask.index_range()) {
indices[i] = mask[i];
}
};
index_mask_to_indices(loose_edges,
new_to_old_edges_map.as_mutable_span().take_back(loose_edges.size()));
for (const int i : polys.index_range()) {
const IndexRange poly = polys[i];
for (const int corner : poly) {
const int new_edge_i = corner_edges[corner];
const int old_edge_i = orig_corner_edges[corner];
new_to_old_edges_map[new_edge_i] = old_edge_i;
}
}
/* Step 5: Resize the mesh to add the new vertices and rebuild the edges. */
add_new_vertices(mesh, new_to_old_verts_map);
add_new_edges(mesh, new_edges, new_to_old_edges_map, propagation_info);
add_new_edges(mesh, new_edges.as_span().cast<int2>(), new_to_old_edges_map, propagation_info);
BKE_mesh_tag_edges_split(&mesh);
}

View File

@ -482,6 +482,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_eevee_specular.glsl
shaders/material/gpu_shader_material_emission.glsl
shaders/material/gpu_shader_material_fractal_noise.glsl
shaders/material/gpu_shader_material_fractal_voronoi.glsl
shaders/material/gpu_shader_material_fresnel.glsl
shaders/material/gpu_shader_material_gamma.glsl
shaders/material/gpu_shader_material_geometry.glsl
@ -546,6 +547,7 @@ set(GLSL_SRC
shaders/material/gpu_shader_material_volume_absorption.glsl
shaders/material/gpu_shader_material_volume_principled.glsl
shaders/material/gpu_shader_material_volume_scatter.glsl
shaders/material/gpu_shader_material_voronoi.glsl
shaders/material/gpu_shader_material_wireframe.glsl
shaders/material/gpu_shader_material_world_normals.glsl
@ -793,8 +795,6 @@ if(WITH_GPU_BUILDTIME_SHADER_BUILDER)
intern/gpu_shader_builder_stubs.cc
${shader_create_info_list_file}
)
setup_platform_linker_flags(shader_builder)
target_link_libraries(shader_builder PUBLIC buildinfoobj)
else()
if(WIN32)
@ -809,8 +809,9 @@ if(WITH_GPU_BUILDTIME_SHADER_BUILDER)
${shader_create_info_list_file}
${MANIFEST}
)
endif()
setup_platform_linker_flags(shader_builder)
target_link_libraries(shader_builder PUBLIC
bf_gpu
bf_intern_clog
@ -848,6 +849,7 @@ if(WITH_GTESTS)
tests/gpu_testing.cc
tests/buffer_texture_test.cc
tests/compute_test.cc
tests/framebuffer_test.cc
tests/immediate_test.cc
tests/index_buffer_test.cc

View File

@ -271,5 +271,36 @@ void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat * /*format*/,
{
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Stubs of IMB_imbuf.h
* \{ */
struct ImBuf *IMB_ibImageFromMemory(const unsigned char * /*mem*/,
size_t /*size*/,
int /*flags*/,
char /*colorspace*/[IM_MAX_SPACE],
const char * /*descr*/)
{
BLI_assert_unreachable();
return nullptr;
}
struct ImBuf *IMB_allocFromBuffer(const uint8_t * /*rect*/,
const float * /*rectf*/,
unsigned int /*w*/,
unsigned int /*h*/,
unsigned int /*channels*/)
{
BLI_assert_unreachable();
return nullptr;
}
bool IMB_saveiff(struct ImBuf * /*ibuf*/, const char * /*filepath*/, int /*flags*/)
{
BLI_assert_unreachable();
return false;
}
/** \} */
}

View File

@ -0,0 +1,133 @@
#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_material_voronoi.glsl)
#define FRACTAL_VORONOI_X_FX(T) \
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
{ \
float amplitude = 1.0; \
float max_amplitude = 0.0; \
float scale = 1.0; \
\
VoronoiOutput Output; \
Output.Distance = 0.0; \
Output.Color = vec3(0.0, 0.0, 0.0); \
Output.Position = vec4(0.0, 0.0, 0.0, 0.0); \
bool zero_input = params.detail == 0.0 || params.roughness == 0.0 || \
params.lacunarity == 0.0; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
VoronoiOutput octave; \
if (params.feature == 0) /* SHD_VORONOI_F1 */ { \
octave = voronoi_f1(params, coord * scale); \
} \
else if (params.feature == 2) /* SHD_VORONOI_SMOOTH_F1 */ { \
octave = voronoi_smooth_f1(params, coord * scale); \
} \
else { \
octave = voronoi_f2(params, coord * scale); \
} \
\
if (zero_input) { \
max_amplitude = 1.0; \
Output = octave; \
break; \
} \
else if (i <= params.detail) { \
max_amplitude += amplitude; \
Output.Distance += octave.Distance * amplitude; \
Output.Color += octave.Color * amplitude; \
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
scale *= params.lacunarity; \
amplitude *= params.roughness; \
} \
else { \
float remainder = params.detail - floor(params.detail); \
if (remainder != 0.0) { \
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
Output.Distance = mix( \
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
Output.Position = mix(Output.Position, \
mix(Output.Position, octave.Position / scale, amplitude), \
remainder); \
} \
} \
} \
\
if (params.normalize) { \
Output.Distance /= max_amplitude * params.max_distance; \
Output.Color /= max_amplitude; \
} \
\
Output.Position = safe_divide(Output.Position, params.scale); \
\
return Output; \
}
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
{ \
float amplitude = 1.0; \
float max_amplitude = 0.5 + 0.5 * params.randomness; \
float scale = 1.0; \
float distance = 8.0; \
\
bool zero_input = params.detail == 0.0 || params.roughness == 0.0 || \
params.lacunarity == 0.0; \
\
for (int i = 0; i <= ceil(params.detail); ++i) { \
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
\
if (zero_input) { \
distance = octave_distance; \
break; \
} \
else if (i <= params.detail) { \
max_amplitude = mix(max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
scale *= params.lacunarity; \
amplitude *= params.roughness; \
} \
else { \
float remainder = params.detail - floor(params.detail); \
if (remainder != 0.0) { \
float lerp_amplitude = mix( \
max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
distance = mix(distance, min(distance, lerp_distance), remainder); \
} \
} \
} \
\
if (params.normalize) { \
distance /= max_amplitude; \
} \
\
return distance; \
}
/* **** 1D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(float)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
/* **** 2D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(vec2)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec2)
/* **** 3D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(vec3)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec3)
/* **** 4D Fractal Voronoi **** */
FRACTAL_VORONOI_X_FX(vec4)
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec4)

View File

@ -0,0 +1,889 @@
#pragma BLENDER_REQUIRE(gpu_shader_common_hash.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
/*
* Original code is under the MIT License, Copyright (c) 2013 Inigo Quilez.
*
* Smooth Voronoi:
*
* - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
*
* Distance To Edge based on:
*
* - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
* - https://www.shadertoy.com/view/ldl3W8
*
* With optimization to change -2..2 scan window to -1..1 for better performance,
* as explained in https://www.shadertoy.com/view/llG3zy.
*/
struct VoronoiParams {
float scale;
float detail;
float roughness;
float lacunarity;
float smoothness;
float exponent;
float randomness;
float max_distance;
bool normalize;
int feature;
int metric;
};
struct VoronoiOutput {
float Distance;
vec3 Color;
vec4 Position;
};
/* **** Distance Functions **** */
float voronoi_distance(float a, float b)
{
return abs(a - b);
}
float voronoi_distance(vec2 a, vec2 b, VoronoiParams params)
{
if (params.metric == 0) // SHD_VORONOI_EUCLIDEAN
{
return distance(a, b);
}
else if (params.metric == 1) // SHD_VORONOI_MANHATTAN
{
return abs(a.x - b.x) + abs(a.y - b.y);
}
else if (params.metric == 2) // SHD_VORONOI_CHEBYCHEV
{
return max(abs(a.x - b.x), abs(a.y - b.y));
}
else if (params.metric == 3) // SHD_VORONOI_MINKOWSKI
{
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent),
1.0 / params.exponent);
}
else {
return 0.0;
}
}
float voronoi_distance(vec3 a, vec3 b, VoronoiParams params)
{
if (params.metric == 0) // SHD_VORONOI_EUCLIDEAN
{
return distance(a, b);
}
else if (params.metric == 1) // SHD_VORONOI_MANHATTAN
{
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
}
else if (params.metric == 2) // SHD_VORONOI_CHEBYCHEV
{
return max(abs(a.x - b.x), max(abs(a.y - b.y), abs(a.z - b.z)));
}
else if (params.metric == 3) // SHD_VORONOI_MINKOWSKI
{
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
pow(abs(a.z - b.z), params.exponent),
1.0 / params.exponent);
}
else {
return 0.0;
}
}
float voronoi_distance(vec4 a, vec4 b, VoronoiParams params)
{
if (params.metric == 0) // SHD_VORONOI_EUCLIDEAN
{
return distance(a, b);
}
else if (params.metric == 1) // SHD_VORONOI_MANHATTAN
{
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
}
else if (params.metric == 2) // SHD_VORONOI_CHEBYCHEV
{
return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
}
else if (params.metric == 3) // SHD_VORONOI_MINKOWSKI
{
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
pow(abs(a.z - b.z), params.exponent) + pow(abs(a.w - b.w), params.exponent),
1.0 / params.exponent);
}
else {
return 0.0;
}
}
/* **** 1D Voronoi **** */
vec4 voronoi_position(float coord)
{
return vec4(0.0, 0.0, 0.0, coord);
}
VoronoiOutput voronoi_f1(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float minDistance = 8.0;
float targetOffset = 0.0;
float targetPosition = 0.0;
for (int i = -1; i <= 1; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_float_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float smoothDistance = 8.0;
float smoothPosition = 0.0;
vec3 smoothColor = vec3(0.0);
for (int i = -2; i <= 2; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
vec3 cellColor = hash_float_to_vec3(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
float offsetF1 = 0.0;
float positionF1 = 0.0;
float offsetF2 = 0.0;
float positionF2 = 0.0;
for (int i = -1; i <= 1; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_float_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * params.randomness;
float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * params.randomness;
float distanceToMidLeft = abs((midPointPosition + leftPointPosition) / 2.0 - localPosition);
float distanceToMidRight = abs((midPointPosition + rightPointPosition) / 2.0 - localPosition);
return min(distanceToMidLeft, distanceToMidRight);
}
float voronoi_n_sphere_radius(VoronoiParams params, float coord)
{
float cellPosition = floor(coord);
float localPosition = coord - cellPosition;
float closestPoint = 0.0;
float closestPointOffset = 0.0;
float minDistance = 8.0;
for (int i = -1; i <= 1; i++) {
float cellOffset = i;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = abs(pointPosition - localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
minDistance = 8.0;
float closestPointToClosestPoint = 0.0;
for (int i = -1; i <= 1; i++) {
if (i == 0) {
continue;
}
float cellOffset = i + closestPointOffset;
float pointPosition = cellOffset +
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = abs(closestPoint - pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
return abs(closestPointToClosestPoint - closestPoint) / 2.0;
}
/* **** 2D Voronoi **** */
vec4 voronoi_position(vec2 coord)
{
return vec4(coord.x, coord.y, 0.0, 0.0);
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec2 coord)
{
vec2 cellPosition = floor(coord);
vec2 localPosition = coord - cellPosition;
float minDistance = 8.0;
vec2 targetOffset = vec2(0.0);
vec2 targetPosition = vec2(0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cellOffset = vec2(i, j);
vec2 pointPosition = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_vec2_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec2 coord)
{
vec2 cellPosition = floor(coord);
vec2 localPosition = coord - cellPosition;
float smoothDistance = 8.0;
vec3 smoothColor = vec3(0.0);
vec2 smoothPosition = vec2(0.0);
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
vec2 cellOffset = vec2(i, j);
vec2 pointPosition = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
vec3 cellColor = hash_vec2_to_vec3(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vec2 coord)
{
vec2 cellPosition = floor(coord);
vec2 localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
vec2 offsetF1 = vec2(0.0);
vec2 positionF1 = vec2(0.0);
vec2 offsetF2 = vec2(0.0);
vec2 positionF2 = vec2(0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cellOffset = vec2(i, j);
vec2 pointPosition = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_vec2_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vec2 coord)
{
vec2 cellPosition = floor(coord);
vec2 localPosition = coord - cellPosition;
vec2 vectorToClosest = vec2(0.0);
float minDistance = 8.0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cellOffset = vec2(i, j);
vec2 vectorToPoint = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
minDistance = 8.0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cellOffset = vec2(i, j);
vec2 vectorToPoint = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness -
localPosition;
vec2 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
normalize(perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
}
return minDistance;
}
float voronoi_n_sphere_radius(VoronoiParams params, vec2 coord)
{
vec2 cellPosition = floor(coord);
vec2 localPosition = coord - cellPosition;
vec2 closestPoint = vec2(0.0);
vec2 closestPointOffset = vec2(0.0);
float minDistance = 8.0;
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cellOffset = vec2(i, j);
vec2 pointPosition = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
minDistance = 8.0;
vec2 closestPointToClosestPoint = vec2(0.0);
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0) {
continue;
}
vec2 cellOffset = vec2(i, j) + closestPointOffset;
vec2 pointPosition = cellOffset +
hash_vec2_to_vec2(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
/* **** 3D Voronoi **** */
vec4 voronoi_position(vec3 coord)
{
return vec4(coord.x, coord.y, coord.z, 0.0);
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
float minDistance = 8.0;
vec3 targetOffset = vec3(0.0);
vec3 targetPosition = vec3(0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec3 cellOffset = vec3(i, j, k);
vec3 pointPosition = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_vec3_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
float smoothDistance = 8.0;
vec3 smoothColor = vec3(0.0);
vec3 smoothPosition = vec3(0.0);
for (int k = -2; k <= 2; k++) {
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
vec3 cellOffset = vec3(i, j, k);
vec3 pointPosition = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
vec3 cellColor = hash_vec3_to_vec3(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
vec3 offsetF1 = vec3(0.0);
vec3 positionF1 = vec3(0.0);
vec3 offsetF2 = vec3(0.0);
vec3 positionF2 = vec3(0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec3 cellOffset = vec3(i, j, k);
vec3 pointPosition = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_vec3_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
vec3 vectorToClosest = vec3(0.0);
float minDistance = 8.0;
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec3 cellOffset = vec3(i, j, k);
vec3 vectorToPoint = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
}
minDistance = 8.0;
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec3 cellOffset = vec3(i, j, k);
vec3 vectorToPoint = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness -
localPosition;
vec3 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
normalize(perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
}
}
return minDistance;
}
float voronoi_n_sphere_radius(VoronoiParams params, vec3 coord)
{
vec3 cellPosition = floor(coord);
vec3 localPosition = coord - cellPosition;
vec3 closestPoint = vec3(0.0);
vec3 closestPointOffset = vec3(0.0);
float minDistance = 8.0;
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec3 cellOffset = vec3(i, j, k);
vec3 pointPosition = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
}
minDistance = 8.0;
vec3 closestPointToClosestPoint = vec3(0.0);
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0 && k == 0) {
continue;
}
vec3 cellOffset = vec3(i, j, k) + closestPointOffset;
vec3 pointPosition = cellOffset +
hash_vec3_to_vec3(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
/* **** 4D Voronoi **** */
vec4 voronoi_position(vec4 coord)
{
return coord;
}
VoronoiOutput voronoi_f1(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
float minDistance = 8.0;
vec4 targetOffset = vec4(0.0);
vec4 targetPosition = vec4(0.0);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec4 cellOffset = vec4(i, j, k, u);
vec4 pointPosition = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < minDistance) {
targetOffset = cellOffset;
minDistance = distanceToPoint;
targetPosition = pointPosition;
}
}
}
}
}
VoronoiOutput octave;
octave.Distance = minDistance;
octave.Color = hash_vec4_to_vec3(cellPosition + targetOffset);
octave.Position = voronoi_position(targetPosition + cellPosition);
return octave;
}
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
float smoothDistance = 8.0;
vec3 smoothColor = vec3(0.0);
vec4 smoothPosition = vec4(0.0);
for (int u = -2; u <= 2; u++) {
for (int k = -2; k <= 2; k++) {
for (int j = -2; j <= 2; j++) {
for (int i = -2; i <= 2; i++) {
vec4 cellOffset = vec4(i, j, k, u);
vec4 pointPosition = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
float h = smoothstep(
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
float correctionFactor = params.smoothness * h * (1.0 - h);
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
correctionFactor /= 1.0 + 3.0 * params.smoothness;
vec3 cellColor = hash_vec4_to_vec3(cellPosition + cellOffset);
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
}
}
}
}
VoronoiOutput octave;
octave.Distance = smoothDistance;
octave.Color = smoothColor;
octave.Position = voronoi_position(cellPosition + smoothPosition);
return octave;
}
VoronoiOutput voronoi_f2(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
float distanceF1 = 8.0;
float distanceF2 = 8.0;
vec4 offsetF1 = vec4(0.0);
vec4 positionF1 = vec4(0.0);
vec4 offsetF2 = vec4(0.0);
vec4 positionF2 = vec4(0.0);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec4 cellOffset = vec4(i, j, k, u);
vec4 pointPosition = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
if (distanceToPoint < distanceF1) {
distanceF2 = distanceF1;
distanceF1 = distanceToPoint;
offsetF2 = offsetF1;
offsetF1 = cellOffset;
positionF2 = positionF1;
positionF1 = pointPosition;
}
else if (distanceToPoint < distanceF2) {
distanceF2 = distanceToPoint;
offsetF2 = cellOffset;
positionF2 = pointPosition;
}
}
}
}
}
VoronoiOutput octave;
octave.Distance = distanceF2;
octave.Color = hash_vec4_to_vec3(cellPosition + offsetF2);
octave.Position = voronoi_position(positionF2 + cellPosition);
return octave;
}
float voronoi_distance_to_edge(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
vec4 vectorToClosest = vec4(0.0);
float minDistance = 8.0;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec4 cellOffset = vec4(i, j, k, u);
vec4 vectorToPoint = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness -
localPosition;
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
vectorToClosest = vectorToPoint;
}
}
}
}
}
minDistance = 8.0;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec4 cellOffset = vec4(i, j, k, u);
vec4 vectorToPoint = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness -
localPosition;
vec4 perpendicularToEdge = vectorToPoint - vectorToClosest;
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
normalize(perpendicularToEdge));
minDistance = min(minDistance, distanceToEdge);
}
}
}
}
}
return minDistance;
}
float voronoi_n_sphere_radius(VoronoiParams params, vec4 coord)
{
vec4 cellPosition = floor(coord);
vec4 localPosition = coord - cellPosition;
vec4 closestPoint = vec4(0.0);
vec4 closestPointOffset = vec4(0.0);
float minDistance = 8.0;
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec4 cellOffset = vec4(i, j, k, u);
vec4 pointPosition = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(pointPosition, localPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPoint = pointPosition;
closestPointOffset = cellOffset;
}
}
}
}
}
minDistance = 8.0;
vec4 closestPointToClosestPoint = vec4(0.0);
for (int u = -1; u <= 1; u++) {
for (int k = -1; k <= 1; k++) {
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
if (i == 0 && j == 0 && k == 0 && u == 0) {
continue;
}
vec4 cellOffset = vec4(i, j, k, u) + closestPointOffset;
vec4 pointPosition = cellOffset +
hash_vec4_to_vec4(cellPosition + cellOffset) * params.randomness;
float distanceToPoint = distance(closestPoint, pointPosition);
if (distanceToPoint < minDistance) {
minDistance = distanceToPoint;
closestPointToClosestPoint = pointPosition;
}
}
}
}
}
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
}

View File

@ -0,0 +1,112 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#include "gpu_testing.hh"
#include "MEM_guardedalloc.h"
#include "BLI_math_vector_types.hh"
#include "GPU_capabilities.h"
#include "GPU_compute.h"
#include "GPU_storage_buffer.h"
#include "GPU_texture.h"
namespace blender::gpu::tests {
static void test_compute_direct()
{
if (!GPU_compute_shader_support()) {
/* We can't test as a the platform does not support compute shaders. */
GTEST_SKIP() << "Skipping test: platform not supported";
return;
}
static constexpr uint SIZE = 32;
/* Build compute shader. */
GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
EXPECT_NE(shader, nullptr);
/* Create texture to store result and attach to shader. */
GPUTexture *texture = GPU_texture_create_2d(
"gpu_shader_compute_2d", SIZE, SIZE, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_GENERAL, nullptr);
EXPECT_NE(texture, nullptr);
GPU_shader_bind(shader);
GPU_texture_image_bind(texture, GPU_shader_get_sampler_binding(shader, "img_output"));
/* Dispatch compute task. */
GPU_compute_dispatch(shader, SIZE, SIZE, 1);
/* Check if compute has been done. */
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
float4 *data = static_cast<float4 *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
const float4 expected_result(1.0f, 0.5f, 0.2f, 1.0f);
EXPECT_NE(data, nullptr);
for (int index = 0; index < SIZE * SIZE; index++) {
EXPECT_EQ(data[index], expected_result);
}
MEM_freeN(data);
/* Cleanup. */
GPU_shader_unbind();
GPU_texture_unbind(texture);
GPU_texture_free(texture);
GPU_shader_free(shader);
}
GPU_TEST(compute_direct)
static void test_compute_indirect()
{
if (!GPU_compute_shader_support()) {
/* We can't test as a the platform does not support compute shaders. */
GTEST_SKIP() << "Skipping test: platform not supported";
return;
}
static constexpr uint SIZE = 32;
/* Build compute shader. */
GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
EXPECT_NE(shader, nullptr);
/* Create texture to store result and attach to shader. */
GPUTexture *texture = GPU_texture_create_2d(
"gpu_shader_compute_2d", SIZE, SIZE, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_GENERAL, nullptr);
EXPECT_NE(texture, nullptr);
GPU_texture_clear(texture, GPU_DATA_FLOAT, float4(0.0f));
GPU_shader_bind(shader);
GPU_texture_image_bind(texture, GPU_shader_get_sampler_binding(shader, "img_output"));
/* Generate compute tasks. */
uint4 commands[1] = {
{SIZE, SIZE, 1, 0},
};
GPUStorageBuf *compute_commands = GPU_storagebuf_create_ex(
sizeof(commands), &commands, GPU_USAGE_STATIC, __func__);
/* Dispatch compute task. */
GPU_compute_dispatch_indirect(shader, compute_commands);
/* Check if compute has been done. */
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
float4 *data = static_cast<float4 *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
const float4 expected_result(1.0f, 0.5f, 0.2f, 1.0f);
EXPECT_NE(data, nullptr);
for (int index = 0; index < SIZE * SIZE; index++) {
EXPECT_EQ(data[index], expected_result);
}
MEM_freeN(data);
/* Cleanup. */
GPU_storagebuf_free(compute_commands);
GPU_shader_unbind();
GPU_texture_unbind(texture);
GPU_texture_free(texture);
GPU_shader_free(shader);
}
GPU_TEST(compute_indirect);
} // namespace blender::gpu::tests

View File

@ -108,9 +108,15 @@ void VKBackend::compute_dispatch(int groups_x_len, int groups_y_len, int groups_
command_buffer.dispatch(groups_x_len, groups_y_len, groups_z_len);
}
void VKBackend::compute_dispatch_indirect(StorageBuf * /*indirect_buf*/)
void VKBackend::compute_dispatch_indirect(StorageBuf *indirect_buf)
{
NOT_YET_IMPLEMENTED;
BLI_assert(indirect_buf);
VKContext &context = *VKContext::get();
context.state_manager_get().apply_bindings();
context.bind_compute_pipeline();
VKStorageBuffer &indirect_buffer = *unwrap(indirect_buf);
VKCommandBuffer &command_buffer = context.command_buffer_get();
command_buffer.dispatch(indirect_buffer);
}
Context *VKBackend::context_alloc(void *ghost_window, void *ghost_context)

View File

@ -13,6 +13,7 @@
#include "vk_index_buffer.hh"
#include "vk_memory.hh"
#include "vk_pipeline.hh"
#include "vk_storage_buffer.hh"
#include "vk_texture.hh"
#include "vk_vertex_buffer.hh"
@ -307,6 +308,12 @@ void VKCommandBuffer::dispatch(int groups_x_len, int groups_y_len, int groups_z_
vkCmdDispatch(vk_command_buffer_, groups_x_len, groups_y_len, groups_z_len);
}
void VKCommandBuffer::dispatch(VKStorageBuffer &command_buffer)
{
ensure_no_active_framebuffer();
vkCmdDispatchIndirect(vk_command_buffer_, command_buffer.vk_handle(), 0);
}
void VKCommandBuffer::submit()
{
ensure_no_active_framebuffer();

View File

@ -21,6 +21,7 @@ class VKFrameBuffer;
class VKIndexBuffer;
class VKPipeline;
class VKPushConstants;
class VKStorageBuffer;
class VKTexture;
class VKVertexBuffer;
@ -160,6 +161,7 @@ class VKCommandBuffer : NonCopyable, NonMovable {
const VkPipelineLayout vk_pipeline_layout,
const VkShaderStageFlags vk_shader_stages);
void dispatch(int groups_x_len, int groups_y_len, int groups_z_len);
void dispatch(VKStorageBuffer &command_buffer);
/** Copy the contents of a texture MIP level to the dst buffer. */
void copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span<VkBufferImageCopy> regions);
void copy(VKTexture &dst_texture, VKBuffer &src_buffer, Span<VkBufferImageCopy> regions);

View File

@ -14,28 +14,32 @@
namespace blender::gpu {
void VKStorageBuffer::update(const void *data)
{
ensure_allocated();
buffer_.update(data);
}
void VKStorageBuffer::ensure_allocated()
{
if (!buffer_.is_allocated()) {
allocate();
}
buffer_.update(data);
}
void VKStorageBuffer::allocate()
{
buffer_.create(size_in_bytes_,
usage_,
static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
static_cast<VkBufferUsageFlagBits>(VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT));
debug::object_label(buffer_.vk_handle(), name_);
}
void VKStorageBuffer::bind(int slot)
{
ensure_allocated();
VKContext &context = *VKContext::get();
if (!buffer_.is_allocated()) {
allocate();
}
VKShader *shader = static_cast<VKShader *>(context.shader);
const VKShaderInterface &shader_interface = shader->interface_get();
const std::optional<VKDescriptorSet::Location> location =
@ -49,10 +53,8 @@ void VKStorageBuffer::unbind() {}
void VKStorageBuffer::clear(uint32_t clear_value)
{
ensure_allocated();
VKContext &context = *VKContext::get();
if (!buffer_.is_allocated()) {
allocate();
}
buffer_.clear(context, clear_value);
}
@ -61,14 +63,12 @@ void VKStorageBuffer::copy_sub(VertBuf * /*src*/,
uint /*src_offset*/,
uint /*copy_size*/)
{
NOT_YET_IMPLEMENTED;
}
void VKStorageBuffer::read(void *data)
{
if (!buffer_.is_allocated()) {
allocate();
}
ensure_allocated();
VKContext &context = *VKContext::get();
VKCommandBuffer &command_buffer = context.command_buffer_get();
command_buffer.submit();

View File

@ -45,8 +45,15 @@ class VKStorageBuffer : public StorageBuf {
return buffer_.size_in_bytes();
}
void ensure_allocated();
private:
void allocate();
};
static inline VKStorageBuffer *unwrap(StorageBuf *storage_buffer)
{
return static_cast<VKStorageBuffer *>(storage_buffer);
}
} // namespace blender::gpu

View File

@ -218,13 +218,29 @@ static bool uri_from_filename(const char *path, char *uri)
char orig_uri[URI_MAX];
#ifdef WIN32
if (strlen(path) < 2 && path[1] != ':') {
/* Not a correct absolute path. */
return 0;
bool path_is_unc = BLI_path_is_unc(path);
char path_unc_normalized[FILE_MAX];
if (path_is_unc) {
STRNCPY(path_unc_normalized, path);
BLI_path_normalize_unc(path_unc_normalized, sizeof(path_unc_normalized));
path = path_unc_normalized;
/* Assign again because a normalized UNC path may resolve to a drive letter. */
path_is_unc = BLI_path_is_unc(path);
}
if (path_is_unc) {
/* Skip over the `\\` prefix, it's not needed for a URI. */
SNPRINTF(orig_uri, "file://%s", BLI_path_slash_skip(path));
}
else if (BLI_path_is_win32_drive(path)) {
SNPRINTF(orig_uri, "file:///%s", path);
/* Always use an uppercase drive/volume letter in the URI. */
orig_uri[8] = char(toupper(orig_uri[8]));
}
else {
/* Not a correct absolute path with a drive letter or UNC prefix. */
return false;
}
SNPRINTF(orig_uri, "file:///%s", path);
/* Always use an uppercase drive/volume letter in the URI. */
orig_uri[8] = char(toupper(orig_uri[8]));
BLI_str_replace_char(orig_uri, '\\', '/');
#else
SNPRINTF(orig_uri, "file://%s", path);

View File

@ -42,11 +42,11 @@ void FileBuffer::close_file()
void FileBuffer::write_header_element(StringRef name, int count)
{
write_fstring("element {} {}\n", (std::string_view)name, count);
write_fstring("element {} {}\n", std::string_view(name), count);
}
void FileBuffer::write_header_scalar_property(StringRef dataType, StringRef name)
{
write_fstring("property {} {}\n", (std::string_view)dataType, (std::string_view)name);
write_fstring("property {} {}\n", std::string_view(dataType), std::string_view(name));
}
void FileBuffer::write_header_list_property(StringRef countType,
@ -54,14 +54,14 @@ void FileBuffer::write_header_list_property(StringRef countType,
StringRef name)
{
write_fstring("property list {} {} {}\n",
(std::string_view)countType,
(std::string_view)dataType,
(std::string_view)name);
std::string_view(countType),
std::string_view(dataType),
std::string_view(name));
}
void FileBuffer::write_string(StringRef s)
{
write_fstring("{}\n", (std::string_view)s);
write_fstring("{}\n", std::string_view(s));
}
void FileBuffer::write_newline()

View File

@ -109,11 +109,11 @@ class FormatHandler : NonCopyable, NonMovable {
}
void write_obj_usemtl(StringRef s)
{
write_impl("usemtl {}\n", (std::string_view)s);
write_impl("usemtl {}\n", std::string_view(s));
}
void write_obj_mtllib(StringRef s)
{
write_impl("mtllib {}\n", (std::string_view)s);
write_impl("mtllib {}\n", std::string_view(s));
}
void write_obj_smooth(int s)
{
@ -121,11 +121,11 @@ class FormatHandler : NonCopyable, NonMovable {
}
void write_obj_group(StringRef s)
{
write_impl("g {}\n", (std::string_view)s);
write_impl("g {}\n", std::string_view(s));
}
void write_obj_object(StringRef s)
{
write_impl("o {}\n", (std::string_view)s);
write_impl("o {}\n", std::string_view(s));
}
void write_obj_edge(int a, int b)
{
@ -170,7 +170,7 @@ class FormatHandler : NonCopyable, NonMovable {
void write_mtl_newmtl(StringRef s)
{
write_impl("newmtl {}\n", (std::string_view)s);
write_impl("newmtl {}\n", std::string_view(s));
}
void write_mtl_float(const char *type, float v)
{
@ -187,12 +187,12 @@ class FormatHandler : NonCopyable, NonMovable {
/* NOTE: options, if present, will have its own leading space. */
void write_mtl_map(const char *type, StringRef options, StringRef value)
{
write_impl("{}{} {}\n", type, (std::string_view)options, (std::string_view)value);
write_impl("{}{} {}\n", type, std::string_view(options), std::string_view(value));
}
void write_string(StringRef s)
{
write_impl("{}\n", (std::string_view)s);
write_impl("{}\n", std::string_view(s));
}
private:

View File

@ -84,8 +84,7 @@ typedef struct CustomData {
* MUST be >= CD_NUMTYPES, but we can't use a define here.
* Correct size is ensured in CustomData_update_typemap assert().
*/
int typemap[52];
char _pad[4];
int typemap[53];
/** Number of layers, size of layers array. */
int totlayer, maxlayer;
/** In editmode, total size of all data layers. */
@ -181,8 +180,9 @@ typedef enum eCustomDataType {
CD_PROP_BOOL = 50,
CD_HAIRLENGTH = 51,
CD_PROP_QUATERNION = 52,
CD_NUMTYPES = 52,
CD_NUMTYPES = 53,
} eCustomDataType;
/* Bits for eCustomDataMask */
@ -224,6 +224,7 @@ typedef enum eCustomDataType {
#define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL)
#define CD_MASK_PROP_INT8 (1ULL << CD_PROP_INT8)
#define CD_MASK_PROP_INT32_2D (1ULL << CD_PROP_INT32_2D)
#define CD_MASK_PROP_QUATERNION (1ULL << CD_PROP_QUATERNION)
#define CD_MASK_HAIRLENGTH (1ULL << CD_HAIRLENGTH)
@ -237,7 +238,7 @@ typedef enum eCustomDataType {
#define CD_MASK_PROP_ALL \
(CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | \
CD_MASK_PROP_COLOR | CD_MASK_PROP_STRING | CD_MASK_PROP_BYTE_COLOR | CD_MASK_PROP_BOOL | \
CD_MASK_PROP_INT8 | CD_MASK_PROP_INT32_2D)
CD_MASK_PROP_INT8 | CD_MASK_PROP_INT32_2D | CD_MASK_PROP_QUATERNION)
/* All color attributes */
#define CD_MASK_COLOR_ALL (CD_MASK_PROP_COLOR | CD_MASK_PROP_BYTE_COLOR)

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