diff options
author | Lukas Stockner <lukas.stockner@freenet.de> | 2017-04-19 21:45:56 +0300 |
---|---|---|
committer | Lukas Stockner <lukas.stockner@freenet.de> | 2017-04-19 21:45:56 +0300 |
commit | d9f006631c5e10cfba9708600077b83c9b2cf6b4 (patch) | |
tree | 3d9663b278ff1a4f148f05662884d9303a06bfe7 /source/blender | |
parent | 374efaf9975bd2af726c76b3f92934060a50cb1b (diff) | |
parent | aaec934096ac0c5c2dc5c5f195b43263010491f3 (diff) |
Merge remote-tracking branch 'origin/master' into temp-cycles-denoising
Diffstat (limited to 'source/blender')
55 files changed, 891 insertions, 256 deletions
diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index e92d5f2d9f7..6b698e5ec66 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -53,41 +53,57 @@ struct AlembicExportParams { double shutter_open; double shutter_close; - /* bools */ - unsigned int selected_only : 1; - unsigned int uvs : 1; - unsigned int normals : 1; - unsigned int vcolors : 1; - unsigned int apply_subdiv : 1; - unsigned int flatten_hierarchy : 1; - unsigned int visible_layers_only : 1; - unsigned int renderable_only : 1; - unsigned int face_sets : 1; - unsigned int use_subdiv_schema : 1; - unsigned int packuv : 1; - unsigned int triangulate : 1; + bool selected_only; + bool uvs; + bool normals; + bool vcolors; + bool apply_subdiv; + bool flatten_hierarchy; + bool visible_layers_only; + bool renderable_only; + bool face_sets; + bool use_subdiv_schema; + bool packuv; + bool triangulate; + bool export_hair; + bool export_particles; unsigned int compression_type : 1; + /* See MOD_TRIANGULATE_NGON_xxx and MOD_TRIANGULATE_QUAD_xxx + * in DNA_modifier_types.h */ int quad_method; int ngon_method; + float global_scale; }; -void ABC_export( +/* The ABC_export and ABC_import functions both take a as_background_job + * parameter, and return a boolean. + * + * When as_background_job=true, returns false immediately after scheduling + * a background job. + * + * When as_background_job=false, performs the export synchronously, and returns + * true when the export was ok, and false if there were any errors. + */ + +bool ABC_export( struct Scene *scene, struct bContext *C, const char *filepath, - const struct AlembicExportParams *params); + const struct AlembicExportParams *params, + bool as_background_job); -void ABC_import(struct bContext *C, +bool ABC_import(struct bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, - bool validate_meshes); + bool validate_meshes, + bool as_background_job); AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *object_paths); diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 0542255d84b..bf485c7ef61 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -49,19 +49,26 @@ using Alembic::Abc::Int32ArraySamplePtr; using Alembic::Abc::FloatArraySamplePtr; using Alembic::Abc::P3fArraySamplePtr; using Alembic::Abc::UcharArraySamplePtr; +using Alembic::Abc::PropertyHeader; +using Alembic::AbcGeom::ICompoundProperty; using Alembic::AbcGeom::ICurves; using Alembic::AbcGeom::ICurvesSchema; using Alembic::AbcGeom::IFloatGeomParam; +using Alembic::AbcGeom::IInt16Property; using Alembic::AbcGeom::ISampleSelector; using Alembic::AbcGeom::kWrapExisting; using Alembic::AbcGeom::CurvePeriodicity; +using Alembic::AbcGeom::OCompoundProperty; using Alembic::AbcGeom::OCurves; using Alembic::AbcGeom::OCurvesSchema; +using Alembic::AbcGeom::OInt16Property; using Alembic::AbcGeom::ON3fGeomParam; using Alembic::AbcGeom::OV2fGeomParam; +#define ABC_CURVE_RESOLUTION_U_PROPNAME "blender:resolution" + /* ************************************************************************** */ AbcCurveWriter::AbcCurveWriter(Scene *scene, @@ -73,6 +80,11 @@ AbcCurveWriter::AbcCurveWriter(Scene *scene, { OCurves curves(parent->alembicXform(), m_name, m_time_sampling); m_schema = curves.getSchema(); + + Curve *cu = static_cast<Curve *>(m_object->data); + OCompoundProperty user_props = m_schema.getUserProperties(); + OInt16Property user_prop_resolu(user_props, ABC_CURVE_RESOLUTION_U_PROPNAME); + user_prop_resolu.set(cu->resolu); } void AbcCurveWriter::do_write() @@ -95,7 +107,7 @@ void AbcCurveWriter::do_write() for (; nurbs; nurbs = nurbs->next) { if (nurbs->bp) { curve_basis = Alembic::AbcGeom::kNoBasis; - curve_type = Alembic::AbcGeom::kLinear; + curve_type = Alembic::AbcGeom::kVariableOrder; const int totpoint = nurbs->pntsu * nurbs->pntsv; @@ -160,7 +172,7 @@ void AbcCurveWriter::do_write() } } - orders.push_back(nurbs->orderu + 1); + orders.push_back(nurbs->orderu); vert_counts.push_back(verts.size()); } @@ -205,11 +217,23 @@ void AbcCurveReader::readObjectData(Main *bmain, float time) cu->flag |= CU_DEFORM_FILL | CU_3D; cu->actvert = CU_ACT_NONE; + cu->resolu = 1; + + const ISampleSelector sample_sel(time); + + ICompoundProperty user_props = m_curves_schema.getUserProperties(); + if (user_props) { + const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME); + if (header != NULL && header->isScalar() && IInt16Property::matches(*header)) { + IInt16Property resolu(user_props, header->getName()); + cu->resolu = resolu.getValue(sample_sel); + } + } m_object = BKE_object_add_only_object(bmain, OB_CURVE, m_object_name.c_str()); m_object->data = cu; - read_curve_sample(cu, m_curves_schema, time); + read_curve_sample(cu, m_curves_schema, sample_sel); if (has_animations(m_curves_schema, m_settings)) { addCacheModifier(); @@ -218,9 +242,8 @@ void AbcCurveReader::readObjectData(Main *bmain, float time) /* ************************************************************************** */ -void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) +void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const ISampleSelector &sample_sel) { - const ISampleSelector sample_sel(time); ICurvesSchema::Sample smp = schema.getValue(sample_sel); const Int32ArraySamplePtr num_vertices = smp.getCurvesNumVertices(); const P3fArraySamplePtr positions = smp.getPositions(); @@ -250,13 +273,18 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) nu->pntsv = 1; nu->flag |= CU_SMOOTH; - nu->orderu = num_verts; - - if (smp.getType() == Alembic::AbcGeom::kCubic) { - nu->orderu = 3; - } - else if (orders && orders->size() > i) { - nu->orderu = static_cast<short>((*orders)[i] - 1); + switch (smp.getType()) { + case Alembic::AbcGeom::kCubic: + nu->orderu = 4; + break; + case Alembic::AbcGeom::kVariableOrder: + if (orders && orders->size() > i) { + nu->orderu = static_cast<short>((*orders)[i]); + break; + } + case Alembic::AbcGeom::kLinear: + default: + nu->orderu = 2; } if (periodicity == Alembic::AbcGeom::kNonPeriodic) { @@ -377,7 +405,7 @@ DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh * /*dm*/, const float if (curve_count != num_vertices->size()) { BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, m_curves_schema, time); + read_curve_sample(curve, m_curves_schema, sample_sel); } else { Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first); diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index 2757d179a47..71b0d205820 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -61,6 +61,8 @@ public: /* ************************************************************************** */ -void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time); +void read_curve_sample(Curve *cu, + const Alembic::AbcGeom::ICurvesSchema &schema, + const Alembic::Abc::ISampleSelector &sample_selector); #endif /* __ABC_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index a8d1587abdb..d70b9625f1d 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -83,6 +83,8 @@ ExportSettings::ExportSettings() , export_vcols(false) , export_face_sets(false) , export_vweigths(false) + , export_hair(true) + , export_particles(true) , apply_subdiv(false) , use_subdiv_schema(false) , export_child_hairs(true) @@ -290,13 +292,7 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) OBox3dProperty archive_bounds_prop = Alembic::AbcGeom::CreateOArchiveBounds(m_writer->archive(), m_trans_sampling_index); - if (m_settings.flatten_hierarchy) { - createTransformWritersFlat(); - } - else { - createTransformWritersHierarchy(bmain->eval_ctx); - } - + createTransformWritersHierarchy(bmain->eval_ctx); createShapeWriters(bmain->eval_ctx); /* Make a list of frames to export. */ @@ -383,24 +379,6 @@ void AbcExporter::createTransformWritersHierarchy(EvaluationContext *eval_ctx) } } -void AbcExporter::createTransformWritersFlat() -{ - Base *base = static_cast<Base *>(m_scene->base.first); - - while (base) { - Object *ob = base->object; - - if (export_object(&m_settings, ob, false) && object_is_shape(ob)) { - std::string name = get_id_name(ob); - m_xforms[name] = new AbcTransformWriter( - ob, m_writer->archive().getTop(), NULL, - m_trans_sampling_index, m_settings); - } - - base = base->next; - } -} - void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent) { /* If an object isn't exported itself, its duplilist shouldn't be @@ -440,12 +418,18 @@ void AbcExporter::exploreTransform(EvaluationContext *eval_ctx, Object *ob, Obje AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *parent, Object *dupliObParent) { - const std::string name = get_object_dag_path_name(ob, dupliObParent); - /* An object should not be its own parent, or we'll get infinite loops. */ BLI_assert(ob != parent); BLI_assert(ob != dupliObParent); + std::string name; + if (m_settings.flatten_hierarchy) { + name = get_id_name(ob); + } + else { + name = get_object_dag_path_name(ob, dupliObParent); + } + /* check if we have already created a transform writer for this object */ AbcTransformWriter *my_writer = getXForm(name); if (my_writer != NULL){ @@ -455,13 +439,23 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *pare AbcTransformWriter *parent_writer = NULL; Alembic::Abc::OObject alembic_parent; - if (parent) { + if (m_settings.flatten_hierarchy || parent == NULL) { + /* Parentless objects still have the "top object" as parent + * in Alembic. */ + alembic_parent = m_writer->archive().getTop(); + } + else { /* Since there are so many different ways to find parents (as evident * in the number of conditions below), we can't really look up the * parent by name. We'll just call createTransformWriter(), which will * return the parent's AbcTransformWriter pointer. */ if (parent->parent) { - parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); + if (parent == dupliObParent) { + parent_writer = createTransformWriter(parent, parent->parent, NULL); + } + else { + parent_writer = createTransformWriter(parent, parent->parent, dupliObParent); + } } else if (parent == dupliObParent) { if (dupliObParent->parent == NULL) { @@ -478,14 +472,15 @@ AbcTransformWriter * AbcExporter::createTransformWriter(Object *ob, Object *pare BLI_assert(parent_writer); alembic_parent = parent_writer->alembicXform(); } - else { - /* Parentless objects still have the "top object" as parent - * in Alembic. */ - alembic_parent = m_writer->archive().getTop(); - } my_writer = new AbcTransformWriter(ob, alembic_parent, parent_writer, m_trans_sampling_index, m_settings); + + /* When flattening, the matrix of the dupliobject has to be added. */ + if (m_settings.flatten_hierarchy && dupliObParent) { + my_writer->m_proxy_from = dupliObParent; + } + m_xforms[name] = my_writer; return my_writer; } @@ -532,6 +527,29 @@ void AbcExporter::exploreObject(EvaluationContext *eval_ctx, Object *ob, Object free_object_duplilist(lb); } +void AbcExporter::createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform) +{ + if (!m_settings.export_hair && !m_settings.export_particles) { + return; + } + + ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); + + for (; psys; psys = psys->next) { + if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { + continue; + } + + if (m_settings.export_hair && psys->part->type == PART_HAIR) { + m_settings.export_child_hairs = true; + m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); + } + else if (m_settings.export_particles && psys->part->type == PART_EMITTER) { + m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); + } + } +} + void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) { if (!object_is_shape(ob)) { @@ -554,21 +572,7 @@ void AbcExporter::createShapeWriter(Object *ob, Object *dupliObParent) return; } - ParticleSystem *psys = static_cast<ParticleSystem *>(ob->particlesystem.first); - - for (; psys; psys = psys->next) { - if (!psys_check_enabled(ob, psys, G.is_rendering) || !psys->part) { - continue; - } - - if (psys->part->type == PART_HAIR) { - m_settings.export_child_hairs = true; - m_shapes.push_back(new AbcHairWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); - } - else if (psys->part->type == PART_EMITTER) { - m_shapes.push_back(new AbcPointsWriter(m_scene, ob, xform, m_shape_sampling_index, m_settings, psys)); - } - } + createParticleSystemsWriters(ob, xform); switch (ob->type) { case OB_MESH: diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h index 0f08037fd17..797a2560d65 100644 --- a/source/blender/alembic/intern/abc_exporter.h +++ b/source/blender/alembic/intern/abc_exporter.h @@ -63,6 +63,8 @@ struct ExportSettings { bool export_vcols; bool export_face_sets; bool export_vweigths; + bool export_hair; + bool export_particles; bool apply_subdiv; bool use_subdiv_schema; @@ -109,12 +111,12 @@ private: void getFrameSet(double step, std::set<double> &frames); void createTransformWritersHierarchy(EvaluationContext *eval_ctx); - void createTransformWritersFlat(); AbcTransformWriter * createTransformWriter(Object *ob, Object *parent, Object *dupliObParent); void exploreTransform(EvaluationContext *eval_ctx, Object *ob, Object *parent, Object *dupliObParent = NULL); void exploreObject(EvaluationContext *eval_ctx, Object *ob, Object *dupliObParent); void createShapeWriters(EvaluationContext *eval_ctx); void createShapeWriter(Object *ob, Object *dupliObParent); + void createParticleSystemsWriters(Object *ob, AbcTransformWriter *xform); AbcTransformWriter *getXForm(const std::string &name); diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index 2e626edeb8b..6e218cac429 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -62,6 +62,7 @@ AbcTransformWriter::AbcTransformWriter(Object *ob, unsigned int time_sampling, ExportSettings &settings) : AbcObjectWriter(NULL, ob, time_sampling, settings, parent) + , m_proxy_from(NULL) { m_is_animated = hasAnimation(m_object); @@ -90,7 +91,8 @@ void AbcTransformWriter::do_write() float yup_mat[4][4]; create_transform_matrix(m_object, yup_mat, - m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD); + m_inherits_xform ? ABC_MATRIX_LOCAL : ABC_MATRIX_WORLD, + m_proxy_from); /* Only apply rotation to root camera, parenting will propagate it. */ if (m_object->type == OB_CAMERA && (!m_inherits_xform || !has_parent_camera(m_object))) { diff --git a/source/blender/alembic/intern/abc_transform.h b/source/blender/alembic/intern/abc_transform.h index 714adc299c1..59388e155dc 100644 --- a/source/blender/alembic/intern/abc_transform.h +++ b/source/blender/alembic/intern/abc_transform.h @@ -41,6 +41,9 @@ class AbcTransformWriter : public AbcObjectWriter { bool m_inherits_xform; public: + Object *m_proxy_from; + +public: AbcTransformWriter(Object *ob, const Alembic::AbcGeom::OObject &abc_parent, AbcTransformWriter *parent, diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 248ca4e64ae..67d2d3b1eb2 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -257,7 +257,8 @@ void convert_matrix(const Imath::M44d &xform, Object *ob, float r_mat[4][4]) /* Recompute transform matrix of object in new coordinate system * (from Z-Up to Y-Up). */ -void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode) +void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode mode, + Object *proxy_from) { float zup_mat[4][4]; @@ -267,11 +268,16 @@ void create_transform_matrix(Object *obj, float r_yup_mat[4][4], AbcMatrixMode m * constraints and modifiers as well as the obj->parentinv matrix. */ invert_m4_m4(obj->parent->imat, obj->parent->obmat); mul_m4_m4m4(zup_mat, obj->parent->imat, obj->obmat); - copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); } else { - copy_m44_axis_swap(r_yup_mat, obj->obmat, ABC_YUP_FROM_ZUP); + copy_m4_m4(zup_mat, obj->obmat); } + + if (proxy_from) { + mul_m4_m4m4(zup_mat, proxy_from->obmat, zup_mat); + } + + copy_m44_axis_swap(r_yup_mat, zup_mat, ABC_YUP_FROM_ZUP); } bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name) diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 7bde9ac6e15..74d0faf97d3 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -62,7 +62,8 @@ typedef enum { ABC_MATRIX_WORLD = 1, ABC_MATRIX_LOCAL = 2, } AbcMatrixMode; -void create_transform_matrix(Object *obj, float r_transform_mat[4][4], AbcMatrixMode mode); +void create_transform_matrix(Object *obj, float r_transform_mat[4][4], + AbcMatrixMode mode, Object *proxy_from); void split(const std::string &s, const char delim, std::vector<std::string> &tokens); diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index 0de0d1a1ab6..104b19beaf0 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -238,6 +238,7 @@ struct ExportJobData { float *progress; bool was_canceled; + bool export_ok; }; static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) @@ -271,6 +272,8 @@ static void export_startjob(void *customdata, short *stop, short *do_update, flo BKE_scene_update_for_newframe(data->bmain->eval_ctx, data->bmain, scene, scene->lay); } + + data->export_ok = !data->was_canceled; } catch (const std::exception &e) { ABC_LOG(data->settings.logger) << "Abc Export error: " << e.what() << '\n'; @@ -297,15 +300,17 @@ static void export_endjob(void *customdata) BKE_spacedata_draw_locks(false); } -void ABC_export( +bool ABC_export( Scene *scene, bContext *C, const char *filepath, - const struct AlembicExportParams *params) + const struct AlembicExportParams *params, + bool as_background_job) { ExportJobData *job = static_cast<ExportJobData *>(MEM_mallocN(sizeof(ExportJobData), "ExportJobData")); job->scene = scene; job->bmain = CTX_data_main(C); + job->export_ok = false; BLI_strncpy(job->filename, filepath, 1024); /* Alright, alright, alright.... @@ -336,6 +341,8 @@ void ABC_export( job->settings.export_normals = params->normals; job->settings.export_uvs = params->uvs; job->settings.export_vcols = params->vcolors; + job->settings.export_hair = params->export_hair; + job->settings.export_particles = params->export_particles; job->settings.apply_subdiv = params->apply_subdiv; job->settings.flatten_hierarchy = params->flatten_hierarchy; job->settings.visible_layers_only = params->visible_layers_only; @@ -352,19 +359,31 @@ void ABC_export( std::swap(job->settings.frame_start, job->settings.frame_end); } - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - job->scene, - "Alembic Export", - WM_JOB_PROGRESS, - WM_JOB_TYPE_ALEMBIC); + if (as_background_job) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + job->scene, + "Alembic Export", + WM_JOB_PROGRESS, + WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, MEM_freeN); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ + short stop = 0, do_update = 0; + float progress = 0.f; - /* setup job */ - WM_jobs_customdata_set(wm_job, job, MEM_freeN); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, export_startjob, NULL, NULL, export_endjob); + export_startjob(job, &stop, &do_update, &progress); + export_endjob(job); + } - WM_jobs_start(CTX_wm_manager(C), wm_job); + return job->export_ok; } /* ********************** Import file ********************** */ @@ -593,6 +612,7 @@ struct ImportJobData { char error_code; bool was_cancelled; + bool import_ok; }; ABC_INLINE bool is_mesh_and_strands(const IObject &object) @@ -801,6 +821,7 @@ static void import_endjob(void *user_data) switch (data->error_code) { default: case ABC_NO_ERROR: + data->import_ok = !data->was_cancelled; break; case ABC_ARCHIVE_FAIL: WM_report(RPT_ERROR, "Could not open Alembic archive for reading! See console for detail."); @@ -816,13 +837,16 @@ static void import_freejob(void *user_data) delete data; } -void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, bool set_frame_range, int sequence_len, int offset, bool validate_meshes) +bool ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence, + bool set_frame_range, int sequence_len, int offset, + bool validate_meshes, bool as_background_job) { /* Using new here since MEM_* funcs do not call ctor to properly initialize * data. */ ImportJobData *job = new ImportJobData(); job->bmain = CTX_data_main(C); job->scene = CTX_data_scene(C); + job->import_ok = false; BLI_strncpy(job->filename, filepath, 1024); job->settings.scale = scale; @@ -836,19 +860,31 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence G.is_break = false; - wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - job->scene, - "Alembic Import", - WM_JOB_PROGRESS, - WM_JOB_TYPE_ALEMBIC); + if (as_background_job) { + wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + job->scene, + "Alembic Import", + WM_JOB_PROGRESS, + WM_JOB_TYPE_ALEMBIC); - /* setup job */ - WM_jobs_customdata_set(wm_job, job, import_freejob); - WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); - WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob); + /* setup job */ + WM_jobs_customdata_set(wm_job, job, import_freejob); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, import_startjob, NULL, NULL, import_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while importing. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + import_startjob(job, &stop, &do_update, &progress); + import_endjob(job); + } - WM_jobs_start(CTX_wm_manager(C), wm_job); + return job->import_ok; } /* ************************************************************************** */ diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index aa7d539538b..bbbabfb8ba2 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -135,6 +135,7 @@ void blf_glyph_cache_clear(FontBLF *font) while ((gc = BLI_pophead(&font->cache))) { blf_glyph_cache_free(gc); } + font->glyph_cache = NULL; } void blf_glyph_cache_free(GlyphCacheBLF *gc) diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index 78d6f6c7cb9..23bb526073b 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -177,6 +177,7 @@ void BKE_pose_eval_bone(struct EvaluationContext *eval_ctx, struct bPoseChannel *pchan); void BKE_pose_constraints_evaluate(struct EvaluationContext *eval_ctx, + struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 193f1154c54..7544e8f5b3e 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -785,6 +785,7 @@ struct ShadeResult; #define SH_NODE_OUTPUT_LINESTYLE 190 #define SH_NODE_UVALONGSTROKE 191 #define SH_NODE_TEX_POINTDENSITY 192 +#define SH_NODE_BSDF_PRINCIPLED 193 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 3bc81a69c86..df0bddede3b 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -628,10 +628,10 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx), } void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, Object *ob, bPoseChannel *pchan) { - Scene *scene = G.main->scene.first; DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); bArmature *arm = (bArmature *)ob->data; if (arm->flag & ARM_RESTPOS) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 318f6480aaf..8a01e120d6d 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -2216,8 +2216,10 @@ void BKE_imbuf_write_prepare(ImBuf *ibuf, const ImageFormatData *imf) ibuf->foptions.flag |= OPENEXR_HALF; ibuf->foptions.flag |= (imf->exr_codec & OPENEXR_COMPRESS); - if (!(imf->flag & R_IMF_FLAG_ZBUF)) - ibuf->zbuf_float = NULL; /* signal for exr saving */ + if (!(imf->flag & R_IMF_FLAG_ZBUF)) { + /* Signal for exr saving. */ + IMB_freezbuffloatImBuf(ibuf); + } } #endif diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index f3223e31b17..63da1b5f9e7 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3568,6 +3568,7 @@ static void registerShaderNodes(void) register_node_type_sh_background(); register_node_type_sh_bsdf_anisotropic(); register_node_type_sh_bsdf_diffuse(); + register_node_type_sh_bsdf_principled(); register_node_type_sh_bsdf_glossy(); register_node_type_sh_bsdf_glass(); register_node_type_sh_bsdf_translucent(); diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index e3b801b3193..eb7abc2f004 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -64,6 +64,7 @@ #include "BLI_strict_flags.h" +#include "BLI_hash.h" /* Dupli-Geometry */ @@ -180,6 +181,22 @@ static DupliObject *make_dupli(const DupliContext *ctx, if (ob->type == OB_MBALL) dob->no_draw = true; + /* random number */ + /* the logic here is designed to match Cycles */ + dob->random_id = BLI_hash_string(dob->ob->id.name + 2); + + if (dob->persistent_id[0] != INT_MAX) { + for(i = 0; i < MAX_DUPLI_RECUR*2; i++) + dob->random_id = BLI_hash_int_2d(dob->random_id, (unsigned int)dob->persistent_id[i]); + } + else { + dob->random_id = BLI_hash_int_2d(dob->random_id, 0); + } + + if (ctx->object != ob) { + dob->random_id ^= BLI_hash_int(BLI_hash_string(ctx->object->id.name + 2)); + } + return dob; } diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h new file mode 100644 index 00000000000..50c7a7f9f0f --- /dev/null +++ b/source/blender/blenlib/BLI_hash.h @@ -0,0 +1,66 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_HASH_H__ +#define __BLI_HASH_H__ + +/** \file BLI_hash.h + * \ingroup bli + */ + +BLI_INLINE unsigned int BLI_hash_int_2d(unsigned int kx, unsigned int ky) +{ +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + + unsigned int a, b, c; + + a = b = c = 0xdeadbeef + (2 << 2) + 13; + a += kx; + b += ky; + + c ^= b; c -= rot(b,14); + a ^= c; a -= rot(c,11); + b ^= a; b -= rot(a,25); + c ^= b; c -= rot(b,16); + a ^= c; a -= rot(c,4); + b ^= a; b -= rot(a,14); + c ^= b; c -= rot(b,24); + + return c; + +#undef rot +} + +BLI_INLINE unsigned int BLI_hash_string(const char *str) +{ + unsigned int i = 0, c; + + while((c = *str++)) + i = i * 37 + c; + + return i; +} + +BLI_INLINE unsigned int BLI_hash_int(unsigned int k) +{ + return BLI_hash_int_2d(k, 0); +} + +#endif // __BLI_HASH_H__ diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index b6a55d34d14..b59e7f99d59 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -44,7 +44,7 @@ void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1); void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file); void BLI_make_exist(char *dir); -void BLI_make_existing_file(const char *name); +bool BLI_make_existing_file(const char *name); void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen); void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen); void BLI_split_file_part(const char *string, char *file, const size_t filelen); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 3277519c66e..fcb02a86a84 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -152,6 +152,7 @@ set(SRC BLI_ghash.h BLI_graph.h BLI_gsqueue.h + BLI_hash.h BLI_hash_md5.h BLI_hash_mm2a.h BLI_heap.h diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 7b765cfa939..40b6aaa18c1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1234,14 +1234,16 @@ void BLI_make_exist(char *dir) /** * Ensures that the parent directory of *name exists. + * + * \return true on success (i.e. given path now exists on FS), false otherwise. */ -void BLI_make_existing_file(const char *name) +bool BLI_make_existing_file(const char *name) { char di[FILE_MAX]; BLI_split_dir_part(name, di, sizeof(di)); /* make if the dir doesn't exist */ - BLI_dir_create_recursive(di); + return BLI_dir_create_recursive(di); } /** diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 10b586342dd..745f8283328 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -130,7 +130,7 @@ struct DepsgraphNodeBuilder { void build_object(Scene *scene, Base *base, Object *ob); void build_object_transform(Scene *scene, Object *ob); void build_object_constraints(Scene *scene, Object *ob); - void build_pose_constraints(Object *ob, bPoseChannel *pchan); + void build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan); void build_rigidbody(Scene *scene); void build_particles(Scene *scene, Object *ob); void build_cloth(Scene *scene, Object *object); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index f2437ce1fac..e307909cb11 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -64,11 +64,12 @@ extern "C" { namespace DEG { -void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) +void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan) { /* create node for constraint stack */ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), + DEPSOP_TYPE_EXEC, + function_bind(BKE_pose_constraints_evaluate, _1, scene, ob, pchan), DEG_OPCODE_BONE_CONSTRAINTS); } @@ -201,7 +202,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) /* constraints */ if (pchan->constraints.first != NULL) { - build_pose_constraints(ob, pchan); + build_pose_constraints(scene, ob, pchan); } /** diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 47f42ab5321..648fe930030 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6047,6 +6047,9 @@ int join_curve_exec(bContext *C, wmOperator *op) cu = ob->data; BLI_movelisttolist(&cu->nurb, &tempbase); + /* Account for mixed 2D/3D curves when joining */ + BKE_curve_curve_dimension_update(cu); + DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode! DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 5879306b06c..d6e40377e63 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -484,7 +484,8 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, bGPdata *gpd = p->gpd; bGPDbrush *brush = p->brush; tGPspoint *pt; - + ToolSettings *ts = p->scene->toolsettings; + /* check painting mode */ if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { /* straight lines only - i.e. only store start and end point in buffer */ @@ -636,7 +637,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, View3D *v3d = p->sa->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->ar); - ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0); + ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); } /* convert screen-coordinates to appropriate coordinates (and store them) */ @@ -756,7 +757,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) int i, totelem; /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */ - int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0; + int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; /* get total number of points to allocate space for * - drawing straight-lines only requires the endpoints @@ -910,7 +911,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) depth_arr[i] = 0.9999f; } else { - if (p->gpd->flag & GP_DATA_DEPTH_STROKE_ENDPOINTS) { + if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE_ENDPOINTS) { /* remove all info between the valid endpoints */ int first_valid = 0; int last_valid = 0; @@ -1794,6 +1795,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */ static void gp_paint_strokeend(tGPsdata *p) { + ToolSettings *ts = p->scene->toolsettings; /* for surface sketching, need to set the right OpenGL context stuff so that * the conversions will project the values correctly... */ @@ -1802,7 +1804,7 @@ static void gp_paint_strokeend(tGPsdata *p) /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(p->win, p->ar); - ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0); + ED_view3d_autodist_init(p->scene, p->ar, v3d, (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 1 : 0); } /* check if doing eraser or not */ diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 3f9eb33e239..62c36552048 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -122,6 +122,8 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op) .renderable_only = RNA_boolean_get(op->ptr, "renderable_only"), .face_sets = RNA_boolean_get(op->ptr, "face_sets"), .use_subdiv_schema = RNA_boolean_get(op->ptr, "subdiv_schema"), + .export_hair = RNA_boolean_get(op->ptr, "export_hair"), + .export_particles = RNA_boolean_get(op->ptr, "export_particles"), .compression_type = RNA_enum_get(op->ptr, "compression_type"), .packuv = RNA_boolean_get(op->ptr, "packuv"), .triangulate = RNA_boolean_get(op->ptr, "triangulate"), @@ -131,15 +133,17 @@ static int wm_alembic_export_exec(bContext *C, wmOperator *op) .global_scale = RNA_float_get(op->ptr, "global_scale"), }; - ABC_export(CTX_data_scene(C), C, filename, ¶ms); + const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job"); + bool ok = ABC_export(CTX_data_scene(C), C, filename, ¶ms, as_background_job); - return OPERATOR_FINISHED; + return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr) { uiLayout *box; uiLayout *row; + uiLayout *col; #ifdef WITH_ALEMBIC_HDF5 box = uiLayoutBox(layout); @@ -231,6 +235,15 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr) row = uiLayoutRow(box, false); uiLayoutSetEnabled(row, triangulate); uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE); + + /* Object Data */ + box = uiLayoutBox(layout); + row = uiLayoutRow(box, false); + uiItemL(row, IFACE_("Particle Systems:"), ICON_PARTICLE_DATA); + + col = uiLayoutColumn(box, true); + uiItemR(col, imfptr, "export_hair", 0, NULL, ICON_NONE); + uiItemR(col, imfptr, "export_particles", 0, NULL, ICON_NONE); } static void wm_alembic_export_draw(bContext *C, wmOperator *op) @@ -348,6 +361,12 @@ void WM_OT_alembic_export(wmOperatorType *ot) RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_quad_method_items, MOD_TRIANGULATE_NGON_BEAUTY, "Polygon Method", "Method for splitting the polygons into triangles"); + RNA_def_boolean(ot->srna, "export_hair", 1, "Export Hair", "Exports hair particle systems as animated curves"); + RNA_def_boolean(ot->srna, "export_particles", 1, "Export Particles", "Exports non-hair particle systems"); + + RNA_def_boolean(ot->srna, "as_background_job", true, "Run as Background Job", + "Enable this to run the import in the background, disable to block Blender while importing"); + /* This dummy prop is used to check whether we need to init the start and * end frame values to that of the scene's, otherwise they are reset at * every change, draw update. */ @@ -482,6 +501,7 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) const bool is_sequence = RNA_boolean_get(op->ptr, "is_sequence"); const bool set_frame_range = RNA_boolean_get(op->ptr, "set_frame_range"); const bool validate_meshes = RNA_boolean_get(op->ptr, "validate_meshes"); + const bool as_background_job = RNA_boolean_get(op->ptr, "as_background_job"); int offset = 0; int sequence_len = 1; @@ -490,9 +510,11 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) sequence_len = get_sequence_len(filename, &offset); } - ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes); + bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range, + sequence_len, offset, validate_meshes, + as_background_job); - return OPERATOR_FINISHED; + return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void WM_OT_alembic_import(wmOperatorType *ot) @@ -523,6 +545,9 @@ void WM_OT_alembic_import(wmOperatorType *ot) RNA_def_boolean(ot->srna, "is_sequence", false, "Is Sequence", "Set to true if the cache is split into separate files"); + + RNA_def_boolean(ot->srna, "as_background_job", true, "Run as Background Job", + "Enable this to run the export in the background, disable to block Blender while exporting"); } #endif diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index b5adf38527b..6460e83e2a0 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -631,71 +631,63 @@ static int fluid_validate_scene(ReportList *reports, Scene *scene, Object *fsDom #define FLUID_SUFFIX_CONFIG_TMP (FLUID_SUFFIX_CONFIG ".tmp") #define FLUID_SUFFIX_SURFACE "fluidsurface" -static int fluid_init_filepaths(Object *fsDomain, char *targetDir, char *targetFile, char *debugStrBuffer) +static bool fluid_init_filepaths( + ReportList *reports, FluidsimSettings *domainSettings, Object *fsDomain, + char *targetDir, char *targetFile) { - FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); - FluidsimSettings *domainSettings= fluidmd->fss; - FILE *fileCfg; - int dirExist = 0; - char newSurfdataPath[FILE_MAX]; /* modified output settings */ const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; - int outStringsChanged = 0; /* prepare names... */ - const char *relbase= modifier_path_relbase(fsDomain); + const char *relbase = modifier_path_relbase(fsDomain); + + /* We do not accept empty paths, they can end in random places silently, see T51176. */ + if (domainSettings->surfdataPath[0] == '\0') { + modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath), + OB_FLUIDSIM_SURF_DIR_DEFAULT); + BKE_reportf(reports, RPT_WARNING, "Fluidsim: empty cache path, reset to default '%s'", + domainSettings->surfdataPath); + } BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); - BLI_strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR); /* if 0'd out below, this value is never used! */ - BLI_path_abs(targetDir, relbase); /* fixed #frame-no */ + BLI_path_abs(targetDir, relbase); /* .tmp: don't overwrite/delete original file */ BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); - // make sure all directories exist - // as the bobjs use the same dir, this only needs to be checked - // for the cfg output - BLI_make_existing_file(targetFile); - - // check selected directory - // simply try to open cfg file for writing to test validity of settings - fileCfg = BLI_fopen(targetFile, "w"); - if (fileCfg) { - dirExist = 1; fclose(fileCfg); - // remove cfg dummy from directory test - BLI_delete(targetFile, false, false); - } - - if (targetDir[0] == '\0' || (!dirExist)) { - char blendFile[FILE_MAX]; - - // invalid dir, reset to current/previous - BLI_split_file_part(G.main->name, blendFile, sizeof(blendFile)); - BLI_replace_extension(blendFile, FILE_MAX, ""); /* strip .blend */ - BLI_snprintf(newSurfdataPath, FILE_MAX, "//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name); - - BLI_snprintf(debugStrBuffer, 256, "fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath); - elbeemDebugOut(debugStrBuffer); - outStringsChanged=1; - } - - /* check if modified output dir is ok */ -#if 0 - if (outStringsChanged) { - char dispmsg[FILE_MAX+256]; - int selection=0; - BLI_strncpy(dispmsg, "Output settings set to: '", sizeof(dispmsg)); - strcat(dispmsg, newSurfdataPath); - strcat(dispmsg, "'%t|Continue with changed settings %x1|Discard and abort %x0"); - - /* ask user if thats what he/she wants... */ - selection = pupmenu(dispmsg); - if (selection < 1) return 0; /* 0 from menu, or -1 aborted */ - BLI_strncpy(targetDir, newSurfdataPath, sizeof(targetDir)); - strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR); - BLI_path_abs(targetDir, G.main->name); /* fixed #frame-no */ + /* Ensure whole path exists and is wirtable. */ + const bool dir_exists = BLI_dir_create_recursive(targetDir); + const bool is_writable = BLI_file_is_writable(targetFile); + + /* We change path to some presumably valid default value, but do not allow bake process to continue, + * this gives user chance to set manually another path. */ + if (!dir_exists || !is_writable) { + modifier_path_init(domainSettings->surfdataPath, sizeof(domainSettings->surfdataPath), + OB_FLUIDSIM_SURF_DIR_DEFAULT); + + if (!dir_exists) { + BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not create cache directory '%s', reset to default '%s'", + targetDir, domainSettings->surfdataPath); + } + else { + BKE_reportf(reports, RPT_ERROR, "Fluidsim: cache directory '%s' is not writable, reset to default '%s'", + targetDir, domainSettings->surfdataPath); + } + + BLI_strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR); + BLI_path_abs(targetDir, relbase); + + /* .tmp: don't overwrite/delete original file */ + BLI_join_dirfile(targetFile, FILE_MAX, targetDir, suffixConfigTmp); + + /* Ensure whole path exists and is wirtable. */ + if (!BLI_dir_create_recursive(targetDir) || !BLI_file_is_writable(targetFile)) { + BKE_reportf(reports, RPT_ERROR, "Fluidsim: could not use default cache directory '%s', " + "please define a valid cache path manually", targetDir); + } + return false; } -#endif - return outStringsChanged; + + return true; } /* ******************************************************************************** */ @@ -857,7 +849,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor char targetDir[FILE_MAX]; // store & modify output settings char targetFile[FILE_MAX]; // temp. store filename from targetDir for access - int outStringsChanged = 0; // modified? copy back before baking float domainMat[4][4]; float invDomMat[4][4]; @@ -943,7 +934,11 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor /* ******** prepare output file paths ******** */ - outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); + if (!fluid_init_filepaths(reports, domainSettings, fsDomain, targetDir, targetFile)) { + fluidbake_free_data(channels, fobjects, fsset, fb); + return false; + } + channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames; @@ -968,11 +963,6 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor /* ******** start writing / exporting ******** */ // use .tmp, don't overwrite/delete original file BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); - - // make sure these directories exist as well - if (outStringsChanged) { - BLI_make_existing_file(targetFile); - } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 93bac3f6660..216cbe9d7f4 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -566,7 +566,7 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo float rast_x = x + off_x * xzoom; float rast_y = y + off_y * yzoom; - GLfloat scissor[4]; + GLfloat viewport[4]; int draw_w, draw_h; /* Determine the smallest number of pixels we need to draw @@ -581,9 +581,9 @@ void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int fo * fails if we zoom in on one really huge pixel so that it * covers the entire screen). */ - glGetFloatv(GL_SCISSOR_BOX, scissor); - draw_w = min_ii(img_w - off_x, ceil((scissor[2] - rast_x) / xzoom)); - draw_h = min_ii(img_h - off_y, ceil((scissor[3] - rast_y) / yzoom)); + glGetFloatv(GL_VIEWPORT, viewport); + draw_w = min_ii(img_w - off_x, ceil((viewport[2] - rast_x) / xzoom)); + draw_h = min_ii(img_h - off_y, ceil((viewport[3] - rast_y) / yzoom)); if (draw_w > 0 && draw_h > 0) { diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index e4f5802a395..8dba0e39524 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1234,6 +1234,7 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_BSDF_GLOSSY: case SH_NODE_BSDF_GLASS: case SH_NODE_BSDF_REFRACTION: + case SH_NODE_BSDF_PRINCIPLED: ntype->draw_buttons = node_shader_buts_glossy; break; case SH_NODE_BSDF_ANISOTROPIC: diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 0d92d22a173..6db23686832 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -98,6 +98,7 @@ typedef enum GPUBuiltin { GPU_PARTICLE_ANG_VELOCITY = (1 << 12), GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), + GPU_OBJECT_INFO = (1 << 15) } GPUBuiltin; typedef enum GPUOpenGLBuiltin { @@ -213,6 +214,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); void GPU_material_enable_alpha(GPUMaterial *material); +GPUBuiltin GPU_get_material_builtins(GPUMaterial *material); GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); /* High level functions to create and use GPU materials */ @@ -230,7 +232,7 @@ void GPU_material_bind( float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); void GPU_material_bind_uniforms( GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi); + float autobumpscale, GPUParticleInfo *pi, float object_info[3]); void GPU_material_unbind(GPUMaterial *material); bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); @@ -345,6 +347,7 @@ struct GPUParticleInfo float location[3]; float velocity[3]; float angular_velocity[3]; + int random_id; }; #ifdef WITH_OPENSUBDIV diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index c3896fbd659..b5512aa108d 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -410,6 +410,8 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfparticlevel"; else if (builtin == GPU_PARTICLE_ANG_VELOCITY) return "unfparticleangvel"; + else if (builtin == GPU_OBJECT_INFO) + return "unfobjectinfo"; else return ""; } diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 964c2b5051e..2f2a16f9e1d 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -798,7 +798,9 @@ bool GPU_fx_do_composite_pass( ssao_shader = GPU_shader_get_builtin_fx_shader(GPU_SHADER_FX_SSAO, is_persp); if (ssao_shader) { const GPUSSAOSettings *fx_ssao = fx->settings.ssao; - float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, fx_ssao->attenuation, 0.0f}; + /* adjust attenuation to be scale invariant */ + float attenuation = fx_ssao->attenuation / (fx_ssao->distance_max * fx_ssao->distance_max); + float ssao_params[4] = {fx_ssao->distance_max, fx_ssao->factor, attenuation, 0.0f}; float sample_params[3]; sample_params[0] = fx->ssao_sample_count_cache; diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 074fadf6003..79934190cbc 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -45,6 +45,7 @@ #include "BLI_math.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_hash.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" @@ -1899,6 +1900,21 @@ static int gpu_get_particle_info(GPUParticleInfo *pi) return 0; } +static void GPU_get_object_info(float oi[3], Material *mat) +{ + Object *ob = GMS.gob; + oi[0] = ob->index; + oi[1] = mat->index; + unsigned int random; + if (GMS.dob) { + random = GMS.dob->random_id; + } + else { + random = BLI_hash_int_2d(BLI_hash_string(GMS.gob->id.name + 2), 0); + } + oi[2] = random * (1.0f/(float)0xFFFFFFFF); +} + int GPU_object_material_bind(int nr, void *attribs) { GPUVertexAttribs *gattribs = attribs; @@ -1958,6 +1974,7 @@ int GPU_object_material_bind(int nr, void *attribs) /* bind glsl material and get attributes */ Material *mat = GMS.gmatbuf[nr]; GPUParticleInfo partile_info; + float object_info[3] = {0}; float auto_bump_scale; @@ -1967,13 +1984,17 @@ int GPU_object_material_bind(int nr, void *attribs) if (GMS.dob) { gpu_get_particle_info(&partile_info); } + + if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) { + GPU_get_object_info(object_info, mat); + } GPU_material_bind( gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info); + GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info); GMS.gboundmat = mat; /* for glsl use alpha blend mode, unless it's set to solid and diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index d3ea8e13691..1f3ae7f708a 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -122,6 +122,8 @@ struct GPUMaterial { int partvel; int partangvel; + int objectinfoloc; + ListBase lamps; bool bound; @@ -268,6 +270,8 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY)); if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY)); + if (material->builtins & GPU_OBJECT_INFO) + material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO)); return 1; } else { @@ -398,9 +402,14 @@ void GPU_material_bind( } } +GPUBuiltin GPU_get_material_builtins(GPUMaterial *material) +{ + return material->builtins; +} + void GPU_material_bind_uniforms( GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi) + float autobumpscale, GPUParticleInfo *pi, float object_info[3]) { if (material->pass) { GPUShader *shader = GPU_pass_shader(material->pass); @@ -449,6 +458,9 @@ void GPU_material_bind_uniforms( if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) { GPU_shader_uniform_vector(shader, material->partangvel, 3, 1, pi->angular_velocity); } + if (material->builtins & GPU_OBJECT_INFO) { + GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info); + } } } diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 14f2764b009..b579f87698c 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -39,6 +39,7 @@ #include "GPU_glew.h" #include "GPU_shader.h" #include "GPU_texture.h" +#include "GPU_material.h" /* TODO(sergey): Find better default values for this constants. */ #define MAX_DEFINE_LENGTH 1024 diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index 50c8e255162..f19ff4ec65a 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -75,7 +75,7 @@ float calculate_ssao_factor(float depth) float f = dot(dir, normal); /* use minor bias here to avoid self shadowing */ - if (f > 0.05 * len + 0.0001) + if (f > 0.05 * len) factor += f * 1.0 / (len * (1.0 + len * len * ssao_params.z)); } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 0f3ffa8244b..b88fba12f55 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2378,11 +2378,19 @@ void shade_alpha_obcolor(vec4 col, vec4 obcol, out vec4 outcol) /*********** NEW SHADER UTILITIES **************/ -float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) +float fresnel_dielectric_0(float eta) +{ + /* compute fresnel reflactance at normal incidence => cosi = 1.0 */ + float A = (eta - 1.0) / (eta + 1.0); + + return A * A; +} + +float fresnel_dielectric_cos(float cosi, float eta) { /* compute fresnel reflectance without explicitly computing * the refracted direction */ - float c = abs(dot(Incoming, Normal)); + float c = abs(cosi); float g = eta * eta - 1.0 + c * c; float result; @@ -2399,6 +2407,13 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) return result; } +float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) +{ + /* compute fresnel reflectance without explicitly computing + * the refracted direction */ + return fresnel_dielectric_cos(dot(Incoming, Normal), eta); +} + float hypot(float x, float y) { return sqrt(x * x + y * y); @@ -2492,6 +2507,57 @@ float floorfrac(float x, out int i) return x - i; } + +/* Principled BSDF operations */ + +float sqr(float a) +{ + return a*a; +} + +float schlick_fresnel(float u) +{ + float m = clamp(1.0 - u, 0.0, 1.0); + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) +{ + if (a >= 1.0) return M_1_PI; + float a2 = a*a; + float t = 1.0 + (a2 - 1.0) * NdotH*NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + +float GTR2(float NdotH, float a) +{ + float a2 = a*a; + float t = 1.0 + (a2 - 1.0) * NdotH*NdotH; + return a2 / (M_PI * t*t); +} + +float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay) +{ + return 1.0 / (M_PI * ax*ay * sqr(sqr(HdotX / ax) + sqr(HdotY / ay) + NdotH*NdotH)); +} + +float smithG_GGX(float NdotV, float alphaG) +{ + float a = alphaG*alphaG; + float b = NdotV*NdotV; + return 1.0 / (NdotV + sqrt(a + b - a * b)); +} + +vec3 rotate_vector(vec3 p, vec3 n, float theta) { + return ( + p * cos(theta) + cross(n, p) * + sin(theta) + n * dot(p, n) * + (1.0 - cos(theta)) + ); +} + + /*********** NEW SHADER NODES ***************/ #define NUM_LIGHTS 3 @@ -2553,6 +2619,126 @@ void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 resu node_bsdf_diffuse(color, 0.0, N, result); } +void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular, + float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat, + float clearcoat_gloss, float ior, float transparency, float refraction_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result) +{ + /* ambient light */ + // TODO: set ambient light to an appropriate value + vec3 L = vec3(mix(0.1, 0.03, metallic)) * base_color.rgb; + + float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0; + + /* set the viewing vector */ + vec3 V = -normalize(I); + + /* get the tangent */ + vec3 Tangent = T; + if (T == vec3(0.0)) { + // if no tangent is set, use a default tangent + Tangent = vec3(1.0, 0.0, 0.0); + if (N.x != 0.0 || N.y != 0.0) { + vec3 N_xz = normalize(vec3(N.x, 0.0, N.z)); + + vec3 axis = normalize(cross(vec3(0.0, 0.0, 1.0), N_xz)); + float angle = acos(dot(vec3(0.0, 0.0, 1.0), N_xz)); + + Tangent = normalize(rotate_vector(vec3(1.0, 0.0, 0.0), axis, angle)); + } + } + + /* rotate tangent */ + if (anisotropic_rotation != 0.0) { + Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI); + } + + /* calculate the tangent and bitangent */ + vec3 Y = normalize(cross(N, Tangent)); + vec3 X = cross(Y, N); + + /* fresnel normalization parameters */ + float F0 = fresnel_dielectric_0(eta); + float F0_norm = 1.0 / (1.0 - F0); + + /* directional lights */ + for (int i = 0; i < NUM_LIGHTS; i++) { + vec3 light_position_world = gl_LightSource[i].position.xyz; + vec3 light_position = normalize(gl_NormalMatrix * light_position_world); + + vec3 H = normalize(light_position + V); + + vec3 light_specular = gl_LightSource[i].specular.rgb; + + float NdotL = dot(N, light_position); + float NdotV = dot(N, V); + float LdotH = dot(light_position, H); + + vec3 diffuse_and_specular_bsdf = vec3(0.0); + if (NdotL >= 0.0 && NdotV >= 0.0) { + float NdotH = dot(N, H); + + float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx. + + vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat + vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic); + vec3 Csheen = mix(vec3(1.0), Ctint, sheen_tint); + + // Diffuse fresnel - go from 1 at normal incidence to .5 at grazing + // and mix in diffuse retro-reflection based on roughness + + float FL = schlick_fresnel(NdotL), FV = schlick_fresnel(NdotV); + float Fd90 = 0.5 + 2.0 * LdotH*LdotH * roughness; + float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV); + + // Based on Hanrahan-Krueger brdf approximation of isotropic bssrdf + // 1.25 scale is used to (roughly) preserve albedo + // Fss90 used to "flatten" retroreflection based on roughness + float Fss90 = LdotH*LdotH * roughness; + float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV); + float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5); + + // specular + float aspect = sqrt(1.0 - anisotropic * 0.9); + float a = sqr(roughness); + float ax = max(0.001, a / aspect); + float ay = max(0.001, a * aspect); + float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a); + float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm; + vec3 Fs = mix(Cspec0, vec3(1.0), FH); + float roughg = sqr(roughness * 0.5 + 0.5); + float Gs = smithG_GGX(NdotL, roughg) * smithG_GGX(NdotV, roughg); + + // sheen + vec3 Fsheen = schlick_fresnel(LdotH) * sheen * Csheen; + + diffuse_and_specular_bsdf = (M_1_PI * mix(Fd, ss, subsurface) * base_color.rgb + Fsheen) + * (1.0 - metallic) + Gs * Fs * Ds; + } + diffuse_and_specular_bsdf *= max(NdotL, 0.0); + + float CNdotL = dot(CN, light_position); + float CNdotV = dot(CN, V); + + vec3 clearcoat_bsdf = vec3(0.0); + if (CNdotL >= 0.0 && CNdotV >= 0.0 && clearcoat > 0.0) { + float CNdotH = dot(CN, H); + //float FH = schlick_fresnel(LdotH); + + // clearcoat (ior = 1.5 -> F0 = 0.04) + float Dr = GTR1(CNdotH, mix(0.1, 0.001, clearcoat_gloss)); + float Fr = fresnel_dielectric_cos(LdotH, 1.5); //mix(0.04, 1.0, FH); + float Gr = smithG_GGX(CNdotL, 0.25) * smithG_GGX(CNdotV, 0.25); + + clearcoat_bsdf = clearcoat * Gr * Fr * Dr * vec3(0.25); + } + clearcoat_bsdf *= max(CNdotL, 0.0); + + L += light_specular * (diffuse_and_specular_bsdf + clearcoat_bsdf); + } + + result = vec4(L, 1.0); +} + void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result) { node_bsdf_diffuse(color, 0.0, N, result); @@ -3563,12 +3749,12 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out constant = strength; } -void node_object_info(out vec3 location, out float object_index, out float material_index, out float random) +void node_object_info(mat4 obmat, vec3 info, out vec3 location, out float object_index, out float material_index, out float random) { - location = vec3(0.0); - object_index = 0.0; - material_index = 0.0; - random = 0.0; + location = obmat[3].xyz; + object_index = info.x; + material_index = info.y; + random = info.z; } void node_normal_map(vec4 tangent, vec3 normal, vec3 texnormal, out vec3 outnormal) diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h index a714195dd5d..846d5788d63 100644 --- a/source/blender/makesdna/DNA_object_fluidsim.h +++ b/source/blender/makesdna/DNA_object_fluidsim.h @@ -179,6 +179,7 @@ typedef struct FluidsimSettings { #define OB_FLUIDSIM_ACTIVE (1 << 1) #define OB_FLUIDSIM_OVERRIDE_TIME (1 << 2) +#define OB_FLUIDSIM_SURF_DIR_DEFAULT "cache_fluid" #define OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME "fluidsurface_preview_####.bobj.gz" #define OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME "fluidsurface_final_####.bobj.gz" #define OB_FLUIDSIM_SURF_FINAL_VEL_FNAME "fluidsurface_final_####.bvel.gz" diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index d24c7faa9f5..6d79e6d49f8 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -335,6 +335,8 @@ typedef struct DupliObject { /* particle this dupli was generated from */ struct ParticleSystem *particle_system; + unsigned int random_id; + unsigned int pad; } DupliObject; /* **************** OBJECT ********************* */ diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 6ed2c55138c..a74758a4f71 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -342,7 +342,7 @@ static void rna_ID_user_clear(ID *id) static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) { - if (GS(id->name) == GS(new_id->name)) { + if ((GS(id->name) == GS(new_id->name)) && (id != new_id)) { /* For now, do not allow remapping data in linked data from here... */ BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); } diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 8d42d746e1c..c3477644979 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2995,6 +2995,15 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p ED_node_tag_update_nodetree(bmain, ntree, node); } +static void rna_ShaderNodePrincipled_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bNodeTree *ntree = (bNodeTree *)ptr->id.data; + bNode *node = (bNode *)ptr->data; + + nodeUpdate(ntree, node); + rna_Node_update(bmain, scene, ptr); +} + static void rna_ShaderNodeSubsurface_update(Main *bmain, Scene *scene, PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->id.data; @@ -3254,6 +3263,12 @@ static EnumPropertyItem node_script_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem node_principled_distribution_items[] = { + { SHD_GLOSSY_GGX, "GGX", 0, "GGX", "" }, + { SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", "" }, + { 0, NULL, 0, NULL, NULL } +}; + /* -- Common nodes ---------------------------------------------------------- */ static void def_group_input(StructRNA *srna) @@ -4188,6 +4203,17 @@ static void def_glass(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_principled(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_principled_distribution_items); + RNA_def_property_ui_text(prop, "Distribution", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodePrincipled_update"); +} + static void def_refraction(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index b3c166a6810..ec6a03e713d 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2897,6 +2897,10 @@ static void rna_def_dupli_object(BlenderRNA *brna) RNA_def_property_enum_items(prop, dupli_items); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "Dupli Type", "Duplicator type that generated this dupli object"); + + prop = RNA_def_property(srna, "random_id", PROP_INT, PROP_UNSIGNED); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Dupli random id", "Random id for this dupli object"); } static void rna_def_object_base(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index c680abe71a4..9b9f0705bb4 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -321,49 +321,55 @@ static void rna_Object_ray_cast( float origin[3], float direction[3], float distance, int *r_success, float r_location[3], float r_normal[3], int *r_index) { - BVHTreeFromMesh treeData = {NULL}; - + bool success = false; + if (ob->derivedFinal == NULL) { BKE_reportf(reports, RPT_ERROR, "Object '%s' has no mesh data to be used for ray casting", ob->id.name + 2); return; } - /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ - bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6); + /* Test BoundBox first (efficiency) */ + BoundBox *bb = BKE_object_boundbox_get(ob); + float distmin; + if (!bb || (isect_ray_aabb_v3_simple(origin, direction, bb->vec[0], bb->vec[6], &distmin, NULL) && distmin <= distance)) { - /* may fail if the mesh has no faces, in that case the ray-cast misses */ - if (treeData.tree != NULL) { - BVHTreeRayHit hit; + BVHTreeFromMesh treeData = {NULL}; - hit.index = -1; - hit.dist = distance; - - normalize_v3(direction); + /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ + bvhtree_from_mesh_looptri(&treeData, ob->derivedFinal, 0.0f, 4, 6); + + /* may fail if the mesh has no faces, in that case the ray-cast misses */ + if (treeData.tree != NULL) { + BVHTreeRayHit hit; + hit.index = -1; + hit.dist = distance; - if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit, - treeData.raycast_callback, &treeData) != -1) - { - if (hit.dist <= distance) { - *r_success = true; + normalize_v3(direction); - copy_v3_v3(r_location, hit.co); - copy_v3_v3(r_normal, hit.no); - *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]); - goto finally; + if (BLI_bvhtree_ray_cast(treeData.tree, origin, direction, 0.0f, &hit, + treeData.raycast_callback, &treeData) != -1) + { + if (hit.dist <= distance) { + *r_success = success = true; + + copy_v3_v3(r_location, hit.co); + copy_v3_v3(r_normal, hit.no); + *r_index = dm_looptri_to_poly_index(ob->derivedFinal, &treeData.looptri[hit.index]); + } } + + free_bvhtree_from_mesh(&treeData); } } + if (success == false) { + *r_success = false; - *r_success = false; - - zero_v3(r_location); - zero_v3(r_normal); - *r_index = -1; - -finally: - free_bvhtree_from_mesh(&treeData); + zero_v3(r_location); + zero_v3(r_normal); + *r_index = -1; + } } static void rna_Object_closest_point_on_mesh( diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 9b202120b82..d3487fca42e 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -208,6 +208,8 @@ static void rna_Scene_alembic_export( int renderable_only, int face_sets, int use_subdiv_schema, + int export_hair, + int export_particles, int compression_type, int packuv, float scale, @@ -241,6 +243,8 @@ static void rna_Scene_alembic_export( .renderable_only = renderable_only, .face_sets = face_sets, .use_subdiv_schema = use_subdiv_schema, + .export_hair = export_hair, + .export_particles = export_particles, .compression_type = compression_type, .packuv = packuv, .triangulate = triangulate, @@ -250,7 +254,7 @@ static void rna_Scene_alembic_export( .global_scale = scale, }; - ABC_export(scene, C, filepath, ¶ms); + ABC_export(scene, C, filepath, ¶ms, true); #ifdef WITH_PYTHON BPy_END_ALLOW_THREADS; @@ -435,8 +439,9 @@ void RNA_api_scene(StructRNA *srna) #endif #ifdef WITH_ALEMBIC + /* XXX Deprecated, will be removed in 2.8 in favour of calling the export operator. */ func = RNA_def_function(srna, "alembic_export", "rna_Scene_alembic_export"); - RNA_def_function_ui_description(func, "Export to Alembic file"); + RNA_def_function_ui_description(func, "Export to Alembic file (deprecated, use the Alembic export operator)"); parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Alembic file"); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); @@ -458,6 +463,8 @@ void RNA_api_scene(StructRNA *srna) RNA_def_boolean(func, "renderable_only" , 0, "Renderable objects only", "Export only objects marked renderable in the outliner"); RNA_def_boolean(func, "face_sets" , 0, "Facesets", "Export face sets"); RNA_def_boolean(func, "subdiv_schema", 0, "Use Alembic subdivision Schema", "Use Alembic subdivision Schema"); + RNA_def_boolean(func, "export_hair", 1, "Export Hair", "Exports hair particle systems as animated curves"); + RNA_def_boolean(func, "export_particles", 1, "Export Particles", "Exports non-hair particle systems"); RNA_def_enum(func, "compression_type", rna_enum_abc_compression_items, 0, "Compression", ""); RNA_def_boolean(func, "packuv" , 0, "Export with packed UV islands", "Export with packed UV islands"); RNA_def_float(func, "scale", 1.0f, 0.0001f, 1000.0f, "Scale", "Value by which to enlarge or shrink the objects with respect to the world's origin", 0.0001f, 1000.0f); diff --git a/source/blender/modifiers/intern/MOD_fluidsim_util.c b/source/blender/modifiers/intern/MOD_fluidsim_util.c index ffbbb1b0745..2ecf06057db 100644 --- a/source/blender/modifiers/intern/MOD_fluidsim_util.c +++ b/source/blender/modifiers/intern/MOD_fluidsim_util.c @@ -78,8 +78,8 @@ void fluidsim_init(FluidsimModifierData *fluidmd) fss->resolutionxyz = 65; fss->previewresxyz = 45; fss->realsize = 0.5; - fss->guiDisplayMode = 2; // preview - fss->renderDisplayMode = 3; // render + fss->guiDisplayMode = OB_FSDOM_PREVIEW; + fss->renderDisplayMode = OB_FSDOM_FINAL; fss->viscosityValue = 1.0; fss->viscosityExponent = 6; @@ -98,7 +98,7 @@ void fluidsim_init(FluidsimModifierData *fluidmd) /* fluid/inflow settings * fss->iniVel --> automatically set to 0 */ - modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), "cache_fluid"); + modifier_path_init(fss->surfdataPath, sizeof(fss->surfdataPath), OB_FLUIDSIM_SURF_DIR_DEFAULT); /* first init of bounding box */ /* no bounding box needed */ @@ -423,8 +423,6 @@ static void fluidsim_read_vel_cache(FluidsimModifierData *fluidmd, DerivedMesh * static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifierData *fluidmd, int framenr, int useRenderParams) { - int displaymode = 0; - int curFrame = framenr /* - 1 */ /*scene->r.sfra*/; /* start with 0 at start frame */ /* why start with 0 as start frame?? Animations + time are frozen for frame 0 anyway. (See physics_fluid.c for that. - DG */ /* If we start with frame 0, we need to remap all animation channels, too, because they will all be 1 frame late if using frame-1! - DG */ @@ -435,25 +433,23 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, MPoly *mpoly; MPoly mp_example = {0}; - if (!useRenderParams) { - displaymode = fss->guiDisplayMode; - } - else { - displaymode = fss->renderDisplayMode; - } + const int displaymode = useRenderParams ? fss->renderDisplayMode : fss->guiDisplayMode; switch (displaymode) { - case 1: + case OB_FSDOM_GEOM: /* just display original object */ return NULL; - case 2: + case OB_FSDOM_PREVIEW: /* use preview mesh */ BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_PREVIEW_OBJ_FNAME); break; - default: /* 3 */ - /* 3. use final mesh */ + case OB_FSDOM_FINAL: + /* use final mesh */ BLI_join_dirfile(targetFile, sizeof(targetFile), fss->surfdataPath, OB_FLUIDSIM_SURF_FINAL_OBJ_FNAME); break; + default: + BLI_assert(!"Wrong fluidsim display type"); + return NULL; } /* offset baked frame */ @@ -494,7 +490,7 @@ static DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, /* load vertex velocities, if they exist... * TODO? use generate flag as loading flag as well? * warning, needs original .bobj.gz mesh loading filename */ - if (displaymode == 3) { + if (displaymode == OB_FSDOM_FINAL) { fluidsim_read_vel_cache(fluidmd, dm, targetFile); } else { diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index d20881df150..3596a2aa12d 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -163,6 +163,7 @@ set(SRC shader/nodes/node_shader_background.c shader/nodes/node_shader_bsdf_anisotropic.c shader/nodes/node_shader_bsdf_diffuse.c + shader/nodes/node_shader_bsdf_principled.c shader/nodes/node_shader_bsdf_glass.c shader/nodes/node_shader_bsdf_glossy.c shader/nodes/node_shader_bsdf_toon.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 4c0047f1d58..804c1897a27 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -106,6 +106,7 @@ void register_node_type_sh_bsdf_transparent(void); void register_node_type_sh_bsdf_velvet(void); void register_node_type_sh_bsdf_toon(void); void register_node_type_sh_bsdf_anisotropic(void); +void register_node_type_sh_bsdf_principled(void); void register_node_type_sh_emission(void); void register_node_type_sh_holdout(void); void register_node_type_sh_volume_absorption(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index a9c0df7d7e8..e754d063397 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -80,6 +80,7 @@ DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BA DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" ) DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" ) +DefNode( ShaderNode, SH_NODE_BSDF_PRINCIPLED, def_principled, "BSDF_PRINCIPLED", BsdfPrincipled, "Principled BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c new file mode 100644 index 00000000000..8b0bfa36324 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -0,0 +1,114 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** OUTPUT ******************** */ + +static bNodeSocketTemplate sh_node_bsdf_principled_in[] = { + { SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f}, + { SOCK_RGBA, 1, N_("Subsurface Color"), 0.7f, 0.1f, 0.1f, 1.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Specular Tint"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Roughness"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Anisotropic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Anisotropic Rotation"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Sheen"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Sheen Tint"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Clearcoat"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Clearcoat Gloss"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, + { SOCK_FLOAT, 1, N_("Transparency"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_FLOAT, 1, N_("Refraction Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, + { SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_VECTOR, 1, N_("Clearcoat Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_VECTOR, 1, N_("Tangent"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_bsdf_principled_out[] = { + { SOCK_SHADER, 0, N_("BSDF")}, + { -1, 0, "" } +}; + +static void node_shader_init_principled(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->custom1 = SHD_GLOSSY_MULTI_GGX; +} + +static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + // normal + if (!in[17].link) + in[17].link = GPU_builtin(GPU_VIEW_NORMAL); + else + GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link); + + // clearcoat normal + if (!in[18].link) + in[18].link = GPU_builtin(GPU_VIEW_NORMAL); + else + GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link); + + return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION)); +} + +static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock; + int distribution = node->custom1; + + for (sock = node->inputs.first; sock; sock = sock->next) { + if (STREQ(sock->name, "Refraction Roughness")) { + if (distribution == SHD_GLOSSY_GGX) + sock->flag &= ~SOCK_UNAVAIL; + else + sock->flag |= SOCK_UNAVAIL; + + } + } +} + +/* node type definition */ +void register_node_type_sh_bsdf_principled(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out); + node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); + node_type_init(&ntype, node_shader_init_principled); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, node_shader_gpu_bsdf_principled); + node_type_update(&ntype, node_shader_update_principled, NULL); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c index d1905246fd4..165d565a5b4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c @@ -39,7 +39,16 @@ static bNodeSocketTemplate sh_node_object_info_out[] = { static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "node_object_info", in, out); + return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO)); +} + +static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out) +{ + ShaderCallData *scd = (ShaderCallData *)data; + copy_v4_v4(out[0]->vec, RE_object_instance_get_matrix(scd->shi->obi, RE_OBJECT_INSTANCE_MATRIX_OB)[3]); + out[1]->vec[0] = RE_object_instance_get_object_pass_index(scd->shi->obi); + out[2]->vec[0] = scd->shi->mat->index; + out[3]->vec[0] = RE_object_instance_get_random_id(scd->shi->obi) * (1.0f/(float)0xFFFFFFFF);; } /* node type definition */ @@ -53,6 +62,7 @@ void register_node_type_sh_object_info(void) node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_object_info); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info); nodeRegisterType(&ntype); } diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index f535aa5aa71..eaa4cf2c69c 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -381,7 +381,7 @@ bool RE_allow_render_generic_object(struct Object *ob); /* RE_updateRenderInstances flag */ enum { RE_OBJECT_INSTANCES_UPDATE_VIEW = (1 << 0), - RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1), + RE_OBJECT_INSTANCES_UPDATE_OBMAT = (1 << 1) }; void RE_updateRenderInstances(Render *re, int flag); diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index ae389fdfd2e..b64c0c8fc52 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -178,6 +178,7 @@ typedef struct ShadeInput { unsigned int lay; int layflag, passflag, combinedflag; + short object_pass_index; struct Group *light_override; struct Material *mat_override; @@ -241,6 +242,9 @@ enum { const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4]; +float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi); +float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi); + enum { RE_VIEW_MATRIX, RE_VIEWINV_MATRIX, diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index b3a5ccdae17..f0323340899 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -382,6 +382,8 @@ typedef struct ObjectInstanceRen { float part_co[3]; float part_vel[3]; float part_avel[3]; + + unsigned int random_id; } ObjectInstanceRen; /* ------------------------------------------------------------------------- */ diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c index 76e6ca8d467..199322795f3 100644 --- a/source/blender/render/intern/source/renderdatabase.c +++ b/source/blender/render/intern/source/renderdatabase.c @@ -66,6 +66,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_hash.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" @@ -1458,6 +1459,14 @@ ObjectInstanceRen *RE_addRenderInstance( } } + /* Fill object info */ + if (dob) { + obi->random_id = dob->random_id; + } + else { + obi->random_id = BLI_hash_int_2d(BLI_hash_string(obi->ob->id.name + 2), 0); + } + RE_updateRenderInstance(re, obi, RE_OBJECT_INSTANCES_UPDATE_OBMAT | RE_OBJECT_INSTANCES_UPDATE_VIEW); if (mat) { diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index a8fb72fb7f8..8dea0930b9e 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -2141,6 +2141,16 @@ const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int m return NULL; } +float RE_object_instance_get_object_pass_index(struct ObjectInstanceRen *obi) +{ + return obi->ob->index; +} + +float RE_object_instance_get_random_id(struct ObjectInstanceRen *obi) +{ + return obi->random_id; +} + const float (*RE_render_current_get_matrix(int matrix_id))[4] { switch (matrix_id) { |