Mesh: Replace auto smooth with node group #108014
@ -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
|
||||
)
|
||||
|
62
build_files/build_environment/patches/oiio_deadlock.diff
Normal file
62
build_files/build_environment/patches/oiio_deadlock.diff
Normal file
@ -0,0 +1,62 @@
|
||||
diff -Naur orig/src/idiff/idiff.cpp external_openimageio/src/idiff/idiff.cpp
|
||||
--- orig/src/idiff/idiff.cpp 2023-06-07 07:47:42 -0600
|
||||
+++ external_openimageio/src/idiff/idiff.cpp 2023-06-07 09:46:47 -0600
|
||||
@@ -399,5 +399,6 @@
|
||||
|
||||
imagecache->invalidate_all(true);
|
||||
ImageCache::destroy(imagecache);
|
||||
+ default_thread_pool()->resize(0);
|
||||
return ret;
|
||||
}
|
||||
diff -Naur orig/src/libutil/thread.cpp external_openimageio/src/libutil/thread.cpp
|
||||
--- orig/src/libutil/thread.cpp 2023-06-07 07:47:42 -0600
|
||||
+++ external_openimageio/src/libutil/thread.cpp 2023-06-07 09:45:39 -0600
|
||||
@@ -151,9 +151,10 @@
|
||||
this->set_thread(i);
|
||||
}
|
||||
} else { // the number of threads is decreased
|
||||
+ std::vector<std::unique_ptr<std::thread>> terminating_threads;
|
||||
for (int i = oldNThreads - 1; i >= nThreads; --i) {
|
||||
*this->flags[i] = true; // this thread will finish
|
||||
- this->terminating_threads.push_back(
|
||||
+ terminating_threads.push_back(
|
||||
std::move(this->threads[i]));
|
||||
this->threads.erase(this->threads.begin() + i);
|
||||
}
|
||||
@@ -162,6 +163,11 @@
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->cv.notify_all();
|
||||
}
|
||||
+ // wait for the terminated threads to finish
|
||||
+ for (auto& thread : terminating_threads) {
|
||||
+ if (thread->joinable())
|
||||
+ thread->join();
|
||||
+ }
|
||||
this->threads.resize(
|
||||
nThreads); // safe to delete because the threads are detached
|
||||
this->flags.resize(
|
||||
@@ -238,16 +244,10 @@
|
||||
if (thread->joinable())
|
||||
thread->join();
|
||||
}
|
||||
- // wait for the terminated threads to finish
|
||||
- for (auto& thread : this->terminating_threads) {
|
||||
- if (thread->joinable())
|
||||
- thread->join();
|
||||
- }
|
||||
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
|
||||
// therefore delete them here
|
||||
this->clear_queue();
|
||||
this->threads.clear();
|
||||
- this->terminating_threads.clear();
|
||||
this->flags.clear();
|
||||
}
|
||||
|
||||
@@ -349,7 +349,6 @@
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<std::thread>> threads;
|
||||
- std::vector<std::unique_ptr<std::thread>> terminating_threads;
|
||||
std::vector<std::shared_ptr<std::atomic<bool>>> flags;
|
||||
mutable pvt::ThreadsafeQueue<std::function<void(int id)>*> q;
|
||||
std::atomic<bool> isDone;
|
5
extern/fmtlib/CMakeLists.txt
vendored
5
extern/fmtlib/CMakeLists.txt
vendored
@ -1,5 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
# NOTE: Resolved up-stream, quiet noisy compiler warnings for now.
|
||||
add_cxx_flag("-Wno-uninitialized")
|
||||
endif()
|
||||
|
||||
set(INC
|
||||
include
|
||||
)
|
||||
|
2
extern/glog/src/config.h
vendored
2
extern/glog/src/config.h
vendored
@ -2,6 +2,8 @@
|
||||
#include "config_mac.h"
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include "config_freebsd.h"
|
||||
#elif defined(__NetBSD__)
|
||||
#include "config_netbsd.h"
|
||||
#elif defined(__OpenBSD__)
|
||||
#include "config_openbsd.h"
|
||||
#elif defined(__MINGW32__)
|
||||
|
192
extern/glog/src/config_netbsd.h
vendored
Normal file
192
extern/glog/src/config_netbsd.h
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
/* define if glog doesn't use RTTI */
|
||||
/* #undef DISABLE_RTTI */
|
||||
|
||||
/* Namespace for Google classes */
|
||||
#define GOOGLE_NAMESPACE google
|
||||
|
||||
/* Define if you have the `dladdr' function */
|
||||
/* #undef HAVE_DLADDR */
|
||||
|
||||
/* Define if you have the `snprintf' function */
|
||||
#define HAVE_SNPRINTF
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
/* #undef HAVE_EXECINFO_H */
|
||||
|
||||
/* Define if you have the `fcntl' function */
|
||||
#define HAVE_FCNTL
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#define HAVE_GLOB_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#define HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if you have the <libunwind.h> header file. */
|
||||
/* #undef HAVE_LIBUNWIND_H */
|
||||
|
||||
/* define if you have google gflags library */
|
||||
#define HAVE_LIB_GFLAGS
|
||||
|
||||
/* define if you have google gmock library */
|
||||
/* #undef HAVE_LIB_GMOCK */
|
||||
|
||||
/* define if you have google gtest library */
|
||||
/* #undef HAVE_LIB_GTEST */
|
||||
|
||||
/* define if you have libunwind */
|
||||
/* #undef HAVE_LIB_UNWIND */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H
|
||||
|
||||
/* define to disable multithreading support. */
|
||||
/* #undef NO_THREADS */
|
||||
|
||||
/* define if the compiler implements namespaces */
|
||||
#define HAVE_NAMESPACES
|
||||
|
||||
/* Define if you have the 'pread' function */
|
||||
#define HAVE_PREAD
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H
|
||||
|
||||
/* Define if you have the 'pwrite' function */
|
||||
#define HAVE_PWRITE
|
||||
|
||||
/* define if the compiler implements pthread_rwlock_* */
|
||||
#define HAVE_RWLOCK 1
|
||||
|
||||
/* Define if you have the 'sigaction' function */
|
||||
#define HAVE_SIGACTION
|
||||
|
||||
/* Define if you have the `sigaltstack' function */
|
||||
#define HAVE_SIGALTSTACK 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <syscall.h> header file. */
|
||||
/* #undef HAVE_SYSCALL_H */
|
||||
|
||||
/* Define to 1 if you have the <syslog.h> header file. */
|
||||
#define HAVE_SYSLOG_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/syscall.h> header file. */
|
||||
#define HAVE_SYS_SYSCALL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ucontext.h> header file. */
|
||||
#define HAVE_SYS_UCONTEXT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#define HAVE_SYS_UTSNAME_H
|
||||
|
||||
/* Define to 1 if you have the <ucontext.h> header file. */
|
||||
#define HAVE_UCONTEXT_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the <unwind.h> header file. */
|
||||
#define HAVE_UNWIND_H 1
|
||||
|
||||
/* define if the compiler supports using expression for operator */
|
||||
#define HAVE_USING_OPERATOR
|
||||
|
||||
/* define if your compiler has __attribute__ */
|
||||
#define HAVE___ATTRIBUTE__
|
||||
|
||||
/* define if your compiler has __builtin_expect */
|
||||
#define HAVE___BUILTIN_EXPECT 1
|
||||
|
||||
/* define if your compiler has __sync_val_compare_and_swap */
|
||||
#define HAVE___SYNC_VAL_COMPARE_AND_SWAP
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
/* #undef LT_OBJDIR */
|
||||
|
||||
/* Name of package */
|
||||
/* #undef PACKAGE */
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
/* #undef PACKAGE_BUGREPORT */
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
/* #undef PACKAGE_NAME */
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
/* #undef PACKAGE_STRING */
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
/* #undef PACKAGE_TARNAME */
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
/* #undef PACKAGE_URL */
|
||||
|
||||
/* Define to the version of this package. */
|
||||
/* #undef PACKAGE_VERSION */
|
||||
|
||||
/* How to access the PC from a struct ucontext */
|
||||
/* #undef PC_FROM_UCONTEXT */
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#define SIZEOF_VOID_P 8
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* the namespace where STL code like vector<> is defined */
|
||||
#define STL_NAMESPACE std
|
||||
|
||||
/* location of source code */
|
||||
#define TEST_SRC_DIR "."
|
||||
|
||||
/* Version number of package */
|
||||
/* #undef VERSION */
|
||||
|
||||
/* Stops putting the code inside the Google namespace */
|
||||
#define _END_GOOGLE_NAMESPACE_ }
|
||||
|
||||
/* Puts following code inside the Google namespace */
|
||||
#define _START_GOOGLE_NAMESPACE_ namespace google {
|
||||
|
||||
#define GOOGLE_GLOG_DLL_DECL
|
||||
|
||||
/* isn't getting defined by configure script when clang compilers are used
|
||||
and cuases compilation errors in stactrace/unwind modules */
|
||||
#ifdef __clang__
|
||||
# define NO_FRAME_POINTER
|
||||
#endif
|
@ -149,7 +149,11 @@ void BlenderSync::sync_light(BL::Object &b_parent,
|
||||
light->set_is_shadow_catcher(b_ob_info.real_object.is_shadow_catcher());
|
||||
|
||||
/* Light group and linking. */
|
||||
light->set_lightgroup(ustring(b_ob_info.real_object.lightgroup()));
|
||||
string lightgroup = b_ob_info.real_object.lightgroup();
|
||||
if (lightgroup.empty()) {
|
||||
lightgroup = b_parent.lightgroup();
|
||||
}
|
||||
light->set_lightgroup(ustring(lightgroup));
|
||||
light->set_light_set_membership(
|
||||
BlenderLightLink::get_light_set_membership(PointerRNA_NULL, b_ob_info.real_object));
|
||||
light->set_shadow_set_membership(
|
||||
|
@ -989,6 +989,48 @@ static const bool *find_sharp_face_attribute(BL::Mesh b_mesh)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const float *find_edge_crease_attribute(BL::Mesh b_mesh)
|
||||
{
|
||||
for (BL::Attribute &b_attribute : b_mesh.attributes) {
|
||||
if (b_attribute.domain() != BL::Attribute::domain_EDGE) {
|
||||
continue;
|
||||
}
|
||||
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
|
||||
continue;
|
||||
}
|
||||
if (b_attribute.name() != "crease_edge") {
|
||||
continue;
|
||||
}
|
||||
BL::FloatAttribute b_float_attribute{b_attribute};
|
||||
if (b_float_attribute.data.length() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const float *find_vert_crease_attribute(BL::Mesh b_mesh)
|
||||
{
|
||||
for (BL::Attribute &b_attribute : b_mesh.attributes) {
|
||||
if (b_attribute.domain() != BL::Attribute::domain_POINT) {
|
||||
continue;
|
||||
}
|
||||
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
|
||||
continue;
|
||||
}
|
||||
if (b_attribute.name() != "crease_vert") {
|
||||
continue;
|
||||
}
|
||||
BL::FloatAttribute b_float_attribute{b_attribute};
|
||||
if (b_float_attribute.data.length() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void create_mesh(Scene *scene,
|
||||
Mesh *mesh,
|
||||
BL::Mesh &b_mesh,
|
||||
@ -1227,11 +1269,12 @@ static void create_subd_mesh(Scene *scene,
|
||||
|
||||
create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
|
||||
|
||||
const int verts_num = b_mesh.vertices.length();
|
||||
const int edges_num = b_mesh.edges.length();
|
||||
|
||||
if (edges_num != 0 && b_mesh.edge_creases.length() > 0) {
|
||||
const float *creases = static_cast<const float *>(b_mesh.edge_creases[0].data[0].ptr.data);
|
||||
const float *creases = find_edge_crease_attribute(b_mesh);
|
||||
|
||||
if (edges_num != 0 && creases != nullptr) {
|
||||
size_t num_creases = 0;
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
if (creases[i] != 0.0f) {
|
||||
@ -1251,11 +1294,10 @@ static void create_subd_mesh(Scene *scene,
|
||||
}
|
||||
}
|
||||
|
||||
for (BL::MeshVertexCreaseLayer &layer : b_mesh.vertex_creases) {
|
||||
const float *creases = static_cast<const float *>(layer.data[0].ptr.data);
|
||||
for (int i = 0; i < layer.data.length(); ++i) {
|
||||
if (creases[i] != 0.0f) {
|
||||
mesh->add_vertex_crease(i, creases[i]);
|
||||
if (const float *vert_creases = find_vert_crease_attribute(b_mesh)) {
|
||||
for (int i = 0; i < verts_num; i++) {
|
||||
if (vert_creases[i] != 0.0f) {
|
||||
mesh->add_vertex_crease(i, vert_creases[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +350,11 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
}
|
||||
|
||||
/* Light group and linking. */
|
||||
object->set_lightgroup(ustring(b_ob.lightgroup()));
|
||||
string lightgroup = b_ob.lightgroup();
|
||||
if (lightgroup.empty()) {
|
||||
lightgroup = b_parent.lightgroup();
|
||||
}
|
||||
object->set_lightgroup(ustring(lightgroup));
|
||||
|
||||
object->set_light_set_membership(BlenderLightLink::get_light_set_membership(b_parent, b_ob));
|
||||
object->set_receiver_light_set(BlenderLightLink::get_receiver_light_set(b_parent, b_ob));
|
||||
|
@ -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_use_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
|
||||
|
@ -104,7 +104,7 @@ ccl_device int bsdf_ashikhmin_velvet_sample(ccl_private const ShaderClosure *sc,
|
||||
float cosHI = fabsf(dot(wi, H));
|
||||
float cosNH = dot(N, H);
|
||||
|
||||
if (!(fabsf(cosNI) > 1e-5f && fabsf(cosNH) < 1.0f - 1e-5f && cosHI > 1e-5f)) {
|
||||
if (!(cosNI > 1e-5f && fabsf(cosNH) < 1.0f - 1e-5f && cosHI > 1e-5f)) {
|
||||
*pdf = 0.0f;
|
||||
*eval = zero_spectrum();
|
||||
return LABEL_NONE;
|
||||
|
@ -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)) :
|
||||
(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;
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ struct CCLShadowContext
|
||||
#endif
|
||||
IntegratorShadowState isect_s;
|
||||
float throughput;
|
||||
float max_t;
|
||||
bool opaque_hit;
|
||||
numhit_t max_hits;
|
||||
numhit_t num_hits;
|
||||
@ -314,7 +315,7 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
|
||||
/* Current implementation in Cycles assumes only single-ray intersection queries. */
|
||||
assert(args->N == 1);
|
||||
|
||||
RTCRay *ray = (RTCRay *)args->ray;
|
||||
const RTCRay *ray = (RTCRay *)args->ray;
|
||||
RTCHit *hit = (RTCHit *)args->hit;
|
||||
#if EMBREE_MAJOR_VERSION >= 4
|
||||
CCLShadowContext *ctx = (CCLShadowContext *)(args->context);
|
||||
@ -367,18 +368,32 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
|
||||
}
|
||||
}
|
||||
|
||||
/* Test if we need to record this transparent intersection. */
|
||||
numhit_t isect_index = ctx->num_recorded_hits;
|
||||
|
||||
/* Always increase the number of recorded hits, even beyond the maximum,
|
||||
* so that we can detect this and trace another ray if needed.
|
||||
* More details about the related logic can be found in implementation of
|
||||
* "shadow_intersections_has_remaining" and "integrate_transparent_shadow"
|
||||
* functions. */
|
||||
++ctx->num_recorded_hits;
|
||||
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
|
||||
const numhit_t max_record_hits = min(ctx->max_hits, numhit_t(INTEGRATOR_SHADOW_ISECT_SIZE));
|
||||
if (ctx->num_recorded_hits < max_record_hits) {
|
||||
/* If maximum number of hits was reached, replace the intersection with the
|
||||
* highest distance. We want to find the N closest intersections. */
|
||||
const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
|
||||
numhit_t isect_index = num_recorded_hits;
|
||||
if (num_recorded_hits + 1 >= max_record_hits) {
|
||||
/* If the maximum number of hits was reached, replace the furthest intersection
|
||||
* with a closer one so we get the N closest intersections. */
|
||||
if (isect_index >= max_record_hits) {
|
||||
/* When recording only N closest hits, max_t will always only decrease.
|
||||
* So let's test if we are already not meeting criteria and can skip max_t recalculation. */
|
||||
if (current_isect.t >= ctx->max_t) {
|
||||
return;
|
||||
}
|
||||
|
||||
float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t);
|
||||
numhit_t max_recorded_hit = numhit_t(0);
|
||||
|
||||
for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) {
|
||||
for (numhit_t i = numhit_t(1); i < max_record_hits; ++i) {
|
||||
const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t);
|
||||
if (isect_t > max_t) {
|
||||
max_recorded_hit = i;
|
||||
@ -386,25 +401,20 @@ ccl_device_forceinline void kernel_embree_filter_occluded_shadow_all_func_impl(
|
||||
}
|
||||
}
|
||||
|
||||
if (num_recorded_hits >= max_record_hits) {
|
||||
isect_index = max_recorded_hit;
|
||||
}
|
||||
|
||||
/* Limit the ray distance and stop counting hits beyond this. */
|
||||
ray->tfar = max(current_isect.t, max_t);
|
||||
/* Limit the ray distance and avoid processing hits beyond this. */
|
||||
ctx->max_t = max_t;
|
||||
|
||||
/* If it's further away than max_t, we don't record this transparent intersection. */
|
||||
if (current_isect.t >= max_t) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
integrator_state_write_shadow_isect(ctx->isect_s, ¤t_isect, isect_index);
|
||||
}
|
||||
|
||||
/* Always increase the number of recorded hits, even beyond the maximum,
|
||||
* so that we can detect this and trace another ray if needed. */
|
||||
++ctx->num_recorded_hits;
|
||||
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
}
|
||||
|
||||
ccl_device_forceinline void kernel_embree_filter_occluded_local_func_impl(
|
||||
const RTCFilterFunctionNArguments *args)
|
||||
{
|
||||
|
@ -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,33 +20,58 @@ 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_accum(ccl_private BsdfEval *eval,
|
||||
const ClosureType closure_type,
|
||||
Spectrum value)
|
||||
ccl_device_inline void bsdf_eval_init(ccl_private BsdfEval *eval, Spectrum value)
|
||||
{
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(closure_type)) {
|
||||
eval->diffuse += value;
|
||||
}
|
||||
else if (CLOSURE_IS_BSDF_GLOSSY(closure_type)) {
|
||||
eval->glossy += value;
|
||||
eval->diffuse = zero_spectrum();
|
||||
eval->glossy = zero_spectrum();
|
||||
eval->sum = value;
|
||||
}
|
||||
|
||||
ccl_device_inline void bsdf_eval_accum(ccl_private BsdfEval *eval,
|
||||
ccl_private const ShaderClosure *sc,
|
||||
const float3 wo,
|
||||
Spectrum value)
|
||||
{
|
||||
if (CLOSURE_IS_BSDF_DIFFUSE(sc->type)) {
|
||||
eval->diffuse += value;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -155,12 +155,15 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg,
|
||||
sd->Ng = Ng;
|
||||
sd->wi = I;
|
||||
sd->shader = shader;
|
||||
if (prim != PRIM_NONE)
|
||||
sd->type = PRIMITIVE_TRIANGLE;
|
||||
else if (lamp != LAMP_NONE)
|
||||
if (lamp != LAMP_NONE) {
|
||||
sd->type = PRIMITIVE_LAMP;
|
||||
else
|
||||
}
|
||||
else if (prim != PRIM_NONE) {
|
||||
sd->type = PRIMITIVE_TRIANGLE;
|
||||
}
|
||||
else {
|
||||
sd->type = PRIMITIVE_NONE;
|
||||
}
|
||||
|
||||
/* primitive */
|
||||
sd->object = object;
|
||||
|
@ -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}
|
||||
)
|
||||
|
137
intern/cycles/kernel/osl/shaders/node_fractal_voronoi.h
Normal file
137
intern/cycles/kernel/osl/shaders/node_fractal_voronoi.h
Normal file
@ -0,0 +1,137 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "node_voronoi.h"
|
||||
#include "stdcycles.h"
|
||||
#include "vector2.h"
|
||||
#include "vector4.h"
|
||||
|
||||
#define vector3 point
|
||||
|
||||
#define FRACTAL_VORONOI_X_FX(T) \
|
||||
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.0; \
|
||||
float scale = 1.0; \
|
||||
\
|
||||
VoronoiOutput Output; \
|
||||
Output.Distance = 0.0; \
|
||||
Output.Color = color(0.0, 0.0, 0.0); \
|
||||
Output.Position = vector4(0.0, 0.0, 0.0, 0.0); \
|
||||
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
VoronoiOutput octave; \
|
||||
if (params.feature == "f1") { \
|
||||
octave = voronoi_f1(params, coord * scale); \
|
||||
} \
|
||||
else if (params.feature == "smooth_f1") { \
|
||||
octave = voronoi_smooth_f1(params, coord * scale); \
|
||||
} \
|
||||
else { \
|
||||
octave = voronoi_f2(params, coord * scale); \
|
||||
} \
|
||||
\
|
||||
if (zero_input) { \
|
||||
max_amplitude = 1.0; \
|
||||
Output = octave; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude += amplitude; \
|
||||
Output.Distance += octave.Distance * amplitude; \
|
||||
Output.Color += octave.Color * amplitude; \
|
||||
Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \
|
||||
Output.Distance = mix( \
|
||||
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \
|
||||
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \
|
||||
Output.Position = mix(Output.Position, \
|
||||
mix(Output.Position, octave.Position / scale, amplitude), \
|
||||
remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
Output.Distance /= max_amplitude * params.max_distance; \
|
||||
Output.Color /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
Output.Position = safe_divide(Output.Position, params.scale); \
|
||||
\
|
||||
return Output; \
|
||||
}
|
||||
|
||||
#define FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(T) \
|
||||
float fractal_voronoi_distance_to_edge(VoronoiParams params, T coord) \
|
||||
{ \
|
||||
float amplitude = 1.0; \
|
||||
float max_amplitude = 0.5 + 0.5 * params.randomness; \
|
||||
float scale = 1.0; \
|
||||
float distance = 8.0; \
|
||||
\
|
||||
int zero_input = params.detail == 0.0 || params.roughness == 0.0 || params.lacunarity == 0.0; \
|
||||
\
|
||||
for (int i = 0; i <= ceil(params.detail); ++i) { \
|
||||
float octave_distance = voronoi_distance_to_edge(params, coord * scale); \
|
||||
\
|
||||
if (zero_input) { \
|
||||
distance = octave_distance; \
|
||||
break; \
|
||||
} \
|
||||
else if (i <= params.detail) { \
|
||||
max_amplitude = mix(max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
scale *= params.lacunarity; \
|
||||
amplitude *= params.roughness; \
|
||||
} \
|
||||
else { \
|
||||
float remainder = params.detail - floor(params.detail); \
|
||||
if (remainder != 0.0) { \
|
||||
float lerp_amplitude = mix( \
|
||||
max_amplitude, (0.5 + 0.5 * params.randomness) / scale, amplitude); \
|
||||
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder); \
|
||||
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude); \
|
||||
distance = mix(distance, min(distance, lerp_distance), remainder); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
if (params.normalize) { \
|
||||
distance /= max_amplitude; \
|
||||
} \
|
||||
\
|
||||
return distance; \
|
||||
}
|
||||
|
||||
/* **** 1D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(float)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float)
|
||||
|
||||
/* **** 2D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector2)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector2)
|
||||
|
||||
/* **** 3D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector3)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector3)
|
||||
|
||||
/* **** 4D Fractal Voronoi **** */
|
||||
|
||||
FRACTAL_VORONOI_X_FX(vector4)
|
||||
|
||||
FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vector4)
|
920
intern/cycles/kernel/osl/shaders/node_voronoi.h
Normal file
920
intern/cycles/kernel/osl/shaders/node_voronoi.h
Normal file
@ -0,0 +1,920 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "node_hash.h"
|
||||
#include "stdcycles.h"
|
||||
#include "vector2.h"
|
||||
#include "vector4.h"
|
||||
|
||||
#define vector3 point
|
||||
|
||||
struct VoronoiParams {
|
||||
float scale;
|
||||
float detail;
|
||||
float roughness;
|
||||
float lacunarity;
|
||||
float smoothness;
|
||||
float exponent;
|
||||
float randomness;
|
||||
float max_distance;
|
||||
int normalize;
|
||||
string feature;
|
||||
string metric;
|
||||
};
|
||||
|
||||
struct VoronoiOutput {
|
||||
float Distance;
|
||||
color Color;
|
||||
vector4 Position;
|
||||
};
|
||||
|
||||
/* **** Distance Functions **** */
|
||||
|
||||
float distance(float a, float b)
|
||||
{
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
float distance(vector2 a, vector2 b)
|
||||
{
|
||||
return length(a - b);
|
||||
}
|
||||
|
||||
float distance(vector4 a, vector4 b)
|
||||
{
|
||||
return length(a - b);
|
||||
}
|
||||
|
||||
float voronoi_distance(float a, float b)
|
||||
{
|
||||
return abs(a - b);
|
||||
}
|
||||
|
||||
float voronoi_distance(vector2 a, vector2 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a.x - b.x) + abs(a.y - b.y);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a.x - b.x), abs(a.y - b.y));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vector3 a, vector3 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a[0] - b[0]), params.exponent) + pow(abs(a[1] - b[1]), params.exponent) +
|
||||
pow(abs(a[2] - b[2]), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float voronoi_distance(vector4 a, vector4 b, VoronoiParams params)
|
||||
{
|
||||
if (params.metric == "euclidean") {
|
||||
return distance(a, b);
|
||||
}
|
||||
else if (params.metric == "manhattan") {
|
||||
return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
|
||||
}
|
||||
else if (params.metric == "chebychev") {
|
||||
return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
|
||||
}
|
||||
else if (params.metric == "minkowski") {
|
||||
return pow(pow(abs(a.x - b.x), params.exponent) + pow(abs(a.y - b.y), params.exponent) +
|
||||
pow(abs(a.z - b.z), params.exponent) + pow(abs(a.w - b.w), params.exponent),
|
||||
1.0 / params.exponent);
|
||||
}
|
||||
else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* **** Safe Division **** */
|
||||
|
||||
vector2 safe_divide(vector2 a, float b)
|
||||
{
|
||||
return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
|
||||
}
|
||||
|
||||
vector4 safe_divide(vector4 a, float b)
|
||||
{
|
||||
return vector4((b != 0.0) ? a.x / b : 0.0,
|
||||
(b != 0.0) ? a.y / b : 0.0,
|
||||
(b != 0.0) ? a.z / b : 0.0,
|
||||
(b != 0.0) ? a.w / b : 0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* Original code is copyright (c) 2013 Inigo Quilez.
|
||||
*
|
||||
* Smooth Voronoi:
|
||||
* - https://wiki.blender.org/wiki/User:OmarSquircleArt/GSoC2019/Documentation/Smooth_Voronoi
|
||||
*
|
||||
* Distance To Edge based on:
|
||||
*
|
||||
* - https://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm
|
||||
* - https://www.shadertoy.com/view/ldl3W8
|
||||
*
|
||||
* With optimization to change -2..2 scan window to -1..1 for better performance,
|
||||
* as explained in https://www.shadertoy.com/view/llG3zy.
|
||||
*/
|
||||
|
||||
/* **** 1D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(float coord)
|
||||
{
|
||||
return vector4(0.0, 0.0, 0.0, coord);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
float targetOffset = 0.0;
|
||||
float targetPosition = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_float_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
float smoothPosition = 0.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_float_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
float offsetF1 = 0.0;
|
||||
float positionF1 = 0.0;
|
||||
float offsetF2 = 0.0;
|
||||
float positionF2 = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_float_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float midPointPosition = hash_float_to_float(cellPosition) * params.randomness;
|
||||
float leftPointPosition = -1.0 + hash_float_to_float(cellPosition - 1.0) * params.randomness;
|
||||
float rightPointPosition = 1.0 + hash_float_to_float(cellPosition + 1.0) * params.randomness;
|
||||
float distanceToMidLeft = abs((midPointPosition + leftPointPosition) / 2.0 - localPosition);
|
||||
float distanceToMidRight = abs((midPointPosition + rightPointPosition) / 2.0 - localPosition);
|
||||
|
||||
return min(distanceToMidLeft, distanceToMidRight);
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, float coord)
|
||||
{
|
||||
float cellPosition = floor(coord);
|
||||
float localPosition = coord - cellPosition;
|
||||
|
||||
float closestPoint = 0.0;
|
||||
float closestPointOffset = 0.0;
|
||||
float minDistance = 8.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
float cellOffset = i;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(pointPosition - localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
float closestPointToClosestPoint = 0.0;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
float cellOffset = i + closestPointOffset;
|
||||
float pointPosition = cellOffset +
|
||||
hash_float_to_float(cellPosition + cellOffset) * params.randomness;
|
||||
float distanceToPoint = abs(closestPoint - pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
|
||||
return abs(closestPointToClosestPoint - closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 2D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector2 coord)
|
||||
{
|
||||
return vector4(coord.x, coord.y, 0.0, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector2 targetOffset = vector2(0.0, 0.0);
|
||||
vector2 targetPosition = vector2(0.0, 0.0);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector2_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector2 smoothPosition = vector2(0.0, 0.0);
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector2_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector2 offsetF1 = vector2(0.0, 0.0);
|
||||
vector2 positionF1 = vector2(0.0, 0.0);
|
||||
vector2 offsetF2 = vector2(0.0, 0.0);
|
||||
vector2 positionF2 = vector2(0.0, 0.0);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector2_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
vector2 vectorToClosest = vector2(0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 vectorToPoint = cellOffset +
|
||||
hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 vectorToPoint = cellOffset +
|
||||
hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
vector2 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
|
||||
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
|
||||
normalize(perpendicularToEdge));
|
||||
minDistance = min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector2 coord)
|
||||
{
|
||||
vector2 cellPosition = floor(coord);
|
||||
vector2 localPosition = coord - cellPosition;
|
||||
|
||||
vector2 closestPoint = vector2(0.0, 0.0);
|
||||
vector2 closestPointOffset = vector2(0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector2 cellOffset = vector2(i, j);
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector2 closestPointToClosestPoint = vector2(0.0, 0.0);
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0) {
|
||||
continue;
|
||||
}
|
||||
vector2 cellOffset = vector2(i, j) + closestPointOffset;
|
||||
vector2 pointPosition = cellOffset + hash_vector2_to_vector2(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 3D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector3 coord)
|
||||
{
|
||||
return vector4(coord.x, coord.y, coord.z, 0.0);
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector3 targetOffset = vector3(0.0, 0.0, 0.0);
|
||||
vector3 targetPosition = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector3_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector3 smoothPosition = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector3_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector3 offsetF1 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 positionF1 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 offsetF2 = vector3(0.0, 0.0, 0.0);
|
||||
vector3 positionF2 = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector3_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
vector3 vectorToClosest = vector3(0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 vectorToPoint = cellOffset +
|
||||
hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 vectorToPoint = cellOffset +
|
||||
hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
|
||||
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
|
||||
normalize((vector)perpendicularToEdge));
|
||||
minDistance = min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector3 coord)
|
||||
{
|
||||
vector3 cellPosition = floor(coord);
|
||||
vector3 localPosition = coord - cellPosition;
|
||||
|
||||
vector3 closestPoint = vector3(0.0, 0.0, 0.0);
|
||||
vector3 closestPointOffset = vector3(0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector3 cellOffset = vector3(i, j, k);
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector3 closestPointToClosestPoint = vector3(0.0, 0.0, 0.0);
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0 && k == 0) {
|
||||
continue;
|
||||
}
|
||||
vector3 cellOffset = vector3(i, j, k) + closestPointOffset;
|
||||
vector3 pointPosition = cellOffset + hash_vector3_to_vector3(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
||||
|
||||
/* **** 4D Voronoi **** */
|
||||
|
||||
vector4 voronoi_position(vector4 coord)
|
||||
{
|
||||
return coord;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f1(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float minDistance = 8.0;
|
||||
vector4 targetOffset = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 targetPosition = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < minDistance) {
|
||||
targetOffset = cellOffset;
|
||||
minDistance = distanceToPoint;
|
||||
targetPosition = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = minDistance;
|
||||
octave.Color = hash_vector4_to_color(cellPosition + targetOffset);
|
||||
octave.Position = voronoi_position(targetPosition + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_smooth_f1(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float smoothDistance = 8.0;
|
||||
vector3 smoothColor = vector3(0.0, 0.0, 0.0);
|
||||
vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -2; u <= 2; u++) {
|
||||
for (int k = -2; k <= 2; k++) {
|
||||
for (int j = -2; j <= 2; j++) {
|
||||
for (int i = -2; i <= 2; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
float h = smoothstep(
|
||||
0.0, 1.0, 0.5 + 0.5 * (smoothDistance - distanceToPoint) / params.smoothness);
|
||||
float correctionFactor = params.smoothness * h * (1.0 - h);
|
||||
smoothDistance = mix(smoothDistance, distanceToPoint, h) - correctionFactor;
|
||||
correctionFactor /= 1.0 + 3.0 * params.smoothness;
|
||||
color cellColor = hash_vector4_to_color(cellPosition + cellOffset);
|
||||
smoothColor = mix(smoothColor, cellColor, h) - correctionFactor;
|
||||
smoothPosition = mix(smoothPosition, pointPosition, h) - correctionFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = smoothDistance;
|
||||
octave.Color = smoothColor;
|
||||
octave.Position = voronoi_position(cellPosition + smoothPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
VoronoiOutput voronoi_f2(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
float distanceF1 = 8.0;
|
||||
float distanceF2 = 8.0;
|
||||
vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 offsetF2 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 positionF2 = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = voronoi_distance(pointPosition, localPosition, params);
|
||||
if (distanceToPoint < distanceF1) {
|
||||
distanceF2 = distanceF1;
|
||||
distanceF1 = distanceToPoint;
|
||||
offsetF2 = offsetF1;
|
||||
offsetF1 = cellOffset;
|
||||
positionF2 = positionF1;
|
||||
positionF1 = pointPosition;
|
||||
}
|
||||
else if (distanceToPoint < distanceF2) {
|
||||
distanceF2 = distanceToPoint;
|
||||
offsetF2 = cellOffset;
|
||||
positionF2 = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VoronoiOutput octave;
|
||||
octave.Distance = distanceF2;
|
||||
octave.Color = hash_vector4_to_color(cellPosition + offsetF2);
|
||||
octave.Position = voronoi_position(positionF2 + cellPosition);
|
||||
return octave;
|
||||
}
|
||||
|
||||
float voronoi_distance_to_edge(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
vector4 vectorToClosest = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 vectorToPoint = cellOffset +
|
||||
hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
float distanceToPoint = dot(vectorToPoint, vectorToPoint);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
vectorToClosest = vectorToPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 vectorToPoint = cellOffset +
|
||||
hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness -
|
||||
localPosition;
|
||||
vector4 perpendicularToEdge = vectorToPoint - vectorToClosest;
|
||||
if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
|
||||
float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
|
||||
normalize(perpendicularToEdge));
|
||||
minDistance = min(minDistance, distanceToEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
float voronoi_n_sphere_radius(VoronoiParams params, vector4 coord)
|
||||
{
|
||||
vector4 cellPosition = floor(coord);
|
||||
vector4 localPosition = coord - cellPosition;
|
||||
|
||||
vector4 closestPoint = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
vector4 closestPointOffset = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
float minDistance = 8.0;
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
vector4 cellOffset = vector4(i, j, k, u);
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(pointPosition, localPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPoint = pointPosition;
|
||||
closestPointOffset = cellOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minDistance = 8.0;
|
||||
vector4 closestPointToClosestPoint = vector4(0.0, 0.0, 0.0, 0.0);
|
||||
for (int u = -1; u <= 1; u++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
if (i == 0 && j == 0 && k == 0 && u == 0) {
|
||||
continue;
|
||||
}
|
||||
vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset;
|
||||
vector4 pointPosition = cellOffset + hash_vector4_to_vector4(cellPosition + cellOffset) *
|
||||
params.randomness;
|
||||
float distanceToPoint = distance(closestPoint, pointPosition);
|
||||
if (distanceToPoint < minDistance) {
|
||||
minDistance = distanceToPoint;
|
||||
closestPointToClosestPoint = pointPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return distance(closestPointToClosestPoint, closestPoint) / 2.0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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(use_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, use_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, "use_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, use_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));
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ extern void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
|
||||
* \param glSettings: Misc OpenGL options.
|
||||
* \param gpuSettings: Misc GPU options.
|
||||
* \return A handle to the new window ( == NULL if creation failed).
|
||||
*/
|
||||
extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
||||
@ -174,17 +174,17 @@ extern GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
bool is_dialog,
|
||||
GHOST_GLSettings glSettings);
|
||||
GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Create a new off-screen context.
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \param systemhandle: The handle to the system.
|
||||
* \param glSettings: Misc OpenGL options.
|
||||
* \param gpuSettings: Misc GPU options.
|
||||
* \return A handle to the new context ( == NULL if creation failed).
|
||||
*/
|
||||
extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GLSettings glSettings);
|
||||
extern GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
@ -192,7 +192,7 @@ extern GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemha
|
||||
* \param contexthandle: Handle to the context to be disposed.
|
||||
* \return Indication of success.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
extern GHOST_TSuccess GHOST_DisposeGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
@ -730,24 +730,24 @@ extern GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle);
|
||||
* \param contexthandle: The handle to the context.
|
||||
* \return A success indicator.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle);
|
||||
extern GHOST_TSuccess GHOST_ActivateGPUContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Release the drawing context bound to this thread.
|
||||
* \param contexthandle: The handle to the context.
|
||||
* \return A success indicator.
|
||||
*/
|
||||
extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
|
||||
extern GHOST_TSuccess GHOST_ReleaseGPUContext(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL frame-buffer handle that serves as a default frame-buffer.
|
||||
* Get the GPU frame-buffer handle that serves as a default frame-buffer.
|
||||
*/
|
||||
extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle);
|
||||
extern unsigned int GHOST_GetContextDefaultGPUFramebuffer(GHOST_ContextHandle contexthandle);
|
||||
|
||||
/**
|
||||
* Get the OpenGL frame-buffer handle that serves as a default frame-buffer.
|
||||
* Get the GPU frame-buffer handle that serves as a default frame-buffer.
|
||||
*/
|
||||
extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle);
|
||||
extern unsigned int GHOST_GetDefaultGPUFramebuffer(GHOST_WindowHandle windowhandle);
|
||||
|
||||
/**
|
||||
* Use multi-touch gestures if supported.
|
||||
@ -1072,7 +1072,7 @@ int GHOST_XrSessionIsRunning(const GHOST_XrContextHandle xr_context);
|
||||
|
||||
/**
|
||||
* Check if \a xr_context has a session that requires an upside-down frame-buffer (compared to
|
||||
* OpenGL). If true, the render result should be flipped vertically for correct output.
|
||||
* GPU). If true, the render result should be flipped vertically for correct output.
|
||||
* \note Only to be called after session start, may otherwise result in a false negative.
|
||||
*/
|
||||
int GHOST_XrSessionNeedsUpsideDownDrawing(const GHOST_XrContextHandle xr_context);
|
||||
|
@ -230,7 +230,7 @@ class GHOST_ISystem {
|
||||
* \param width: The width the window.
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param glSettings: Misc OpenGL settings.
|
||||
* \param gpuSettings: Misc GPU settings.
|
||||
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
|
||||
* \param is_dialog: Stay on top of parent window, no icon in taskbar, can't be minimized.
|
||||
* \param parentWindow: Parent (embedder) window
|
||||
@ -242,7 +242,7 @@ class GHOST_ISystem {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = NULL) = 0;
|
||||
@ -259,7 +259,7 @@ class GHOST_ISystem {
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) = 0;
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) = 0;
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
@ -64,9 +64,9 @@ typedef struct {
|
||||
} GHOST_CursorBitmapRef;
|
||||
|
||||
typedef enum {
|
||||
GHOST_glStereoVisual = (1 << 0),
|
||||
GHOST_glDebugContext = (1 << 1),
|
||||
} GHOST_GLFlags;
|
||||
GHOST_gpuStereoVisual = (1 << 0),
|
||||
GHOST_gpuDebugContext = (1 << 1),
|
||||
} GHOST_GPUFlags;
|
||||
|
||||
typedef enum GHOST_DialogOptions {
|
||||
GHOST_DialogWarning = (1 << 0),
|
||||
@ -170,14 +170,15 @@ typedef enum {
|
||||
GHOST_kModifierKeyNum
|
||||
} GHOST_TModifierKey;
|
||||
|
||||
/**
|
||||
* \note these values are stored in #wmWindow::windowstate,
|
||||
* don't change, only add new values.
|
||||
*/
|
||||
typedef enum {
|
||||
GHOST_kWindowStateNormal = 0,
|
||||
GHOST_kWindowStateMaximized,
|
||||
GHOST_kWindowStateMinimized,
|
||||
GHOST_kWindowStateFullScreen,
|
||||
GHOST_kWindowStateEmbedded,
|
||||
// GHOST_kWindowStateModified,
|
||||
// GHOST_kWindowStateUnModified,
|
||||
GHOST_kWindowStateMaximized = 1,
|
||||
GHOST_kWindowStateMinimized = 2,
|
||||
GHOST_kWindowStateFullScreen = 3,
|
||||
} GHOST_TWindowState;
|
||||
|
||||
typedef enum {
|
||||
@ -680,7 +681,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
int flags;
|
||||
GHOST_TDrawingContextType context_type;
|
||||
} GHOST_GLSettings;
|
||||
} GHOST_GPUSettings;
|
||||
|
||||
typedef enum {
|
||||
/** Axis that cursor grab will wrap. */
|
||||
|
@ -135,15 +135,15 @@ void GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle,
|
||||
system->getAllDisplayDimensions(*width, *height);
|
||||
}
|
||||
|
||||
GHOST_ContextHandle GHOST_CreateOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GLSettings glSettings)
|
||||
GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
|
||||
return (GHOST_ContextHandle)system->createOffscreenContext(glSettings);
|
||||
return (GHOST_ContextHandle)system->createOffscreenContext(gpuSettings);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_DisposeOpenGLContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_TSuccess GHOST_DisposeGPUContext(GHOST_SystemHandle systemhandle,
|
||||
GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
@ -161,7 +161,7 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
bool is_dialog,
|
||||
GHOST_GLSettings glSettings)
|
||||
GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
|
||||
@ -171,7 +171,7 @@ GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle,
|
||||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings,
|
||||
gpuSettings,
|
||||
false,
|
||||
is_dialog,
|
||||
(GHOST_IWindow *)parent_windowhandle);
|
||||
@ -716,7 +716,7 @@ GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandl
|
||||
return window->activateDrawingContext();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
GHOST_TSuccess GHOST_ActivateGPUContext(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
if (context) {
|
||||
@ -726,21 +726,21 @@ GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
|
||||
GHOST_TSuccess GHOST_ReleaseGPUContext(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->releaseDrawingContext();
|
||||
}
|
||||
|
||||
uint GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle)
|
||||
uint GHOST_GetContextDefaultGPUFramebuffer(GHOST_ContextHandle contexthandle)
|
||||
{
|
||||
GHOST_IContext *context = (GHOST_IContext *)contexthandle;
|
||||
|
||||
return context->getDefaultFramebuffer();
|
||||
}
|
||||
|
||||
uint GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle)
|
||||
uint GHOST_GetDefaultGPUFramebuffer(GHOST_WindowHandle windowhandle)
|
||||
{
|
||||
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
|
||||
|
||||
|
@ -215,6 +215,7 @@ class GHOST_DeviceVK {
|
||||
device_features.geometryShader = VK_TRUE;
|
||||
device_features.dualSrcBlend = VK_TRUE;
|
||||
device_features.logicOp = VK_TRUE;
|
||||
device_features.imageCubeArray = VK_TRUE;
|
||||
#endif
|
||||
|
||||
VkDeviceCreateInfo device_create_info = {};
|
||||
@ -309,7 +310,7 @@ static GHOST_TSuccess ensure_vulkan_device(VkInstance vk_instance,
|
||||
|
||||
#if STRICT_REQUIREMENTS
|
||||
if (!device_vk.features.geometryShader || !device_vk.features.dualSrcBlend ||
|
||||
!device_vk.features.logicOp)
|
||||
!device_vk.features.logicOp || !device_vk.features.imageCubeArray)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -397,12 +397,12 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
|
||||
const GHOST_DisplaySetting &settings,
|
||||
const bool stereoVisual)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
|
||||
if (stereoVisual) {
|
||||
glSettings.flags |= GHOST_glStereoVisual;
|
||||
gpuSettings.flags |= GHOST_gpuStereoVisual;
|
||||
}
|
||||
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
gpuSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
/* NOTE: don't use #getCurrentDisplaySetting() because on X11 we may
|
||||
* be zoomed in and the desktop may be bigger than the viewport. */
|
||||
GHOST_ASSERT(m_displayManager,
|
||||
@ -414,7 +414,7 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
|
||||
settings.xPixels,
|
||||
settings.yPixels,
|
||||
GHOST_kWindowStateNormal,
|
||||
glSettings,
|
||||
gpuSettings,
|
||||
true /* exclusive */);
|
||||
return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ class GHOST_System : public GHOST_ISystem {
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) = 0;
|
||||
virtual GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) = 0;
|
||||
|
||||
/**
|
||||
* Returns whether a window is valid.
|
||||
|
@ -77,7 +77,7 @@ class GHOST_SystemCocoa : public GHOST_System {
|
||||
* \param width: The width the window.
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param glSettings: Misc OpenGL settings.
|
||||
* \param gpuSettings: Misc GPU settings.
|
||||
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
|
||||
* \param parentWindow: Parent (embedder) window.
|
||||
* \return The new window (or 0 if creation failed).
|
||||
@ -88,7 +88,7 @@ class GHOST_SystemCocoa : public GHOST_System {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = NULL);
|
||||
@ -98,7 +98,7 @@ class GHOST_SystemCocoa : public GHOST_System {
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings);
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
@ -696,7 +696,7 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
@ -725,9 +725,9 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
||||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings.context_type,
|
||||
glSettings.flags & GHOST_glStereoVisual,
|
||||
glSettings.flags & GHOST_glDebugContext,
|
||||
gpuSettings.context_type,
|
||||
gpuSettings.flags & GHOST_gpuStereoVisual,
|
||||
gpuSettings.flags & GHOST_gpuDebugContext,
|
||||
is_dialog,
|
||||
(GHOST_WindowCocoa *)parentWindow);
|
||||
|
||||
@ -755,11 +755,11 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
GHOST_Context *context = new GHOST_ContextVK(false, NULL, 1, 2, debug_context);
|
||||
if (!context->initializeDrawingContext()) {
|
||||
delete context;
|
||||
@ -769,7 +769,7 @@ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GLSettings glSet
|
||||
}
|
||||
#endif
|
||||
|
||||
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, glSettings.context_type);
|
||||
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, NULL, gpuSettings.context_type);
|
||||
if (context->initializeDrawingContext())
|
||||
return context;
|
||||
else
|
||||
|
@ -79,7 +79,7 @@ class GHOST_SystemHeadless : public GHOST_System {
|
||||
void getAllDisplayDimensions(uint32_t & /*width*/, uint32_t & /*height*/) const override
|
||||
{ /* nop */
|
||||
}
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings /*glSettings*/) override
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings /*gpuSettings*/) override
|
||||
{
|
||||
#ifdef __linux__
|
||||
GHOST_Context *context;
|
||||
@ -150,7 +150,7 @@ class GHOST_SystemHeadless : public GHOST_System {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool /*exclusive*/,
|
||||
const bool /*is_dialog*/,
|
||||
const GHOST_IWindow *parentWindow) override
|
||||
@ -162,8 +162,8 @@ class GHOST_SystemHeadless : public GHOST_System {
|
||||
height,
|
||||
state,
|
||||
parentWindow,
|
||||
glSettings.context_type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0));
|
||||
gpuSettings.context_type,
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0));
|
||||
}
|
||||
|
||||
GHOST_IWindow *getWindowUnderCursor(int32_t /*x*/, int32_t /*y*/) override
|
||||
|
@ -42,7 +42,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool /* is_dialog */,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
@ -56,8 +56,8 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
|
||||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings.context_type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
gpuSettings.context_type,
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
exclusive,
|
||||
parentWindow);
|
||||
|
||||
@ -125,7 +125,7 @@ uint8_t GHOST_SystemSDL::getNumDisplays() const
|
||||
return SDL_GetNumVideoDisplays();
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
|
||||
GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GPUSettings /*gpuSettings*/)
|
||||
{
|
||||
GHOST_Context *context = new GHOST_ContextSDL(false,
|
||||
nullptr,
|
||||
|
@ -60,7 +60,7 @@ class GHOST_SystemSDL : public GHOST_System {
|
||||
|
||||
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const override;
|
||||
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) override;
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) override;
|
||||
|
||||
GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
|
||||
|
||||
@ -73,7 +73,7 @@ class GHOST_SystemSDL : public GHOST_System {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = nullptr) override;
|
||||
|
@ -6279,7 +6279,7 @@ static GHOST_Context *createOffscreenContext_impl(GHOST_SystemWayland *system,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
#ifdef USE_EVENT_BACKGROUND_THREAD
|
||||
std::lock_guard lock_server_guard{*server_mutex};
|
||||
@ -6289,9 +6289,9 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glS
|
||||
wl_surface *wl_surface = wl_compositor_create_surface(wl_compositor());
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
GHOST_Context *context = new GHOST_ContextVK(false,
|
||||
GHOST_kVulkanPlatformWayland,
|
||||
0,
|
||||
@ -6310,7 +6310,7 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings glS
|
||||
return context;
|
||||
}
|
||||
#else
|
||||
(void)glSettings;
|
||||
(void)gpuSettings;
|
||||
#endif
|
||||
|
||||
wl_egl_window *egl_window = wl_surface ? wl_egl_window_create(wl_surface, 1, 1) : nullptr;
|
||||
@ -6359,7 +6359,7 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
|
||||
const uint32_t width,
|
||||
const uint32_t height,
|
||||
const GHOST_TWindowState state,
|
||||
const GHOST_GLSettings glSettings,
|
||||
const GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
@ -6374,9 +6374,9 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
|
||||
height,
|
||||
state,
|
||||
parentWindow,
|
||||
glSettings.context_type,
|
||||
gpuSettings.context_type,
|
||||
is_dialog,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
exclusive);
|
||||
|
||||
if (window) {
|
||||
|
@ -157,7 +157,7 @@ class GHOST_SystemWayland : public GHOST_System {
|
||||
|
||||
void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const override;
|
||||
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) override;
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) override;
|
||||
|
||||
GHOST_TSuccess disposeContext(GHOST_IContext *context) override;
|
||||
|
||||
@ -167,7 +167,7 @@ class GHOST_SystemWayland : public GHOST_System {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow) override;
|
||||
|
@ -224,7 +224,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool /*exclusive*/,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
@ -237,11 +237,11 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
|
||||
width,
|
||||
height,
|
||||
state,
|
||||
glSettings.context_type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
gpuSettings.context_type,
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
false,
|
||||
(GHOST_WindowWin32 *)parentWindow,
|
||||
((glSettings.flags & GHOST_glDebugContext) != 0),
|
||||
((gpuSettings.flags & GHOST_gpuDebugContext) != 0),
|
||||
is_dialog);
|
||||
|
||||
if (window->getValid()) {
|
||||
@ -263,15 +263,15 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title,
|
||||
* Never explicitly delete the window, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemWin32::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
|
||||
GHOST_Context *context = nullptr;
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
/* Vulkan does not need a window. */
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
context = new GHOST_ContextVK(false, (HWND)0, 1, 2, debug_context);
|
||||
|
||||
if (!context->initializeDrawingContext()) {
|
||||
|
@ -103,7 +103,7 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
* \param width: The width the window.
|
||||
* \param height: The height the window.
|
||||
* \param state: The state of the window when opened.
|
||||
* \param glSettings: Misc OpenGL settings.
|
||||
* \param gpuSettings: Misc GPU settings.
|
||||
* \param exclusive: Use to show the window on top and ignore others (used full-screen).
|
||||
* \param parentWindow: Parent window.
|
||||
* \return The new window (or 0 if creation failed).
|
||||
@ -114,7 +114,7 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = 0);
|
||||
@ -124,7 +124,7 @@ class GHOST_SystemWin32 : public GHOST_System {
|
||||
* Never explicitly delete the window, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings);
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings);
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
@ -304,7 +304,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive,
|
||||
const bool is_dialog,
|
||||
const GHOST_IWindow *parentWindow)
|
||||
@ -324,11 +324,11 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
|
||||
height,
|
||||
state,
|
||||
(GHOST_WindowX11 *)parentWindow,
|
||||
glSettings.context_type,
|
||||
gpuSettings.context_type,
|
||||
is_dialog,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0),
|
||||
((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
|
||||
exclusive,
|
||||
(glSettings.flags & GHOST_glDebugContext) != 0);
|
||||
(gpuSettings.flags & GHOST_gpuDebugContext) != 0);
|
||||
|
||||
if (window) {
|
||||
/* Both are now handle in GHOST_WindowX11.cc
|
||||
@ -399,7 +399,7 @@ static GHOST_Context *create_glx_context(Display *display,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSettings)
|
||||
GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
/* During development:
|
||||
* try 4.x compatibility profile
|
||||
@ -411,11 +411,11 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
|
||||
* try 3.3 core profile
|
||||
* no fall-backs. */
|
||||
|
||||
const bool debug_context = (glSettings.flags & GHOST_glDebugContext) != 0;
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
GHOST_Context *context = nullptr;
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
if (glSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
if (gpuSettings.context_type == GHOST_kDrawingContextTypeVulkan) {
|
||||
context = new GHOST_ContextVK(
|
||||
false, GHOST_kVulkanPlatformX11, 0, m_display, NULL, NULL, 1, 2, debug_context);
|
||||
|
||||
|
@ -124,7 +124,7 @@ class GHOST_SystemX11 : public GHOST_System {
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
GHOST_TWindowState state,
|
||||
GHOST_GLSettings glSettings,
|
||||
GHOST_GPUSettings gpuSettings,
|
||||
const bool exclusive = false,
|
||||
const bool is_dialog = false,
|
||||
const GHOST_IWindow *parentWindow = nullptr) override;
|
||||
@ -134,7 +134,7 @@ class GHOST_SystemX11 : public GHOST_System {
|
||||
* Never explicitly delete the context, use #disposeContext() instead.
|
||||
* \return The new context (or 0 if creation failed).
|
||||
*/
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings) override;
|
||||
GHOST_IContext *createOffscreenContext(GHOST_GPUSettings gpuSettings) override;
|
||||
|
||||
/**
|
||||
* Dispose of a context.
|
||||
|
@ -332,9 +332,6 @@ static bool gwl_window_state_set_for_libdecor(libdecor_frame *frame,
|
||||
libdecor_frame_set_fullscreen(frame, nullptr);
|
||||
break;
|
||||
}
|
||||
case GHOST_kWindowStateEmbedded: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -377,9 +374,6 @@ static bool gwl_window_state_set_for_xdg(xdg_toplevel *toplevel,
|
||||
xdg_toplevel_set_fullscreen(toplevel, nullptr);
|
||||
break;
|
||||
}
|
||||
case GHOST_kWindowStateEmbedded: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -412,7 +412,7 @@ bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr userData)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
char *title1 = "gears - main window";
|
||||
char *title2 = "gears - secondary window";
|
||||
GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(processEvent, NULL);
|
||||
@ -433,7 +433,7 @@ int main(int argc, char **argv)
|
||||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
if (!sMainWindow) {
|
||||
printf("could not create main window\n");
|
||||
exit(-1);
|
||||
@ -450,7 +450,7 @@ int main(int argc, char **argv)
|
||||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
if (!sSecondaryWindow) {
|
||||
printf("could not create secondary window\n");
|
||||
exit(-1);
|
||||
|
@ -406,13 +406,13 @@ Application::Application(GHOST_ISystem *system)
|
||||
m_exitRequested(false),
|
||||
stereo(false)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
glSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
gpuSettings.context_type = GHOST_kDrawingContextTypeOpenGL;
|
||||
fApp = this;
|
||||
|
||||
// Create the main window
|
||||
m_mainWindow = system->createWindow(
|
||||
"gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
|
||||
"gears - main window", 10, 64, 320, 200, GHOST_kWindowStateNormal, gpuSettings);
|
||||
|
||||
if (!m_mainWindow) {
|
||||
std::cout << "could not create main window\n";
|
||||
@ -421,7 +421,7 @@ Application::Application(GHOST_ISystem *system)
|
||||
|
||||
// Create a secondary window
|
||||
m_secondaryWindow = system->createWindow(
|
||||
"gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, glSettings);
|
||||
"gears - secondary window", 340, 64, 320, 200, GHOST_kWindowStateNormal, gpuSettings);
|
||||
if (!m_secondaryWindow) {
|
||||
std::cout << "could not create secondary window\n";
|
||||
exit(-1);
|
||||
|
@ -306,7 +306,7 @@ MainWindow *mainwindow_new(MultiTestApp *app)
|
||||
{
|
||||
GHOST_SystemHandle sys = multitestapp_get_system(app);
|
||||
GHOST_WindowHandle win;
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
|
||||
win = GHOST_CreateWindow(sys,
|
||||
NULL,
|
||||
@ -318,7 +318,7 @@ MainWindow *mainwindow_new(MultiTestApp *app)
|
||||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
|
||||
if (win) {
|
||||
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
|
||||
@ -557,7 +557,7 @@ static void loggerwindow_handle(void *priv, GHOST_EventHandle evt)
|
||||
|
||||
LoggerWindow *loggerwindow_new(MultiTestApp *app)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
GHOST_SystemHandle sys = multitestapp_get_system(app);
|
||||
uint32_t screensize[2];
|
||||
GHOST_WindowHandle win;
|
||||
@ -573,7 +573,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
|
||||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
|
||||
if (win) {
|
||||
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
|
||||
@ -761,7 +761,7 @@ static void extrawindow_handle(void *priv, GHOST_EventHandle evt)
|
||||
|
||||
ExtraWindow *extrawindow_new(MultiTestApp *app)
|
||||
{
|
||||
GHOST_GLSettings glSettings = {0};
|
||||
GHOST_GPUSettings gpuSettings = {0};
|
||||
GHOST_SystemHandle sys = multitestapp_get_system(app);
|
||||
GHOST_WindowHandle win;
|
||||
|
||||
@ -775,7 +775,7 @@ ExtraWindow *extrawindow_new(MultiTestApp *app)
|
||||
GHOST_kWindowStateNormal,
|
||||
false,
|
||||
GHOST_kDrawingContextTypeOpenGL,
|
||||
glSettings);
|
||||
gpuSettings);
|
||||
|
||||
if (win) {
|
||||
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
|
||||
|
@ -25,7 +25,7 @@
|
||||
# define HAVE_MALLOC_STATS
|
||||
#elif defined(__FreeBSD__)
|
||||
# include <malloc_np.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
# undef USE_MALLOC_USABLE_SIZE
|
||||
#elif defined(__APPLE__)
|
||||
# include <malloc/malloc.h>
|
||||
|
@ -350,7 +350,7 @@ def main():
|
||||
if name.rpartition(".")[2].isdigit():
|
||||
continue
|
||||
|
||||
if not ob_eval.data.attributes.active_color:
|
||||
if (not hasattr(ob_eval.data, 'attributes')) or not ob_eval.data.attributes.active_color:
|
||||
print("Skipping:", name, "(no vertex colors)")
|
||||
continue
|
||||
|
||||
|
@ -571,8 +571,6 @@ class KeyframesCo:
|
||||
keyframe_points.foreach_set("co", co_buffer)
|
||||
keyframe_points.foreach_set("interpolation", ipo_buffer)
|
||||
|
||||
# TODO: in Blender 4.0 the next lines can be replaced with one call to `fcurve.update()`.
|
||||
# See https://projects.blender.org/blender/blender/issues/107126 for more info.
|
||||
keyframe_points.sort()
|
||||
keyframe_points.deduplicate()
|
||||
keyframe_points.handles_recalc()
|
||||
# This also deduplicates keys where baked keys were inserted on the
|
||||
# same frame as existing ones.
|
||||
fcurve.update()
|
||||
|
@ -178,6 +178,8 @@ class Object(bpy_types.ID):
|
||||
def children(self):
|
||||
"""All the children of this object.
|
||||
|
||||
:type: tuple of `Object`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.objects))`` time."""
|
||||
import bpy
|
||||
return tuple(child for child in bpy.data.objects
|
||||
@ -187,6 +189,8 @@ class Object(bpy_types.ID):
|
||||
def children_recursive(self):
|
||||
"""A list of all children from this object.
|
||||
|
||||
:type: tuple of `Object`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.objects))`` time."""
|
||||
import bpy
|
||||
parent_child_map = {}
|
||||
@ -209,6 +213,8 @@ class Object(bpy_types.ID):
|
||||
"""
|
||||
The collections this object is in.
|
||||
|
||||
:type: tuple of `Collection`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.collections) + len(bpy.data.scenes))`` time."""
|
||||
import bpy
|
||||
return (
|
||||
@ -225,6 +231,8 @@ class Object(bpy_types.ID):
|
||||
def users_scene(self):
|
||||
"""The scenes this object is in.
|
||||
|
||||
:type: tuple of `Scene`
|
||||
|
||||
.. note:: Takes ``O(len(bpy.data.scenes) * len(bpy.data.objects))`` time."""
|
||||
import bpy
|
||||
return tuple(scene for scene in bpy.data.scenes
|
||||
@ -523,6 +531,36 @@ def ord_ind(i1, i2):
|
||||
return i2, i1
|
||||
|
||||
|
||||
def _name_convention_attribute_get(attributes, name, domain, data_type):
|
||||
try:
|
||||
attribute = attributes[name]
|
||||
except KeyError:
|
||||
return None
|
||||
if attribute.domain != domain:
|
||||
return None
|
||||
if attribute.data_type != data_type:
|
||||
return None
|
||||
return attribute
|
||||
|
||||
|
||||
def _name_convention_attribute_ensure(attributes, name, domain, data_type):
|
||||
try:
|
||||
attribute = attributes[name]
|
||||
except KeyError:
|
||||
return attributes.new(name, data_type, domain)
|
||||
if attribute.domain == domain and attribute.data_type == data_type:
|
||||
return attribute
|
||||
attributes.remove(attribute)
|
||||
return attributes.new(name, data_type, domain)
|
||||
|
||||
|
||||
def _name_convention_attribute_remove(attributes, name):
|
||||
try:
|
||||
attributes.remove(attributes[name])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
class Mesh(bpy_types.ID):
|
||||
__slots__ = ()
|
||||
|
||||
@ -597,6 +635,32 @@ class Mesh(bpy_types.ID):
|
||||
def edge_keys(self):
|
||||
return [ed.key for ed in self.edges]
|
||||
|
||||
@property
|
||||
def vertex_creases(self):
|
||||
"""
|
||||
Vertex crease values for subdivision surface, corresponding to the "crease_vert" attribute.
|
||||
"""
|
||||
return _name_convention_attribute_get(self.attributes, "crease_vert", 'POINT', 'FLOAT')
|
||||
|
||||
def vertex_creases_ensure(self):
|
||||
return _name_convention_attribute_ensure(self.attributes, "crease_vert", 'POINT', 'FLOAT')
|
||||
|
||||
def vertex_creases_remove(self):
|
||||
_name_convention_attribute_remove(self.attributes, "crease_vert")
|
||||
|
||||
@property
|
||||
def edge_creases(self):
|
||||
"""
|
||||
Edge crease values for subdivision surface, corresponding to the "crease_edge" attribute.
|
||||
"""
|
||||
return _name_convention_attribute_get(self.attributes, "crease_edge", 'EDGE', 'FLOAT')
|
||||
|
||||
def edge_creases_ensure(self):
|
||||
return _name_convention_attribute_ensure(self.attributes, "crease_edge", 'EDGE', 'FLOAT')
|
||||
|
||||
def edge_creases_remove(self):
|
||||
_name_convention_attribute_remove(self.attributes, "crease_edge")
|
||||
|
||||
|
||||
class MeshEdge(StructRNA):
|
||||
__slots__ = ()
|
||||
|
@ -931,6 +931,8 @@ def km_user_interface(_params):
|
||||
("ui.reset_default_button", {"type": 'BACK_SPACE', "value": 'PRESS'}, {"properties": [("all", True)]}),
|
||||
# UI lists (polls check if there's a UI list under the cursor).
|
||||
("ui.list_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
|
||||
# UI views (polls check if there's a UI view under the cursor).
|
||||
("ui.view_start_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
@ -1836,6 +1838,10 @@ def km_graph_editor(params):
|
||||
("graph.delete", {"type": 'DEL', "value": 'PRESS'}, {"properties": [("confirm", False)]}),
|
||||
("graph.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
|
||||
("graph.keyframe_insert", {"type": 'I', "value": 'PRESS'}, None),
|
||||
("graph.keyframe_jump", {"type": 'UP_ARROW', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("next", True)]}),
|
||||
("graph.keyframe_jump", {"type": 'DOWN_ARROW', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("next", False)]}),
|
||||
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "ctrl": True}, None),
|
||||
("graph.click_insert", {"type": params.action_mouse, "value": 'CLICK', "shift": True, "ctrl": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
@ -4504,6 +4510,11 @@ def km_grease_pencil_edit(params):
|
||||
|
||||
items.extend([
|
||||
*_template_items_select_actions(params, "grease_pencil.select_all"),
|
||||
# Select linked
|
||||
("grease_pencil.select_linked", {"type": 'L', "value": 'PRESS'}, None),
|
||||
("grease_pencil.select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
|
||||
("grease_pencil.select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||
("grease_pencil.select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True, "repeat": True}, None),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -44,10 +44,9 @@ def geometry_modifier_poll(context):
|
||||
|
||||
|
||||
def get_context_modifier(context):
|
||||
area = context.area
|
||||
if (area is not None) and (area.type == 'PROPERTIES'):
|
||||
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
|
||||
|
@ -109,17 +109,6 @@ class MESH_UL_vgroups(UIList):
|
||||
layout.label(text="", icon_value=icon)
|
||||
|
||||
|
||||
class MESH_UL_fmaps(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):
|
||||
# assert(isinstance(item, bpy.types.FaceMap))
|
||||
fmap = item
|
||||
if self.layout_type in {'DEFAULT', 'COMPACT'}:
|
||||
layout.prop(fmap, "name", text="", emboss=False, icon='FACE_MAPS')
|
||||
elif self.layout_type == 'GRID':
|
||||
layout.alignment = 'CENTER'
|
||||
layout.label(text="", icon_value=icon)
|
||||
|
||||
|
||||
class MESH_UL_shape_keys(UIList):
|
||||
def draw_item(self, _context, layout, _data, item, icon, active_data, _active_propname, index):
|
||||
# assert(isinstance(item, bpy.types.ShapeKey))
|
||||
@ -280,50 +269,6 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
|
||||
layout.prop(context.tool_settings, "vertex_group_weight", text="Weight")
|
||||
|
||||
|
||||
class DATA_PT_face_maps(MeshButtonsPanel, Panel):
|
||||
bl_label = "Face Maps"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH', 'BLENDER_WORKBENCH_NEXT'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.object
|
||||
return (obj and obj.type == 'MESH')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
ob = context.object
|
||||
facemap = ob.face_maps.active
|
||||
|
||||
rows = 2
|
||||
if facemap:
|
||||
rows = 4
|
||||
|
||||
row = layout.row()
|
||||
row.template_list("MESH_UL_fmaps", "", ob, "face_maps", ob.face_maps, "active_index", rows=rows)
|
||||
|
||||
col = row.column(align=True)
|
||||
col.operator("object.face_map_add", icon='ADD', text="")
|
||||
col.operator("object.face_map_remove", icon='REMOVE', text="")
|
||||
|
||||
if facemap:
|
||||
col.separator()
|
||||
col.operator("object.face_map_move", icon='TRIA_UP', text="").direction = 'UP'
|
||||
col.operator("object.face_map_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
|
||||
|
||||
if ob.face_maps and (ob.mode == 'EDIT' and ob.type == 'MESH'):
|
||||
row = layout.row()
|
||||
|
||||
sub = row.row(align=True)
|
||||
sub.operator("object.face_map_assign", text="Assign")
|
||||
sub.operator("object.face_map_remove_from", text="Remove")
|
||||
|
||||
sub = row.row(align=True)
|
||||
sub.operator("object.face_map_select", text="Select")
|
||||
sub.operator("object.face_map_deselect", text="Deselect")
|
||||
|
||||
|
||||
class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
|
||||
bl_label = "Shape Keys"
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH', 'BLENDER_WORKBENCH_NEXT'}
|
||||
@ -486,16 +431,6 @@ class DATA_PT_customdata(MeshButtonsPanel, Panel):
|
||||
col.operator("mesh.customdata_mask_clear", icon='X')
|
||||
col.operator("mesh.customdata_skin_clear", icon='X')
|
||||
|
||||
if me.has_crease_edge:
|
||||
col.operator("mesh.customdata_crease_edge_clear", icon='X')
|
||||
else:
|
||||
col.operator("mesh.customdata_crease_edge_add", icon='ADD')
|
||||
|
||||
if me.has_crease_vertex:
|
||||
col.operator("mesh.customdata_crease_vertex_clear", icon='X')
|
||||
else:
|
||||
col.operator("mesh.customdata_crease_vertex_add", icon='ADD')
|
||||
|
||||
|
||||
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, Panel):
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH', 'BLENDER_WORKBENCH_NEXT'}
|
||||
@ -707,7 +642,6 @@ classes = (
|
||||
MESH_MT_color_attribute_context_menu,
|
||||
MESH_MT_attribute_context_menu,
|
||||
MESH_UL_vgroups,
|
||||
MESH_UL_fmaps,
|
||||
MESH_UL_shape_keys,
|
||||
MESH_UL_uvmaps,
|
||||
MESH_UL_attributes,
|
||||
@ -716,7 +650,6 @@ classes = (
|
||||
DATA_PT_shape_keys,
|
||||
DATA_PT_uv_texture,
|
||||
DATA_PT_vertex_colors,
|
||||
DATA_PT_face_maps,
|
||||
DATA_PT_mesh_attributes,
|
||||
DATA_PT_normals,
|
||||
DATA_PT_texture_space,
|
||||
|
@ -12,6 +12,7 @@ from bpy.types import (
|
||||
ParticleSettings,
|
||||
Texture,
|
||||
)
|
||||
from bpy.app.translations import contexts as i18n_contexts
|
||||
|
||||
from rna_prop_ui import PropertyPanel
|
||||
from bl_ui.properties_paint_common import brush_texture_settings
|
||||
@ -512,10 +513,10 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, Panel):
|
||||
sub.prop(tex, "repeat_x", text="Repeat X")
|
||||
sub.prop(tex, "repeat_y", text="Y")
|
||||
|
||||
col = flow.column()
|
||||
col = flow.column(heading="Mirror")
|
||||
sub = col.column()
|
||||
sub.active = (tex.repeat_x > 1)
|
||||
sub.prop(tex, "use_mirror_x", text="Mirror X")
|
||||
sub.prop(tex, "use_mirror_x", text="X")
|
||||
|
||||
sub = col.column()
|
||||
sub.active = (tex.repeat_y > 1)
|
||||
@ -527,8 +528,8 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, Panel):
|
||||
col = flow.column()
|
||||
col.prop(tex, "checker_distance", text="Distance")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(tex, "use_checker_even", text="Tiles Even")
|
||||
col = flow.column(heading="Tiles")
|
||||
col.prop(tex, "use_checker_even", text="Even", text_ctxt=i18n_contexts.amount)
|
||||
col.prop(tex, "use_checker_odd", text="Odd")
|
||||
else:
|
||||
del flow
|
||||
|
@ -1221,7 +1221,7 @@ class IMAGE_PT_tools_brush_display(Panel, BrushButtonsPanel, DisplayPanel):
|
||||
bl_context = ".paint_common_2d"
|
||||
bl_parent_id = "IMAGE_PT_paint_settings"
|
||||
bl_category = "Tool"
|
||||
bl_label = "Brush Tip"
|
||||
bl_label = "Cursor"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_ui_units_x = 15
|
||||
|
||||
|
@ -3111,7 +3111,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
||||
*_tools_annotate,
|
||||
],
|
||||
'EDIT_GPENCIL': [
|
||||
*_tools_gpencil_select,
|
||||
*_tools_select,
|
||||
_defs_view3d_generic.cursor,
|
||||
None,
|
||||
*_tools_transform,
|
||||
|
@ -2030,6 +2030,22 @@ class VIEW3D_MT_select_edit_gpencil(Menu):
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("grease_pencil.select_linked", text="Linked")
|
||||
|
||||
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")
|
||||
|
||||
|
||||
class VIEW3D_MT_select_paint_mask(Menu):
|
||||
bl_label = "Select"
|
||||
@ -2103,7 +2119,7 @@ class VIEW3D_MT_select_edit_curves(Menu):
|
||||
layout.separator()
|
||||
|
||||
layout.operator("curves.select_random", text="Random")
|
||||
layout.operator("curves.select_end", text="Endpoints")
|
||||
layout.operator("curves.select_ends", text="Endpoints")
|
||||
layout.operator("curves.select_linked", text="Linked")
|
||||
|
||||
layout.separator()
|
||||
@ -2121,7 +2137,7 @@ class VIEW3D_MT_select_sculpt_curves(Menu):
|
||||
layout.operator("curves.select_all", text="None").action = 'DESELECT'
|
||||
layout.operator("curves.select_all", text="Invert").action = 'INVERT'
|
||||
layout.operator("sculpt_curves.select_random", text="Random")
|
||||
layout.operator("curves.select_end", text="Endpoints")
|
||||
layout.operator("curves.select_ends", text="Endpoints")
|
||||
layout.operator("sculpt_curves.select_grow", text="Grow")
|
||||
|
||||
|
||||
|
@ -335,6 +335,7 @@ compositor_node_categories = [
|
||||
NodeItem("CompositorNodeSunBeams"),
|
||||
NodeItem("CompositorNodeDenoise"),
|
||||
NodeItem("CompositorNodeAntiAliasing"),
|
||||
NodeItem("CompositorNodeKuwahara"),
|
||||
]),
|
||||
CompositorNodeCategory("CMP_OP_VECTOR", "Vector", items=[
|
||||
NodeItem("CompositorNodeNormal"),
|
||||
|
@ -124,6 +124,7 @@ class AssetLibrary {
|
||||
*/
|
||||
AssetRepresentation &add_external_asset(StringRef relative_asset_path,
|
||||
StringRef name,
|
||||
int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_local_id_asset(StringRef relative_asset_path, ID &id);
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
|
||||
#include "DNA_ID_enums.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -22,6 +24,8 @@ typedef struct AssetRepresentation AssetRepresentation;
|
||||
|
||||
const char *AS_asset_representation_name_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
ID_Type AS_asset_representation_id_type_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
struct ID *AS_asset_representation_local_id_get(const AssetRepresentation *asset)
|
||||
@ -30,6 +34,9 @@ bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_
|
||||
bool AS_asset_representation_is_never_link(const AssetRepresentation *asset)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
bool AS_asset_representation_may_override_import_method(const AssetRepresentation *asset);
|
||||
bool AS_asset_representation_use_relative_path_get(const AssetRepresentation *asset);
|
||||
|
||||
/**
|
||||
* C version of #AssetRepresentation::make_weak_reference. Returned pointer needs freeing with
|
||||
* #MEM_delete() or #BKE_asset_weak_reference_free().
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "DNA_ID_enums.h"
|
||||
#include "DNA_asset_types.h"
|
||||
|
||||
#include "AS_asset_identifier.hh"
|
||||
@ -42,6 +43,7 @@ class AssetRepresentation {
|
||||
|
||||
struct ExternalAsset {
|
||||
std::string name;
|
||||
int id_type = 0;
|
||||
std::unique_ptr<AssetMetaData> metadata_ = nullptr;
|
||||
};
|
||||
union {
|
||||
@ -55,6 +57,7 @@ class AssetRepresentation {
|
||||
/** Constructs an asset representation for an external ID. The asset will not be editable. */
|
||||
AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/**
|
||||
@ -85,6 +88,7 @@ class AssetRepresentation {
|
||||
std::unique_ptr<AssetWeakReference> make_weak_reference() const;
|
||||
|
||||
StringRefNull get_name() const;
|
||||
ID_Type get_id_type() const;
|
||||
AssetMetaData &get_metadata() const;
|
||||
/**
|
||||
* Get the import method to use for this asset. A different one may be used if
|
||||
@ -114,6 +118,9 @@ class AssetRepresentation {
|
||||
/* C-Handle */
|
||||
struct AssetRepresentation;
|
||||
|
||||
const blender::StringRefNull AS_asset_representation_library_relative_identifier_get(
|
||||
const AssetRepresentation *asset_handle);
|
||||
|
||||
std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset);
|
||||
/**
|
||||
* Get the absolute path to the .blend file containing the given asset. String will be empty if
|
||||
@ -123,5 +130,3 @@ std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *a
|
||||
std::string AS_asset_representation_full_library_path_get(const ::AssetRepresentation *asset);
|
||||
std::optional<eAssetImportMethod> AS_asset_representation_import_method_get(
|
||||
const ::AssetRepresentation *asset_handle);
|
||||
bool AS_asset_representation_may_override_import_method(const ::AssetRepresentation *asset_handle);
|
||||
bool AS_asset_representation_use_relative_path_get(const ::AssetRepresentation *asset_handle);
|
||||
|
@ -230,11 +230,12 @@ void AssetLibrary::refresh()
|
||||
|
||||
AssetRepresentation &AssetLibrary::add_external_asset(StringRef relative_asset_path,
|
||||
StringRef name,
|
||||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata)
|
||||
{
|
||||
AssetIdentifier identifier = asset_identifier_from_library(relative_asset_path);
|
||||
return asset_storage_->add_external_asset(
|
||||
std::move(identifier), name, std::move(metadata), *this);
|
||||
std::move(identifier), name, id_type, std::move(metadata), *this);
|
||||
}
|
||||
|
||||
AssetRepresentation &AssetLibrary::add_local_id_asset(StringRef relative_asset_path, ID &id)
|
||||
|
@ -21,6 +21,7 @@ namespace blender::asset_system {
|
||||
|
||||
AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
: identifier_(identifier),
|
||||
@ -29,6 +30,7 @@ AssetRepresentation::AssetRepresentation(AssetIdentifier &&identifier,
|
||||
external_asset_()
|
||||
{
|
||||
external_asset_.name = name;
|
||||
external_asset_.id_type = id_type;
|
||||
external_asset_.metadata_ = std::move(metadata);
|
||||
}
|
||||
|
||||
@ -87,6 +89,15 @@ StringRefNull AssetRepresentation::get_name() const
|
||||
return external_asset_.name;
|
||||
}
|
||||
|
||||
ID_Type AssetRepresentation::get_id_type() const
|
||||
{
|
||||
if (is_local_id_) {
|
||||
return GS(local_asset_id_->name);
|
||||
}
|
||||
|
||||
return ID_Type(external_asset_.id_type);
|
||||
}
|
||||
|
||||
AssetMetaData &AssetRepresentation::get_metadata() const
|
||||
{
|
||||
return is_local_id_ ? *local_asset_id_->asset_data : *external_asset_.metadata_;
|
||||
@ -135,6 +146,15 @@ const AssetLibrary &AssetRepresentation::owner_asset_library() const
|
||||
|
||||
using namespace blender;
|
||||
|
||||
const StringRefNull AS_asset_representation_library_relative_identifier_get(
|
||||
const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
const asset_system::AssetIdentifier &identifier = asset->get_identifier();
|
||||
return identifier.library_relative_identifier();
|
||||
}
|
||||
|
||||
std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
@ -183,6 +203,13 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset_ha
|
||||
return asset->get_name().c_str();
|
||||
}
|
||||
|
||||
ID_Type AS_asset_representation_id_type_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
reinterpret_cast<const asset_system::AssetRepresentation *>(asset_handle);
|
||||
return asset->get_id_type();
|
||||
}
|
||||
|
||||
AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset_handle)
|
||||
{
|
||||
const asset_system::AssetRepresentation *asset =
|
||||
|
@ -27,11 +27,12 @@ AssetRepresentation &AssetStorage::add_local_id_asset(AssetIdentifier &&identifi
|
||||
|
||||
AssetRepresentation &AssetStorage::add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
const int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library)
|
||||
{
|
||||
return *external_assets_.lookup_key_or_add(std::make_unique<AssetRepresentation>(
|
||||
std::move(identifier), name, std::move(metadata), owner_asset_library));
|
||||
std::move(identifier), name, id_type, std::move(metadata), owner_asset_library));
|
||||
}
|
||||
|
||||
bool AssetStorage::remove_asset(AssetRepresentation &asset)
|
||||
|
@ -37,6 +37,7 @@ class AssetStorage {
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
AssetRepresentation &add_external_asset(AssetIdentifier &&identifier,
|
||||
StringRef name,
|
||||
int id_type,
|
||||
std::unique_ptr<AssetMetaData> metadata,
|
||||
const AssetLibrary &owner_asset_library);
|
||||
/** See #AssetLibrary::add_external_asset(). */
|
||||
|
@ -32,7 +32,8 @@ class AssetRepresentationTest : public AssetLibraryTestBase {
|
||||
AssetRepresentation &add_dummy_asset(AssetLibrary &library, StringRef relative_path)
|
||||
{
|
||||
std::unique_ptr<AssetMetaData> dummy_metadata = std::make_unique<AssetMetaData>();
|
||||
return library.add_external_asset(relative_path, "Some asset name", std::move(dummy_metadata));
|
||||
return library.add_external_asset(
|
||||
relative_path, "Some asset name", 0, std::move(dummy_metadata));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,13 @@ typedef struct AssetTypeInfo {
|
||||
struct AssetMetaData *BKE_asset_metadata_create(void);
|
||||
void BKE_asset_metadata_free(struct AssetMetaData **asset_data);
|
||||
|
||||
/**
|
||||
* Create a copy of the #AssetMetaData so that it can be assigned to another asset.
|
||||
*
|
||||
* The caller becomes the owner of the returned pointer.
|
||||
*/
|
||||
struct AssetMetaData *BKE_asset_metadata_copy(const struct AssetMetaData *source);
|
||||
|
||||
struct AssetTagEnsureResult {
|
||||
struct AssetTag *tag;
|
||||
/* Set to false if a tag of this name was already present. */
|
||||
|
@ -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 {
|
||||
|
@ -27,13 +27,13 @@ extern "C" {
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 5
|
||||
#define BLENDER_FILE_SUBVERSION 7
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
* was written with too new a version. */
|
||||
#define BLENDER_FILE_MIN_VERSION 400
|
||||
#define BLENDER_FILE_MIN_SUBVERSION 2
|
||||
#define BLENDER_FILE_MIN_SUBVERSION 3
|
||||
|
||||
/** User readable version string. */
|
||||
const char *BKE_blender_version_string(void);
|
||||
|
@ -51,5 +51,8 @@ struct GeometryDeformation {
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig);
|
||||
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
const Object &ob_orig);
|
||||
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
|
||||
const Object &ob_orig,
|
||||
int drawing_index);
|
||||
|
||||
} // namespace blender::bke::crazyspace
|
||||
|
@ -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,
|
||||
|
@ -612,8 +612,8 @@ int CustomData_layertype_layers_max(eCustomDataType type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/** \return The maximum length for a layer name with the given prefix. */
|
||||
int CustomData_name_max_length_calc(blender::StringRef name);
|
||||
/** \return The maximum size in bytes needed for a layer name with the given prefix. */
|
||||
int CustomData_name_maxncpy_calc(blender::StringRef name);
|
||||
|
||||
#endif
|
||||
|
||||
@ -705,7 +705,8 @@ enum {
|
||||
|
||||
CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */
|
||||
|
||||
CD_FAKE_BWEIGHT = CD_FAKE | 300, /* UV seam flag for edges. */
|
||||
CD_FAKE_BWEIGHT = CD_FAKE | 300,
|
||||
CD_FAKE_CREASE = CD_FAKE | 400,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -733,7 +734,7 @@ enum {
|
||||
typedef struct CustomDataTransferLayerMap {
|
||||
struct CustomDataTransferLayerMap *next, *prev;
|
||||
|
||||
eCustomDataType data_type;
|
||||
int data_type;
|
||||
int mix_mode;
|
||||
float mix_factor;
|
||||
/** If non-NULL, array of weights, one for each dest item, replaces mix_factor. */
|
||||
|
@ -59,7 +59,7 @@ typedef struct BMEditMesh {
|
||||
int mirror_cdlayer;
|
||||
|
||||
/**
|
||||
* Enable for evaluated copies, causes the edit-mesh to free the memory, not it's contents.
|
||||
* Enable for evaluated copies, causes the edit-mesh to free the memory, not its contents.
|
||||
*/
|
||||
char is_shallow_copy;
|
||||
|
||||
|
@ -180,9 +180,6 @@ struct Mesh *BKE_mesh_new_nomain_from_curve_displist(const struct Object *ob,
|
||||
|
||||
bool BKE_mesh_attribute_required(const char *name);
|
||||
|
||||
bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me);
|
||||
bool BKE_mesh_clear_facemap_customdata(struct Mesh *me);
|
||||
|
||||
float (*BKE_mesh_orco_verts_get(struct Object *ob))[3];
|
||||
void BKE_mesh_orco_verts_transform(struct Mesh *me, float (*orco)[3], int totvert, int invert);
|
||||
|
||||
|
@ -129,7 +129,7 @@ struct CornerNormalSpaceArray {
|
||||
*/
|
||||
Array<Array<int>> corners_by_space;
|
||||
/** Whether to create the above map when calculating normals. */
|
||||
bool create_corners_by_space;
|
||||
bool create_corners_by_space = false;
|
||||
};
|
||||
|
||||
void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space,
|
||||
|
@ -40,6 +40,7 @@ void BKE_mesh_legacy_face_set_to_generic(struct Mesh *mesh);
|
||||
* Copy edge creases from edges to a separate layer.
|
||||
*/
|
||||
void BKE_mesh_legacy_edge_crease_to_layers(struct Mesh *mesh);
|
||||
void BKE_mesh_legacy_crease_to_generic(struct Mesh *mesh);
|
||||
|
||||
/**
|
||||
* Copy bevel weights from vertices and edges to separate layers.
|
||||
@ -84,6 +85,8 @@ void BKE_mesh_legacy_convert_polys_to_offsets(Mesh *mesh);
|
||||
|
||||
void BKE_mesh_legacy_convert_loops_to_corners(struct Mesh *mesh);
|
||||
|
||||
void BKE_mesh_legacy_face_map_to_generic(struct Mesh *mesh);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -1061,6 +1061,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i
|
||||
#define CMP_NODE_INPAINT 272
|
||||
#define CMP_NODE_DESPECKLE 273
|
||||
#define CMP_NODE_ANTIALIASING 274
|
||||
#define CMP_NODE_KUWAHARA 275
|
||||
|
||||
#define CMP_NODE_GLARE 301
|
||||
#define CMP_NODE_TONEMAP 302
|
||||
|
@ -1,37 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
* \brief Functions for dealing with object face-maps.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ListBase;
|
||||
struct Object;
|
||||
struct bFaceMap;
|
||||
|
||||
struct bFaceMap *BKE_object_facemap_add(struct Object *ob);
|
||||
struct bFaceMap *BKE_object_facemap_add_name(struct Object *ob, const char *name);
|
||||
void BKE_object_facemap_remove(struct Object *ob, struct bFaceMap *fmap);
|
||||
void BKE_object_facemap_clear(struct Object *ob);
|
||||
|
||||
int BKE_object_facemap_name_index(struct Object *ob, const char *name);
|
||||
void BKE_object_facemap_unique_name(struct Object *ob, struct bFaceMap *fmap);
|
||||
struct bFaceMap *BKE_object_facemap_find_name(struct Object *ob, const char *name);
|
||||
void BKE_object_facemap_copy_list(struct ListBase *outbase, const struct ListBase *inbase);
|
||||
|
||||
int *BKE_object_facemap_index_map_create(struct Object *ob_src,
|
||||
struct Object *ob_dst,
|
||||
int *r_map_len);
|
||||
void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -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
|
||||
@ -255,7 +255,7 @@ typedef struct PanelType {
|
||||
|
||||
char idname[BKE_ST_MAXNAME]; /* unique name */
|
||||
char label[BKE_ST_MAXNAME]; /* for panel header */
|
||||
char *description; /* for panel tooltip */
|
||||
const char *description; /* for panel tooltip */
|
||||
char translation_context[BKE_ST_MAXNAME];
|
||||
char context[BKE_ST_MAXNAME]; /* for buttons window */
|
||||
char category[BKE_ST_MAXNAME]; /* for category tabs */
|
||||
|
@ -59,11 +59,6 @@ void texttool_suggest_select(SuggItem *sel);
|
||||
SuggItem *texttool_suggest_selected(void);
|
||||
int *texttool_suggest_top(void);
|
||||
|
||||
/* Documentation */
|
||||
void texttool_docs_show(const char *docs);
|
||||
char *texttool_docs_get(void);
|
||||
void texttool_docs_clear(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -470,7 +470,7 @@ void BKE_tracking_camera_principal_point_pixel_set(struct MovieClip *clip,
|
||||
* extra parameters of distortions models. */
|
||||
bool BKE_tracking_camera_distortion_equal(const struct MovieTrackingCamera *a,
|
||||
const struct MovieTrackingCamera *b);
|
||||
/* Hashes distortion related paramaters of camera. Ideally, this implementation will be
|
||||
/* Hashes distortion related parameters of camera. Ideally, this implementation will be
|
||||
* abstracted away in the future, but for now, one needs to be careful about it and handle any
|
||||
* extra parameters of distortions models. */
|
||||
uint64_t BKE_tracking_camera_distortion_hash(const struct MovieTrackingCamera *camera);
|
||||
|
@ -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,
|
||||
|
@ -241,7 +241,6 @@ set(SRC
|
||||
intern/object.cc
|
||||
intern/object_deform.c
|
||||
intern/object_dupli.cc
|
||||
intern/object_facemap.c
|
||||
intern/object_update.cc
|
||||
intern/ocean.c
|
||||
intern/ocean_spectrum.c
|
||||
@ -457,7 +456,6 @@ set(SRC
|
||||
BKE_node_tree_zones.hh
|
||||
BKE_object.h
|
||||
BKE_object_deform.h
|
||||
BKE_object_facemap.h
|
||||
BKE_ocean.h
|
||||
BKE_outliner_treehash.hh
|
||||
BKE_packedFile.h
|
||||
|
@ -65,7 +65,7 @@ static void pchan_deform_accumulate(const DualQuat *deform_dq,
|
||||
BLI_assert(!co_accum);
|
||||
|
||||
if (deform_dq->scale_weight) {
|
||||
/* FIX https://projects.blender.org/blender/blender/issues/32022 */
|
||||
/* FIX #32022. */
|
||||
DualQuat mdq = *deform_dq;
|
||||
float dst[3];
|
||||
mul_v3_m4v3(dst, mdq.scale, co_in);
|
||||
@ -74,7 +74,7 @@ static void pchan_deform_accumulate(const DualQuat *deform_dq,
|
||||
mdq.trans[1] += .5f * (mdq.quat[0] * dst[0] + mdq.quat[2] * dst[2] - mdq.quat[3] * dst[1]);
|
||||
mdq.trans[2] += .5f * (mdq.quat[0] * dst[1] + mdq.quat[3] * dst[0] - mdq.quat[1] * dst[2]);
|
||||
mdq.trans[3] += .5f * (mdq.quat[0] * dst[2] + mdq.quat[1] * dst[1] - mdq.quat[2] * dst[0]);
|
||||
mdq.scale_weight = 0.f;
|
||||
mdq.scale_weight = 0.0f;
|
||||
add_weighted_dq_dq(dq_accum, &mdq, weight);
|
||||
}
|
||||
else {
|
||||
|
@ -39,6 +39,38 @@ void BKE_asset_metadata_free(AssetMetaData **asset_data)
|
||||
*asset_data = nullptr;
|
||||
}
|
||||
|
||||
AssetMetaData *BKE_asset_metadata_copy(const AssetMetaData *source)
|
||||
{
|
||||
AssetMetaData *copy = BKE_asset_metadata_create();
|
||||
|
||||
copy->local_type_info = source->local_type_info;
|
||||
|
||||
if (source->properties) {
|
||||
copy->properties = IDP_CopyProperty(source->properties);
|
||||
}
|
||||
|
||||
BKE_asset_metadata_catalog_id_set(copy, source->catalog_id, source->catalog_simple_name);
|
||||
|
||||
if (source->author) {
|
||||
copy->author = BLI_strdup(source->author);
|
||||
}
|
||||
if (source->description) {
|
||||
copy->description = BLI_strdup(source->description);
|
||||
}
|
||||
if (source->copyright) {
|
||||
copy->copyright = BLI_strdup(source->copyright);
|
||||
}
|
||||
if (source->license) {
|
||||
copy->license = BLI_strdup(source->license);
|
||||
}
|
||||
|
||||
BLI_duplicatelist(©->tags, &source->tags);
|
||||
copy->active_tag = source->active_tag;
|
||||
copy->tot_tags = source->tot_tags;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
AssetMetaData::~AssetMetaData()
|
||||
{
|
||||
if (properties) {
|
||||
|
@ -174,7 +174,7 @@ bool BKE_id_attribute_rename(ID *id,
|
||||
* is clamped to it's maximum length, otherwise assigning an over-long name multiple times
|
||||
* will add `.001` suffix unnecessarily. */
|
||||
{
|
||||
const int new_name_maxncpy = CustomData_name_max_length_calc(new_name);
|
||||
const int new_name_maxncpy = CustomData_name_maxncpy_calc(new_name);
|
||||
/* NOTE: A function that performs a clamped comparison without copying would be handy here. */
|
||||
char new_name_clamped[MAX_CUSTOMDATA_LAYER_NAME];
|
||||
BLI_strncpy_utf8(new_name_clamped, new_name, new_name_maxncpy);
|
||||
@ -255,7 +255,7 @@ static bool unique_name_cb(void *arg, const char *name)
|
||||
bool BKE_id_attribute_calc_unique_name(ID *id, const char *name, char *outname)
|
||||
{
|
||||
AttrUniqueData data{id};
|
||||
const int name_maxncpy = CustomData_name_max_length_calc(name);
|
||||
const int name_maxncpy = CustomData_name_maxncpy_calc(name);
|
||||
|
||||
/* Set default name if none specified.
|
||||
* NOTE: We only call IFACE_() if needed to avoid locale lookup overhead. */
|
||||
|
@ -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)
|
||||
|
@ -208,14 +208,13 @@ static void setup_app_userdef(BlendFileData *bfd)
|
||||
BKE_blender_userdef_data_set_and_free(bfd->user);
|
||||
bfd->user = nullptr;
|
||||
|
||||
/* Security issue: any blend file could include a USER block.
|
||||
/* Security issue: any blend file could include a #BLO_CODE_USER block.
|
||||
*
|
||||
* Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
|
||||
* to load the preferences defined in the users home dir.
|
||||
* Preferences are loaded from #BLENDER_STARTUP_FILE and later on load #BLENDER_USERPREF_FILE,
|
||||
* to load the preferences defined in the users home directory.
|
||||
*
|
||||
* This means we will never accidentally (or maliciously)
|
||||
* enable scripts auto-execution by loading a `.blend` file.
|
||||
*/
|
||||
* enable scripts auto-execution by loading a `.blend` file. */
|
||||
U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
|
||||
}
|
||||
}
|
||||
@ -417,7 +416,7 @@ static void swap_wm_data_for_blendfile(ReuseOldBMainData *reuse_data, const bool
|
||||
* for further processing in WM code. */
|
||||
if (load_ui && new_wm != nullptr) {
|
||||
/* Support window-manager ID references being held between file load operations by keeping
|
||||
* #Main.wm.first memory address in-place, while swapping all of it's contents.
|
||||
* #Main.wm.first memory address in-place, while swapping all of its contents.
|
||||
*
|
||||
* This is needed so items such as key-maps can be held by an add-on,
|
||||
* without it pointing to invalid memory, see: #86431. */
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "BKE_curves.hh"
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_geometry_set.hh"
|
||||
#include "BKE_grease_pencil.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_wrapper.h"
|
||||
@ -662,4 +663,37 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
|
||||
return get_evaluated_curves_deformation(ob_eval, ob_orig);
|
||||
}
|
||||
|
||||
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
|
||||
const Object &ob_orig,
|
||||
const int drawing_index)
|
||||
{
|
||||
BLI_assert(ob_orig.type == OB_GREASE_PENCIL);
|
||||
const GreasePencil &grease_pencil_orig = *static_cast<const GreasePencil *>(ob_orig.data);
|
||||
|
||||
GreasePencilDrawingBase *drawing_base = grease_pencil_orig.drawings()[drawing_index];
|
||||
|
||||
GeometryDeformation deformation;
|
||||
if (drawing_base->type == GP_DRAWING) {
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
|
||||
/* Use the undeformed positions by default. */
|
||||
deformation.positions = drawing->geometry.wrap().positions();
|
||||
}
|
||||
else if (drawing_base->type == GP_DRAWING_REFERENCE) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
if (ob_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
const GeometrySet *geometry_eval = ob_eval->runtime.geometry_set_eval;
|
||||
if (geometry_eval == nullptr) {
|
||||
return deformation;
|
||||
}
|
||||
|
||||
/* TODO: Read `GeometryComponentEditData` from `geometry_eval` and populate deformation with it.
|
||||
*/
|
||||
|
||||
return deformation;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::crazyspace
|
||||
|
@ -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));
|
||||
|
@ -1170,6 +1170,7 @@ void CurvesGeometry::remove_points(const IndexMask &points_to_delete,
|
||||
}
|
||||
if (points_to_delete.size() == this->points_num()) {
|
||||
*this = {};
|
||||
return;
|
||||
}
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask points_to_copy = points_to_delete.complement(this->points_range(), memory);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user