UI: Asset Shelf (Experimental Feature) #104831
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}
|
||||
)
|
||||
|
|
|
@ -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)
|
|
@ -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
|
@ -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
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 ¶ms);
|
||||
float voronoi_distance(const float3 a, const float3 b, const VoronoiParams ¶ms);
|
||||
float voronoi_distance(const float4 a, const float4 b, const VoronoiParams ¶ms);
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float coord);
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float2 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float2 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float2 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float2 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float2 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float2 coord);
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float3 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float3 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float3 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float3 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float3 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float3 coord);
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
float4 voronoi_position(const float4 coord);
|
||||
VoronoiOutput voronoi_f1(const VoronoiParams ¶ms, const float4 coord);
|
||||
VoronoiOutput voronoi_smooth_f1(const VoronoiParams ¶ms,
|
||||
const float4 coord,
|
||||
const bool calc_color);
|
||||
VoronoiOutput voronoi_f2(const VoronoiParams ¶ms, const float4 coord);
|
||||
float voronoi_distance_to_edge(const VoronoiParams ¶ms, const float4 coord);
|
||||
float voronoi_n_sphere_radius(const VoronoiParams ¶ms, const float4 coord);
|
||||
|
||||
/* Fractal Voronoi Noise */
|
||||
|
||||
template<typename T>
|
||||
VoronoiOutput fractal_voronoi_x_fx(const VoronoiParams ¶ms,
|
||||
const T coord,
|
||||
const bool calc_color);
|
||||
template<typename T>
|
||||
float fractal_voronoi_distance_to_edge(const VoronoiParams ¶ms, const T coord);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -8,12 +8,4 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void ED_operatortypes_io(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
void ED_operatortypes_io();
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
}
|
||||
|
|
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue