diff options
author | Sergey Sharybin <sergey@blender.org> | 2022-05-18 18:03:19 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey@blender.org> | 2022-05-18 18:03:19 +0300 |
commit | b712dbe5de2dcba3338f42b74b75388453d52d23 (patch) | |
tree | ce1939518256c3580002245d272efe79491f47ac | |
parent | 708547ab06519ce741a091a20777cd5b1bf27120 (diff) | |
parent | c56103356f642041f76c0be84772a40f1caad9df (diff) |
Merge branch 'blender-v3.2-release'
22 files changed, 379 insertions, 59 deletions
diff --git a/intern/opensubdiv/internal/evaluator/eval_output.h b/intern/opensubdiv/internal/evaluator/eval_output.h index 9ca09f011a1..bc5494bfe41 100644 --- a/intern/opensubdiv/internal/evaluator/eval_output.h +++ b/intern/opensubdiv/internal/evaluator/eval_output.h @@ -46,6 +46,8 @@ class EvalOutputAPI::EvalOutput { virtual void updateVaryingData(const float *src, int start_vertex, int num_vertices) = 0; + virtual void updateVertexData(const float *src, int start_vertex, int num_vertices) = 0; + virtual void updateFaceVaryingData(const int face_varying_channel, const float *src, int start_vertex, @@ -70,6 +72,11 @@ class EvalOutputAPI::EvalOutput { const int num_patch_coords, float *varying) = 0; + // NOTE: vertex_data must point to a memory of at least float*num_vertex_data. + virtual void evalPatchesVertexData(const PatchCoord *patch_coord, + const int num_patch_coords, + float *vertex_data) = 0; + virtual void evalPatchesFaceVarying(const int face_varying_channel, const PatchCoord *patch_coord, const int num_patch_coords, @@ -331,11 +338,13 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { const StencilTable *varying_stencils, const vector<const StencilTable *> &all_face_varying_stencils, const int face_varying_width, + const int vertex_data_width, const PatchTable *patch_table, EvaluatorCache *evaluator_cache = NULL, DEVICE_CONTEXT *device_context = NULL) : src_desc_(0, 3, 3), src_varying_desc_(0, 3, 3), + src_vertex_data_desc_(0, vertex_data_width, vertex_data_width), face_varying_width_(face_varying_width), evaluator_cache_(evaluator_cache), device_context_(device_context) @@ -352,6 +361,16 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { device_context_); varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils, device_context_); + + // Optionally allocate additional data to be subdivided like vertex coordinates. + if (vertex_data_width > 0) { + src_vertex_data_ = SRC_VERTEX_BUFFER::Create( + vertex_data_width, num_total_vertices, device_context_); + } + else { + src_vertex_data_ = NULL; + } + // Create evaluators for every face varying channel. face_varying_evaluators_.reserve(all_face_varying_stencils.size()); int face_varying_channel = 0; @@ -370,6 +389,7 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { { delete src_data_; delete src_varying_data_; + delete src_vertex_data_; delete patch_table_; delete vertex_stencils_; delete varying_stencils_; @@ -390,6 +410,11 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); } + void updateVertexData(const float *src, int start_vertex, int num_vertices) override + { + src_vertex_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + void updateFaceVaryingData(const int face_varying_channel, const float *src, int start_vertex, @@ -426,6 +451,22 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { vertex_stencils_, eval_instance, device_context_); + + // Evaluate smoothly interpolated vertex data. + if (src_vertex_data_) { + BufferDescriptor dst_vertex_data_desc = src_vertex_data_desc_; + dst_vertex_data_desc.offset += num_coarse_vertices_ * src_vertex_data_desc_.stride; + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_vertex_data_desc_, dst_vertex_data_desc, device_context_); + EVALUATOR::EvalStencils(src_vertex_data_, + src_vertex_data_desc_, + src_vertex_data_, + dst_vertex_data_desc, + vertex_stencils_, + eval_instance, + device_context_); + } + // Evaluate varying data. if (hasVaryingData()) { BufferDescriptor dst_varying_desc = src_varying_desc_; @@ -521,6 +562,27 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { device_context_); } + // NOTE: data must point to a memory of at least float*num_vertex_data. + void evalPatchesVertexData(const PatchCoord *patch_coord, + const int num_patch_coords, + float *data) override + { + RawDataWrapperBuffer<float> vertex_data(data); + BufferDescriptor vertex_desc(0, src_vertex_data_desc_.length, src_vertex_data_desc_.length); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_vertex_data_desc_, vertex_desc, device_context_); + EVALUATOR::EvalPatches(src_vertex_data_, + src_vertex_data_desc_, + &vertex_data, + vertex_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + } + void evalPatchesFaceVarying(const int face_varying_channel, const PatchCoord *patch_coord, const int num_patch_coords, @@ -560,9 +622,11 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { private: SRC_VERTEX_BUFFER *src_data_; SRC_VERTEX_BUFFER *src_varying_data_; + SRC_VERTEX_BUFFER *src_vertex_data_; PATCH_TABLE *patch_table_; BufferDescriptor src_desc_; BufferDescriptor src_varying_desc_; + BufferDescriptor src_vertex_data_desc_; int num_coarse_vertices_; diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h index 42aa052863a..35fd03f6158 100644 --- a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h +++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h @@ -44,6 +44,7 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer, const StencilTable *varying_stencils, const vector<const StencilTable *> &all_face_varying_stencils, const int face_varying_width, + const int vertex_data_width, const PatchTable *patch_table, EvaluatorCache *evaluator_cache = NULL) : VolatileEvalOutput<CpuVertexBuffer, @@ -54,6 +55,7 @@ class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer, varying_stencils, all_face_varying_stencils, face_varying_width, + vertex_data_width, patch_table, evaluator_cache) { diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc index b352ed2c014..566071d581b 100644 --- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc +++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc @@ -45,6 +45,7 @@ GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils, const StencilTable *varying_stencils, const vector<const StencilTable *> &all_face_varying_stencils, const int face_varying_width, + const int vertex_data_width, const PatchTable *patch_table, VolatileEvalOutput::EvaluatorCache *evaluator_cache) : VolatileEvalOutput<GLVertexBuffer, @@ -55,6 +56,7 @@ GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils, varying_stencils, all_face_varying_stencils, face_varying_width, + vertex_data_width, patch_table, evaluator_cache) { diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h index dc137e4322e..2306a87b87c 100644 --- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h +++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h @@ -40,6 +40,7 @@ class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer, const StencilTable *varying_stencils, const vector<const StencilTable *> &all_face_varying_stencils, const int face_varying_width, + const int vertex_data_width, const PatchTable *patch_table, EvaluatorCache *evaluator_cache = NULL); diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc index 567afd3a763..8a54ed653dc 100644 --- a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc +++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc @@ -36,6 +36,14 @@ void setCoarsePositions(OpenSubdiv_Evaluator *evaluator, evaluator->impl->eval_output->setCoarsePositions(positions, start_vertex_index, num_vertices); } +void setVertexData(OpenSubdiv_Evaluator *evaluator, + const float *vertex_data, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setVertexData(vertex_data, start_vertex_index, num_vertices); +} + void setVaryingData(OpenSubdiv_Evaluator *evaluator, const float *varying_data, const int start_vertex_index, @@ -115,6 +123,15 @@ void evaluatePatchesLimit(OpenSubdiv_Evaluator *evaluator, patch_coords, num_patch_coords, P, dPdu, dPdv); } +void evaluateVertexData(OpenSubdiv_Evaluator *evaluator, + const int ptex_face_index, + float face_u, + float face_v, + float vertex_data[3]) +{ + evaluator->impl->eval_output->evaluateVertexData(ptex_face_index, face_u, face_v, vertex_data); +} + void evaluateVarying(OpenSubdiv_Evaluator *evaluator, const int ptex_face_index, float face_u, @@ -206,6 +223,7 @@ void wrapFVarSrcBuffer(struct OpenSubdiv_Evaluator *evaluator, void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) { evaluator->setCoarsePositions = setCoarsePositions; + evaluator->setVertexData = setVertexData; evaluator->setVaryingData = setVaryingData; evaluator->setFaceVaryingData = setFaceVaryingData; @@ -217,6 +235,7 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) evaluator->evaluateLimit = evaluateLimit; evaluator->evaluateVarying = evaluateVarying; + evaluator->evaluateVertexData = evaluateVertexData; evaluator->evaluateFaceVarying = evaluateFaceVarying; evaluator->evaluatePatchesLimit = evaluatePatchesLimit; @@ -239,12 +258,16 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type, - OpenSubdiv_EvaluatorCache *evaluator_cache) + OpenSubdiv_EvaluatorCache *evaluator_cache, + const OpenSubdiv_EvaluatorSettings *settings) { OpenSubdiv_Evaluator *evaluator = MEM_new<OpenSubdiv_Evaluator>(__func__); assignFunctionPointers(evaluator); - evaluator->impl = openSubdiv_createEvaluatorInternal( - topology_refiner, evaluator_type, evaluator_cache ? evaluator_cache->impl : nullptr); + evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner, + evaluator_type, + evaluator_cache ? evaluator_cache->impl : + nullptr, + settings); evaluator->type = evaluator->impl ? evaluator_type : static_cast<eOpenSubdivEvaluator>(0); return evaluator; } diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc index 755b8bfbc81..bb9e6e7bd0d 100644 --- a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc @@ -182,6 +182,14 @@ void EvalOutputAPI::setVaryingData(const float *varying_data, implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices); } +void EvalOutputAPI::setVertexData(const float *vertex_data, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + implementation_->updateVertexData(vertex_data, start_vertex_index, num_vertices); +} + void EvalOutputAPI::setFaceVaryingData(const int face_varying_channel, const float *face_varying_data, const int start_vertex_index, @@ -286,6 +294,20 @@ void EvalOutputAPI::evaluateVarying(const int ptex_face_index, implementation_->evalPatchesVarying(&patch_coord, 1, varying); } +void EvalOutputAPI::evaluateVertexData(const int ptex_face_index, + float face_u, + float face_v, + float vertex_data[]) +{ + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + assert(face_v <= 1.0f); + const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v); + PatchCoord patch_coord(*handle, face_u, face_v); + implementation_->evalPatchesVertexData(&patch_coord, 1, vertex_data); +} + void EvalOutputAPI::evaluateFaceVarying(const int face_varying_channel, const int ptex_face_index, float face_u, @@ -403,7 +425,8 @@ OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl() OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type, - OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr) + OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr, + const OpenSubdiv_EvaluatorSettings *settings) { // Only CPU and GLCompute are implemented at the moment. if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU && @@ -422,6 +445,7 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( const bool has_face_varying_data = (num_face_varying_channels != 0); const int level = topology_refiner->getSubdivisionLevel(topology_refiner); const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner); + const int vertex_data_width = settings->num_vertex_data; // Common settings for stencils and patches. const bool stencil_generate_intermediate_levels = is_adaptive; const bool stencil_generate_offsets = true; @@ -526,12 +550,17 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( varying_stencils, all_face_varying_stencils, 2, + vertex_data_width, patch_table, evaluator_cache); } else { - eval_output = new blender::opensubdiv::CpuEvalOutput( - vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table); + eval_output = new blender::opensubdiv::CpuEvalOutput(vertex_stencils, + varying_stencils, + all_face_varying_stencils, + 2, + vertex_data_width, + patch_table); } blender::opensubdiv::PatchMap *patch_map = new blender::opensubdiv::PatchMap(*patch_table); diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h index e24d47cba79..8ecfa4477be 100644 --- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h @@ -32,6 +32,7 @@ struct OpenSubdiv_Buffer; struct OpenSubdiv_EvaluatorCacheImpl; +struct OpenSubdiv_EvaluatorSettings; struct OpenSubdiv_PatchCoord; struct OpenSubdiv_TopologyRefiner; @@ -60,6 +61,8 @@ class EvalOutputAPI { void setCoarsePositions(const float *positions, const int start_vertex_index, const int num_vertices); + // Set vertex data from a continuous array of data. + void setVertexData(const float *data, const int start_vertex_index, const int num_vertices); // Set varying data from a continuous array of data. void setVaryingData(const float *varying_data, const int start_vertex_index, @@ -115,6 +118,9 @@ class EvalOutputAPI { float dPdv[3]); // Evaluate varying data at a given bilinear coordinate of given ptex face. + void evaluateVertexData(const int ptes_face_index, float face_u, float face_v, float data[]); + + // Evaluate varying data at a given bilinear coordinate of given ptex face. void evaluateVarying(const int ptes_face_index, float face_u, float face_v, float varying[3]); // Evaluate facee-varying data at a given bilinear coordinate of given @@ -198,7 +204,8 @@ struct OpenSubdiv_EvaluatorImpl { OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( struct OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type, - OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr); + OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr, + const OpenSubdiv_EvaluatorSettings *settings); void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator); diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h index 1afd3e966f6..98e1db6e323 100644 --- a/intern/opensubdiv/opensubdiv_evaluator_capi.h +++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h @@ -69,6 +69,11 @@ typedef struct OpenSubdiv_Evaluator { const float *positions, const int start_vertex_index, const int num_vertices); + // Set vertex data from a continuous array of coordinates. + void (*setVertexData)(struct OpenSubdiv_Evaluator *evaluator, + const float *data, + const int start_vertex_index, + const int num_vertices); // Set varying data from a continuous array of data. void (*setVaryingData)(struct OpenSubdiv_Evaluator *evaluator, const float *varying_data, @@ -129,6 +134,13 @@ typedef struct OpenSubdiv_Evaluator { float dPdu[3], float dPdv[3]); + // Evaluate vertex data at a given bilinear coordinate of given ptex face. + void (*evaluateVertexData)(struct OpenSubdiv_Evaluator *evaluator, + const int ptex_face_index, + float face_u, + float face_v, + float data[]); + // Evaluate varying data at a given bilinear coordinate of given ptex face. void (*evaluateVarying)(struct OpenSubdiv_Evaluator *evaluator, const int ptex_face_index, @@ -215,10 +227,16 @@ typedef struct OpenSubdiv_EvaluatorCache { struct OpenSubdiv_EvaluatorCacheImpl *impl; } OpenSubdiv_EvaluatorCache; +typedef struct OpenSubdiv_EvaluatorSettings { + // Number of smoothly interpolated vertex data channels. + int num_vertex_data; +} OpenSubdiv_EvaluatorSettings; + OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( struct OpenSubdiv_TopologyRefiner *topology_refiner, eOpenSubdivEvaluator evaluator_type, - OpenSubdiv_EvaluatorCache *evaluator_cache); + OpenSubdiv_EvaluatorCache *evaluator_cache, + const OpenSubdiv_EvaluatorSettings *settings); void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator); diff --git a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc index bc39326b57d..78c1d23d2cc 100644 --- a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc +++ b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc @@ -23,7 +23,8 @@ OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/, eOpenSubdivEvaluator /*evaluator_type*/, - OpenSubdiv_EvaluatorCache * /*evaluator_cache*/) + OpenSubdiv_EvaluatorCache * /*evaluator_cache*/, + const OpenSubdiv_EvaluatorSettings * /*settings*/) { return NULL; } diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 4482e13e1cf..3d194ba77dc 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -56,7 +56,7 @@ template<typename T> T mix3(const float3 &weights, const T &v0, const T &v1, con template<> inline int8_t mix3(const float3 &weights, const int8_t &v0, const int8_t &v1, const int8_t &v2) { - return static_cast<int8_t>(weights.x * v0 + weights.y * v1 + weights.z * v2); + return static_cast<int8_t>(std::round(weights.x * v0 + weights.y * v1 + weights.z * v2)); } template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v1, const bool &v2) @@ -66,7 +66,7 @@ template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v template<> inline int mix3(const float3 &weights, const int &v0, const int &v1, const int &v2) { - return static_cast<int>(weights.x * v0 + weights.y * v1 + weights.z * v2); + return static_cast<int>(std::round(weights.x * v0 + weights.y * v1 + weights.z * v2)); } template<> @@ -131,12 +131,12 @@ template<> inline bool mix2(const float factor, const bool &a, const bool &b) template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b) { - return static_cast<int8_t>((1.0f - factor) * a + factor * b); + return static_cast<int8_t>(std::round((1.0f - factor) * a + factor * b)); } template<> inline int mix2(const float factor, const int &a, const int &b) { - return static_cast<int>((1.0f - factor) * a + factor * b); + return static_cast<int>(std::round((1.0f - factor) * a + factor * b)); } template<> inline float mix2(const float factor, const float &a, const float &b) @@ -356,7 +356,7 @@ template<> struct DefaultMixerStruct<ColorGeometry4b> { template<> struct DefaultMixerStruct<int> { static int double_to_int(const double &value) { - return static_cast<int>(value); + return static_cast<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. */ @@ -375,7 +375,7 @@ template<> struct DefaultMixerStruct<bool> { template<> struct DefaultMixerStruct<int8_t> { static int8_t float_to_int8_t(const float &value) { - return static_cast<int8_t>(value); + return static_cast<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>; diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index a33140b721d..7673f18317a 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -15,6 +15,7 @@ extern "C" { struct Mesh; struct OpenSubdiv_EvaluatorCache; +struct OpenSubdiv_EvaluatorSettings; struct Subdiv; typedef enum eSubdivEvaluatorType { @@ -25,7 +26,8 @@ typedef enum eSubdivEvaluatorType { /* Returns true if evaluator is ready for use. */ bool BKE_subdiv_eval_begin(struct Subdiv *subdiv, eSubdivEvaluatorType evaluator_type, - struct OpenSubdiv_EvaluatorCache *evaluator_cache); + struct OpenSubdiv_EvaluatorCache *evaluator_cache, + const struct OpenSubdiv_EvaluatorSettings *settings); /* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse * mesh. */ @@ -60,6 +62,13 @@ void BKE_subdiv_eval_limit_point_and_derivatives(struct Subdiv *subdiv, void BKE_subdiv_eval_limit_point_and_normal( struct Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]); +/* Evaluate smoothly interpolated vertex data (such as orco). */ +void BKE_subdiv_eval_vertex_data(struct Subdiv *subdiv, + const int ptex_face_index, + const float u, + const float v, + float r_vertex_data[]); + /* Evaluate face-varying layer (such as UV). */ void BKE_subdiv_eval_face_varying(struct Subdiv *subdiv, int face_varying_channel, diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index fb44fc46531..5cf0ca6e062 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -1165,6 +1165,10 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, BKE_id_free(nullptr, mesh_orco_cloth); } + /* Remove temporary data layer only needed for modifier evaluation. + * Save some memory, and ensure GPU subdivision does not need to deal with this. */ + CustomData_free_layers(&mesh_final->vdata, CD_CLOTH_ORCO, mesh_final->totvert); + /* Compute normals. */ if (is_own_mesh) { mesh_calc_modifier_final_normals(mesh_input, &final_datamask, sculpt_dyntopo, mesh_final); diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index b76e2b3aec6..8246de12ebf 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -1073,7 +1073,9 @@ static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_c converter_init(reshape_smooth_context, &converter); Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter); - BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL); + + OpenSubdiv_EvaluatorSettings evaluator_settings = {0}; + BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL, &evaluator_settings); reshape_smooth_context->reshape_subdiv = reshape_subdiv; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 49a8406d92d..cf3b4f7bdf2 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -670,6 +670,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->progress = nullptr; ntree->execdata = nullptr; + ntree->runtime_flag = 0; ntree->field_inferencing_interface = nullptr; BKE_ntree_update_tag_missing_runtime_data(ntree); diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index baf3a0c8d22..8afe7ce7520 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -12,6 +12,7 @@ #include "DNA_node_types.h" #include "BKE_anim_data.h" +#include "BKE_image.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_node_tree_update.h" @@ -984,6 +985,7 @@ class NodeTreeMainUpdater { this->remove_unused_previews_when_necessary(ntree); this->ensure_tree_ref(ntree, tree_ref); + this->update_has_image_animation(*tree_ref); if (ntree.type == NTREE_GEOMETRY) { if (node_field_inferencing::update_field_inferencing(*tree_ref)) { result.interface_changed = true; @@ -1254,6 +1256,35 @@ class NodeTreeMainUpdater { BKE_node_preview_remove_unused(&ntree); } + void update_has_image_animation(const NodeTreeRef &tree_ref) + { + bNodeTree &ntree = *tree_ref.btree(); + ntree.runtime_flag &= ~NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; + if (ntree.type != NTREE_SHADER) { + return; + } + + /* Check if a used node group has an animated image. */ + for (const NodeRef *group_node : tree_ref.nodes_by_type("NodeGroup")) { + const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id); + if (group != nullptr) { + if (group->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) { + ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; + return; + } + } + } + /* Check if the tree itself has an animated image. */ + for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) + for (const NodeRef *node : tree_ref.nodes_by_type(idname)) { + Image *image = reinterpret_cast<Image *>(node->bnode()->id); + if (image != nullptr && BKE_image_is_animated(image)) { + ntree.runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; + return; + } + } + } + void update_node_levels(bNodeTree &ntree) { ntreeUpdateNodeLevels(&ntree); diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c index 37978d5c2cc..562bf2e7d61 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.c +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -48,7 +48,8 @@ static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type( bool BKE_subdiv_eval_begin(Subdiv *subdiv, eSubdivEvaluatorType evaluator_type, - OpenSubdiv_EvaluatorCache *evaluator_cache) + OpenSubdiv_EvaluatorCache *evaluator_cache, + const OpenSubdiv_EvaluatorSettings *settings) { BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); if (subdiv->topology_refiner == NULL) { @@ -61,7 +62,7 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv, opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type); BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner( - subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache); + subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache, settings); BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); if (subdiv->evaluator == NULL) { return false; @@ -183,13 +184,52 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv, MEM_freeN(buffer); } +static void set_vertex_data_from_orco(Subdiv *subdiv, const Mesh *mesh) +{ + const float(*orco)[3] = CustomData_get_layer(&mesh->vdata, CD_ORCO); + const float(*cloth_orco)[3] = CustomData_get_layer(&mesh->vdata, CD_CLOTH_ORCO); + + if (orco || cloth_orco) { + OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; + OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; + const int num_verts = topology_refiner->getNumVertices(topology_refiner); + + if (orco && cloth_orco) { + /* Set one by one if have both. */ + for (int i = 0; i < num_verts; i++) { + float data[6]; + copy_v3_v3(data, orco[i]); + copy_v3_v3(data + 3, cloth_orco[i]); + evaluator->setVertexData(evaluator, data, i, 1); + } + } + else { + /* Faster single call if we have either. */ + if (orco) { + evaluator->setVertexData(evaluator, orco[0], 0, num_verts); + } + else if (cloth_orco) { + evaluator->setVertexData(evaluator, cloth_orco[0], 0, num_verts); + } + } + } +} + +static void get_mesh_evaluator_settings(OpenSubdiv_EvaluatorSettings *settings, const Mesh *mesh) +{ + settings->num_vertex_data = (CustomData_has_layer(&mesh->vdata, CD_ORCO) ? 3 : 0) + + (CustomData_has_layer(&mesh->vdata, CD_CLOTH_ORCO) ? 3 : 0); +} + bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, const float (*coarse_vertex_cos)[3], eSubdivEvaluatorType evaluator_type, OpenSubdiv_EvaluatorCache *evaluator_cache) { - if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) { + OpenSubdiv_EvaluatorSettings settings = {0}; + get_mesh_evaluator_settings(&settings, mesh); + if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) { return false; } return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos); @@ -212,6 +252,8 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv, const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index); set_face_varying_data_from_uv(subdiv, mesh, mloopuv, layer_index); } + /* Set vertex data to orco. */ + set_vertex_data_from_orco(subdiv, mesh); /* Update evaluator to the new coarse geometry. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE); subdiv->evaluator->refine(subdiv->evaluator); @@ -287,6 +329,12 @@ void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv, normalize_v3(r_N); } +void BKE_subdiv_eval_vertex_data( + Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_vertex_data[]) +{ + subdiv->evaluator->evaluateVertexData(subdiv->evaluator, ptex_face_index, u, v, r_vertex_data); +} + void BKE_subdiv_eval_face_varying(Subdiv *subdiv, const int face_varying_channel, const int ptex_face_index, diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index 83427adcb43..e846dc2d807 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -44,6 +44,9 @@ typedef struct SubdivMeshContext { /* UV layers interpolation. */ int num_uv_layers; MLoopUV *uv_layers[MAX_MTFACE]; + /* Orco interpolation. */ + float (*orco)[3]; + float (*cloth_orco)[3]; /* Per-subdivided vertex counter of averaged values. */ int *accumulated_counters; bool have_displacement; @@ -69,6 +72,9 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx) ctx->poly_origindex = CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX); /* UV layers interpolation. */ subdiv_mesh_ctx_cache_uv_layers(ctx); + /* Orco interpolation. */ + ctx->orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORCO); + ctx->cloth_orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_CLOTH_ORCO); } static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices) @@ -417,6 +423,34 @@ static void subdiv_mesh_tls_free(void *tls_v) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Evaluation helper functions + * \{ */ + +static void subdiv_vertex_orco_evaluate(const SubdivMeshContext *ctx, + const int ptex_face_index, + const float u, + const float v, + const int subdiv_vertex_index) +{ + if (ctx->orco || ctx->cloth_orco) { + float vertex_data[6]; + BKE_subdiv_eval_vertex_data(ctx->subdiv, ptex_face_index, u, v, vertex_data); + + if (ctx->orco) { + copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data); + if (ctx->cloth_orco) { + copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data + 3); + } + } + else if (ctx->cloth_orco) { + copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Accumulation helpers * \{ */ @@ -530,6 +564,8 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co); /* Apply displacement. */ add_v3_v3(subdiv_vert->co, D); + /* Evaluate undeformed texture coordinate. */ + subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index); /* Remove facedot flag. This can happen if there is more than one subsurf modifier. */ BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index); } @@ -556,6 +592,8 @@ static void evaluate_vertex_and_apply_displacement_interpolate( BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_vert->co); /* Apply displacement. */ add_v3_v3(subdiv_vert->co, D); + /* Evaluate undeformed texture coordinate. */ + subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index); } static void subdiv_mesh_vertex_displacement_every_corner_or_edge( @@ -723,6 +761,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context subdiv_vertex_data_interpolate(ctx, subdiv_vert, &tls->vertex_interpolation, u, v); BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, subdiv_vert->co); subdiv_mesh_tag_center_vertex(coarse_poly, subdiv_vertex_index, u, v, subdiv_mesh); + subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index); } /** \} */ diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh index 81f5343056e..034c6968c94 100644 --- a/source/blender/blenlib/BLI_math_base.hh +++ b/source/blender/blenlib/BLI_math_base.hh @@ -108,12 +108,20 @@ template<typename T, BLI_ENABLE_IF((is_math_float_type<FactorT>))> inline T interpolate(const T &a, const T &b, const FactorT &t) { - return a * (1 - t) + b * t; + auto result = a * (1 - t) + b * t; + if constexpr (std::is_integral_v<T> && std::is_floating_point_v<FactorT>) { + result = std::round(result); + } + return result; } template<typename T> inline T midpoint(const T &a, const T &b) { - return (a + b) * T(0.5); + auto result = (a + b) * T(0.5); + if constexpr (std::is_integral_v<T>) { + result = std::round(result); + } + return result; } } // namespace blender::math diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 4782f1c4a5d..c6fc3cd5d0b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1078,14 +1078,17 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) void DepsgraphNodeBuilder::build_animation_images(ID *id) { - /* GPU materials might use an animated image. However, these materials have no been built yet. We - * could scan the entire node tree recursively to check if any texture node has a video. That is - * quite expensive. For now just always add this operation node, because it is very fast. */ - /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node - * tree. */ - const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO); - - if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) { + /* GPU materials might use an animated image. However, these materials have no been built yet so + * we have to check if they might be created during evaluation. */ + bool has_image_animation = false; + if (ELEM(GS(id->name), ID_MA, ID_WO)) { + bNodeTree *ntree = *BKE_ntree_ptr_from_id(id); + if (ntree != nullptr && ntree->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) { + has_image_animation = true; + } + } + + if (has_image_animation || BKE_image_user_id_has_animation(id)) { ID *id_cow = get_cow_id(id); add_operation_node( id, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 5eccb5a4eb2..3eeab23823c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1446,10 +1446,15 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) void DepsgraphRelationBuilder::build_animation_images(ID *id) { /* See #DepsgraphNodeBuilder::build_animation_images. */ - const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO); + bool has_image_animation = false; + if (ELEM(GS(id->name), ID_MA, ID_WO)) { + bNodeTree *ntree = *BKE_ntree_ptr_from_id(id); + if (ntree != nullptr && ntree->runtime_flag & NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION) { + has_image_animation = true; + } + } - /* TODO: can we check for existence of node for performance? */ - if (can_have_gpu_material || BKE_image_user_id_has_animation(id)) { + if (has_image_animation || BKE_image_user_id_has_animation(id)) { OperationKey image_animation_key( id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION); TimeSourceKey time_src_key; diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 99524184323..7800ce797aa 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -676,6 +676,40 @@ static void track_colors(MovieTrackingTrack *track, int act, float col[3], float } } +static void set_draw_marker_area_color(const MovieTrackingTrack *track, + const MovieTrackingMarker *marker, + const bool is_track_active, + const bool is_area_selected, + const float color[3], + const float selected_color[3]) +{ + if (track->flag & TRACK_LOCKED) { + if (is_track_active) { + immUniformThemeColor(TH_ACT_MARKER); + } + else if (is_area_selected) { + immUniformThemeColorShade(TH_LOCK_MARKER, 64); + } + else { + immUniformThemeColor(TH_LOCK_MARKER); + } + } + else if (marker->flag & MARKER_DISABLED) { + if (is_track_active) { + immUniformThemeColor(TH_ACT_MARKER); + } + else if (is_area_selected) { + immUniformThemeColorShade(TH_DIS_MARKER, 128); + } + else { + immUniformThemeColor(TH_DIS_MARKER); + } + } + else { + immUniformColor3fv(is_area_selected ? selected_color : color); + } +} + static void draw_marker_areas(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker, @@ -785,31 +819,7 @@ static void draw_marker_areas(SpaceClip *sc, GPU_matrix_push(); GPU_matrix_translate_2fv(marker_pos); - if (track->flag & TRACK_LOCKED) { - if (act) { - immUniformThemeColor(TH_ACT_MARKER); - } - else if (track->pat_flag & SELECT) { - immUniformThemeColorShade(TH_LOCK_MARKER, 64); - } - else { - immUniformThemeColor(TH_LOCK_MARKER); - } - } - else if (marker->flag & MARKER_DISABLED) { - if (act) { - immUniformThemeColor(TH_ACT_MARKER); - } - else if (track->pat_flag & SELECT) { - immUniformThemeColorShade(TH_DIS_MARKER, 128); - } - else { - immUniformThemeColor(TH_DIS_MARKER); - } - } - else { - immUniformColor3fv((track->pat_flag & SELECT) ? scol : col); - } + set_draw_marker_area_color(track, marker, act, track->pat_flag & SELECT, col, scol); if (tiny) { immUniform1f("dash_width", 6.0f); @@ -834,6 +844,8 @@ static void draw_marker_areas(SpaceClip *sc, 0; if ((track->search_flag & SELECT) == sel && (sc->flag & SC_SHOW_MARKER_SEARCH) && show_search) { + set_draw_marker_area_color(track, marker, act, track->search_flag & SELECT, col, scol); + imm_draw_box_wire_2d(shdr_pos, marker->search_min[0], marker->search_min[1], diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 92c4d8fe938..e9c12e52bce 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -499,7 +499,13 @@ typedef struct bNodeTree { int type; - char _pad1[4]; + /** + * Used to cache run-time information of the node tree. + * #eNodeTreeRuntimeFlag. + */ + uint8_t runtime_flag; + + char _pad1[3]; /** * Sockets in groups have unique identifiers, adding new sockets always @@ -601,6 +607,11 @@ typedef enum eNodeTreeExecutionMode { NTREE_EXECUTION_MODE_FULL_FRAME = 1, } eNodeTreeExecutionMode; +typedef enum eNodeTreeRuntimeFlag { + /** There is a node that references an image with animation. */ + NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION = 1 << 0, +} eNodeTreeRuntimeFlag; + /* socket value structs for input buttons * DEPRECATED now using ID properties */ |