diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2020-02-02 14:04:19 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2020-02-07 14:18:15 +0300 |
commit | d9c5f0d25fc91b069158ae1ab4fddc21bfd85846 (patch) | |
tree | 18f55163c5b06385d055d5a79a4c653d3da6e595 | |
parent | 46c9872afaa8053f8b2894c038402b1beb3ac66c (diff) |
Cleanup: split Cycles Hair and Mesh classes, with Geometry base class
56 files changed, 3509 insertions, 2931 deletions
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index bdb014d31ef..2540786a014 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -380,11 +380,11 @@ static Mesh *xml_add_mesh(Scene *scene, const Transform &tfm) { /* create mesh */ Mesh *mesh = new Mesh(); - scene->meshes.push_back(mesh); + scene->geometry.push_back(mesh); /* create object*/ Object *object = new Object(); - object->mesh = mesh; + object->geometry = mesh; object->tfm = tfm; scene->objects.push_back(object); diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index e42151d8f48..affd5685337 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -17,6 +17,7 @@ #include "render/attribute.h" #include "render/camera.h" #include "render/curves.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/object.h" #include "render/scene.h" @@ -107,12 +108,12 @@ static void InterpolateKeySegments( } static bool ObtainCacheParticleData( - Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background) + Geometry *geom, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background) { int curvenum = 0; int keyno = 0; - if (!(mesh && b_mesh && b_ob && CData)) + if (!(geom && b_mesh && b_ob && CData)) return false; Transform tfm = get_transform(b_ob->matrix_world()); @@ -128,7 +129,7 @@ static bool ObtainCacheParticleData( if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) && (b_part.type() == BL::ParticleSettings::type_HAIR)) { - int shader = clamp(b_part.material() - 1, 0, mesh->used_shaders.size() - 1); + int shader = clamp(b_part.material() - 1, 0, geom->used_shaders.size() - 1); int display_step = background ? b_part.render_step() : b_part.display_step(); int totparts = b_psys.particles.length(); int totchild = background ? b_psys.child_particles.length() : @@ -202,14 +203,14 @@ static bool ObtainCacheParticleData( return true; } -static bool ObtainCacheParticleUV(Mesh *mesh, +static bool ObtainCacheParticleUV(Geometry *geom, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num) { - if (!(mesh && b_mesh && b_ob && CData)) + if (!(geom && b_mesh && b_ob && CData)) return false; CData->curve_uv.clear(); @@ -265,14 +266,14 @@ static bool ObtainCacheParticleUV(Mesh *mesh, return true; } -static bool ObtainCacheParticleVcol(Mesh *mesh, +static bool ObtainCacheParticleVcol(Geometry *geom, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num) { - if (!(mesh && b_mesh && b_ob && CData)) + if (!(geom && b_mesh && b_ob && CData)) return false; CData->curve_vcol.clear(); @@ -594,21 +595,55 @@ static void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, in /* texture coords still needed */ } -static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) +static void export_hair_motion_validate_attribute(Hair *hair, + int motion_step, + int num_motion_keys, + bool have_motion) +{ + Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + const int num_keys = hair->curve_keys.size(); + + if (num_motion_keys != num_keys || !have_motion) { + /* No motion or hair "topology" changed, remove attributes again. */ + if (num_motion_keys != num_keys) { + VLOG(1) << "Hair topology changed, removing attribute."; + } + else { + VLOG(1) << "No motion, removing attribute."; + } + hair->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); + } + else if (motion_step > 0) { + VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; + + /* Motion, fill up previous steps that we might have skipped because + * they had no motion, but we need them anyway now. */ + for (int step = 0; step < motion_step; step++) { + float4 *mP = attr_mP->data_float4() + step * num_keys; + + for (int key = 0; key < num_keys; key++) { + mP[key] = float3_to_float4(hair->curve_keys[key]); + mP[key].w = hair->curve_radius[key]; + } + } + } +} + +static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData) { int num_keys = 0; int num_curves = 0; - if (mesh->num_curves()) + if (hair->num_curves()) return; Attribute *attr_intercept = NULL; Attribute *attr_random = NULL; - if (mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) - attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); - if (mesh->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) - attr_random = mesh->curve_attributes.add(ATTR_STD_CURVE_RANDOM); + if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) + attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT); + if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) + attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM); /* compute and reserve size of arrays */ for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { @@ -621,10 +656,10 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa } if (num_curves > 0) { - VLOG(1) << "Exporting curve segments for mesh " << mesh->name; + VLOG(1) << "Exporting curve segments for mesh " << hair->name; } - mesh->reserve_curves(mesh->num_curves() + num_curves, mesh->curve_keys.size() + num_keys); + hair->reserve_curves(hair->num_curves() + num_curves, hair->curve_keys.size() + num_keys); num_keys = 0; num_curves = 0; @@ -649,7 +684,7 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa (curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1)) { radius = 0.0f; } - mesh->add_curve_key(ickey_loc, radius); + hair->add_curve_key(ickey_loc, radius); if (attr_intercept) attr_intercept->add(time); @@ -660,16 +695,16 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa attr_random->add(hash_uint2_to_float(num_curves, 0)); } - mesh->add_curve(num_keys, CData->psys_shader[sys]); + hair->add_curve(num_keys, CData->psys_shader[sys]); num_keys += num_curve_keys; num_curves++; } } /* check allocation */ - if ((mesh->curve_keys.size() != num_keys) || (mesh->num_curves() != num_curves)) { + if ((hair->curve_keys.size() != num_keys) || (hair->num_curves() != num_curves)) { VLOG(1) << "Allocation failed, clearing data"; - mesh->clear(); + hair->clear(); } } @@ -713,24 +748,24 @@ static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int cu return lerp(mP, mP2, remainder); } -static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int motion_step) +static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step) { - VLOG(1) << "Exporting curve motion segments for mesh " << mesh->name << ", motion step " + VLOG(1) << "Exporting curve motion segments for hair " << hair->name << ", motion step " << motion_step; /* find attribute */ - Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); bool new_attribute = false; /* add new attribute if it doesn't exist already */ if (!attr_mP) { VLOG(1) << "Creating new motion vertex position attribute"; - attr_mP = mesh->curve_attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + attr_mP = hair->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); new_attribute = true; } /* export motion vectors for curve keys */ - size_t numkeys = mesh->curve_keys.size(); + size_t numkeys = hair->curve_keys.size(); float4 *mP = attr_mP->data_float4() + motion_step * numkeys; bool have_motion = false; int i = 0; @@ -741,24 +776,24 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { /* Curve lengths may not match! Curves can be clipped. */ - int curve_key_end = (num_curves + 1 < (int)mesh->curve_first_key.size() ? - mesh->curve_first_key[num_curves + 1] : - (int)mesh->curve_keys.size()); - const int num_center_curve_keys = curve_key_end - mesh->curve_first_key[num_curves]; + int curve_key_end = (num_curves + 1 < (int)hair->curve_first_key.size() ? + hair->curve_first_key[num_curves + 1] : + (int)hair->curve_keys.size()); + const int num_center_curve_keys = curve_key_end - hair->curve_first_key[num_curves]; const int is_num_keys_different = CData->curve_keynum[curve] - num_center_curve_keys; if (!is_num_keys_different) { for (int curvekey = CData->curve_firstkey[curve]; curvekey < CData->curve_firstkey[curve] + CData->curve_keynum[curve]; curvekey++) { - if (i < mesh->curve_keys.size()) { + if (i < hair->curve_keys.size()) { mP[i] = CurveSegmentMotionCV(CData, sys, curve, curvekey); if (!have_motion) { /* unlike mesh coordinates, these tend to be slightly different * between frames due to particle transforms into/out of object * space, so we use an epsilon to detect actual changes */ - float4 curve_key = float3_to_float4(mesh->curve_keys[i]); - curve_key.w = mesh->curve_radius[i]; + float4 curve_key = float3_to_float4(hair->curve_keys[i]); + curve_key.w = hair->curve_radius[i]; if (len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f) have_motion = true; } @@ -784,40 +819,15 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int /* in case of new attribute, we verify if there really was any motion */ if (new_attribute) { - if (i != numkeys || !have_motion) { - /* No motion or hair "topology" changed, remove attributes again. */ - if (i != numkeys) { - VLOG(1) << "Hair topology changed, removing attribute."; - } - else { - VLOG(1) << "No motion, removing attribute."; - } - mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); - } - else if (motion_step > 0) { - VLOG(1) << "Filling in new motion vertex position for motion_step " << motion_step; - /* motion, fill up previous steps that we might have skipped because - * they had no motion, but we need them anyway now */ - for (int step = 0; step < motion_step; step++) { - float4 *mP = attr_mP->data_float4() + step * numkeys; - - for (int key = 0; key < numkeys; key++) { - mP[key] = float3_to_float4(mesh->curve_keys[key]); - mP[key].w = mesh->curve_radius[key]; - } - } - } + export_hair_motion_validate_attribute(hair, motion_step, i, have_motion); } } -static void ExportCurveTriangleUV(ParticleCurveData *CData, - int vert_offset, - int resol, - float2 *uvdata) +static void ExportCurveTriangleUV(ParticleCurveData *CData, int resol, float2 *uvdata) { if (uvdata == NULL) return; - int vertexindex = vert_offset; + int vertexindex = 0; for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; @@ -845,15 +855,12 @@ static void ExportCurveTriangleUV(ParticleCurveData *CData, } } -static void ExportCurveTriangleVcol(ParticleCurveData *CData, - int vert_offset, - int resol, - uchar4 *cdata) +static void ExportCurveTriangleVcol(ParticleCurveData *CData, int resol, uchar4 *cdata) { if (cdata == NULL) return; - int vertexindex = vert_offset; + int vertexindex = 0; for (int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { for (int curve = CData->psys_firstcurve[sys]; @@ -952,7 +959,7 @@ void BlenderSync::sync_curve_settings() if ((b_psys->settings().render_type() == BL::ParticleSettings::render_type_PATH) && (b_psys->settings().type() == BL::ParticleSettings::type_HAIR)) { BL::ID key = BKE_object_is_modified(*b_ob) ? *b_ob : b_ob->data(); - mesh_map.set_recalc(key); + geometry_map.set_recalc(key); object_map.set_recalc(*b_ob); } } @@ -987,28 +994,28 @@ bool BlenderSync::object_has_particle_hair(BL::Object b_ob) /* Old particle hair. */ void BlenderSync::sync_particle_hair( - Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step) + Geometry *geom, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step) { + Hair *hair = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom) : NULL; + Mesh *mesh = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom) : NULL; + + /* obtain general settings */ if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) { return; } - /* obtain general settings */ - const int primitive = scene->curve_system_manager->primitive; const int triangle_method = scene->curve_system_manager->triangle_method; const int resolution = scene->curve_system_manager->resolution; - const size_t vert_num = mesh->verts.size(); - const size_t tri_num = mesh->num_triangles(); int used_res = 1; /* extract particle hair data - should be combined with connecting to mesh later*/ ParticleCurveData CData; - ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview); + ObtainCacheParticleData(geom, &b_mesh, &b_ob, &CData, !preview); /* add hair geometry to mesh */ - if (primitive == CURVE_TRIANGLES) { + if (mesh) { if (triangle_method == CURVE_CAMERA_TRIANGLES) { /* obtain camera parameters */ float3 RotCam; @@ -1032,31 +1039,31 @@ void BlenderSync::sync_particle_hair( } else { if (motion) - ExportCurveSegmentsMotion(mesh, &CData, motion_step); + ExportCurveSegmentsMotion(hair, &CData, motion_step); else - ExportCurveSegments(scene, mesh, &CData); + ExportCurveSegments(scene, hair, &CData); } /* generated coordinates from first key. we should ideally get this from * blender to handle deforming objects */ if (!motion) { - if (mesh->need_attribute(scene, ATTR_STD_GENERATED)) { + if (geom->need_attribute(scene, ATTR_STD_GENERATED)) { float3 loc, size; mesh_texture_space(b_mesh, loc, size); - if (primitive == CURVE_TRIANGLES) { + if (mesh) { Attribute *attr_generated = mesh->attributes.add(ATTR_STD_GENERATED); float3 *generated = attr_generated->data_float3(); - for (size_t i = vert_num; i < mesh->verts.size(); i++) + for (size_t i = 0; i < mesh->verts.size(); i++) generated[i] = mesh->verts[i] * size - loc; } else { - Attribute *attr_generated = mesh->curve_attributes.add(ATTR_STD_GENERATED); + Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED); float3 *generated = attr_generated->data_float3(); - for (size_t i = 0; i < mesh->num_curves(); i++) { - float3 co = mesh->curve_keys[mesh->get_curve(i).first_key]; + for (size_t i = 0; i < hair->num_curves(); i++) { + float3 co = hair->curve_keys[hair->get_curve(i).first_key]; generated[i] = co * size - loc; } } @@ -1069,21 +1076,21 @@ void BlenderSync::sync_particle_hair( int vcol_num = 0; for (b_mesh.vertex_colors.begin(l); l != b_mesh.vertex_colors.end(); ++l, vcol_num++) { - if (!mesh->need_attribute(scene, ustring(l->name().c_str()))) + if (!geom->need_attribute(scene, ustring(l->name().c_str()))) continue; - ObtainCacheParticleVcol(mesh, &b_mesh, &b_ob, &CData, !preview, vcol_num); + ObtainCacheParticleVcol(geom, &b_mesh, &b_ob, &CData, !preview, vcol_num); - if (primitive == CURVE_TRIANGLES) { + if (mesh) { Attribute *attr_vcol = mesh->attributes.add( ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE); uchar4 *cdata = attr_vcol->data_uchar4(); - ExportCurveTriangleVcol(&CData, tri_num * 3, used_res, cdata); + ExportCurveTriangleVcol(&CData, used_res, cdata); } else { - Attribute *attr_vcol = mesh->curve_attributes.add( + Attribute *attr_vcol = hair->attributes.add( ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CURVE); float3 *fdata = attr_vcol->data_float3(); @@ -1111,12 +1118,12 @@ void BlenderSync::sync_particle_hair( ustring name = ustring(l->name().c_str()); /* UV map */ - if (mesh->need_attribute(scene, name) || mesh->need_attribute(scene, std)) { + if (geom->need_attribute(scene, name) || geom->need_attribute(scene, std)) { Attribute *attr_uv; - ObtainCacheParticleUV(mesh, &b_mesh, &b_ob, &CData, !preview, uv_num); + ObtainCacheParticleUV(geom, &b_mesh, &b_ob, &CData, !preview, uv_num); - if (primitive == CURVE_TRIANGLES) { + if (mesh) { if (active_render) attr_uv = mesh->attributes.add(std, name); else @@ -1124,13 +1131,13 @@ void BlenderSync::sync_particle_hair( float2 *uv = attr_uv->data_float2(); - ExportCurveTriangleUV(&CData, tri_num * 3, used_res, uv); + ExportCurveTriangleUV(&CData, used_res, uv); } else { if (active_render) - attr_uv = mesh->curve_attributes.add(std, name); + attr_uv = hair->attributes.add(std, name); else - attr_uv = mesh->curve_attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE); + attr_uv = hair->attributes.add(name, TypeFloat2, ATTR_ELEMENT_CURVE); float2 *uv = attr_uv->data_float2(); @@ -1145,44 +1152,56 @@ void BlenderSync::sync_particle_hair( } } } - - mesh->geometry_flags |= Mesh::GEOMETRY_CURVES; } -void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh) +void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Geometry *geom) { - /* compares curve_keys rather than strands in order to handle quick hair - * adjustments in dynamic BVH - other methods could probably do this better*/ + Hair *hair = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom) : NULL; + Mesh *mesh = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom) : NULL; + + /* Compares curve_keys rather than strands in order to handle quick hair + * adjustments in dynamic BVH - other methods could probably do this better. */ array<float3> oldcurve_keys; array<float> oldcurve_radius; - oldcurve_keys.steal_data(mesh->curve_keys); - oldcurve_radius.steal_data(mesh->curve_radius); + array<int> oldtriangles; + if (hair) { + oldcurve_keys.steal_data(hair->curve_keys); + oldcurve_radius.steal_data(hair->curve_radius); + } + else { + oldtriangles.steal_data(mesh->triangles); + } if (view_layer.use_hair && scene->curve_system_manager->use_curves) { /* Particle hair. */ - bool need_undeformed = mesh->need_attribute(scene, ATTR_STD_GENERATED); + bool need_undeformed = geom->need_attribute(scene, ATTR_STD_GENERATED); BL::Mesh b_mesh = object_to_mesh( b_data, b_ob, b_depsgraph, need_undeformed, Mesh::SUBDIVISION_NONE); if (b_mesh) { - sync_particle_hair(mesh, b_mesh, b_ob, false); + sync_particle_hair(geom, b_mesh, b_ob, false); free_object_to_mesh(b_data, b_ob, b_mesh); } } /* tag update */ - bool rebuild = (oldcurve_keys != mesh->curve_keys) || (oldcurve_radius != mesh->curve_radius); - mesh->tag_update(scene, rebuild); + const bool rebuild = (hair && ((oldcurve_keys != hair->curve_keys) || + (oldcurve_radius != hair->curve_radius))) || + (mesh && (oldtriangles != mesh->triangles)); + + geom->tag_update(scene, rebuild); } void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, - Mesh *mesh, + Geometry *geom, int motion_step) { - /* Skip if no curves were exported. */ - size_t numkeys = mesh->curve_keys.size(); - if (numkeys == 0) { + Hair *hair = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom) : NULL; + Mesh *mesh = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom) : NULL; + + /* Skip if nothing exported. */ + if ((hair && hair->num_keys() == 0) || (mesh && mesh->verts.size() == 0)) { return; } @@ -1191,17 +1210,18 @@ void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph, /* Particle hair. */ BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_depsgraph, false, Mesh::SUBDIVISION_NONE); if (b_mesh) { - sync_particle_hair(mesh, b_mesh, b_ob, true, motion_step); + sync_particle_hair(geom, b_mesh, b_ob, true, motion_step); free_object_to_mesh(b_data, b_ob, b_mesh); return; } } /* No deformation on this frame, copy coordinates if other frames did have it. */ - Attribute *attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (attr_mP) { - float3 *keys = &mesh->curve_keys[0]; - memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys); + if (hair) { + hair->copy_center_to_motion_step(motion_step); + } + else { + mesh->copy_center_to_motion_step(motion_step); } } diff --git a/intern/cycles/blender/blender_geometry.cpp b/intern/cycles/blender/blender_geometry.cpp index 151b741b003..8b803835b62 100644 --- a/intern/cycles/blender/blender_geometry.cpp +++ b/intern/cycles/blender/blender_geometry.cpp @@ -15,6 +15,8 @@ * limitations under the License. */ +#include "render/curves.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/object.h" @@ -23,18 +25,22 @@ CCL_NAMESPACE_BEGIN -Mesh *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, - BL::Object &b_ob, - BL::Object &b_ob_instance, - bool object_updated, - bool use_particle_hair) +Geometry *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, + BL::Object &b_ob, + BL::Object &b_ob_instance, + bool object_updated, + bool use_particle_hair) { /* Test if we can instance or if the object is modified. */ BL::ID b_ob_data = b_ob.data(); BL::ID b_key_id = (BKE_object_is_modified(b_ob)) ? b_ob_instance : b_ob_data; - MeshKey key(b_key_id.ptr.data, use_particle_hair); + GeometryKey key(b_key_id.ptr.data, use_particle_hair); BL::Material material_override = view_layer.material_override; Shader *default_shader = scene->default_surface; + Geometry::Type geom_type = (use_particle_hair && + (scene->curve_system_manager->primitive != CURVE_TRIANGLES)) ? + Geometry::HAIR : + Geometry::MESH; /* Find shader indices. */ vector<Shader *> used_shaders; @@ -58,53 +64,76 @@ Mesh *BlenderSync::sync_geometry(BL::Depsgraph &b_depsgraph, } /* Test if we need to sync. */ - Mesh *mesh; + Geometry *geom = geometry_map.find(key); + bool sync = true; + if (geom == NULL) { + /* Add new geometry if it did not exist yet. */ + if (geom_type == Geometry::HAIR) { + geom = new Hair(); + } + else { + geom = new Mesh(); + } + geometry_map.add(key, geom); + } + else { + /* Test if we need to update existing geometry. */ + sync = geometry_map.update(geom, b_key_id); + } - if (!mesh_map.sync(&mesh, b_key_id, key)) { - /* If transform was applied to mesh, need full update. */ - if (object_updated && mesh->transform_applied) + if (!sync) { + /* If transform was applied to geometry, need full update. */ + if (object_updated && geom->transform_applied) { ; - /* Test if shaders changed, these can be object level so mesh + } + /* Test if shaders changed, these can be object level so geometry * does not get tagged for recalc. */ - else if (mesh->used_shaders != used_shaders) + else if (geom->used_shaders != used_shaders) { ; + } else { /* Even if not tagged for recalc, we may need to sync anyway - * because the shader needs different mesh attributes. */ + * because the shader needs different geometry attributes. */ bool attribute_recalc = false; - foreach (Shader *shader, mesh->used_shaders) - if (shader->need_update_mesh) + foreach (Shader *shader, geom->used_shaders) { + if (shader->need_update_geometry) { attribute_recalc = true; + } + } - if (!attribute_recalc) - return mesh; + if (!attribute_recalc) { + return geom; + } } } - /* Ensure we only sync instanced meshes once. */ - if (mesh_synced.find(mesh) != mesh_synced.end()) - return mesh; + /* Ensure we only sync instanced geometry once. */ + if (geometry_synced.find(geom) != geometry_synced.end()) { + return geom; + } progress.set_sync_status("Synchronizing object", b_ob.name()); - mesh_synced.insert(mesh); + geometry_synced.insert(geom); - mesh->clear(); - mesh->used_shaders = used_shaders; - mesh->name = ustring(b_ob_data.name().c_str()); + geom->clear(); + geom->used_shaders = used_shaders; + geom->name = ustring(b_ob_data.name().c_str()); if (use_particle_hair) { - sync_hair(b_depsgraph, b_ob, mesh); + sync_hair(b_depsgraph, b_ob, geom); } else if (object_fluid_gas_domain_find(b_ob)) { + Mesh *mesh = static_cast<Mesh *>(geom); sync_volume(b_ob, mesh); } else { + Mesh *mesh = static_cast<Mesh *>(geom); sync_mesh(b_depsgraph, b_ob, mesh); } - return mesh; + return geom; } void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, @@ -113,32 +142,33 @@ void BlenderSync::sync_geometry_motion(BL::Depsgraph &b_depsgraph, float motion_time, bool use_particle_hair) { - /* Ensure we only sync instanced meshes once. */ - Mesh *mesh = object->mesh; + /* Ensure we only sync instanced geometry once. */ + Geometry *geom = object->geometry; - if (mesh_motion_synced.find(mesh) != mesh_motion_synced.end()) + if (geometry_motion_synced.find(geom) != geometry_motion_synced.end()) return; - mesh_motion_synced.insert(mesh); + geometry_motion_synced.insert(geom); - /* Ensure we only motion sync meshes that also had mesh synced, to avoid + /* Ensure we only motion sync geometry that also had geometry synced, to avoid * unnecessary work and to ensure that its attributes were clear. */ - if (mesh_synced.find(mesh) == mesh_synced.end()) + if (geometry_synced.find(geom) == geometry_synced.end()) return; - /* Find time matching motion step required by mesh. */ - int motion_step = mesh->motion_step(motion_time); + /* Find time matching motion step required by geometry. */ + int motion_step = geom->motion_step(motion_time); if (motion_step < 0) { return; } if (use_particle_hair) { - sync_hair_motion(b_depsgraph, b_ob, mesh, motion_step); + sync_hair_motion(b_depsgraph, b_ob, geom, motion_step); } else if (object_fluid_gas_domain_find(b_ob)) { /* No volume motion blur support yet. */ } else { + Mesh *mesh = static_cast<Mesh *>(geom); sync_mesh_motion(b_depsgraph, b_ob, mesh, motion_step); } } diff --git a/intern/cycles/blender/blender_id_map.h b/intern/cycles/blender/blender_id_map.h index 52031cd9f34..83c93bb09ee 100644 --- a/intern/cycles/blender/blender_id_map.h +++ b/intern/cycles/blender/blender_id_map.h @@ -72,41 +72,61 @@ template<typename K, typename T> class id_map { used_set.clear(); } - bool sync(T **r_data, const BL::ID &id) + /* Add new data. */ + void add(const K &key, T *data) { - return sync(r_data, id, id, id.ptr.owner_id); + assert(find(key) == NULL); + scene_data->push_back(data); + b_map[key] = data; + used(data); } - bool sync(T **r_data, const BL::ID &id, const K &key) + /* Update existing data. */ + bool update(T *data, const BL::ID &id) { - return sync(r_data, id, id, key); + return update(data, id, id); + } + bool update(T *data, const BL::ID &id, const BL::ID &parent) + { + bool recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); + if (parent.ptr.data && parent.ptr.data != id.ptr.data) { + recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); + } + used(data); + return recalc; } - bool sync(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key) + /* Combined add and update as needed. */ + bool add_or_update(T **r_data, const BL::ID &id) + { + return add_or_update(r_data, id, id, id.ptr.owner_id); + } + bool add_or_update(T **r_data, const BL::ID &id, const K &key) + { + return add_or_update(r_data, id, id, key); + } + bool add_or_update(T **r_data, const BL::ID &id, const BL::ID &parent, const K &key) { T *data = find(key); bool recalc; if (!data) { - /* add data if it didn't exist yet */ + /* Add data if it didn't exist yet. */ data = new T(); - scene_data->push_back(data); - b_map[key] = data; + add(key, data); recalc = true; } else { - recalc = (b_recalc.find(id.ptr.data) != b_recalc.end()); - if (parent.ptr.data && parent.ptr.data != id.ptr.data) { - recalc = recalc || (b_recalc.find(parent.ptr.data) != b_recalc.end()); - } + /* check if updated needed. */ + recalc = update(data, id, parent); } - used(data); - *r_data = data; return recalc; } + /* Combined add or update for convenience. */ + bool is_used(const K &key) { T *data = find(key); @@ -220,20 +240,20 @@ struct ObjectKey { } }; -/* Mesh Key +/* Geometry Key * * We export separate geomtry for a mesh and its particle hair, so key needs to * distinguish between them. */ -struct MeshKey { +struct GeometryKey { void *id; bool use_particle_hair; - MeshKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair) + GeometryKey(void *id, bool use_particle_hair) : id(id), use_particle_hair(use_particle_hair) { } - bool operator<(const MeshKey &k) const + bool operator<(const GeometryKey &k) const { if (id < k.id) { return true; diff --git a/intern/cycles/blender/blender_light.cpp b/intern/cycles/blender/blender_light.cpp index a8e28a011d7..5351de2e84b 100644 --- a/intern/cycles/blender/blender_light.cpp +++ b/intern/cycles/blender/blender_light.cpp @@ -39,9 +39,9 @@ void BlenderSync::sync_light(BL::Object &b_parent, BL::Light b_light(b_ob.data()); /* Update if either object or light data changed. */ - if (!light_map.sync(&light, b_ob, b_parent, key)) { + if (!light_map.add_or_update(&light, b_ob, b_parent, key)) { Shader *shader; - if (!shader_map.sync(&shader, b_light)) { + if (!shader_map.add_or_update(&shader, b_light)) { if (light->is_portal) *use_portal = true; return; @@ -176,7 +176,7 @@ void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) Light *light; ObjectKey key(b_world, 0, b_world, false); - if (light_map.sync(&light, b_world, b_world, key) || world_recalc || + if (light_map.add_or_update(&light, b_world, b_world, key) || world_recalc || b_world.ptr.data != world_map) { light->type = LIGHT_BACKGROUND; if (sampling_method == SAMPLING_MANUAL) { diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 00faafe29ee..332c26161dc 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -719,7 +719,6 @@ static void create_mesh(Scene *scene, /* allocate memory */ mesh->reserve_mesh(numverts, numtris); mesh->reserve_subd_faces(numfaces, numngons, numcorners); - mesh->geometry_flags |= Mesh::GEOMETRY_TRIANGLES; /* create vertex coordinates and normals */ BL::Mesh::vertices_iterator v; @@ -1053,18 +1052,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph, } /* No deformation on this frame, copy coordinates if other frames did have it. */ - Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (attr_mP) { - Attribute *attr_mN = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - Attribute *attr_N = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL); - float3 *P = &mesh->verts[0]; - float3 *N = (attr_N) ? attr_N->data_float3() : NULL; - - memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts); - if (attr_mN) - memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts); - } + mesh->copy_center_to_motion_step(motion_step); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 13dfd0867ba..2b1d1eff7e5 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -191,7 +191,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, } /* mesh deformation */ - if (object->mesh) + if (object->geometry) sync_geometry_motion(b_depsgraph, b_ob, object, motion_time, use_particle_hair); } @@ -201,11 +201,11 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* test if we need to sync */ bool object_updated = false; - if (object_map.sync(&object, b_ob, b_parent, key)) + if (object_map.add_or_update(&object, b_ob, b_parent, key)) object_updated = true; /* mesh sync */ - object->mesh = sync_geometry( + object->geometry = sync_geometry( b_depsgraph, b_ob, b_ob_instance, object_updated, use_particle_hair); /* special case not tracked by object update flags */ @@ -248,7 +248,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* object sync * transform comparison should not be needed, but duplis don't work perfect * in the depsgraph and may not signal changes, so this is a workaround */ - if (object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) { + if (object_updated || (object->geometry && object->geometry->need_update) || + tfm != object->tfm) { object->name = b_ob.name().c_str(); object->pass_id = b_ob.pass_index(); object->color = get_float3(b_ob.color()); @@ -257,23 +258,23 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* motion blur */ Scene::MotionType need_motion = scene->need_motion(); - if (need_motion != Scene::MOTION_NONE && object->mesh) { - Mesh *mesh = object->mesh; - mesh->use_motion_blur = false; - mesh->motion_steps = 0; + if (need_motion != Scene::MOTION_NONE && object->geometry) { + Geometry *geom = object->geometry; + geom->use_motion_blur = false; + geom->motion_steps = 0; uint motion_steps; if (need_motion == Scene::MOTION_BLUR) { motion_steps = object_motion_steps(b_parent, b_ob); - mesh->motion_steps = motion_steps; + geom->motion_steps = motion_steps; if (motion_steps && object_use_deform_motion(b_parent, b_ob)) { - mesh->use_motion_blur = true; + geom->use_motion_blur = true; } } else { motion_steps = 3; - mesh->motion_steps = motion_steps; + geom->motion_steps = motion_steps; } object->motion.clear(); @@ -324,13 +325,13 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, if (!motion) { /* prepare for sync */ light_map.pre_sync(); - mesh_map.pre_sync(); + geometry_map.pre_sync(); object_map.pre_sync(); particle_system_map.pre_sync(); motion_times.clear(); } else { - mesh_motion_synced.clear(); + geometry_motion_synced.clear(); } /* initialize culling */ @@ -394,8 +395,8 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, /* handle removed data and modified pointers */ if (light_map.post_sync()) scene->light_manager->tag_update(scene); - if (mesh_map.post_sync()) - scene->mesh_manager->tag_update(scene); + if (geometry_map.post_sync()) + scene->geometry_manager->tag_update(scene); if (object_map.post_sync()) scene->object_manager->tag_update(scene); if (particle_system_map.post_sync()) @@ -403,7 +404,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, } if (motion) - mesh_motion_synced.clear(); + geometry_motion_synced.clear(); } void BlenderSync::sync_motion(BL::RenderSettings &b_render, diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp index d74f132ed60..e5eab1ae62b 100644 --- a/intern/cycles/blender/blender_particles.cpp +++ b/intern/cycles/blender/blender_particles.cpp @@ -39,7 +39,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob, object->hide_on_missing_motion = true; /* test if we need particle data */ - if (!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE)) + if (!object->geometry->need_attribute(scene, ATTR_STD_PARTICLE)) return false; /* don't handle child particles yet */ @@ -53,10 +53,10 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob, ParticleSystem *psys; bool first_use = !particle_system_map.is_used(key); - bool need_update = particle_system_map.sync(&psys, b_ob, b_instance.object(), key); + bool need_update = particle_system_map.add_or_update(&psys, b_ob, b_instance.object(), key); /* no update needed? */ - if (!need_update && !object->mesh->need_update && !scene->object_manager->need_update) + if (!need_update && !object->geometry->need_update && !scene->object_manager->need_update) return true; /* first time used in this sync loop? clear and tag update */ diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 663f3d72110..1490348743e 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -720,9 +720,12 @@ void BlenderSession::bake(BL::Depsgraph &b_depsgraph_, int tri_offset = 0; for (size_t i = 0; i < scene->objects.size(); i++) { - if (strcmp(scene->objects[i]->name.c_str(), b_object.name().c_str()) == 0) { + const Object *object = scene->objects[i]; + const Geometry *geom = object->geometry; + if (object->name == b_object.name() && geom->type == Geometry::MESH) { + const Mesh *mesh = static_cast<const Mesh *>(geom); object_index = i; - tri_offset = scene->objects[i]->mesh->tri_offset; + tri_offset = mesh->prim_offset; break; } } diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 206058259af..635405e42c7 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -1255,7 +1255,7 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) Shader *shader; /* test if we need to sync */ - if (shader_map.sync(&shader, b_mat) || shader->need_sync_object || update_all) { + if (shader_map.add_or_update(&shader, b_mat) || shader->need_sync_object || update_all) { ShaderGraph *graph = new ShaderGraph(); shader->name = b_mat.name().c_str(); @@ -1480,7 +1480,7 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) Shader *shader; /* test if we need to sync */ - if (shader_map.sync(&shader, b_light) || update_all) { + if (shader_map.add_or_update(&shader, b_light) || update_all) { ShaderGraph *graph = new ShaderGraph(); /* create nodes */ diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index bb8a132ebb7..8960c84567e 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -56,7 +56,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine, b_scene(b_scene), shader_map(&scene->shaders), object_map(&scene->objects), - mesh_map(&scene->meshes), + geometry_map(&scene->geometry), light_map(&scene->lights), particle_system_map(&scene->particle_systems), world_map(NULL), @@ -108,12 +108,15 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d } if (dicing_prop_changed) { - for (const pair<MeshKey, Mesh *> &iter : mesh_map.key_to_scene_data()) { - Mesh *mesh = iter.second; - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { - PointerRNA id_ptr; - RNA_id_pointer_create((::ID *)iter.first.id, &id_ptr); - mesh_map.set_recalc(BL::ID(id_ptr)); + for (const pair<GeometryKey, Geometry *> &iter : geometry_map.key_to_scene_data()) { + Geometry *geom = iter.second; + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { + PointerRNA id_ptr; + RNA_id_pointer_create((::ID *)iter.first.id, &id_ptr); + geometry_map.set_recalc(BL::ID(id_ptr)); + } } } } @@ -148,7 +151,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d if (updated_geometry || (object_subdivision_type(b_ob, preview, experimental) != Mesh::SUBDIVISION_NONE)) { BL::ID key = BKE_object_is_modified(b_ob) ? b_ob : b_ob.data(); - mesh_map.set_recalc(key); + geometry_map.set_recalc(key); } } else if (object_is_light(b_ob)) { @@ -166,7 +169,7 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d /* Mesh */ else if (b_id.is_a(&RNA_Mesh)) { BL::Mesh b_mesh(b_id); - mesh_map.set_recalc(b_mesh); + geometry_map.set_recalc(b_mesh); } /* World */ else if (b_id.is_a(&RNA_World)) { @@ -213,7 +216,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render, sync_images(); sync_curve_settings(); - mesh_synced.clear(); /* use for objects and motion sync */ + geometry_synced.clear(); /* use for objects and motion sync */ if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE || scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) { @@ -221,7 +224,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render, } sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state); - mesh_synced.clear(); + geometry_synced.clear(); /* Shader sync done at the end, since object sync uses it. * false = don't delete unused shaders, not supported. */ diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 295d9d2e307..f8134ff8b5c 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -40,6 +40,7 @@ class BlenderObjectCulling; class BlenderViewportParameters; class Camera; class Film; +class Hair; class Light; class Mesh; class Object; @@ -142,10 +143,13 @@ class BlenderSync { void sync_mesh_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step); /* Hair */ - void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh); - void sync_hair_motion(BL::Depsgraph b_depsgraph, BL::Object b_ob, Mesh *mesh, int motion_step); + void sync_hair(BL::Depsgraph b_depsgraph, BL::Object b_ob, Geometry *geom); + void sync_hair_motion(BL::Depsgraph b_depsgraph, + BL::Object b_ob, + Geometry *geom, + int motion_step); void sync_particle_hair( - Mesh *mesh, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); + Geometry *geom, BL::Mesh &b_mesh, BL::Object &b_ob, bool motion, int motion_step = 0); void sync_curve_settings(); bool object_has_particle_hair(BL::Object b_ob); @@ -154,11 +158,11 @@ class BlenderSync { BL::RenderSettings &b_render, BL::Object &b_ob, int width, int height, float motion_time); /* Geometry */ - Mesh *sync_geometry(BL::Depsgraph &b_depsgrpah, - BL::Object &b_ob, - BL::Object &b_ob_instance, - bool object_updated, - bool use_particle_hair); + Geometry *sync_geometry(BL::Depsgraph &b_depsgrpah, + BL::Object &b_ob, + BL::Object &b_ob_instance, + bool object_updated, + bool use_particle_hair); void sync_geometry_motion(BL::Depsgraph &b_depsgraph, BL::Object &b_ob, Object *object, @@ -199,11 +203,11 @@ class BlenderSync { id_map<void *, Shader> shader_map; id_map<ObjectKey, Object> object_map; - id_map<MeshKey, Mesh> mesh_map; + id_map<GeometryKey, Geometry> geometry_map; id_map<ObjectKey, Light> light_map; id_map<ParticleSystemKey, ParticleSystem> particle_system_map; - set<Mesh *> mesh_synced; - set<Mesh *> mesh_motion_synced; + set<Geometry *> geometry_synced; + set<Geometry *> geometry_motion_synced; set<float> motion_times; void *world_map; bool world_recalc; diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 16c721da06a..3a8b0fe7fa2 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -17,6 +17,7 @@ #include "bvh/bvh.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/object.h" @@ -99,31 +100,33 @@ int BVHStackEntry::encodeIdx() const /* BVH */ -BVH::BVH(const BVHParams ¶ms_, const vector<Mesh *> &meshes_, const vector<Object *> &objects_) - : params(params_), meshes(meshes_), objects(objects_) +BVH::BVH(const BVHParams ¶ms_, + const vector<Geometry *> &geometry_, + const vector<Object *> &objects_) + : params(params_), geometry(geometry_), objects(objects_) { } BVH *BVH::create(const BVHParams ¶ms, - const vector<Mesh *> &meshes, + const vector<Geometry *> &geometry, const vector<Object *> &objects) { switch (params.bvh_layout) { case BVH_LAYOUT_BVH2: - return new BVH2(params, meshes, objects); + return new BVH2(params, geometry, objects); case BVH_LAYOUT_BVH4: - return new BVH4(params, meshes, objects); + return new BVH4(params, geometry, objects); case BVH_LAYOUT_BVH8: - return new BVH8(params, meshes, objects); + return new BVH8(params, geometry, objects); case BVH_LAYOUT_EMBREE: #ifdef WITH_EMBREE - return new BVHEmbree(params, meshes, objects); + return new BVHEmbree(params, geometry, objects); #else break; #endif case BVH_LAYOUT_OPTIX: #ifdef WITH_OPTIX - return new BVHOptiX(params, meshes, objects); + return new BVHOptiX(params, geometry, objects); #else break; #endif @@ -217,36 +220,36 @@ void BVH::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility) } else { /* Primitives. */ - const Mesh *mesh = ob->mesh; - if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ - int str_offset = (params.top_level) ? mesh->curve_offset : 0; - Mesh::Curve curve = mesh->get_curve(pidx - str_offset); + const Hair *hair = static_cast<const Hair *>(ob->geometry); + int prim_offset = (params.top_level) ? hair->prim_offset : 0; + Hair::Curve curve = hair->get_curve(pidx - prim_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); + curve.bounds_grow(k, &hair->curve_keys[0], &hair->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; /* Motion curves. */ - if (mesh->use_motion_blur) { - Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (hair->use_motion_blur) { + Attribute *attr = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; + size_t hair_size = hair->curve_keys.size(); + size_t steps = hair->motion_steps - 1; float3 *key_steps = attr->data_float3(); for (size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i * mesh_size, &mesh->curve_radius[0], bbox); + curve.bounds_grow(k, key_steps + i * hair_size, &hair->curve_radius[0], bbox); } } } else { /* Triangles. */ - int tri_offset = (params.top_level) ? mesh->tri_offset : 0; - Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); + const Mesh *mesh = static_cast<const Mesh *>(ob->geometry); + int prim_offset = (params.top_level) ? mesh->prim_offset : 0; + Mesh::Triangle triangle = mesh->get_triangle(pidx - prim_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); @@ -276,7 +279,7 @@ void BVH::pack_triangle(int idx, float4 tri_verts[3]) { int tob = pack.prim_object[idx]; assert(tob >= 0 && tob < objects.size()); - const Mesh *mesh = objects[tob]->mesh; + const Mesh *mesh = static_cast<const Mesh *>(objects[tob]->geometry); int tidx = pack.prim_index[idx]; Mesh::Triangle t = mesh->get_triangle(tidx); @@ -347,15 +350,13 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) const bool use_obvh = (params.bvh_layout == BVH_LAYOUT_BVH8); /* Adjust primitive index to point to the triangle in the global array, for - * meshes with transform applied and already in the top level BVH. + * geometry with transform applied and already in the top level BVH. */ - for (size_t i = 0; i < pack.prim_index.size(); i++) + for (size_t i = 0; i < pack.prim_index.size(); i++) { if (pack.prim_index[i] != -1) { - if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE) - pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset; - else - pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset; + pack.prim_index[i] += objects[pack.prim_object[i]]->geometry->prim_offset; } + } /* track offsets of instanced BVH data in global array */ size_t prim_offset = pack.prim_index.size(); @@ -375,10 +376,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) size_t pack_leaf_nodes_offset = leaf_nodes_size; size_t object_offset = 0; - foreach (Mesh *mesh, meshes) { - BVH *bvh = mesh->bvh; + foreach (Geometry *geom, geometry) { + BVH *bvh = geom->bvh; - if (mesh->need_build_bvh(params.bvh_layout)) { + if (geom->need_build_bvh(params.bvh_layout)) { prim_index_size += bvh->pack.prim_index.size(); prim_tri_verts_size += bvh->pack.prim_tri_verts.size(); nodes_size += bvh->pack.nodes.size(); @@ -410,36 +411,35 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) int4 *pack_leaf_nodes = (pack.leaf_nodes.size()) ? &pack.leaf_nodes[0] : NULL; float2 *pack_prim_time = (pack.prim_time.size()) ? &pack.prim_time[0] : NULL; - map<Mesh *, int> mesh_map; + map<Geometry *, int> geometry_map; /* merge */ foreach (Object *ob, objects) { - Mesh *mesh = ob->mesh; + Geometry *geom = ob->geometry; /* We assume that if mesh doesn't need own BVH it was already included * into a top-level BVH and no packing here is needed. */ - if (!mesh->need_build_bvh(params.bvh_layout)) { + if (!geom->need_build_bvh(params.bvh_layout)) { pack.object_node[object_offset++] = 0; continue; } /* if mesh already added once, don't add it again, but used set * node offset for this object */ - map<Mesh *, int>::iterator it = mesh_map.find(mesh); + map<Geometry *, int>::iterator it = geometry_map.find(geom); - if (mesh_map.find(mesh) != mesh_map.end()) { + if (geometry_map.find(geom) != geometry_map.end()) { int noffset = it->second; pack.object_node[object_offset++] = noffset; continue; } - BVH *bvh = mesh->bvh; + BVH *bvh = geom->bvh; int noffset = nodes_offset; int noffset_leaf = nodes_leaf_offset; - int mesh_tri_offset = mesh->tri_offset; - int mesh_curve_offset = mesh->curve_offset; + int geom_prim_offset = geom->prim_offset; /* fill in node indexes for instances */ if (bvh->pack.root_index == -1) @@ -447,7 +447,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) else pack.object_node[object_offset++] = noffset; - mesh_map[mesh] = pack.object_node[object_offset - 1]; + geometry_map[geom] = pack.object_node[object_offset - 1]; /* merge primitive, object and triangle indexes */ if (bvh->pack.prim_index.size()) { @@ -460,11 +460,11 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) for (size_t i = 0; i < bvh_prim_index_size; i++) { if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset; + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; pack_prim_tri_index[pack_prim_index_offset] = -1; } else { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] + pack_prim_tri_verts_offset; } diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 92082e4de86..bdde38640c9 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -33,7 +33,7 @@ struct BVHStackEntry; class BVHParams; class BoundBox; class LeafNode; -class Mesh; +class Geometry; class Object; class Progress; @@ -84,11 +84,11 @@ class BVH { public: PackedBVH pack; BVHParams params; - vector<Mesh *> meshes; + vector<Geometry *> geometry; vector<Object *> objects; static BVH *create(const BVHParams ¶ms, - const vector<Mesh *> &meshes, + const vector<Geometry *> &geometry, const vector<Object *> &objects); virtual ~BVH() { @@ -102,7 +102,9 @@ class BVH { void refit(Progress &progress); protected: - BVH(const BVHParams ¶ms, const vector<Mesh *> &meshes, const vector<Object *> &objects); + BVH(const BVHParams ¶ms, + const vector<Geometry *> &geometry, + const vector<Object *> &objects); /* Refit range of primitives. */ void refit_primitives(int start, int end, BoundBox &bbox, uint &visibility); diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp index b1a9148c297..c903070429e 100644 --- a/intern/cycles/bvh/bvh2.cpp +++ b/intern/cycles/bvh/bvh2.cpp @@ -26,9 +26,9 @@ CCL_NAMESPACE_BEGIN BVH2::BVH2(const BVHParams ¶ms_, - const vector<Mesh *> &meshes_, + const vector<Geometry *> &geometry_, const vector<Object *> &objects_) - : BVH(params_, meshes_, objects_) + : BVH(params_, geometry_, objects_) { } diff --git a/intern/cycles/bvh/bvh2.h b/intern/cycles/bvh/bvh2.h index a3eaff9cf65..fa3e45b72d2 100644 --- a/intern/cycles/bvh/bvh2.h +++ b/intern/cycles/bvh/bvh2.h @@ -46,7 +46,9 @@ class BVH2 : public BVH { protected: /* constructor */ friend class BVH; - BVH2(const BVHParams ¶ms, const vector<Mesh *> &meshes, const vector<Object *> &objects); + BVH2(const BVHParams ¶ms, + const vector<Geometry *> &geometry, + const vector<Object *> &objects); /* Building process. */ virtual BVHNode *widen_children_nodes(const BVHNode *root) override; diff --git a/intern/cycles/bvh/bvh4.cpp b/intern/cycles/bvh/bvh4.cpp index 89b42ee1d21..143c3e54f94 100644 --- a/intern/cycles/bvh/bvh4.cpp +++ b/intern/cycles/bvh/bvh4.cpp @@ -32,9 +32,9 @@ CCL_NAMESPACE_BEGIN */ BVH4::BVH4(const BVHParams ¶ms_, - const vector<Mesh *> &meshes_, + const vector<Geometry *> &geometry_, const vector<Object *> &objects_) - : BVH(params_, meshes_, objects_) + : BVH(params_, geometry_, objects_) { params.bvh_layout = BVH_LAYOUT_BVH4; } diff --git a/intern/cycles/bvh/bvh4.h b/intern/cycles/bvh/bvh4.h index c44f2833c84..afbb9007afb 100644 --- a/intern/cycles/bvh/bvh4.h +++ b/intern/cycles/bvh/bvh4.h @@ -46,7 +46,9 @@ class BVH4 : public BVH { protected: /* constructor */ friend class BVH; - BVH4(const BVHParams ¶ms, const vector<Mesh *> &meshes, const vector<Object *> &objects); + BVH4(const BVHParams ¶ms, + const vector<Geometry *> &geometry, + const vector<Object *> &objects); /* Building process. */ virtual BVHNode *widen_children_nodes(const BVHNode *root) override; diff --git a/intern/cycles/bvh/bvh8.cpp b/intern/cycles/bvh/bvh8.cpp index d3516525f78..342dd9e85a5 100644 --- a/intern/cycles/bvh/bvh8.cpp +++ b/intern/cycles/bvh/bvh8.cpp @@ -28,6 +28,7 @@ #include "bvh/bvh8.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/object.h" @@ -37,9 +38,9 @@ CCL_NAMESPACE_BEGIN BVH8::BVH8(const BVHParams ¶ms_, - const vector<Mesh *> &meshes_, + const vector<Geometry *> &geometry_, const vector<Object *> &objects_) - : BVH(params_, meshes_, objects_) + : BVH(params_, geometry_, objects_) { } @@ -429,37 +430,37 @@ void BVH8::refit_node(int idx, bool leaf, BoundBox &bbox, uint &visibility) } else { /* Primitives. */ - const Mesh *mesh = ob->mesh; - if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { /* Curves. */ - int str_offset = (params.top_level) ? mesh->curve_offset : 0; - Mesh::Curve curve = mesh->get_curve(pidx - str_offset); + const Hair *hair = static_cast<const Hair *>(ob->geometry); + int prim_offset = (params.top_level) ? hair->prim_offset : 0; + Hair::Curve curve = hair->get_curve(pidx - prim_offset); int k = PRIMITIVE_UNPACK_SEGMENT(pack.prim_type[prim]); - curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bbox); + curve.bounds_grow(k, &hair->curve_keys[0], &hair->curve_radius[0], bbox); visibility |= PATH_RAY_CURVE; /* Motion curves. */ - if (mesh->use_motion_blur) { - Attribute *attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (hair->use_motion_blur) { + Attribute *attr = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; + size_t hair_size = hair->curve_keys.size(); + size_t steps = hair->motion_steps - 1; float3 *key_steps = attr->data_float3(); for (size_t i = 0; i < steps; i++) { - curve.bounds_grow(k, key_steps + i * mesh_size, &mesh->curve_radius[0], bbox); + curve.bounds_grow(k, key_steps + i * hair_size, &hair->curve_radius[0], bbox); } } } } else { /* Triangles. */ - int tri_offset = (params.top_level) ? mesh->tri_offset : 0; - Mesh::Triangle triangle = mesh->get_triangle(pidx - tri_offset); + const Mesh *mesh = static_cast<const Mesh *>(ob->geometry); + int prim_offset = (params.top_level) ? mesh->prim_offset : 0; + Mesh::Triangle triangle = mesh->get_triangle(pidx - prim_offset); const float3 *vpos = &mesh->verts[0]; triangle.bounds_grow(vpos, bbox); diff --git a/intern/cycles/bvh/bvh8.h b/intern/cycles/bvh/bvh8.h index 5f26fd423e1..d23fa528e3e 100644 --- a/intern/cycles/bvh/bvh8.h +++ b/intern/cycles/bvh/bvh8.h @@ -57,7 +57,9 @@ class BVH8 : public BVH { protected: /* constructor */ friend class BVH; - BVH8(const BVHParams ¶ms, const vector<Mesh *> &meshes, const vector<Object *> &objects); + BVH8(const BVHParams ¶ms, + const vector<Geometry *> &geometry, + const vector<Object *> &objects); /* Building process. */ virtual BVHNode *widen_children_nodes(const BVHNode *root) override; diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 1d9b006e8cb..b472c55d156 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -22,6 +22,7 @@ #include "bvh/bvh_params.h" #include "bvh_split.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/object.h" #include "render/scene.h" @@ -194,21 +195,21 @@ void BVHBuild::add_reference_triangles(BoundBox &root, BoundBox ¢er, Mesh *m } } -void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i) +void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair, int i) { const Attribute *curve_attr_mP = NULL; - if (mesh->has_motion_blur()) { - curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (hair->has_motion_blur()) { + curve_attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); } - const size_t num_curves = mesh->num_curves(); + const size_t num_curves = hair->num_curves(); for (uint j = 0; j < num_curves; j++) { - const Mesh::Curve curve = mesh->get_curve(j); - const float *curve_radius = &mesh->curve_radius[0]; + const Hair::Curve curve = hair->get_curve(j); + const float *curve_radius = &hair->curve_radius[0]; for (int k = 0; k < curve.num_keys - 1; k++) { if (curve_attr_mP == NULL) { /* Really simple logic for static hair. */ BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); + curve.bounds_grow(k, &hair->curve_keys[0], curve_radius, bounds); if (bounds.valid()) { int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k); references.push_back(BVHReference(bounds, j, i, packed_type)); @@ -223,9 +224,9 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Mesh *mesh */ /* TODO(sergey): Support motion steps for spatially split BVH. */ BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); - const size_t num_keys = mesh->curve_keys.size(); - const size_t num_steps = mesh->motion_steps; + curve.bounds_grow(k, &hair->curve_keys[0], curve_radius, bounds); + const size_t num_keys = hair->curve_keys.size(); + const size_t num_steps = hair->motion_steps; const float3 *key_steps = curve_attr_mP->data_float3(); for (size_t step = 0; step < num_steps - 1; step++) { curve.bounds_grow(k, key_steps + step * num_keys, curve_radius, bounds); @@ -244,10 +245,10 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Mesh *mesh */ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); - const size_t num_steps = mesh->motion_steps; - const float3 *curve_keys = &mesh->curve_keys[0]; + const size_t num_steps = hair->motion_steps; + const float3 *curve_keys = &hair->curve_keys[0]; const float3 *key_steps = curve_attr_mP->data_float3(); - const size_t num_keys = mesh->curve_keys.size(); + const size_t num_keys = hair->curve_keys.size(); /* Calculate bounding box of the previous time step. * Will be reused later to avoid duplicated work on * calculating BVH time step boundbox. @@ -302,13 +303,15 @@ void BVHBuild::add_reference_curves(BoundBox &root, BoundBox ¢er, Mesh *mesh } } -void BVHBuild::add_reference_mesh(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i) +void BVHBuild::add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, int i) { - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); add_reference_triangles(root, center, mesh, i); } - if (params.primitive_mask & PRIMITIVE_ALL_CURVE) { - add_reference_curves(root, center, mesh, i); + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + add_reference_curves(root, center, hair, i); } } @@ -319,16 +322,30 @@ void BVHBuild::add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob center.grow(ob->bounds.center2()); } -static size_t count_curve_segments(Mesh *mesh) +static size_t count_curve_segments(Hair *hair) { - size_t num = 0, num_curves = mesh->num_curves(); + size_t num = 0, num_curves = hair->num_curves(); for (size_t i = 0; i < num_curves; i++) - num += mesh->get_curve(i).num_keys - 1; + num += hair->get_curve(i).num_keys - 1; return num; } +static size_t count_primitives(Geometry *geom) +{ + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + return mesh->num_triangles(); + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + return count_curve_segments(hair); + } + + return 0; +} + void BVHBuild::add_references(BVHRange &root) { /* reserve space for references */ @@ -339,24 +356,14 @@ void BVHBuild::add_references(BVHRange &root) if (!ob->is_traceable()) { continue; } - if (!ob->mesh->is_instanced()) { - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { - num_alloc_references += ob->mesh->num_triangles(); - } - if (params.primitive_mask & PRIMITIVE_ALL_CURVE) { - num_alloc_references += count_curve_segments(ob->mesh); - } + if (!ob->geometry->is_instanced()) { + num_alloc_references += count_primitives(ob->geometry); } else num_alloc_references++; } else { - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { - num_alloc_references += ob->mesh->num_triangles(); - } - if (params.primitive_mask & PRIMITIVE_ALL_CURVE) { - num_alloc_references += count_curve_segments(ob->mesh); - } + num_alloc_references += count_primitives(ob->geometry); } } @@ -372,13 +379,13 @@ void BVHBuild::add_references(BVHRange &root) ++i; continue; } - if (!ob->mesh->is_instanced()) - add_reference_mesh(bounds, center, ob->mesh, i); + if (!ob->geometry->is_instanced()) + add_reference_geometry(bounds, center, ob->geometry, i); else add_reference_object(bounds, center, ob, i); } else - add_reference_mesh(bounds, center, ob->mesh, i); + add_reference_geometry(bounds, center, ob->geometry, i); i++; diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index 9685e26cfac..3fe4c3799e2 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -35,6 +35,8 @@ class BVHNode; class BVHSpatialSplitBuildTask; class BVHParams; class InnerNode; +class Geometry; +class Hair; class Mesh; class Object; class Progress; @@ -65,8 +67,8 @@ class BVHBuild { /* Adding references. */ void add_reference_triangles(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i); - void add_reference_curves(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i); - void add_reference_mesh(BoundBox &root, BoundBox ¢er, Mesh *mesh, int i); + void add_reference_curves(BoundBox &root, BoundBox ¢er, Hair *hair, int i); + void add_reference_geometry(BoundBox &root, BoundBox ¢er, Geometry *geom, int i); void add_reference_object(BoundBox &root, BoundBox ¢er, Object *ob, int i); void add_references(BVHRange &root); diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp index 3e4978a2c0a..88302f11e7e 100644 --- a/intern/cycles/bvh/bvh_embree.cpp +++ b/intern/cycles/bvh/bvh_embree.cpp @@ -49,6 +49,7 @@ # include "kernel/kernel_globals.h" # include "kernel/kernel_random.h" +# include "render/hair.h" # include "render/mesh.h" # include "render/object.h" # include "util/util_foreach.h" @@ -301,10 +302,24 @@ RTCDevice BVHEmbree::rtc_shared_device = NULL; int BVHEmbree::rtc_shared_users = 0; thread_mutex BVHEmbree::rtc_shared_mutex; +static size_t count_primitives(Geometry *geom) +{ + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + return mesh->num_triangles(); + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + return hair->num_segments(); + } + + return 0; +} + BVHEmbree::BVHEmbree(const BVHParams ¶ms_, - const vector<Mesh *> &meshes_, + const vector<Geometry *> &geometry_, const vector<Object *> &objects_) - : BVH(params_, meshes_, objects_), + : BVH(params_, geometry_, objects_), scene(NULL), mem_used(0), top_level(NULL), @@ -436,29 +451,15 @@ void BVHEmbree::build(Progress &progress, Stats *stats_) if (!ob->is_traceable()) { continue; } - if (!ob->mesh->is_instanced()) { - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { - prim_count += ob->mesh->num_triangles(); - } - if (params.primitive_mask & PRIMITIVE_ALL_CURVE) { - for (size_t j = 0; j < ob->mesh->num_curves(); ++j) { - prim_count += ob->mesh->get_curve(j).num_segments(); - } - } + if (!ob->geometry->is_instanced()) { + prim_count += count_primitives(ob->geometry); } else { ++prim_count; } } else { - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) { - prim_count += ob->mesh->num_triangles(); - } - if (params.primitive_mask & PRIMITIVE_ALL_CURVE) { - for (size_t j = 0; j < ob->mesh->num_curves(); ++j) { - prim_count += ob->mesh->get_curve(j).num_segments(); - } - } + prim_count += count_primitives(ob->geometry); } } @@ -477,7 +478,7 @@ void BVHEmbree::build(Progress &progress, Stats *stats_) ++i; continue; } - if (!ob->mesh->is_instanced()) { + if (!ob->geometry->is_instanced()) { add_object(ob, i); } else { @@ -528,22 +529,29 @@ BVHNode *BVHEmbree::widen_children_nodes(const BVHNode * /*root*/) void BVHEmbree::add_object(Object *ob, int i) { - Mesh *mesh = ob->mesh; - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) { - add_triangles(ob, i); + Geometry *geom = ob->geometry; + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->num_triangles() > 0) { + add_triangles(ob, mesh, i); + } } - if (params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) { - add_curves(ob, i); + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + if (hair->num_curves() > 0) { + add_curves(ob, hair, i); + } } } void BVHEmbree::add_instance(Object *ob, int i) { - if (!ob || !ob->mesh) { + if (!ob || !ob->geometry) { assert(0); return; } - BVHEmbree *instance_bvh = (BVHEmbree *)(ob->mesh->bvh); + BVHEmbree *instance_bvh = (BVHEmbree *)(ob->geometry->bvh); if (instance_bvh->top_level != this) { instance_bvh->top_level = this; @@ -577,10 +585,9 @@ void BVHEmbree::add_instance(Object *ob, int i) rtcReleaseGeometry(geom_id); } -void BVHEmbree::add_triangles(Object *ob, int i) +void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i) { size_t prim_offset = pack.prim_index.size(); - Mesh *mesh = ob->mesh; const Attribute *attr_mP = NULL; size_t num_motion_steps = 1; if (mesh->has_motion_blur()) { @@ -684,31 +691,31 @@ void BVHEmbree::update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh) } } -void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh) +void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair) { const Attribute *attr_mP = NULL; size_t num_motion_steps = 1; - if (mesh->has_motion_blur()) { - attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (hair->has_motion_blur()) { + attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr_mP) { - num_motion_steps = mesh->motion_steps; + num_motion_steps = hair->motion_steps; } } - const size_t num_curves = mesh->num_curves(); + const size_t num_curves = hair->num_curves(); size_t num_keys = 0; for (size_t j = 0; j < num_curves; ++j) { - const Mesh::Curve c = mesh->get_curve(j); + const Hair::Curve c = hair->get_curve(j); num_keys += c.num_keys; } /* Copy the CV data to Embree */ const int t_mid = (num_motion_steps - 1) / 2; - const float *curve_radius = &mesh->curve_radius[0]; + const float *curve_radius = &hair->curve_radius[0]; for (int t = 0; t < num_motion_steps; ++t) { const float3 *verts; if (t == t_mid || attr_mP == NULL) { - verts = &mesh->curve_keys[0]; + verts = &hair->curve_keys[0]; } else { int t_ = (t > t_mid) ? (t - 1) : t; @@ -726,9 +733,9 @@ void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh assert(rtc_verts); if (rtc_verts) { if (use_curves && rtc_tangents) { - const size_t num_curves = mesh->num_curves(); + const size_t num_curves = hair->num_curves(); for (size_t j = 0; j < num_curves; ++j) { - Mesh::Curve c = mesh->get_curve(j); + Hair::Curve c = hair->get_curve(j); int fk = c.first_key; rtc_verts[0] = float3_to_float4(verts[fk]); rtc_verts[0].w = curve_radius[fk]; @@ -760,23 +767,22 @@ void BVHEmbree::update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh } } -void BVHEmbree::add_curves(Object *ob, int i) +void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i) { size_t prim_offset = pack.prim_index.size(); - const Mesh *mesh = ob->mesh; const Attribute *attr_mP = NULL; size_t num_motion_steps = 1; - if (mesh->has_motion_blur()) { - attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (hair->has_motion_blur()) { + attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (attr_mP) { - num_motion_steps = mesh->motion_steps; + num_motion_steps = hair->motion_steps; } } - const size_t num_curves = mesh->num_curves(); + const size_t num_curves = hair->num_curves(); size_t num_segments = 0; for (size_t j = 0; j < num_curves; ++j) { - Mesh::Curve c = mesh->get_curve(j); + Hair::Curve c = hair->get_curve(j); assert(c.num_segments() > 0); num_segments += c.num_segments(); } @@ -802,7 +808,7 @@ void BVHEmbree::add_curves(Object *ob, int i) geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT, sizeof(int), num_segments); size_t rtc_index = 0; for (size_t j = 0; j < num_curves; ++j) { - Mesh::Curve c = mesh->get_curve(j); + Hair::Curve c = hair->get_curve(j); for (size_t k = 0; k < c.num_segments(); ++k) { rtc_indices[rtc_index] = c.first_key + k; /* Cycles specific data. */ @@ -819,7 +825,7 @@ void BVHEmbree::add_curves(Object *ob, int i) rtcSetGeometryBuildQuality(geom_id, build_quality); rtcSetGeometryTimeStepCount(geom_id, num_motion_steps); - update_curve_vertex_buffer(geom_id, mesh); + update_curve_vertex_buffer(geom_id, hair); rtcSetGeometryUserData(geom_id, (void *)prim_offset); rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_func); @@ -840,10 +846,7 @@ void BVHEmbree::pack_nodes(const BVHNode *) for (size_t i = 0; i < pack.prim_index.size(); ++i) { if (pack.prim_index[i] != -1) { - if (pack.prim_type[i] & PRIMITIVE_ALL_CURVE) - pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->curve_offset; - else - pack.prim_index[i] += objects[pack.prim_object[i]]->mesh->tri_offset; + pack.prim_index[i] += objects[pack.prim_object[i]]->geometry->prim_offset; } } @@ -857,22 +860,22 @@ void BVHEmbree::pack_nodes(const BVHNode *) size_t pack_prim_tri_verts_offset = prim_tri_verts_size; size_t object_offset = 0; - map<Mesh *, int> mesh_map; + map<Geometry *, int> geometry_map; foreach (Object *ob, objects) { - Mesh *mesh = ob->mesh; - BVH *bvh = mesh->bvh; + Geometry *geom = ob->geometry; + BVH *bvh = geom->bvh; - if (mesh->need_build_bvh(BVH_LAYOUT_EMBREE)) { - if (mesh_map.find(mesh) == mesh_map.end()) { + if (geom->need_build_bvh(BVH_LAYOUT_EMBREE)) { + if (geometry_map.find(geom) == geometry_map.end()) { prim_index_size += bvh->pack.prim_index.size(); prim_tri_verts_size += bvh->pack.prim_tri_verts.size(); - mesh_map[mesh] = 1; + geometry_map[geom] = 1; } } } - mesh_map.clear(); + geometry_map.clear(); pack.prim_index.resize(prim_index_size); pack.prim_type.resize(prim_index_size); @@ -890,38 +893,37 @@ void BVHEmbree::pack_nodes(const BVHNode *) /* merge */ foreach (Object *ob, objects) { - Mesh *mesh = ob->mesh; + Geometry *geom = ob->geometry; /* We assume that if mesh doesn't need own BVH it was already included * into a top-level BVH and no packing here is needed. */ - if (!mesh->need_build_bvh(BVH_LAYOUT_EMBREE)) { + if (!geom->need_build_bvh(BVH_LAYOUT_EMBREE)) { pack.object_node[object_offset++] = prim_offset; continue; } - /* if mesh already added once, don't add it again, but used set + /* if geom already added once, don't add it again, but used set * node offset for this object */ - map<Mesh *, int>::iterator it = mesh_map.find(mesh); + map<Geometry *, int>::iterator it = geometry_map.find(geom); - if (mesh_map.find(mesh) != mesh_map.end()) { + if (geometry_map.find(geom) != geometry_map.end()) { int noffset = it->second; pack.object_node[object_offset++] = noffset; continue; } - BVHEmbree *bvh = (BVHEmbree *)mesh->bvh; + BVHEmbree *bvh = (BVHEmbree *)geom->bvh; rtc_memory_monitor_func(stats, unaccounted_mem, true); unaccounted_mem = 0; - int mesh_tri_offset = mesh->tri_offset; - int mesh_curve_offset = mesh->curve_offset; + int prim_offset = geom->prim_offset; /* fill in node indexes for instances */ pack.object_node[object_offset++] = prim_offset; - mesh_map[mesh] = pack.object_node[object_offset - 1]; + geometry_map[geom] = pack.object_node[object_offset - 1]; /* merge primitive, object and triangle indexes */ if (bvh->pack.prim_index.size()) { @@ -932,11 +934,11 @@ void BVHEmbree::pack_nodes(const BVHNode *) for (size_t i = 0; i < bvh_prim_index_size; ++i) { if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset; + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + prim_offset; pack_prim_tri_index[pack_prim_index_offset] = -1; } else { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + prim_offset; pack_prim_tri_index[pack_prim_index_offset] = bvh_prim_tri_index[i] + pack_prim_tri_verts_offset; } @@ -966,15 +968,22 @@ void BVHEmbree::refit_nodes() /* Update all vertex buffers, then tell Embree to rebuild/-fit the BVHs. */ unsigned geom_id = 0; foreach (Object *ob, objects) { - if (!params.top_level || (ob->is_traceable() && !ob->mesh->is_instanced())) { - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && ob->mesh->num_triangles() > 0) { - update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), ob->mesh); - rtcCommitGeometry(rtcGetGeometry(scene, geom_id)); + if (!params.top_level || (ob->is_traceable() && !ob->geometry->is_instanced())) { + Geometry *geom = ob->geometry; + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->num_triangles() > 0) { + update_tri_vertex_buffer(rtcGetGeometry(scene, geom_id), mesh); + rtcCommitGeometry(rtcGetGeometry(scene, geom_id)); + } } - - if (params.primitive_mask & PRIMITIVE_ALL_CURVE && ob->mesh->num_curves() > 0) { - update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id + 1), ob->mesh); - rtcCommitGeometry(rtcGetGeometry(scene, geom_id + 1)); + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + if (hair->num_curves() > 0) { + update_curve_vertex_buffer(rtcGetGeometry(scene, geom_id + 1), hair); + rtcCommitGeometry(rtcGetGeometry(scene, geom_id + 1)); + } } } geom_id += 2; diff --git a/intern/cycles/bvh/bvh_embree.h b/intern/cycles/bvh/bvh_embree.h index 123e87dd9b0..eb121d060b7 100644 --- a/intern/cycles/bvh/bvh_embree.h +++ b/intern/cycles/bvh/bvh_embree.h @@ -31,6 +31,8 @@ CCL_NAMESPACE_BEGIN +class Geometry; +class Hair; class Mesh; class BVHEmbree : public BVH { @@ -47,7 +49,7 @@ class BVHEmbree : public BVH { protected: friend class BVH; BVHEmbree(const BVHParams ¶ms, - const vector<Mesh *> &meshes, + const vector<Geometry *> &geometry, const vector<Object *> &objects); virtual void pack_nodes(const BVHNode *) override; @@ -55,8 +57,8 @@ class BVHEmbree : public BVH { void add_object(Object *ob, int i); void add_instance(Object *ob, int i); - void add_curves(Object *ob, int i); - void add_triangles(Object *ob, int i); + void add_curves(const Object *ob, const Hair *hair, int i); + void add_triangles(const Object *ob, const Mesh *mesh, int i); ssize_t mem_used; @@ -69,7 +71,7 @@ class BVHEmbree : public BVH { private: void delete_rtcScene(); void update_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh); - void update_curve_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh); + void update_curve_vertex_buffer(RTCGeometry geom_id, const Hair *hair); static RTCDevice rtc_shared_device; static int rtc_shared_users; diff --git a/intern/cycles/bvh/bvh_optix.cpp b/intern/cycles/bvh/bvh_optix.cpp index 86d755ab06a..a3b6261dcad 100644 --- a/intern/cycles/bvh/bvh_optix.cpp +++ b/intern/cycles/bvh/bvh_optix.cpp @@ -18,6 +18,8 @@ #ifdef WITH_OPTIX # include "bvh/bvh_optix.h" +# include "render/hair.h" +# include "render/geometry.h" # include "render/mesh.h" # include "render/object.h" # include "util/util_logging.h" @@ -26,9 +28,9 @@ CCL_NAMESPACE_BEGIN BVHOptiX::BVHOptiX(const BVHParams ¶ms_, - const vector<Mesh *> &meshes_, + const vector<Geometry *> &geometry_, const vector<Object *> &objects_) - : BVH(params_, meshes_, objects_) + : BVH(params_, geometry_, objects_) { } @@ -56,47 +58,52 @@ void BVHOptiX::copy_to_device(Progress &progress, DeviceScene *dscene) void BVHOptiX::pack_blas() { // Bottom-level BVH can contain multiple primitive types, so merge them: - assert(meshes.size() == 1 && objects.size() == 1); // These are build per-mesh - Mesh *const mesh = meshes[0]; - - if (params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) { - const size_t num_curves = mesh->num_curves(); - const size_t num_segments = mesh->num_segments(); - pack.prim_type.reserve(pack.prim_type.size() + num_segments); - pack.prim_index.reserve(pack.prim_index.size() + num_segments); - pack.prim_object.reserve(pack.prim_object.size() + num_segments); - // 'pack.prim_time' is only used in geom_curve_intersect.h - // It is not needed because of OPTIX_MOTION_FLAG_[START|END]_VANISH - - uint type = PRIMITIVE_CURVE; - if (mesh->use_motion_blur && mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) - type = PRIMITIVE_MOTION_CURVE; - - for (size_t j = 0; j < num_curves; ++j) { - const Mesh::Curve curve = mesh->get_curve(j); - for (size_t k = 0; k < curve.num_segments(); ++k) { - pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k)); - // Each curve segment points back to its curve index - pack.prim_index.push_back_reserved(j); - pack.prim_object.push_back_reserved(0); + assert(geometry.size() == 1 && objects.size() == 1); // These are built per-mesh + Geometry *const geom = geometry[0]; + + if (geom->type == Geometry::HAIR) { + Hair *const hair = static_cast<Hair *const>(geom); + if (hair->num_curves() > 0) { + const size_t num_curves = hair->num_curves(); + const size_t num_segments = hair->num_segments(); + pack.prim_type.reserve(pack.prim_type.size() + num_segments); + pack.prim_index.reserve(pack.prim_index.size() + num_segments); + pack.prim_object.reserve(pack.prim_object.size() + num_segments); + // 'pack.prim_time' is only used in geom_curve_intersect.h + // It is not needed because of OPTIX_MOTION_FLAG_[START|END]_VANISH + + uint type = PRIMITIVE_CURVE; + if (hair->use_motion_blur && hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) + type = PRIMITIVE_MOTION_CURVE; + + for (size_t j = 0; j < num_curves; ++j) { + const Hair::Curve curve = hair->get_curve(j); + for (size_t k = 0; k < curve.num_segments(); ++k) { + pack.prim_type.push_back_reserved(PRIMITIVE_PACK_SEGMENT(type, k)); + // Each curve segment points back to its curve index + pack.prim_index.push_back_reserved(j); + pack.prim_object.push_back_reserved(0); + } } } } - - if (params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) { - const size_t num_triangles = mesh->num_triangles(); - pack.prim_type.reserve(pack.prim_type.size() + num_triangles); - pack.prim_index.reserve(pack.prim_index.size() + num_triangles); - pack.prim_object.reserve(pack.prim_object.size() + num_triangles); - - uint type = PRIMITIVE_TRIANGLE; - if (mesh->use_motion_blur && mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) - type = PRIMITIVE_MOTION_TRIANGLE; - - for (size_t k = 0; k < num_triangles; ++k) { - pack.prim_type.push_back_reserved(type); - pack.prim_index.push_back_reserved(k); - pack.prim_object.push_back_reserved(0); + else if (geom->type == Geometry::MESH) { + Mesh *const mesh = static_cast<Mesh *const>(geom); + if (mesh->num_triangles() > 0) { + const size_t num_triangles = mesh->num_triangles(); + pack.prim_type.reserve(pack.prim_type.size() + num_triangles); + pack.prim_index.reserve(pack.prim_index.size() + num_triangles); + pack.prim_object.reserve(pack.prim_object.size() + num_triangles); + + uint type = PRIMITIVE_TRIANGLE; + if (mesh->use_motion_blur && mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) + type = PRIMITIVE_MOTION_TRIANGLE; + + for (size_t k = 0; k < num_triangles; ++k) { + pack.prim_type.push_back_reserved(type); + pack.prim_index.push_back_reserved(k); + pack.prim_object.push_back_reserved(0); + } } } @@ -116,8 +123,8 @@ void BVHOptiX::pack_tlas() // Calculate total packed size size_t prim_index_size = 0; size_t prim_tri_verts_size = 0; - foreach (Mesh *mesh, meshes) { - BVH *const bvh = mesh->bvh; + foreach (Geometry *geom, geometry) { + BVH *const bvh = geom->bvh; prim_index_size += bvh->pack.prim_index.size(); prim_tri_verts_size += bvh->pack.prim_tri_verts.size(); } @@ -141,13 +148,12 @@ void BVHOptiX::pack_tlas() pack.prim_tri_verts.resize(prim_tri_verts_size); float4 *pack_prim_tri_verts = pack.prim_tri_verts.data(); - // Top-level BVH should only contain instances, see 'Mesh::need_build_bvh' + // Top-level BVH should only contain instances, see 'Geometry::need_build_bvh' // Iterate over scene mesh list instead of objects, since the 'prim_offset' is calculated based // on that list, which may be ordered differently from the object list. - foreach (Mesh *mesh, meshes) { - PackedBVH &bvh_pack = mesh->bvh->pack; - int mesh_tri_offset = mesh->tri_offset; - int mesh_curve_offset = mesh->curve_offset; + foreach (Geometry *geom, geometry) { + PackedBVH &bvh_pack = geom->bvh->pack; + int geom_prim_offset = geom->prim_offset; // Merge primitive, object and triangle indexes if (!bvh_pack.prim_index.empty()) { @@ -158,16 +164,16 @@ void BVHOptiX::pack_tlas() for (size_t i = 0; i < bvh_pack.prim_index.size(); i++, pack_offset++) { if (bvh_pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_offset] = bvh_prim_index[i] + mesh_curve_offset; + pack_prim_index[pack_offset] = bvh_prim_index[i] + geom_prim_offset; pack_prim_tri_index[pack_offset] = -1; } else { - pack_prim_index[pack_offset] = bvh_prim_index[i] + mesh_tri_offset; + pack_prim_index[pack_offset] = bvh_prim_index[i] + geom_prim_offset; pack_prim_tri_index[pack_offset] = bvh_prim_tri_index[i] + pack_verts_offset; } pack_prim_type[pack_offset] = bvh_prim_type[i]; - pack_prim_object[pack_offset] = 0; // Unused for instanced meshes + pack_prim_object[pack_offset] = 0; // Unused for instanced geometry pack_prim_visibility[pack_offset] = bvh_prim_visibility[i]; } } @@ -182,15 +188,24 @@ void BVHOptiX::pack_tlas() } } - // Merge visibility flags of all objects and fix object indices for non-instanced meshes + // Merge visibility flags of all objects and fix object indices for non-instanced geometry foreach (Object *ob, objects) { - Mesh *const mesh = ob->mesh; - for (size_t i = 0; i < mesh->num_primitives(); ++i) { - if (!ob->mesh->is_instanced()) { - assert(pack.prim_object[mesh->prim_offset + i] == 0); - pack.prim_object[mesh->prim_offset + i] = ob->get_device_index(); + Geometry *const geom = ob->geometry; + size_t num_primitives = 0; + + if (geom->type == Geometry::MESH) { + num_primitives = static_cast<Mesh *const>(geom)->num_triangles(); + } + else if (geom->type == Geometry::HAIR) { + num_primitives = static_cast<Hair *const>(geom)->num_segments(); + } + + for (size_t i = 0; i < num_primitives; ++i) { + if (!geom->is_instanced()) { + assert(pack.prim_object[geom->optix_prim_offset + i] == 0); + pack.prim_object[geom->optix_prim_offset + i] = ob->get_device_index(); } - pack.prim_visibility[mesh->prim_offset + i] |= ob->visibility_for_tracing(); + pack.prim_visibility[geom->optix_prim_offset + i] |= ob->visibility_for_tracing(); } } } diff --git a/intern/cycles/bvh/bvh_optix.h b/intern/cycles/bvh/bvh_optix.h index 35033fe635f..e4745b093b5 100644 --- a/intern/cycles/bvh/bvh_optix.h +++ b/intern/cycles/bvh/bvh_optix.h @@ -26,11 +26,16 @@ CCL_NAMESPACE_BEGIN +class Geometry; +class Optix; + class BVHOptiX : public BVH { friend class BVH; public: - BVHOptiX(const BVHParams ¶ms, const vector<Mesh *> &meshes, const vector<Object *> &objects); + BVHOptiX(const BVHParams ¶ms, + const vector<Geometry *> &geometry, + const vector<Object *> &objects); virtual ~BVHOptiX(); virtual void build(Progress &progress, Stats *) override; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 2731662a39d..5e2c4b63f1b 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -69,9 +69,6 @@ class BVHParams { /* BVH layout to be built. */ BVHLayout bvh_layout; - /* Mask of primitives to be included into the BVH. */ - int primitive_mask; - /* Use unaligned bounding boxes. * Only used for curves BVH. */ @@ -120,8 +117,6 @@ class BVHParams { bvh_layout = BVH_LAYOUT_BVH2; use_unaligned_nodes = false; - primitive_mask = PRIMITIVE_ALL; - num_motion_curve_steps = 0; num_motion_triangle_steps = 0; diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index bd261c10d55..7e787674b74 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -20,6 +20,7 @@ #include "bvh/bvh_build.h" #include "bvh/bvh_sort.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/object.h" @@ -378,7 +379,7 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh, } } -void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh, +void BVHSpatialSplit::split_curve_primitive(const Hair *hair, const Transform *tfm, int prim_index, int segment_index, @@ -388,11 +389,11 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh, BoundBox &right_bounds) { /* curve split: NOTE - Currently ignores curve width and needs to be fixed.*/ - Mesh::Curve curve = mesh->get_curve(prim_index); + Hair::Curve curve = hair->get_curve(prim_index); const int k0 = curve.first_key + segment_index; const int k1 = k0 + 1; - float3 v0 = mesh->curve_keys[k0]; - float3 v1 = mesh->curve_keys[k1]; + float3 v0 = hair->curve_keys[k0]; + float3 v1 = hair->curve_keys[k1]; if (tfm != NULL) { v0 = transform_point(tfm, v0); @@ -436,13 +437,13 @@ void BVHSpatialSplit::split_triangle_reference(const BVHReference &ref, } void BVHSpatialSplit::split_curve_reference(const BVHReference &ref, - const Mesh *mesh, + const Hair *hair, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds) { - split_curve_primitive(mesh, + split_curve_primitive(hair, NULL, ref.prim_index(), PRIMITIVE_UNPACK_SEGMENT(ref.prim_type()), @@ -455,15 +456,22 @@ void BVHSpatialSplit::split_curve_reference(const BVHReference &ref, void BVHSpatialSplit::split_object_reference( const Object *object, int dim, float pos, BoundBox &left_bounds, BoundBox &right_bounds) { - Mesh *mesh = object->mesh; - for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) { - split_triangle_primitive(mesh, &object->tfm, tri_idx, dim, pos, left_bounds, right_bounds); + Geometry *geom = object->geometry; + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + for (int tri_idx = 0; tri_idx < mesh->num_triangles(); ++tri_idx) { + split_triangle_primitive(mesh, &object->tfm, tri_idx, dim, pos, left_bounds, right_bounds); + } } - for (int curve_idx = 0; curve_idx < mesh->num_curves(); ++curve_idx) { - Mesh::Curve curve = mesh->get_curve(curve_idx); - for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) { - split_curve_primitive( - mesh, &object->tfm, curve_idx, segment_idx, dim, pos, left_bounds, right_bounds); + else if (geom->type == Geometry::MESH) { + Hair *hair = static_cast<Hair *>(geom); + for (int curve_idx = 0; curve_idx < hair->num_curves(); ++curve_idx) { + Hair::Curve curve = hair->get_curve(curve_idx); + for (int segment_idx = 0; segment_idx < curve.num_keys - 1; ++segment_idx) { + split_curve_primitive( + hair, &object->tfm, curve_idx, segment_idx, dim, pos, left_bounds, right_bounds); + } } } } @@ -481,13 +489,14 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder, /* loop over vertices/edges. */ const Object *ob = builder.objects[ref.prim_object()]; - const Mesh *mesh = ob->mesh; if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) { + Mesh *mesh = static_cast<Mesh *>(ob->geometry); split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds); } else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) { - split_curve_reference(ref, mesh, dim, pos, left_bounds, right_bounds); + Hair *hair = static_cast<Hair *>(ob->geometry); + split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds); } else { split_object_reference(ob, dim, pos, left_bounds, right_bounds); diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h index eddd1c27f49..5f2e41cf343 100644 --- a/intern/cycles/bvh/bvh_split.h +++ b/intern/cycles/bvh/bvh_split.h @@ -24,6 +24,8 @@ CCL_NAMESPACE_BEGIN class BVHBuild; +class Hair; +class Mesh; struct Transform; /* Object Split */ @@ -113,7 +115,7 @@ class BVHSpatialSplit { float pos, BoundBox &left_bounds, BoundBox &right_bounds); - void split_curve_primitive(const Mesh *mesh, + void split_curve_primitive(const Hair *hair, const Transform *tfm, int prim_index, int segment_index, @@ -134,7 +136,7 @@ class BVHSpatialSplit { BoundBox &left_bounds, BoundBox &right_bounds); void split_curve_reference(const BVHReference &ref, - const Mesh *mesh, + const Hair *hair, int dim, float pos, BoundBox &left_bounds, diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp index 1843ca403a5..f0995f343fe 100644 --- a/intern/cycles/bvh/bvh_unaligned.cpp +++ b/intern/cycles/bvh/bvh_unaligned.cpp @@ -16,7 +16,7 @@ #include "bvh/bvh_unaligned.h" -#include "render/mesh.h" +#include "render/hair.h" #include "render/object.h" #include "bvh/bvh_binning.h" @@ -71,10 +71,10 @@ bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *ali if (type & PRIMITIVE_CURVE) { const int curve_index = ref.prim_index(); const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); - const Mesh *mesh = object->mesh; - const Mesh::Curve &curve = mesh->get_curve(curve_index); + const Hair *hair = static_cast<const Hair *>(object->geometry); + const Hair::Curve &curve = hair->get_curve(curve_index); const int key = curve.first_key + segment; - const float3 v1 = mesh->curve_keys[key], v2 = mesh->curve_keys[key + 1]; + const float3 v1 = hair->curve_keys[key], v2 = hair->curve_keys[key + 1]; float length; const float3 axis = normalize_len(v2 - v1, &length); if (length > 1e-6f) { @@ -96,10 +96,10 @@ BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim, if (type & PRIMITIVE_CURVE) { const int curve_index = prim.prim_index(); const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); - const Mesh *mesh = object->mesh; - const Mesh::Curve &curve = mesh->get_curve(curve_index); + const Hair *hair = static_cast<const Hair *>(object->geometry); + const Hair::Curve &curve = hair->get_curve(curve_index); curve.bounds_grow( - segment, &mesh->curve_keys[0], &mesh->curve_radius[0], aligned_space, bounds); + segment, &hair->curve_keys[0], &hair->curve_radius[0], aligned_space, bounds); } else { bounds = prim.bounds().transformed(&aligned_space); diff --git a/intern/cycles/device/device_optix.cpp b/intern/cycles/device/device_optix.cpp index f479cbd7414..98469fb37b0 100644 --- a/intern/cycles/device/device_optix.cpp +++ b/intern/cycles/device/device_optix.cpp @@ -22,6 +22,7 @@ # include "device/device_denoising.h" # include "bvh/bvh.h" # include "render/scene.h" +# include "render/hair.h" # include "render/mesh.h" # include "render/object.h" # include "render/buffers.h" @@ -1229,8 +1230,8 @@ class OptiXDevice : public Device { assert(bvh->params.top_level); unsigned int num_instances = 0; - unordered_map<Mesh *, vector<OptixTraversableHandle>> meshes; - meshes.reserve(bvh->meshes.size()); + unordered_map<Geometry *, OptixTraversableHandle> geometry; + geometry.reserve(bvh->geometry.size()); // Free all previous acceleration structures for (CUdeviceptr mem : as_mem) { @@ -1241,23 +1242,25 @@ class OptiXDevice : public Device { // Build bottom level acceleration structures (BLAS) // Note: Always keep this logic in sync with bvh_optix.cpp! for (Object *ob : bvh->objects) { - // Skip meshes for which acceleration structure already exists - if (meshes.find(ob->mesh) != meshes.end()) + // Skip geometry for which acceleration structure already exists + Geometry *geom = ob->geometry; + if (geometry.find(geom) != geometry.end()) continue; - Mesh *const mesh = ob->mesh; - vector<OptixTraversableHandle> handles; - handles.reserve(2); + if (geom->type == Geometry::HAIR) { + // Build BLAS for curve primitives + Hair *const hair = static_cast<Hair *const>(ob->geometry); + if (hair->num_curves() == 0) { + continue; + } - // Build BLAS for curve primitives - if (bvh->params.primitive_mask & PRIMITIVE_ALL_CURVE && mesh->num_curves() > 0) { - const size_t num_curves = mesh->num_curves(); - const size_t num_segments = mesh->num_segments(); + const size_t num_curves = hair->num_curves(); + const size_t num_segments = hair->num_segments(); size_t num_motion_steps = 1; - Attribute *motion_keys = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (motion_blur && mesh->use_motion_blur && motion_keys) { - num_motion_steps = mesh->motion_steps; + Attribute *motion_keys = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (motion_blur && hair->use_motion_blur && motion_keys) { + num_motion_steps = hair->motion_steps; } device_vector<OptixAabb> aabb_data(this, "temp_aabb_data", MEM_READ_ONLY); @@ -1266,21 +1269,21 @@ class OptiXDevice : public Device { // Get AABBs for each motion step for (size_t step = 0; step < num_motion_steps; ++step) { // The center step for motion vertices is not stored in the attribute - const float3 *keys = mesh->curve_keys.data(); + const float3 *keys = hair->curve_keys.data(); size_t center_step = (num_motion_steps - 1) / 2; if (step != center_step) { size_t attr_offset = (step > center_step) ? step - 1 : step; // Technically this is a float4 array, but sizeof(float3) is the same as sizeof(float4) - keys = motion_keys->data_float3() + attr_offset * mesh->curve_keys.size(); + keys = motion_keys->data_float3() + attr_offset * hair->curve_keys.size(); } size_t i = step * num_segments; for (size_t j = 0; j < num_curves; ++j) { - const Mesh::Curve c = mesh->get_curve(j); + const Hair::Curve c = hair->get_curve(j); for (size_t k = 0; k < c.num_segments(); ++i, ++k) { BoundBox bounds = BoundBox::empty; - c.bounds_grow(k, keys, mesh->curve_radius.data(), bounds); + c.bounds_grow(k, keys, hair->curve_radius.data(), bounds); aabb_data[i].minX = bounds.min.x; aabb_data[i].minY = bounds.min.y; @@ -1311,16 +1314,24 @@ class OptiXDevice : public Device { build_input.aabbArray.strideInBytes = sizeof(OptixAabb); build_input.aabbArray.flags = &build_flags; build_input.aabbArray.numSbtRecords = 1; - build_input.aabbArray.primitiveIndexOffset = mesh->prim_offset; + build_input.aabbArray.primitiveIndexOffset = hair->optix_prim_offset; // Allocate memory for new BLAS and build it - handles.emplace_back(); - if (!build_optix_bvh(build_input, num_motion_steps, handles.back())) + OptixTraversableHandle handle; + if (build_optix_bvh(build_input, num_motion_steps, handle)) { + geometry.insert({ob->geometry, handle}); + } + else { return false; + } } + else if (geom->type == Geometry::MESH) { + // Build BLAS for triangle primitives + Mesh *const mesh = static_cast<Mesh *const>(ob->geometry); + if (mesh->num_triangles() == 0) { + continue; + } - // Build BLAS for triangle primitives - if (bvh->params.primitive_mask & PRIMITIVE_ALL_TRIANGLE && mesh->num_triangles() > 0) { const size_t num_verts = mesh->verts.size(); size_t num_motion_steps = 1; @@ -1375,23 +1386,24 @@ class OptiXDevice : public Device { // buffers for that purpose. OptiX does not allow this to be zero though, so just pass in // one and rely on that having the same meaning in this case. build_input.triangleArray.numSbtRecords = 1; - // Triangle primitives are packed right after the curve primitives of this mesh - build_input.triangleArray.primitiveIndexOffset = mesh->prim_offset + mesh->num_segments(); + build_input.triangleArray.primitiveIndexOffset = mesh->optix_prim_offset; // Allocate memory for new BLAS and build it - handles.emplace_back(); - if (!build_optix_bvh(build_input, num_motion_steps, handles.back())) + OptixTraversableHandle handle; + if (build_optix_bvh(build_input, num_motion_steps, handle)) { + geometry.insert({ob->geometry, handle}); + } + else { return false; + } } - - meshes.insert({mesh, handles}); } // Fill instance descriptions device_vector<OptixAabb> aabbs(this, "tlas_aabbs", MEM_READ_ONLY); - aabbs.alloc(bvh->objects.size() * 2); + aabbs.alloc(bvh->objects.size()); device_vector<OptixInstance> instances(this, "tlas_instances", MEM_READ_ONLY); - instances.alloc(bvh->objects.size() * 2); + instances.alloc(bvh->objects.size()); for (Object *ob : bvh->objects) { // Skip non-traceable objects @@ -1399,113 +1411,117 @@ class OptiXDevice : public Device { continue; // Create separate instance for triangle/curve meshes of an object - for (OptixTraversableHandle handle : meshes[ob->mesh]) { - OptixAabb &aabb = aabbs[num_instances]; - aabb.minX = ob->bounds.min.x; - aabb.minY = ob->bounds.min.y; - aabb.minZ = ob->bounds.min.z; - aabb.maxX = ob->bounds.max.x; - aabb.maxY = ob->bounds.max.y; - aabb.maxZ = ob->bounds.max.z; - - OptixInstance &instance = instances[num_instances++]; - memset(&instance, 0, sizeof(instance)); - - // Clear transform to identity matrix - instance.transform[0] = 1.0f; - instance.transform[5] = 1.0f; - instance.transform[10] = 1.0f; - - // Set user instance ID to object index - instance.instanceId = ob->get_device_index(); - - // Volumes have a special bit set in the visibility mask so a trace can mask only volumes - // See 'scene_intersect_volume' in bvh.h - instance.visibilityMask = (ob->mesh->has_volume ? 3 : 1); - - // Insert motion traversable if object has motion - if (motion_blur && ob->use_motion()) { - size_t motion_keys = max(ob->motion.size(), 2) - 2; - size_t motion_transform_size = sizeof(OptixSRTMotionTransform) + - motion_keys * sizeof(OptixSRTData); - - const CUDAContextScope scope(cuda_context); - - CUdeviceptr motion_transform_gpu = 0; - check_result_cuda_ret(cuMemAlloc(&motion_transform_gpu, motion_transform_size)); - as_mem.push_back(motion_transform_gpu); - - // Allocate host side memory for motion transform and fill it with transform data - OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>( - new uint8_t[motion_transform_size]); - motion_transform.child = handle; - motion_transform.motionOptions.numKeys = ob->motion.size(); - motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE; - motion_transform.motionOptions.timeBegin = 0.0f; - motion_transform.motionOptions.timeEnd = 1.0f; - - OptixSRTData *const srt_data = motion_transform.srtData; - array<DecomposedTransform> decomp(ob->motion.size()); - transform_motion_decompose(decomp.data(), ob->motion.data(), ob->motion.size()); - - for (size_t i = 0; i < ob->motion.size(); ++i) { - // Scale - srt_data[i].sx = decomp[i].y.w; // scale.x.x - srt_data[i].sy = decomp[i].z.w; // scale.y.y - srt_data[i].sz = decomp[i].w.w; // scale.z.z - - // Shear - srt_data[i].a = decomp[i].z.x; // scale.x.y - srt_data[i].b = decomp[i].z.y; // scale.x.z - srt_data[i].c = decomp[i].w.x; // scale.y.z - assert(decomp[i].z.z == 0.0f); // scale.y.x - assert(decomp[i].w.y == 0.0f); // scale.z.x - assert(decomp[i].w.z == 0.0f); // scale.z.y - - // Pivot point - srt_data[i].pvx = 0.0f; - srt_data[i].pvy = 0.0f; - srt_data[i].pvz = 0.0f; - - // Rotation - srt_data[i].qx = decomp[i].x.x; - srt_data[i].qy = decomp[i].x.y; - srt_data[i].qz = decomp[i].x.z; - srt_data[i].qw = decomp[i].x.w; - - // Translation - srt_data[i].tx = decomp[i].y.x; - srt_data[i].ty = decomp[i].y.y; - srt_data[i].tz = decomp[i].y.z; - } + auto handle_it = geometry.find(ob->geometry); + if (handle_it == geometry.end()) { + continue; + } + OptixTraversableHandle handle = handle_it->second; - // Upload motion transform to GPU - cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size); - delete[] reinterpret_cast<uint8_t *>(&motion_transform); + OptixAabb &aabb = aabbs[num_instances]; + aabb.minX = ob->bounds.min.x; + aabb.minY = ob->bounds.min.y; + aabb.minZ = ob->bounds.min.z; + aabb.maxX = ob->bounds.max.x; + aabb.maxY = ob->bounds.max.y; + aabb.maxZ = ob->bounds.max.z; - // Disable instance transform if object uses motion transform already - instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM; + OptixInstance &instance = instances[num_instances++]; + memset(&instance, 0, sizeof(instance)); - // Get traversable handle to motion transform - optixConvertPointerToTraversableHandle(context, - motion_transform_gpu, - OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM, - &instance.traversableHandle); + // Clear transform to identity matrix + instance.transform[0] = 1.0f; + instance.transform[5] = 1.0f; + instance.transform[10] = 1.0f; + + // Set user instance ID to object index + instance.instanceId = ob->get_device_index(); + + // Volumes have a special bit set in the visibility mask so a trace can mask only volumes + // See 'scene_intersect_volume' in bvh.h + instance.visibilityMask = (ob->geometry->has_volume ? 3 : 1); + + // Insert motion traversable if object has motion + if (motion_blur && ob->use_motion()) { + size_t motion_keys = max(ob->motion.size(), 2) - 2; + size_t motion_transform_size = sizeof(OptixSRTMotionTransform) + + motion_keys * sizeof(OptixSRTData); + + const CUDAContextScope scope(cuda_context); + + CUdeviceptr motion_transform_gpu = 0; + check_result_cuda_ret(cuMemAlloc(&motion_transform_gpu, motion_transform_size)); + as_mem.push_back(motion_transform_gpu); + + // Allocate host side memory for motion transform and fill it with transform data + OptixSRTMotionTransform &motion_transform = *reinterpret_cast<OptixSRTMotionTransform *>( + new uint8_t[motion_transform_size]); + motion_transform.child = handle; + motion_transform.motionOptions.numKeys = ob->motion.size(); + motion_transform.motionOptions.flags = OPTIX_MOTION_FLAG_NONE; + motion_transform.motionOptions.timeBegin = 0.0f; + motion_transform.motionOptions.timeEnd = 1.0f; + + OptixSRTData *const srt_data = motion_transform.srtData; + array<DecomposedTransform> decomp(ob->motion.size()); + transform_motion_decompose(decomp.data(), ob->motion.data(), ob->motion.size()); + + for (size_t i = 0; i < ob->motion.size(); ++i) { + // Scale + srt_data[i].sx = decomp[i].y.w; // scale.x.x + srt_data[i].sy = decomp[i].z.w; // scale.y.y + srt_data[i].sz = decomp[i].w.w; // scale.z.z + + // Shear + srt_data[i].a = decomp[i].z.x; // scale.x.y + srt_data[i].b = decomp[i].z.y; // scale.x.z + srt_data[i].c = decomp[i].w.x; // scale.y.z + assert(decomp[i].z.z == 0.0f); // scale.y.x + assert(decomp[i].w.y == 0.0f); // scale.z.x + assert(decomp[i].w.z == 0.0f); // scale.z.y + + // Pivot point + srt_data[i].pvx = 0.0f; + srt_data[i].pvy = 0.0f; + srt_data[i].pvz = 0.0f; + + // Rotation + srt_data[i].qx = decomp[i].x.x; + srt_data[i].qy = decomp[i].x.y; + srt_data[i].qz = decomp[i].x.z; + srt_data[i].qw = decomp[i].x.w; + + // Translation + srt_data[i].tx = decomp[i].y.x; + srt_data[i].ty = decomp[i].y.y; + srt_data[i].tz = decomp[i].y.z; } - else { - instance.traversableHandle = handle; - if (ob->mesh->is_instanced()) { - // Set transform matrix - memcpy(instance.transform, &ob->tfm, sizeof(instance.transform)); - } - else { - // Disable instance transform if mesh already has it applied to vertex data - instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM; - // Non-instanced objects read ID from prim_object, so - // distinguish them from instanced objects with high bit set - instance.instanceId |= 0x800000; - } + // Upload motion transform to GPU + cuMemcpyHtoD(motion_transform_gpu, &motion_transform, motion_transform_size); + delete[] reinterpret_cast<uint8_t *>(&motion_transform); + + // Disable instance transform if object uses motion transform already + instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM; + + // Get traversable handle to motion transform + optixConvertPointerToTraversableHandle(context, + motion_transform_gpu, + OPTIX_TRAVERSABLE_TYPE_SRT_MOTION_TRANSFORM, + &instance.traversableHandle); + } + else { + instance.traversableHandle = handle; + + if (ob->geometry->is_instanced()) { + // Set transform matrix + memcpy(instance.transform, &ob->tfm, sizeof(instance.transform)); + } + else { + // Disable instance transform if geometry already has it applied to vertex data + instance.flags = OPTIX_INSTANCE_FLAG_DISABLE_TRANSFORM; + // Non-instanced objects read ID from prim_object, so + // distinguish them from instanced objects with high bit set + instance.instanceId |= 0x800000; } } } @@ -2603,8 +2619,8 @@ bool device_optix_init() # ifdef WITH_CUDA_DYNLOAD // Load NVRTC function pointers for adaptive kernel compilation if (DebugFlags().cuda.adaptive_compile && cuewInit(CUEW_INIT_NVRTC) != CUEW_SUCCESS) { - VLOG(1) - << "CUEW initialization failed for NVRTC. Adaptive kernel compilation won't be available."; + VLOG(1) << "CUEW initialization failed for NVRTC. Adaptive kernel compilation won't be " + "available."; } # endif diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index a4461ec7abb..a79d44b82f3 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -153,12 +153,12 @@ struct NodeType { template<typename T> const NodeType *structname::register_type() #define NODE_ABSTRACT_DECLARE \ - template<typename T> static const NodeType *register_type(); \ - static const NodeType *node_type; + template<typename T> static const NodeType *register_base_type(); \ + static const NodeType *node_base_type; #define NODE_ABSTRACT_DEFINE(structname) \ - const NodeType *structname::node_type = structname::register_type<structname>(); \ - template<typename T> const NodeType *structname::register_type() + const NodeType *structname::node_base_type = structname::register_base_type<structname>(); \ + template<typename T> const NodeType *structname::register_base_type() /* Sock Definition Macros */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 4cac6e9ca5f..1e1d161ff9b 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -726,8 +726,8 @@ typedef enum PrimitiveType { typedef enum AttributePrimitive { ATTR_PRIM_TRIANGLE = 0, - ATTR_PRIM_CURVE, ATTR_PRIM_SUBD, + ATTR_PRIM_CURVE, ATTR_PRIM_TYPES } AttributePrimitive; diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index 92578b888a6..9e876b8d95c 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -19,7 +19,9 @@ set(SRC coverage.cpp denoising.cpp film.cpp + geometry.cpp graph.cpp + hair.cpp image.cpp integrator.cpp light.cpp @@ -54,7 +56,9 @@ set(SRC_HEADERS coverage.h denoising.h film.h + geometry.h graph.h + hair.h image.h integrator.h light.h diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index b65c2faa788..fcba901ae6c 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -15,6 +15,7 @@ */ #include "render/image.h" +#include "render/hair.h" #include "render/mesh.h" #include "render/attribute.h" @@ -52,13 +53,13 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_) type == TypeRGBA); } -void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only) +void Attribute::resize(Geometry *geom, AttributePrimitive prim, bool reserve_only) { if (reserve_only) { - buffer.reserve(buffer_size(mesh, prim)); + buffer.reserve(buffer_size(geom, prim)); } else { - buffer.resize(buffer_size(mesh, prim), 0); + buffer.resize(buffer_size(geom, prim), 0); } } @@ -157,13 +158,13 @@ size_t Attribute::data_sizeof() const return sizeof(float3); } -size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const +size_t Attribute::element_size(Geometry *geom, AttributePrimitive prim) const { if (flags & ATTR_FINAL_SIZE) { return buffer.size() / data_sizeof(); } - size_t size; + size_t size = 0; switch (element) { case ATTR_ELEMENT_OBJECT: @@ -172,54 +173,74 @@ size_t Attribute::element_size(Mesh *mesh, AttributePrimitive prim) const size = 1; break; case ATTR_ELEMENT_VERTEX: - size = mesh->verts.size() + mesh->num_ngons; - if (prim == ATTR_PRIM_SUBD) { - size -= mesh->num_subd_verts; + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + size = mesh->verts.size() + mesh->num_ngons; + if (prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts; + } } break; case ATTR_ELEMENT_VERTEX_MOTION: - size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); - if (prim == ATTR_PRIM_SUBD) { - size -= mesh->num_subd_verts * (mesh->motion_steps - 1); + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + size = (mesh->verts.size() + mesh->num_ngons) * (mesh->motion_steps - 1); + if (prim == ATTR_PRIM_SUBD) { + size -= mesh->num_subd_verts * (mesh->motion_steps - 1); + } } break; case ATTR_ELEMENT_FACE: - if (prim == ATTR_PRIM_TRIANGLE) { - size = mesh->num_triangles(); - } - else { - size = mesh->subd_faces.size() + mesh->num_ngons; + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles(); + } + else { + size = mesh->subd_faces.size() + mesh->num_ngons; + } } break; case ATTR_ELEMENT_CORNER: case ATTR_ELEMENT_CORNER_BYTE: - if (prim == ATTR_PRIM_TRIANGLE) { - size = mesh->num_triangles() * 3; - } - else { - size = mesh->subd_face_corners.size() + mesh->num_ngons; + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (prim == ATTR_PRIM_TRIANGLE) { + size = mesh->num_triangles() * 3; + } + else { + size = mesh->subd_face_corners.size() + mesh->num_ngons; + } } break; case ATTR_ELEMENT_CURVE: - size = mesh->num_curves(); + if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + size = hair->num_curves(); + } break; case ATTR_ELEMENT_CURVE_KEY: - size = mesh->curve_keys.size(); + if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + size = hair->curve_keys.size(); + } break; case ATTR_ELEMENT_CURVE_KEY_MOTION: - size = mesh->curve_keys.size() * (mesh->motion_steps - 1); + if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + size = hair->curve_keys.size() * (hair->motion_steps - 1); + } break; default: - size = 0; break; } return size; } -size_t Attribute::buffer_size(Mesh *mesh, AttributePrimitive prim) const +size_t Attribute::buffer_size(Geometry *geom, AttributePrimitive prim) const { - return element_size(mesh, prim) * data_sizeof(); + return element_size(geom, prim) * data_sizeof(); } bool Attribute::same_storage(TypeDesc a, TypeDesc b) @@ -336,13 +357,44 @@ AttributeStandard Attribute::name_standard(const char *name) return ATTR_STD_NONE; } +void Attribute::get_uv_tiles(Geometry *geom, + AttributePrimitive prim, + unordered_set<int> &tiles) const +{ + if (type != TypeFloat2) { + return; + } + + const int num = element_size(geom, prim); + const float2 *uv = data_float2(); + for (int i = 0; i < num; i++, uv++) { + float u = uv->x, v = uv->y; + int x = (int)u, y = (int)v; + + if (x < 0 || y < 0 || x >= 10) { + continue; + } + + /* Be conservative in corners - precisely touching the right or upper edge of a tile + * should not load its right/upper neighbor as well. */ + if (x > 0 && (u < x + 1e-6f)) { + x--; + } + if (y > 0 && (v < y + 1e-6f)) { + y--; + } + + tiles.insert(1001 + 10 * y + x); + } +} + /* Attribute Set */ AttributeSet::AttributeSet() { triangle_mesh = NULL; - curve_mesh = NULL; subd_mesh = NULL; + hair = NULL; } AttributeSet::~AttributeSet() @@ -378,10 +430,10 @@ Attribute *AttributeSet::add(ustring name, TypeDesc type, AttributeElement eleme /* this is weak .. */ if (triangle_mesh) attr->resize(triangle_mesh, ATTR_PRIM_TRIANGLE, false); - if (curve_mesh) - attr->resize(curve_mesh, ATTR_PRIM_CURVE, false); if (subd_mesh) attr->resize(subd_mesh, ATTR_PRIM_SUBD, false); + if (hair) + attr->resize(hair, ATTR_PRIM_CURVE, false); return attr; } @@ -478,7 +530,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) break; } } - else if (curve_mesh) { + else if (hair) { switch (std) { case ATTR_STD_UV: attr = add(name, TypeFloat2, ATTR_ELEMENT_CURVE); @@ -563,10 +615,10 @@ void AttributeSet::resize(bool reserve_only) foreach (Attribute &attr, attributes) { if (triangle_mesh) attr.resize(triangle_mesh, ATTR_PRIM_TRIANGLE, reserve_only); - if (curve_mesh) - attr.resize(curve_mesh, ATTR_PRIM_CURVE, reserve_only); if (subd_mesh) attr.resize(subd_mesh, ATTR_PRIM_SUBD, reserve_only); + if (hair) + attr.resize(hair, ATTR_PRIM_CURVE, reserve_only); } } diff --git a/intern/cycles/render/attribute.h b/intern/cycles/render/attribute.h index ebab0fe7f88..d4bf630aeb6 100644 --- a/intern/cycles/render/attribute.h +++ b/intern/cycles/render/attribute.h @@ -21,6 +21,7 @@ #include "util/util_list.h" #include "util/util_param.h" +#include "util/util_set.h" #include "util/util_types.h" #include "util/util_vector.h" @@ -31,6 +32,8 @@ class AttributeRequest; class AttributeRequestSet; class AttributeSet; class ImageManager; +class Geometry; +class Hair; class Mesh; struct Transform; @@ -61,12 +64,12 @@ class Attribute { } ~Attribute(); void set(ustring name, TypeDesc type, AttributeElement element); - void resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only); + void resize(Geometry *geom, AttributePrimitive prim, bool reserve_only); void resize(size_t num_elements); size_t data_sizeof() const; - size_t element_size(Mesh *mesh, AttributePrimitive prim) const; - size_t buffer_size(Mesh *mesh, AttributePrimitive prim) const; + size_t element_size(Geometry *geom, AttributePrimitive prim) const; + size_t buffer_size(Geometry *geom, AttributePrimitive prim) const; char *data() { @@ -157,6 +160,8 @@ class Attribute { static bool same_storage(TypeDesc a, TypeDesc b); static const char *standard_name(AttributeStandard std); static AttributeStandard name_standard(const char *name); + + void get_uv_tiles(Geometry *geom, AttributePrimitive prim, unordered_set<int> &tiles) const; }; /* Attribute Set @@ -166,8 +171,8 @@ class Attribute { class AttributeSet { public: Mesh *triangle_mesh; - Mesh *curve_mesh; Mesh *subd_mesh; + Hair *hair; list<Attribute> attributes; AttributeSet(); @@ -200,7 +205,7 @@ class AttributeRequest { ustring name; AttributeStandard std; - /* temporary variables used by MeshManager */ + /* temporary variables used by GeometryManager */ TypeDesc triangle_type, curve_type, subd_type; AttributeDescriptor triangle_desc, curve_desc, subd_desc; diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index b906357b7b5..9613da7c152 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -253,8 +253,8 @@ int BakeManager::aa_samples(Scene *scene, BakeData *bake_data, ShaderEvalType ty /* Only antialias normal if mesh has bump mapping. */ Object *object = scene->objects[bake_data->object()]; - if (object->mesh) { - foreach (Shader *shader, object->mesh->used_shaders) { + if (object->geometry) { + foreach (Shader *shader, object->geometry->used_shaders) { if (shader->has_bump) { return scene->integrator->aa_samples; } diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 38306a63c74..14ccf6696bd 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -498,7 +498,7 @@ void Camera::device_update_volume(Device * /*device*/, DeviceScene *dscene, Scen BoundBox viewplane_boundbox = viewplane_bounds_get(); for (size_t i = 0; i < scene->objects.size(); ++i) { Object *object = scene->objects[i]; - if (object->mesh->has_volume && viewplane_boundbox.intersects(object->bounds)) { + if (object->geometry->has_volume && viewplane_boundbox.intersects(object->bounds)) { /* TODO(sergey): Consider adding more grained check. */ VLOG(1) << "Detected camera inside volume."; kcam->is_inside_volume = 1; diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 4af0f3c45f0..00356790261 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -593,13 +593,13 @@ bool Film::modified(const Film &film) void Film::tag_passes_update(Scene *scene, const vector<Pass> &passes_, bool update_passes) { if (Pass::contains(passes, PASS_UV) != Pass::contains(passes_, PASS_UV)) { - scene->mesh_manager->tag_update(scene); + scene->geometry_manager->tag_update(scene); foreach (Shader *shader, scene->shaders) - shader->need_update_mesh = true; + shader->need_update_geometry = true; } else if (Pass::contains(passes, PASS_MOTION) != Pass::contains(passes_, PASS_MOTION)) { - scene->mesh_manager->tag_update(scene); + scene->geometry_manager->tag_update(scene); } else if (Pass::contains(passes, PASS_AO) != Pass::contains(passes_, PASS_AO)) { scene->integrator->tag_update(scene); diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp new file mode 100644 index 00000000000..a75a114e4f2 --- /dev/null +++ b/intern/cycles/render/geometry.cpp @@ -0,0 +1,1548 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bvh/bvh.h" +#include "bvh/bvh_build.h" + +#ifdef WITH_EMBREE +# include "bvh/bvh_embree.h" +#endif + +#include "render/attribute.h" +#include "render/camera.h" +#include "render/geometry.h" +#include "render/hair.h" +#include "render/light.h" +#include "render/mesh.h" +#include "render/nodes.h" +#include "render/object.h" +#include "render/scene.h" +#include "render/shader.h" +#include "render/stats.h" + +#include "subd/subd_split.h" +#include "subd/subd_patch_table.h" + +#include "kernel/osl/osl_globals.h" + +#include "util/util_foreach.h" +#include "util/util_logging.h" +#include "util/util_progress.h" + +CCL_NAMESPACE_BEGIN + +/* Geometry */ + +NODE_ABSTRACT_DEFINE(Geometry) +{ + NodeType *type = NodeType::add("geometry_base", NULL); + + SOCKET_UINT(motion_steps, "Motion Steps", 3); + SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); + + return type; +} + +Geometry::Geometry(const NodeType *node_type, const Type type) : Node(node_type), type(type) +{ + need_update = true; + need_update_rebuild = false; + + transform_applied = false; + transform_negative_scaled = false; + transform_normal = transform_identity(); + bounds = BoundBox::empty; + + has_volume = false; + has_surface_bssrdf = false; + + bvh = NULL; + attr_map_offset = 0; + optix_prim_offset = 0; + prim_offset = 0; +} + +Geometry::~Geometry() +{ + delete bvh; +} + +void Geometry::clear() +{ + used_shaders.clear(); + transform_applied = false; + transform_negative_scaled = false; + transform_normal = transform_identity(); +} + +bool Geometry::need_attribute(Scene *scene, AttributeStandard std) +{ + if (std == ATTR_STD_NONE) + return false; + + if (scene->need_global_attribute(std)) + return true; + + foreach (Shader *shader, used_shaders) + if (shader->attributes.find(std)) + return true; + + return false; +} + +bool Geometry::need_attribute(Scene * /*scene*/, ustring name) +{ + if (name == ustring()) + return false; + + foreach (Shader *shader, used_shaders) + if (shader->attributes.find(name)) + return true; + + return false; +} + +float Geometry::motion_time(int step) const +{ + return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; +} + +int Geometry::motion_step(float time) const +{ + if (motion_steps > 1) { + int attr_step = 0; + + for (int step = 0; step < motion_steps; step++) { + float step_time = motion_time(step); + if (step_time == time) { + return attr_step; + } + + /* Center step is stored in a separate attribute. */ + if (step != motion_steps / 2) { + attr_step++; + } + } + } + + return -1; +} + +bool Geometry::need_build_bvh(BVHLayout layout) const +{ + return !transform_applied || has_surface_bssrdf || layout == BVH_LAYOUT_OPTIX; +} + +bool Geometry::is_instanced() const +{ + /* Currently we treat subsurface objects as instanced. + * + * While it might be not very optimal for ray traversal, it avoids having + * duplicated BVH in the memory, saving quite some space. + */ + return !transform_applied || has_surface_bssrdf; +} + +bool Geometry::has_true_displacement() const +{ + foreach (Shader *shader, used_shaders) { + if (shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) { + return true; + } + } + + return false; +} + +void Geometry::compute_bvh( + Device *device, DeviceScene *dscene, SceneParams *params, Progress *progress, int n, int total) +{ + if (progress->get_cancel()) + return; + + compute_bounds(); + + const BVHLayout bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout, + device->get_bvh_layout_mask()); + if (need_build_bvh(bvh_layout)) { + string msg = "Updating Geometry BVH "; + if (name.empty()) + msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); + else + msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); + + Object object; + object.geometry = this; + + vector<Geometry *> geometry; + geometry.push_back(this); + vector<Object *> objects; + objects.push_back(&object); + + if (bvh && !need_update_rebuild) { + progress->set_status(msg, "Refitting BVH"); + + bvh->geometry = geometry; + bvh->objects = objects; + + bvh->refit(*progress); + } + else { + progress->set_status(msg, "Building BVH"); + + BVHParams bparams; + bparams.use_spatial_split = params->use_bvh_spatial_split; + bparams.bvh_layout = bvh_layout; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = params->num_bvh_time_steps; + bparams.num_motion_curve_steps = params->num_bvh_time_steps; + bparams.bvh_type = params->bvh_type; + bparams.curve_flags = dscene->data.curve.curveflags; + bparams.curve_subdivisions = dscene->data.curve.subdivisions; + + delete bvh; + bvh = BVH::create(bparams, geometry, objects); + MEM_GUARDED_CALL(progress, bvh->build, *progress); + } + } + + need_update = false; + need_update_rebuild = false; +} + +bool Geometry::has_motion_blur() const +{ + return (use_motion_blur && attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)); +} + +bool Geometry::has_voxel_attributes() const +{ + foreach (const Attribute &attr, attributes.attributes) { + if (attr.element == ATTR_ELEMENT_VOXEL) { + return true; + } + } + + return false; +} + +void Geometry::tag_update(Scene *scene, bool rebuild) +{ + need_update = true; + + if (rebuild) { + need_update_rebuild = true; + scene->light_manager->need_update = true; + } + else { + foreach (Shader *shader, used_shaders) + if (shader->has_surface_emission) + scene->light_manager->need_update = true; + } + + scene->geometry_manager->need_update = true; + scene->object_manager->need_update = true; +} + +/* Geometry Manager */ + +GeometryManager::GeometryManager() +{ + need_update = true; + need_flags_update = true; +} + +GeometryManager::~GeometryManager() +{ +} + +void GeometryManager::update_osl_attributes(Device *device, + Scene *scene, + vector<AttributeRequestSet> &geom_attributes) +{ +#ifdef WITH_OSL + /* for OSL, a hash map is used to lookup the attribute by name. */ + OSLGlobals *og = (OSLGlobals *)device->osl_memory(); + + og->object_name_map.clear(); + og->attribute_map.clear(); + og->object_names.clear(); + + og->attribute_map.resize(scene->objects.size() * ATTR_PRIM_TYPES); + + for (size_t i = 0; i < scene->objects.size(); i++) { + /* set object name to object index map */ + Object *object = scene->objects[i]; + og->object_name_map[object->name] = i; + og->object_names.push_back(object->name); + + /* set object attributes */ + foreach (ParamValue &attr, object->attributes) { + OSLGlobals::Attribute osl_attr; + + osl_attr.type = attr.type(); + osl_attr.desc.element = ATTR_ELEMENT_OBJECT; + osl_attr.value = attr; + osl_attr.desc.offset = 0; + osl_attr.desc.flags = 0; + + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr; + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr; + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; + } + + /* find geometry attributes */ + size_t j; + + for (j = 0; j < scene->geometry.size(); j++) + if (scene->geometry[j] == object->geometry) + break; + + AttributeRequestSet &attributes = geom_attributes[j]; + + /* set object attributes */ + foreach (AttributeRequest &req, attributes.requests) { + OSLGlobals::Attribute osl_attr; + + if (req.triangle_desc.element != ATTR_ELEMENT_NONE) { + osl_attr.desc = req.triangle_desc; + + if (req.triangle_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if (req.triangle_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else if (req.triangle_type == TypeFloat2) + osl_attr.type = TypeFloat2; + else if (req.triangle_type == TypeRGBA) + osl_attr.type = TypeRGBA; + else + osl_attr.type = TypeDesc::TypeColor; + + if (req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr; + } + else if (req.name != ustring()) { + /* add lookup by geometry attribute name */ + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr; + } + } + + if (req.curve_desc.element != ATTR_ELEMENT_NONE) { + osl_attr.desc = req.curve_desc; + + if (req.curve_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if (req.curve_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else if (req.curve_type == TypeFloat2) + osl_attr.type = TypeFloat2; + else if (req.curve_type == TypeRGBA) + osl_attr.type = TypeRGBA; + else + osl_attr.type = TypeDesc::TypeColor; + + if (req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr; + } + else if (req.name != ustring()) { + /* add lookup by geometry attribute name */ + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; + } + } + + if (req.subd_desc.element != ATTR_ELEMENT_NONE) { + osl_attr.desc = req.subd_desc; + + if (req.subd_type == TypeDesc::TypeFloat) + osl_attr.type = TypeDesc::TypeFloat; + else if (req.subd_type == TypeDesc::TypeMatrix) + osl_attr.type = TypeDesc::TypeMatrix; + else if (req.subd_type == TypeFloat2) + osl_attr.type = TypeFloat2; + else if (req.subd_type == TypeRGBA) + osl_attr.type = TypeRGBA; + else + osl_attr.type = TypeDesc::TypeColor; + + if (req.std != ATTR_STD_NONE) { + /* if standard attribute, add lookup by geom: name convention */ + ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr; + } + else if (req.name != ustring()) { + /* add lookup by geometry attribute name */ + og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr; + } + } + } + } +#else + (void)device; + (void)scene; + (void)geom_attributes; +#endif +} + +void GeometryManager::update_svm_attributes(Device *, + DeviceScene *dscene, + Scene *scene, + vector<AttributeRequestSet> &geom_attributes) +{ + /* for SVM, the attributes_map table is used to lookup the offset of an + * attribute, based on a unique shader attribute id. */ + + /* compute array stride */ + int attr_map_size = 0; + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + geom->attr_map_offset = attr_map_size; + attr_map_size += (geom_attributes[i].size() + 1) * ATTR_PRIM_TYPES; + } + + if (attr_map_size == 0) + return; + + /* create attribute map */ + uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size); + memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint)); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* set object attributes */ + int index = geom->attr_map_offset; + + foreach (AttributeRequest &req, attributes.requests) { + uint id; + + if (req.std == ATTR_STD_NONE) + id = scene->shader_manager->get_attribute_id(req.name); + else + id = scene->shader_manager->get_attribute_id(req.std); + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->num_triangles()) { + attr_map[index].x = id; + attr_map[index].y = req.triangle_desc.element; + attr_map[index].z = as_uint(req.triangle_desc.offset); + + if (req.triangle_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (req.triangle_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (req.triangle_type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else if (req.triangle_type == TypeRGBA) + attr_map[index].w = NODE_ATTR_RGBA; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + + attr_map[index].w |= req.triangle_desc.flags << 8; + } + } + + index++; + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->subd_faces.size()) { + attr_map[index].x = id; + attr_map[index].y = req.subd_desc.element; + attr_map[index].z = as_uint(req.subd_desc.offset); + + if (req.subd_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (req.subd_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (req.subd_type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else if (req.triangle_type == TypeRGBA) + attr_map[index].w = NODE_ATTR_RGBA; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + + attr_map[index].w |= req.subd_desc.flags << 8; + } + } + + index++; + + if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + if (hair->num_curves()) { + attr_map[index].x = id; + attr_map[index].y = req.curve_desc.element; + attr_map[index].z = as_uint(req.curve_desc.offset); + + if (req.curve_type == TypeDesc::TypeFloat) + attr_map[index].w = NODE_ATTR_FLOAT; + else if (req.curve_type == TypeDesc::TypeMatrix) + attr_map[index].w = NODE_ATTR_MATRIX; + else if (req.curve_type == TypeFloat2) + attr_map[index].w = NODE_ATTR_FLOAT2; + else + attr_map[index].w = NODE_ATTR_FLOAT3; + + attr_map[index].w |= req.curve_desc.flags << 8; + } + } + + index++; + } + + /* terminator */ + for (int j = 0; j < ATTR_PRIM_TYPES; j++) { + attr_map[index].x = ATTR_STD_NONE; + attr_map[index].y = 0; + attr_map[index].z = 0; + attr_map[index].w = 0; + + index++; + } + } + + /* copy to device */ + dscene->attributes_map.copy_to_device(); +} + +static void update_attribute_element_size(Geometry *geom, + Attribute *mattr, + AttributePrimitive prim, + size_t *attr_float_size, + size_t *attr_float2_size, + size_t *attr_float3_size, + size_t *attr_uchar4_size) +{ + if (mattr) { + size_t size = mattr->element_size(geom, prim); + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* pass */ + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + *attr_uchar4_size += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + *attr_float_size += size; + } + else if (mattr->type == TypeFloat2) { + *attr_float2_size += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + *attr_float3_size += size * 4; + } + else { + *attr_float3_size += size; + } + } +} + +static void update_attribute_element_offset(Geometry *geom, + device_vector<float> &attr_float, + size_t &attr_float_offset, + device_vector<float2> &attr_float2, + size_t &attr_float2_offset, + device_vector<float4> &attr_float3, + size_t &attr_float3_offset, + device_vector<uchar4> &attr_uchar4, + size_t &attr_uchar4_offset, + Attribute *mattr, + AttributePrimitive prim, + TypeDesc &type, + AttributeDescriptor &desc) +{ + if (mattr) { + /* store element and type */ + desc.element = mattr->element; + desc.flags = mattr->flags; + type = mattr->type; + + /* store attribute data in arrays */ + size_t size = mattr->element_size(geom, prim); + + AttributeElement &element = desc.element; + int &offset = desc.offset; + + if (mattr->element == ATTR_ELEMENT_VOXEL) { + /* store slot in offset value */ + VoxelAttribute *voxel_data = mattr->data_voxel(); + offset = voxel_data->slot; + } + else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { + uchar4 *data = mattr->data_uchar4(); + offset = attr_uchar4_offset; + + assert(attr_uchar4.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_uchar4[offset + k] = data[k]; + } + attr_uchar4_offset += size; + } + else if (mattr->type == TypeDesc::TypeFloat) { + float *data = mattr->data_float(); + offset = attr_float_offset; + + assert(attr_float.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_float[offset + k] = data[k]; + } + attr_float_offset += size; + } + else if (mattr->type == TypeFloat2) { + float2 *data = mattr->data_float2(); + offset = attr_float2_offset; + + assert(attr_float2.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_float2[offset + k] = data[k]; + } + attr_float2_offset += size; + } + else if (mattr->type == TypeDesc::TypeMatrix) { + Transform *tfm = mattr->data_transform(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size * 3); + for (size_t k = 0; k < size * 3; k++) { + attr_float3[offset + k] = (&tfm->x)[k]; + } + attr_float3_offset += size * 3; + } + else { + float4 *data = mattr->data_float4(); + offset = attr_float3_offset; + + assert(attr_float3.size() >= offset + size); + for (size_t k = 0; k < size; k++) { + attr_float3[offset + k] = data[k]; + } + attr_float3_offset += size; + } + + /* mesh vertex/curve index is global, not per object, so we sneak + * a correction for that in here */ + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && + desc.flags & ATTR_SUBDIVIDED) { + /* indices for subdivided attributes are retrieved + * from patch table so no need for correction here*/ + } + else if (element == ATTR_ELEMENT_VERTEX) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_VERTEX_MOTION) + offset -= mesh->vert_offset; + else if (element == ATTR_ELEMENT_FACE) { + if (prim == ATTR_PRIM_TRIANGLE) + offset -= mesh->prim_offset; + else + offset -= mesh->face_offset; + } + else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { + if (prim == ATTR_PRIM_TRIANGLE) + offset -= 3 * mesh->prim_offset; + else + offset -= mesh->corner_offset; + } + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + if (element == ATTR_ELEMENT_CURVE) + offset -= hair->prim_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY) + offset -= hair->curvekey_offset; + else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) + offset -= hair->curvekey_offset; + } + } + else { + /* attribute not found */ + desc.element = ATTR_ELEMENT_NONE; + desc.offset = 0; + } +} + +void GeometryManager::device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + progress.set_status("Updating Mesh", "Computing attributes"); + + /* gather per mesh requested attributes. as meshes may have multiple + * shaders assigned, this merges the requested attributes that have + * been set per shader by the shader manager */ + vector<AttributeRequestSet> geom_attributes(scene->geometry.size()); + + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + + scene->need_global_attributes(geom_attributes[i]); + + foreach (Shader *shader, geom->used_shaders) { + geom_attributes[i].add(shader->attributes); + } + } + + /* mesh attribute are stored in a single array per data type. here we fill + * those arrays, and set the offset and element type to create attribute + * maps next */ + + /* Pre-allocate attributes to avoid arrays re-allocation which would + * take 2x of overall attribute memory usage. + */ + size_t attr_float_size = 0; + size_t attr_float2_size = 0; + size_t attr_float3_size = 0; + size_t attr_uchar4_size = 0; + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + foreach (AttributeRequest &req, attributes.requests) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *subd_mattr = mesh->subd_attributes.find(req); + + update_attribute_element_size(mesh, + triangle_mattr, + ATTR_PRIM_TRIANGLE, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + update_attribute_element_size(mesh, + subd_mattr, + ATTR_PRIM_SUBD, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + Attribute *curve_mattr = hair->attributes.find(req); + + update_attribute_element_size(hair, + curve_mattr, + ATTR_PRIM_CURVE, + &attr_float_size, + &attr_float2_size, + &attr_float3_size, + &attr_uchar4_size); + } + } + } + + dscene->attributes_float.alloc(attr_float_size); + dscene->attributes_float2.alloc(attr_float2_size); + dscene->attributes_float3.alloc(attr_float3_size); + dscene->attributes_uchar4.alloc(attr_uchar4_size); + + size_t attr_float_offset = 0; + size_t attr_float2_offset = 0; + size_t attr_float3_offset = 0; + size_t attr_uchar4_offset = 0; + + /* Fill in attributes. */ + for (size_t i = 0; i < scene->geometry.size(); i++) { + Geometry *geom = scene->geometry[i]; + AttributeRequestSet &attributes = geom_attributes[i]; + + /* todo: we now store std and name attributes from requests even if + * they actually refer to the same mesh attributes, optimize */ + foreach (AttributeRequest &req, attributes.requests) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + Attribute *triangle_mattr = mesh->attributes.find(req); + Attribute *subd_mattr = mesh->subd_attributes.find(req); + + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + triangle_mattr, + ATTR_PRIM_TRIANGLE, + req.triangle_type, + req.triangle_desc); + update_attribute_element_offset(mesh, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + subd_mattr, + ATTR_PRIM_SUBD, + req.subd_type, + req.subd_desc); + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + Attribute *curve_mattr = hair->attributes.find(req); + + update_attribute_element_offset(hair, + dscene->attributes_float, + attr_float_offset, + dscene->attributes_float2, + attr_float2_offset, + dscene->attributes_float3, + attr_float3_offset, + dscene->attributes_uchar4, + attr_uchar4_offset, + curve_mattr, + ATTR_PRIM_CURVE, + req.curve_type, + req.curve_desc); + } + + if (progress.get_cancel()) + return; + } + } + + /* create attribute lookup maps */ + if (scene->shader_manager->use_osl()) + update_osl_attributes(device, scene, geom_attributes); + + update_svm_attributes(device, dscene, scene, geom_attributes); + + if (progress.get_cancel()) + return; + + /* copy to device */ + progress.set_status("Updating Mesh", "Copying Attributes to device"); + + if (dscene->attributes_float.size()) { + dscene->attributes_float.copy_to_device(); + } + if (dscene->attributes_float2.size()) { + dscene->attributes_float2.copy_to_device(); + } + if (dscene->attributes_float3.size()) { + dscene->attributes_float3.copy_to_device(); + } + if (dscene->attributes_uchar4.size()) { + dscene->attributes_uchar4.copy_to_device(); + } + + if (progress.get_cancel()) + return; + + /* After mesh attributes and patch tables have been copied to device memory, + * we need to update offsets in the objects. */ + scene->object_manager->device_update_mesh_offsets(device, dscene, scene); +} + +void GeometryManager::mesh_calc_offset(Scene *scene) +{ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + + size_t patch_size = 0; + size_t face_size = 0; + size_t corner_size = 0; + + size_t optix_prim_size = 0; + + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + + mesh->vert_offset = vert_size; + mesh->prim_offset = tri_size; + + mesh->patch_offset = patch_size; + mesh->face_offset = face_size; + mesh->corner_offset = corner_size; + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + if (mesh->subd_faces.size()) { + Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + + /* patch tables are stored in same array so include them in patch_size */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + + face_size += mesh->subd_faces.size(); + corner_size += mesh->subd_face_corners.size(); + + mesh->optix_prim_offset = optix_prim_size; + optix_prim_size += mesh->num_triangles(); + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + + hair->curvekey_offset = curve_key_size; + hair->prim_offset = curve_size; + + curve_key_size += hair->curve_keys.size(); + curve_size += hair->num_curves(); + + hair->optix_prim_offset = optix_prim_size; + optix_prim_size += hair->num_segments(); + } + } +} + +void GeometryManager::device_update_mesh( + Device *, DeviceScene *dscene, Scene *scene, bool for_displacement, Progress &progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + + size_t curve_key_size = 0; + size_t curve_size = 0; + + size_t patch_size = 0; + + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + + if (mesh->subd_faces.size()) { + Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; + patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; + + /* patch tables are stored in same array so include them in patch_size */ + if (mesh->patch_table) { + mesh->patch_table_offset = patch_size; + patch_size += mesh->patch_table->total_size(); + } + } + } + else if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + + curve_key_size += hair->curve_keys.size(); + curve_size += hair->num_curves(); + } + } + + /* Create mapping from triangle to primitive triangle array. */ + vector<uint> tri_prim_index(tri_size); + if (for_displacement) { + /* For displacement kernels we do some trickery to make them believe + * we've got all required data ready. However, that data is different + * from final render kernels since we don't have BVH yet, so can't + * really use same semantic of arrays. + */ + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + for (size_t i = 0; i < mesh->num_triangles(); ++i) { + tri_prim_index[i + mesh->prim_offset] = 3 * (i + mesh->prim_offset); + } + } + } + } + else { + for (size_t i = 0; i < dscene->prim_index.size(); ++i) { + if ((dscene->prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + tri_prim_index[dscene->prim_index[i]] = dscene->prim_tri_index[i]; + } + } + } + + /* Fill in all the arrays. */ + if (tri_size != 0) { + /* normals */ + progress.set_status("Updating Mesh", "Computing normals"); + + uint *tri_shader = dscene->tri_shader.alloc(tri_size); + float4 *vnormal = dscene->tri_vnormal.alloc(vert_size); + uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size); + uint *tri_patch = dscene->tri_patch.alloc(tri_size); + float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]); + mesh->pack_normals(&vnormal[mesh->vert_offset]); + mesh->pack_verts(tri_prim_index, + &tri_vindex[mesh->prim_offset], + &tri_patch[mesh->prim_offset], + &tri_patch_uv[mesh->vert_offset], + mesh->vert_offset, + mesh->prim_offset); + if (progress.get_cancel()) + return; + } + } + + /* vertex coordinates */ + progress.set_status("Updating Mesh", "Copying Mesh to device"); + + dscene->tri_shader.copy_to_device(); + dscene->tri_vnormal.copy_to_device(); + dscene->tri_vindex.copy_to_device(); + dscene->tri_patch.copy_to_device(); + dscene->tri_patch_uv.copy_to_device(); + } + + if (curve_size != 0) { + progress.set_status("Updating Mesh", "Copying Strands to device"); + + float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); + float4 *curves = dscene->curves.alloc(curve_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + hair->pack_curves(scene, + &curve_keys[hair->curvekey_offset], + &curves[hair->prim_offset], + hair->curvekey_offset); + if (progress.get_cancel()) + return; + } + } + + dscene->curve_keys.copy_to_device(); + dscene->curves.copy_to_device(); + } + + if (patch_size != 0) { + progress.set_status("Updating Mesh", "Copying Patches to device"); + + uint *patch_data = dscene->patches.alloc(patch_size); + + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + mesh->pack_patches(&patch_data[mesh->patch_offset], + mesh->vert_offset, + mesh->face_offset, + mesh->corner_offset); + + if (mesh->patch_table) { + mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], + mesh->patch_table_offset); + } + + if (progress.get_cancel()) + return; + } + } + + dscene->patches.copy_to_device(); + } + + if (for_displacement) { + float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3); + foreach (Geometry *geom, scene->geometry) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + for (size_t i = 0; i < mesh->num_triangles(); ++i) { + Mesh::Triangle t = mesh->get_triangle(i); + size_t offset = 3 * (i + mesh->prim_offset); + prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]); + prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]); + prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]); + } + } + } + dscene->prim_tri_verts.copy_to_device(); + } +} + +void GeometryManager::device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + /* bvh build */ + progress.set_status("Updating Scene BVH", "Building"); + + BVHParams bparams; + bparams.top_level = true; + bparams.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, + device->get_bvh_layout_mask()); + bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; + bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; + bparams.bvh_type = scene->params.bvh_type; + bparams.curve_flags = dscene->data.curve.curveflags; + bparams.curve_subdivisions = dscene->data.curve.subdivisions; + + VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; + +#ifdef WITH_EMBREE + if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { + if (dscene->data.bvh.scene) { + BVHEmbree::destroy(dscene->data.bvh.scene); + } + } +#endif + + BVH *bvh = BVH::create(bparams, scene->geometry, scene->objects); + bvh->build(progress, &device->stats); + + if (progress.get_cancel()) { +#ifdef WITH_EMBREE + if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { + if (dscene->data.bvh.scene) { + BVHEmbree::destroy(dscene->data.bvh.scene); + } + } +#endif + delete bvh; + return; + } + + /* copy to device */ + progress.set_status("Updating Scene BVH", "Copying BVH to device"); + + PackedBVH &pack = bvh->pack; + + if (pack.nodes.size()) { + dscene->bvh_nodes.steal_data(pack.nodes); + dscene->bvh_nodes.copy_to_device(); + } + if (pack.leaf_nodes.size()) { + dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); + dscene->bvh_leaf_nodes.copy_to_device(); + } + if (pack.object_node.size()) { + dscene->object_node.steal_data(pack.object_node); + dscene->object_node.copy_to_device(); + } + if (pack.prim_tri_index.size()) { + dscene->prim_tri_index.steal_data(pack.prim_tri_index); + dscene->prim_tri_index.copy_to_device(); + } + if (pack.prim_tri_verts.size()) { + dscene->prim_tri_verts.steal_data(pack.prim_tri_verts); + dscene->prim_tri_verts.copy_to_device(); + } + if (pack.prim_type.size()) { + dscene->prim_type.steal_data(pack.prim_type); + dscene->prim_type.copy_to_device(); + } + if (pack.prim_visibility.size()) { + dscene->prim_visibility.steal_data(pack.prim_visibility); + dscene->prim_visibility.copy_to_device(); + } + if (pack.prim_index.size()) { + dscene->prim_index.steal_data(pack.prim_index); + dscene->prim_index.copy_to_device(); + } + if (pack.prim_object.size()) { + dscene->prim_object.steal_data(pack.prim_object); + dscene->prim_object.copy_to_device(); + } + if (pack.prim_time.size()) { + dscene->prim_time.steal_data(pack.prim_time); + dscene->prim_time.copy_to_device(); + } + + dscene->data.bvh.root = pack.root_index; + dscene->data.bvh.bvh_layout = bparams.bvh_layout; + dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); + + bvh->copy_to_device(progress, dscene); + + delete bvh; +} + +void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) +{ + if (!need_update && !need_flags_update) { + return; + } + + progress.set_status("Updating Meshes Flags"); + + /* Update flags. */ + bool volume_images_updated = false; + + foreach (Geometry *geom, scene->geometry) { + geom->has_volume = false; + + foreach (const Shader *shader, geom->used_shaders) { + if (shader->has_volume) { + geom->has_volume = true; + } + if (shader->has_surface_bssrdf) { + geom->has_surface_bssrdf = true; + } + } + + if (need_update && geom->has_volume && geom->type == Geometry::MESH) { + /* Create volume meshes if there is voxel data. */ + if (geom->has_voxel_attributes()) { + if (!volume_images_updated) { + progress.set_status("Updating Meshes Volume Bounds"); + device_update_volume_images(device, scene, progress); + volume_images_updated = true; + } + + Mesh *mesh = static_cast<Mesh *>(geom); + create_volume_mesh(scene, mesh, progress); + } + } + } + + need_flags_update = false; +} + +void GeometryManager::device_update_displacement_images(Device *device, + Scene *scene, + Progress &progress) +{ + progress.set_status("Updating Displacement Images"); + TaskPool pool; + ImageManager *image_manager = scene->image_manager; + set<int> bump_images; + foreach (Geometry *geom, scene->geometry) { + if (geom->need_update) { + foreach (Shader *shader, geom->used_shaders) { + if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { + continue; + } + foreach (ShaderNode *node, shader->graph->nodes) { + if (node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) { + continue; + } + + ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node); + foreach (int slot, image_node->slots) { + if (slot != -1) { + bump_images.insert(slot); + } + } + } + } + } + } + foreach (int slot, bump_images) { + pool.push(function_bind( + &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress)); + } + pool.wait_work(); +} + +void GeometryManager::device_update_volume_images(Device *device, Scene *scene, Progress &progress) +{ + progress.set_status("Updating Volume Images"); + TaskPool pool; + ImageManager *image_manager = scene->image_manager; + set<int> volume_images; + + foreach (Geometry *geom, scene->geometry) { + if (!geom->need_update) { + continue; + } + + foreach (Attribute &attr, geom->attributes.attributes) { + if (attr.element != ATTR_ELEMENT_VOXEL) { + continue; + } + + VoxelAttribute *voxel = attr.data_voxel(); + + if (voxel->slot != -1) { + volume_images.insert(voxel->slot); + } + } + } + + foreach (int slot, volume_images) { + pool.push(function_bind( + &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress)); + } + pool.wait_work(); +} + +void GeometryManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress) +{ + if (!need_update) + return; + + VLOG(1) << "Total " << scene->geometry.size() << " meshes."; + + bool true_displacement_used = false; + size_t total_tess_needed = 0; + + foreach (Geometry *geom, scene->geometry) { + foreach (Shader *shader, geom->used_shaders) { + if (shader->need_update_geometry) + geom->need_update = true; + } + + if (geom->need_update && geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + + /* Update normals. */ + mesh->add_face_normals(); + mesh->add_vertex_normals(); + + if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { + mesh->add_undisplaced(); + } + + /* Test if we need tessellation. */ + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 && + mesh->subd_params) { + total_tess_needed++; + } + + /* Test if we need displacement. */ + if (mesh->has_true_displacement()) { + true_displacement_used = true; + } + + if (progress.get_cancel()) + return; + } + } + + /* Tessellate meshes that are using subdivision */ + if (total_tess_needed) { + Camera *dicing_camera = scene->dicing_camera; + dicing_camera->update(scene); + + size_t i = 0; + foreach (Geometry *geom, scene->geometry) { + if (!(geom->need_update && geom->type == Geometry::MESH)) { + continue; + } + + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 && + mesh->subd_params) { + string msg = "Tessellating "; + if (mesh->name == "") + msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed); + else + msg += string_printf( + "%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)total_tess_needed); + + progress.set_status("Updating Mesh", msg); + + mesh->subd_params->camera = dicing_camera; + DiagSplit dsplit(*mesh->subd_params); + mesh->tessellate(&dsplit); + + i++; + + if (progress.get_cancel()) + return; + } + } + } + + /* Update images needed for true displacement. */ + bool old_need_object_flags_update = false; + if (true_displacement_used) { + VLOG(1) << "Updating images used for true displacement."; + device_update_displacement_images(device, scene, progress); + old_need_object_flags_update = scene->object_manager->need_flags_update; + scene->object_manager->device_update_flags(device, dscene, scene, progress, false); + } + + /* Device update. */ + device_free(device, dscene); + + mesh_calc_offset(scene); + if (true_displacement_used) { + device_update_mesh(device, dscene, scene, true, progress); + } + if (progress.get_cancel()) + return; + + device_update_attributes(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + + /* Update displacement. */ + bool displacement_done = false; + size_t num_bvh = 0; + BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, + device->get_bvh_layout_mask()); + + foreach (Geometry *geom, scene->geometry) { + if (geom->need_update) { + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (displace(device, dscene, scene, mesh, progress)) { + displacement_done = true; + } + } + + if (geom->need_build_bvh(bvh_layout)) { + num_bvh++; + } + } + + if (progress.get_cancel()) + return; + } + + /* Device re-update after displacement. */ + if (displacement_done) { + device_free(device, dscene); + + device_update_attributes(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + } + + TaskPool pool; + + size_t i = 0; + foreach (Geometry *geom, scene->geometry) { + if (geom->need_update) { + pool.push(function_bind( + &Geometry::compute_bvh, geom, device, dscene, &scene->params, &progress, i, num_bvh)); + if (geom->need_build_bvh(bvh_layout)) { + i++; + } + } + } + + TaskPool::Summary summary; + pool.wait_work(&summary); + VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); + + foreach (Shader *shader, scene->shaders) { + shader->need_update_geometry = false; + } + + Scene::MotionType need_motion = scene->need_motion(); + bool motion_blur = need_motion == Scene::MOTION_BLUR; + + /* Update objects. */ + vector<Object *> volume_objects; + foreach (Object *object, scene->objects) { + object->compute_bounds(motion_blur); + } + + if (progress.get_cancel()) + return; + + device_update_bvh(device, dscene, scene, progress); + if (progress.get_cancel()) + return; + + device_update_mesh(device, dscene, scene, false, progress); + if (progress.get_cancel()) + return; + + need_update = false; + + if (true_displacement_used) { + /* Re-tag flags for update, so they're re-evaluated + * for meshes with correct bounding boxes. + * + * This wouldn't cause wrong results, just true + * displacement might be less optimal ot calculate. + */ + scene->object_manager->need_flags_update = old_need_object_flags_update; + } +} + +void GeometryManager::device_free(Device *device, DeviceScene *dscene) +{ + dscene->bvh_nodes.free(); + dscene->bvh_leaf_nodes.free(); + dscene->object_node.free(); + dscene->prim_tri_verts.free(); + dscene->prim_tri_index.free(); + dscene->prim_type.free(); + dscene->prim_visibility.free(); + dscene->prim_index.free(); + dscene->prim_object.free(); + dscene->prim_time.free(); + dscene->tri_shader.free(); + dscene->tri_vnormal.free(); + dscene->tri_vindex.free(); + dscene->tri_patch.free(); + dscene->tri_patch_uv.free(); + dscene->curves.free(); + dscene->curve_keys.free(); + dscene->patches.free(); + dscene->attributes_map.free(); + dscene->attributes_float.free(); + dscene->attributes_float2.free(); + dscene->attributes_float3.free(); + dscene->attributes_uchar4.free(); + + /* Signal for shaders like displacement not to do ray tracing. */ + dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE; + +#ifdef WITH_OSL + OSLGlobals *og = (OSLGlobals *)device->osl_memory(); + + if (og) { + og->object_name_map.clear(); + og->attribute_map.clear(); + og->object_names.clear(); + } +#else + (void)device; +#endif +} + +void GeometryManager::tag_update(Scene *scene) +{ + need_update = true; + scene->object_manager->need_update = true; +} + +void GeometryManager::collect_statistics(const Scene *scene, RenderStats *stats) +{ + foreach (Geometry *geometry, scene->geometry) { + stats->mesh.geometry.add_entry( + NamedSizeEntry(string(geometry->name.c_str()), geometry->get_total_size_in_bytes())); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/geometry.h b/intern/cycles/render/geometry.h new file mode 100644 index 00000000000..711da1c81e8 --- /dev/null +++ b/intern/cycles/render/geometry.h @@ -0,0 +1,202 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __GEOMETRY_H__ +#define __GEOMETRY_H__ + +#include "graph/node.h" + +#include "bvh/bvh_params.h" + +#include "render/attribute.h" + +#include "util/util_boundbox.h" +#include "util/util_transform.h" +#include "util/util_set.h" +#include "util/util_types.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +class BVH; +class Device; +class DeviceScene; +class Mesh; +class Progress; +class RenderStats; +class Scene; +class SceneParams; +class Shader; + +/* Geometry + * + * Base class for geometric types like Mesh and Hair. */ + +class Geometry : public Node { + public: + NODE_ABSTRACT_DECLARE + + enum Type { + MESH, + HAIR, + }; + + Type type; + + /* Attributes */ + AttributeSet attributes; + + /* Shaders */ + vector<Shader *> used_shaders; + + /* Transform */ + BoundBox bounds; + bool transform_applied; + bool transform_negative_scaled; + Transform transform_normal; + + /* Motion Blur */ + uint motion_steps; + bool use_motion_blur; + + /* BVH */ + BVH *bvh; + size_t attr_map_offset; + size_t prim_offset; + size_t optix_prim_offset; + + /* Shader Properties */ + bool has_volume; /* Set in the device_update_flags(). */ + bool has_surface_bssrdf; /* Set in the device_update_flags(). */ + + /* Update Flags */ + bool need_update; + bool need_update_rebuild; + + /* Constructor/Destructor */ + explicit Geometry(const NodeType *node_type, const Type type); + virtual ~Geometry(); + + /* Geometry */ + virtual void clear(); + virtual void compute_bounds() = 0; + virtual void apply_transform(const Transform &tfm, const bool apply_to_motion) = 0; + + /* Attribute Requests */ + bool need_attribute(Scene *scene, AttributeStandard std); + bool need_attribute(Scene *scene, ustring name); + + /* UDIM */ + virtual void get_uv_tiles(ustring map, unordered_set<int> &tiles) = 0; + + /* Convert between normalized -1..1 motion time and index in the + * VERTEX_MOTION attribute. */ + float motion_time(int step) const; + int motion_step(float time) const; + + /* BVH */ + void compute_bvh(Device *device, + DeviceScene *dscene, + SceneParams *params, + Progress *progress, + int n, + int total); + + /* Check whether the geometry should have own BVH built separately. Briefly, + * own BVH is needed for geometry, if: + * + * - It is instanced multiple times, so each instance object should share the + * same BVH tree. + * - Special ray intersection is needed, for example to limit subsurface rays + * to only the geometry itself. + * - The BVH layout requires the top level to only contain instances. + */ + bool need_build_bvh(BVHLayout layout) const; + + /* Test if the geometry should be treated as instanced. */ + bool is_instanced() const; + + bool has_true_displacement() const; + bool has_motion_blur() const; + bool has_voxel_attributes() const; + + /* Updates */ + void tag_update(Scene *scene, bool rebuild); +}; + +/* Geometry Manager */ + +class GeometryManager { + public: + /* Update Flags */ + bool need_update; + bool need_flags_update; + + /* Constructor/Destructor */ + GeometryManager(); + ~GeometryManager(); + + /* Device Updates */ + void device_update_preprocess(Device *device, Scene *scene, Progress &progress); + void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + void device_free(Device *device, DeviceScene *dscene); + + /* Updates */ + void tag_update(Scene *scene); + + /* Statistics */ + void collect_statistics(const Scene *scene, RenderStats *stats); + + protected: + bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress); + + void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); + + /* Attributes */ + void update_osl_attributes(Device *device, + Scene *scene, + vector<AttributeRequestSet> &geom_attributes); + void update_svm_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + vector<AttributeRequestSet> &geom_attributes); + + /* Compute verts/triangles/curves offsets in global arrays. */ + void mesh_calc_offset(Scene *scene); + + void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + + void device_update_mesh(Device *device, + DeviceScene *dscene, + Scene *scene, + bool for_displacement, + Progress &progress); + + void device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress &progress); + + void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); + + void device_update_displacement_images(Device *device, Scene *scene, Progress &progress); + + void device_update_volume_images(Device *device, Scene *scene, Progress &progress); +}; + +CCL_NAMESPACE_END + +#endif /* __GEOMETRY_H__ */ diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp new file mode 100644 index 00000000000..a35d4b6f1da --- /dev/null +++ b/intern/cycles/render/hair.cpp @@ -0,0 +1,489 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "render/curves.h" +#include "render/hair.h" +#include "render/scene.h" + +CCL_NAMESPACE_BEGIN + +/* Hair Curve */ + +void Hair::Curve::bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + BoundBox &bounds) const +{ + float3 P[4]; + + P[0] = curve_keys[max(first_key + k - 1, first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + + float3 lower; + float3 upper; + + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); + + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); + + bounds.grow(lower, mr); + bounds.grow(upper, mr); +} + +void Hair::Curve::bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform &aligned_space, + BoundBox &bounds) const +{ + float3 P[4]; + + P[0] = curve_keys[max(first_key + k - 1, first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + + P[0] = transform_point(&aligned_space, P[0]); + P[1] = transform_point(&aligned_space, P[1]); + P[2] = transform_point(&aligned_space, P[2]); + P[3] = transform_point(&aligned_space, P[3]); + + float3 lower; + float3 upper; + + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); + + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); + + bounds.grow(lower, mr); + bounds.grow(upper, mr); +} + +void Hair::Curve::bounds_grow(float4 keys[4], BoundBox &bounds) const +{ + float3 P[4] = { + float4_to_float3(keys[0]), + float4_to_float3(keys[1]), + float4_to_float3(keys[2]), + float4_to_float3(keys[3]), + }; + + float3 lower; + float3 upper; + + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); + + float mr = max(keys[1].w, keys[2].w); + + bounds.grow(lower, mr); + bounds.grow(upper, mr); +} + +void Hair::Curve::motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + float time, + size_t k0, + size_t k1, + float4 r_keys[2]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[2]; + float4 next_keys[2]; + keys_for_step( + curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step, k0, k1, curr_keys); + keys_for_step( + curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step + 1, k0, k1, next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; + r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; +} + +void Hair::Curve::cardinal_motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + float time, + size_t k0, + size_t k1, + size_t k2, + size_t k3, + float4 r_keys[4]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time * max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[4]; + float4 next_keys[4]; + cardinal_keys_for_step(curve_keys, + curve_radius, + key_steps, + num_curve_keys, + num_steps, + step, + k0, + k1, + k2, + k3, + curr_keys); + cardinal_keys_for_step(curve_keys, + curve_radius, + key_steps, + num_curve_keys, + num_steps, + step + 1, + k0, + k1, + k2, + k3, + next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; + r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; + r_keys[2] = (1.0f - t) * curr_keys[2] + t * next_keys[2]; + r_keys[3] = (1.0f - t) * curr_keys[3] + t * next_keys[3]; +} + +void Hair::Curve::keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + float4 r_keys[2]) const +{ + k0 = max(k0, 0); + k1 = min(k1, num_keys - 1); + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular key location. */ + /* TODO(sergey): Consider adding make_float4(float3, float) + * function. + */ + r_keys[0] = make_float4(curve_keys[first_key + k0].x, + curve_keys[first_key + k0].y, + curve_keys[first_key + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(curve_keys[first_key + k1].x, + curve_keys[first_key + k1].y, + curve_keys[first_key + k1].z, + curve_radius[first_key + k1]); + } + else { + /* Center step is not stored in this array. */ + if (step > center_step) { + step--; + } + const size_t offset = first_key + step * num_curve_keys; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + curve_radius[first_key + k1]); + } +} + +void Hair::Curve::cardinal_keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + size_t k2, + size_t k3, + float4 r_keys[4]) const +{ + k0 = max(k0, 0); + k3 = min(k3, num_keys - 1); + const size_t center_step = ((num_steps - 1) / 2); + if (step == center_step) { + /* Center step: regular key location. */ + r_keys[0] = make_float4(curve_keys[first_key + k0].x, + curve_keys[first_key + k0].y, + curve_keys[first_key + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(curve_keys[first_key + k1].x, + curve_keys[first_key + k1].y, + curve_keys[first_key + k1].z, + curve_radius[first_key + k1]); + r_keys[2] = make_float4(curve_keys[first_key + k2].x, + curve_keys[first_key + k2].y, + curve_keys[first_key + k2].z, + curve_radius[first_key + k2]); + r_keys[3] = make_float4(curve_keys[first_key + k3].x, + curve_keys[first_key + k3].y, + curve_keys[first_key + k3].z, + curve_radius[first_key + k3]); + } + else { + /* Center step is not stored in this array. */ + if (step > center_step) { + step--; + } + const size_t offset = first_key + step * num_curve_keys; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + curve_radius[first_key + k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + curve_radius[first_key + k1]); + r_keys[2] = make_float4(key_steps[offset + k2].x, + key_steps[offset + k2].y, + key_steps[offset + k2].z, + curve_radius[first_key + k2]); + r_keys[3] = make_float4(key_steps[offset + k3].x, + key_steps[offset + k3].y, + key_steps[offset + k3].z, + curve_radius[first_key + k3]); + } +} + +/* Hair */ + +NODE_DEFINE(Hair) +{ + NodeType *type = NodeType::add("hair", create, NodeType::NONE, Geometry::node_base_type); + + SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>()); + SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>()); + SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>()); + SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>()); + + return type; +} + +Hair::Hair() : Geometry(node_type, Geometry::HAIR) +{ + curvekey_offset = 0; + + attributes.hair = this; +} + +Hair::~Hair() +{ +} + +void Hair::resize_curves(int numcurves, int numkeys) +{ + curve_keys.resize(numkeys); + curve_radius.resize(numkeys); + curve_first_key.resize(numcurves); + curve_shader.resize(numcurves); + + attributes.resize(); +} + +void Hair::reserve_curves(int numcurves, int numkeys) +{ + curve_keys.reserve(numkeys); + curve_radius.reserve(numkeys); + curve_first_key.reserve(numcurves); + curve_shader.reserve(numcurves); + + attributes.resize(true); +} + +void Hair::clear() +{ + Geometry::clear(); + + curve_keys.clear(); + curve_radius.clear(); + curve_first_key.clear(); + curve_shader.clear(); + + attributes.clear(); +} + +void Hair::add_curve_key(float3 co, float radius) +{ + curve_keys.push_back_reserved(co); + curve_radius.push_back_reserved(radius); +} + +void Hair::add_curve(int first_key, int shader) +{ + curve_first_key.push_back_reserved(first_key); + curve_shader.push_back_reserved(shader); +} + +void Hair::copy_center_to_motion_step(const int motion_step) +{ + Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (attr_mP) { + float3 *keys = &curve_keys[0]; + size_t numkeys = curve_keys.size(); + memcpy(attr_mP->data_float3() + motion_step * numkeys, keys, sizeof(float3) * numkeys); + } +} + +void Hair::get_uv_tiles(ustring map, unordered_set<int> &tiles) +{ + Attribute *attr; + + if (map.empty()) { + attr = attributes.find(ATTR_STD_UV); + } + else { + attr = attributes.find(map); + } + + if (attr) { + attr->get_uv_tiles(this, ATTR_PRIM_CURVE, tiles); + } +} + +void Hair::compute_bounds() +{ + BoundBox bnds = BoundBox::empty; + size_t curve_keys_size = curve_keys.size(); + + if (curve_keys_size > 0) { + for (size_t i = 0; i < curve_keys_size; i++) + bnds.grow(curve_keys[i], curve_radius[i]); + + Attribute *curve_attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if (use_motion_blur && curve_attr) { + size_t steps_size = curve_keys.size() * (motion_steps - 1); + float3 *key_steps = curve_attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + bnds.grow(key_steps[i]); + } + + if (!bnds.valid()) { + bnds = BoundBox::empty; + + /* skip nan or inf coordinates */ + for (size_t i = 0; i < curve_keys_size; i++) + bnds.grow_safe(curve_keys[i], curve_radius[i]); + + if (use_motion_blur && curve_attr) { + size_t steps_size = curve_keys.size() * (motion_steps - 1); + float3 *key_steps = curve_attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + bnds.grow_safe(key_steps[i]); + } + } + } + + if (!bnds.valid()) { + /* empty mesh */ + bnds.grow(make_float3(0.0f, 0.0f, 0.0f)); + } + + bounds = bnds; +} + +void Hair::apply_transform(const Transform &tfm, const bool apply_to_motion) +{ + /* compute uniform scale */ + float3 c0 = transform_get_column(&tfm, 0); + float3 c1 = transform_get_column(&tfm, 1); + float3 c2 = transform_get_column(&tfm, 2); + float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f); + + /* apply transform to curve keys */ + for (size_t i = 0; i < curve_keys.size(); i++) { + float3 co = transform_point(&tfm, curve_keys[i]); + float radius = curve_radius[i] * scalar; + + /* scale for curve radius is only correct for uniform scale */ + curve_keys[i] = co; + curve_radius[i] = radius; + } + + if (apply_to_motion) { + Attribute *curve_attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (curve_attr) { + /* apply transform to motion curve keys */ + size_t steps_size = curve_keys.size() * (motion_steps - 1); + float4 *key_steps = curve_attr->data_float4(); + + for (size_t i = 0; i < steps_size; i++) { + float3 co = transform_point(&tfm, float4_to_float3(key_steps[i])); + float radius = key_steps[i].w * scalar; + + /* scale for curve radius is only correct for uniform scale */ + key_steps[i] = float3_to_float4(co); + key_steps[i].w = radius; + } + } + } +} + +void Hair::pack_curves(Scene *scene, + float4 *curve_key_co, + float4 *curve_data, + size_t curvekey_offset) +{ + size_t curve_keys_size = curve_keys.size(); + + /* pack curve keys */ + if (curve_keys_size) { + float3 *keys_ptr = curve_keys.data(); + float *radius_ptr = curve_radius.data(); + + for (size_t i = 0; i < curve_keys_size; i++) + curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]); + } + + /* pack curve segments */ + size_t curve_num = num_curves(); + + for (size_t i = 0; i < curve_num; i++) { + Curve curve = get_curve(i); + int shader_id = curve_shader[i]; + Shader *shader = (shader_id < used_shaders.size()) ? used_shaders[shader_id] : + scene->default_surface; + shader_id = scene->shader_manager->get_shader_id(shader, false); + + curve_data[i] = make_float4(__int_as_float(curve.first_key + curvekey_offset), + __int_as_float(curve.num_keys), + __int_as_float(shader_id), + 0.0f); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h new file mode 100644 index 00000000000..79f77a78753 --- /dev/null +++ b/intern/cycles/render/hair.h @@ -0,0 +1,151 @@ +/* + * Copyright 2011-2020 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HAIR_H__ +#define __HAIR_H__ + +#include "render/geometry.h" + +CCL_NAMESPACE_BEGIN + +class Hair : public Geometry { + public: + NODE_DECLARE + + /* Hair Curve */ + struct Curve { + int first_key; + int num_keys; + + int num_segments() const + { + return num_keys - 1; + } + + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + BoundBox &bounds) const; + void bounds_grow(float4 keys[4], BoundBox &bounds) const; + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform &aligned_space, + BoundBox &bounds) const; + + void motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + float time, + size_t k0, + size_t k1, + float4 r_keys[2]) const; + void cardinal_motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + float time, + size_t k0, + size_t k1, + size_t k2, + size_t k3, + float4 r_keys[4]) const; + + void keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + float4 r_keys[2]) const; + void cardinal_keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_curve_keys, + size_t num_steps, + size_t step, + size_t k0, + size_t k1, + size_t k2, + size_t k3, + float4 r_keys[4]) const; + }; + + array<float3> curve_keys; + array<float> curve_radius; + array<int> curve_first_key; + array<int> curve_shader; + + /* BVH */ + size_t curvekey_offset; + + /* Constructor/Destructor */ + Hair(); + ~Hair(); + + /* Geometry */ + void clear() override; + + void resize_curves(int numcurves, int numkeys); + void reserve_curves(int numcurves, int numkeys); + void add_curve_key(float3 loc, float radius); + void add_curve(int first_key, int shader); + + void copy_center_to_motion_step(const int motion_step); + + void compute_bounds() override; + void apply_transform(const Transform &tfm, const bool apply_to_motion) override; + + /* Curves */ + Curve get_curve(size_t i) const + { + int first = curve_first_key[i]; + int next_first = (i + 1 < curve_first_key.size()) ? curve_first_key[i + 1] : curve_keys.size(); + + Curve curve = {first, next_first - first}; + return curve; + } + + size_t num_keys() const + { + return curve_keys.size(); + } + + size_t num_curves() const + { + return curve_first_key.size(); + } + + size_t num_segments() const + { + return curve_keys.size() - curve_first_key.size(); + } + + /* UDIM */ + void get_uv_tiles(ustring map, unordered_set<int> &tiles) override; + + /* BVH */ + void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); +}; + +CCL_NAMESPACE_END + +#endif /* __HAIR_H__ */ diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 664217d6f26..509637aedd9 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -232,7 +232,10 @@ void LightManager::disable_ineffective_light(Scene *scene) bool LightManager::object_usable_as_light(Object *object) { - Mesh *mesh = object->mesh; + Geometry *geom = object->geometry; + if (geom->type != Geometry::MESH) { + return false; + } /* Skip objects with NaNs */ if (!object->bounds.valid()) { return false; @@ -243,10 +246,10 @@ bool LightManager::object_usable_as_light(Object *object) } /* Skip if we have no emission shaders. */ /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll - * iterate all mesh shaders twice (when counting and when calculating + * iterate all geometry shaders twice (when counting and when calculating * triangle area. */ - foreach (const Shader *shader, mesh->used_shaders) { + foreach (const Shader *shader, geom->used_shaders) { if (shader->use_mis && shader->has_surface_emission) { return true; } @@ -285,8 +288,9 @@ void LightManager::device_update_distribution(Device *, if (!object_usable_as_light(object)) { continue; } + /* Count triangles. */ - Mesh *mesh = object->mesh; + Mesh *mesh = static_cast<Mesh *>(object->geometry); size_t mesh_num_triangles = mesh->num_triangles(); for (size_t i = 0; i < mesh_num_triangles; i++) { int shader_index = mesh->shader[i]; @@ -320,7 +324,7 @@ void LightManager::device_update_distribution(Device *, continue; } /* Sum area. */ - Mesh *mesh = object->mesh; + Mesh *mesh = static_cast<Mesh *>(object->geometry); bool transform_applied = mesh->transform_applied; Transform tfm = object->tfm; int object_id = j; @@ -352,7 +356,7 @@ void LightManager::device_update_distribution(Device *, if (shader->use_mis && shader->has_surface_emission) { distribution[offset].totarea = totarea; - distribution[offset].prim = i + mesh->tri_offset; + distribution[offset].prim = i + mesh->prim_offset; distribution[offset].mesh_light.shader_flag = shader_flag; distribution[offset].mesh_light.object_id = object_id; offset++; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index d9e6d998ebd..792848e744a 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -17,19 +17,13 @@ #include "bvh/bvh.h" #include "bvh/bvh_build.h" -#include "render/camera.h" -#include "render/curves.h" #include "device/device.h" + #include "render/graph.h" -#include "render/shader.h" -#include "render/light.h" +#include "render/hair.h" #include "render/mesh.h" -#include "render/nodes.h" #include "render/object.h" #include "render/scene.h" -#include "render/stats.h" - -#include "kernel/osl/osl_globals.h" #include "subd/subd_split.h" #include "subd/subd_patch_table.h" @@ -39,10 +33,6 @@ #include "util/util_progress.h" #include "util/util_set.h" -#ifdef WITH_EMBREE -# include "bvh/bvh_embree.h" -#endif - CCL_NAMESPACE_BEGIN /* Triangle */ @@ -120,263 +110,6 @@ bool Mesh::Triangle::valid(const float3 *verts) const return isfinite3_safe(verts[v[0]]) && isfinite3_safe(verts[v[1]]) && isfinite3_safe(verts[v[2]]); } -/* Curve */ - -void Mesh::Curve::bounds_grow(const int k, - const float3 *curve_keys, - const float *curve_radius, - BoundBox &bounds) const -{ - float3 P[4]; - - P[0] = curve_keys[max(first_key + k - 1, first_key)]; - P[1] = curve_keys[first_key + k]; - P[2] = curve_keys[first_key + k + 1]; - P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; - - float3 lower; - float3 upper; - - curvebounds(&lower.x, &upper.x, P, 0); - curvebounds(&lower.y, &upper.y, P, 1); - curvebounds(&lower.z, &upper.z, P, 2); - - float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); - - bounds.grow(lower, mr); - bounds.grow(upper, mr); -} - -void Mesh::Curve::bounds_grow(const int k, - const float3 *curve_keys, - const float *curve_radius, - const Transform &aligned_space, - BoundBox &bounds) const -{ - float3 P[4]; - - P[0] = curve_keys[max(first_key + k - 1, first_key)]; - P[1] = curve_keys[first_key + k]; - P[2] = curve_keys[first_key + k + 1]; - P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; - - P[0] = transform_point(&aligned_space, P[0]); - P[1] = transform_point(&aligned_space, P[1]); - P[2] = transform_point(&aligned_space, P[2]); - P[3] = transform_point(&aligned_space, P[3]); - - float3 lower; - float3 upper; - - curvebounds(&lower.x, &upper.x, P, 0); - curvebounds(&lower.y, &upper.y, P, 1); - curvebounds(&lower.z, &upper.z, P, 2); - - float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); - - bounds.grow(lower, mr); - bounds.grow(upper, mr); -} - -void Mesh::Curve::bounds_grow(float4 keys[4], BoundBox &bounds) const -{ - float3 P[4] = { - float4_to_float3(keys[0]), - float4_to_float3(keys[1]), - float4_to_float3(keys[2]), - float4_to_float3(keys[3]), - }; - - float3 lower; - float3 upper; - - curvebounds(&lower.x, &upper.x, P, 0); - curvebounds(&lower.y, &upper.y, P, 1); - curvebounds(&lower.z, &upper.z, P, 2); - - float mr = max(keys[1].w, keys[2].w); - - bounds.grow(lower, mr); - bounds.grow(upper, mr); -} - -void Mesh::Curve::motion_keys(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - float time, - size_t k0, - size_t k1, - float4 r_keys[2]) const -{ - /* Figure out which steps we need to fetch and their interpolation factor. */ - const size_t max_step = num_steps - 1; - const size_t step = min((int)(time * max_step), max_step - 1); - const float t = time * max_step - step; - /* Fetch vertex coordinates. */ - float4 curr_keys[2]; - float4 next_keys[2]; - keys_for_step( - curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step, k0, k1, curr_keys); - keys_for_step( - curve_keys, curve_radius, key_steps, num_curve_keys, num_steps, step + 1, k0, k1, next_keys); - /* Interpolate between steps. */ - r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; - r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; -} - -void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - float time, - size_t k0, - size_t k1, - size_t k2, - size_t k3, - float4 r_keys[4]) const -{ - /* Figure out which steps we need to fetch and their interpolation factor. */ - const size_t max_step = num_steps - 1; - const size_t step = min((int)(time * max_step), max_step - 1); - const float t = time * max_step - step; - /* Fetch vertex coordinates. */ - float4 curr_keys[4]; - float4 next_keys[4]; - cardinal_keys_for_step(curve_keys, - curve_radius, - key_steps, - num_curve_keys, - num_steps, - step, - k0, - k1, - k2, - k3, - curr_keys); - cardinal_keys_for_step(curve_keys, - curve_radius, - key_steps, - num_curve_keys, - num_steps, - step + 1, - k0, - k1, - k2, - k3, - next_keys); - /* Interpolate between steps. */ - r_keys[0] = (1.0f - t) * curr_keys[0] + t * next_keys[0]; - r_keys[1] = (1.0f - t) * curr_keys[1] + t * next_keys[1]; - r_keys[2] = (1.0f - t) * curr_keys[2] + t * next_keys[2]; - r_keys[3] = (1.0f - t) * curr_keys[3] + t * next_keys[3]; -} - -void Mesh::Curve::keys_for_step(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - size_t step, - size_t k0, - size_t k1, - float4 r_keys[2]) const -{ - k0 = max(k0, 0); - k1 = min(k1, num_keys - 1); - const size_t center_step = ((num_steps - 1) / 2); - if (step == center_step) { - /* Center step: regular key location. */ - /* TODO(sergey): Consider adding make_float4(float3, float) - * function. - */ - r_keys[0] = make_float4(curve_keys[first_key + k0].x, - curve_keys[first_key + k0].y, - curve_keys[first_key + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(curve_keys[first_key + k1].x, - curve_keys[first_key + k1].y, - curve_keys[first_key + k1].z, - curve_radius[first_key + k1]); - } - else { - /* Center step is not stored in this array. */ - if (step > center_step) { - step--; - } - const size_t offset = first_key + step * num_curve_keys; - r_keys[0] = make_float4(key_steps[offset + k0].x, - key_steps[offset + k0].y, - key_steps[offset + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(key_steps[offset + k1].x, - key_steps[offset + k1].y, - key_steps[offset + k1].z, - curve_radius[first_key + k1]); - } -} - -void Mesh::Curve::cardinal_keys_for_step(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - size_t step, - size_t k0, - size_t k1, - size_t k2, - size_t k3, - float4 r_keys[4]) const -{ - k0 = max(k0, 0); - k3 = min(k3, num_keys - 1); - const size_t center_step = ((num_steps - 1) / 2); - if (step == center_step) { - /* Center step: regular key location. */ - r_keys[0] = make_float4(curve_keys[first_key + k0].x, - curve_keys[first_key + k0].y, - curve_keys[first_key + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(curve_keys[first_key + k1].x, - curve_keys[first_key + k1].y, - curve_keys[first_key + k1].z, - curve_radius[first_key + k1]); - r_keys[2] = make_float4(curve_keys[first_key + k2].x, - curve_keys[first_key + k2].y, - curve_keys[first_key + k2].z, - curve_radius[first_key + k2]); - r_keys[3] = make_float4(curve_keys[first_key + k3].x, - curve_keys[first_key + k3].y, - curve_keys[first_key + k3].z, - curve_radius[first_key + k3]); - } - else { - /* Center step is not stored in this array. */ - if (step > center_step) { - step--; - } - const size_t offset = first_key + step * num_curve_keys; - r_keys[0] = make_float4(key_steps[offset + k0].x, - key_steps[offset + k0].y, - key_steps[offset + k0].z, - curve_radius[first_key + k0]); - r_keys[1] = make_float4(key_steps[offset + k1].x, - key_steps[offset + k1].y, - key_steps[offset + k1].z, - curve_radius[first_key + k1]); - r_keys[2] = make_float4(key_steps[offset + k2].x, - key_steps[offset + k2].y, - key_steps[offset + k2].z, - curve_radius[first_key + k2]); - r_keys[3] = make_float4(key_steps[offset + k3].x, - key_steps[offset + k3].y, - key_steps[offset + k3].z, - curve_radius[first_key + k3]); - } -} - /* SubdFace */ float3 Mesh::SubdFace::normal(const Mesh *mesh) const @@ -392,60 +125,30 @@ float3 Mesh::SubdFace::normal(const Mesh *mesh) const NODE_DEFINE(Mesh) { - NodeType *type = NodeType::add("mesh", create); - - SOCKET_UINT(motion_steps, "Motion Steps", 3); - SOCKET_BOOLEAN(use_motion_blur, "Use Motion Blur", false); + NodeType *type = NodeType::add("mesh", create, NodeType::NONE, Geometry::node_base_type); SOCKET_INT_ARRAY(triangles, "Triangles", array<int>()); SOCKET_POINT_ARRAY(verts, "Vertices", array<float3>()); SOCKET_INT_ARRAY(shader, "Shader", array<int>()); SOCKET_BOOLEAN_ARRAY(smooth, "Smooth", array<bool>()); - SOCKET_POINT_ARRAY(curve_keys, "Curve Keys", array<float3>()); - SOCKET_FLOAT_ARRAY(curve_radius, "Curve Radius", array<float>()); - SOCKET_INT_ARRAY(curve_first_key, "Curve First Key", array<int>()); - SOCKET_INT_ARRAY(curve_shader, "Curve Shader", array<int>()); - return type; } -Mesh::Mesh() : Node(node_type) +Mesh::Mesh() : Geometry(node_type, Geometry::MESH) { - need_update = true; - need_update_rebuild = false; - transform_applied = false; - transform_negative_scaled = false; - transform_normal = transform_identity(); - bounds = BoundBox::empty; - - bvh = NULL; - - tri_offset = 0; vert_offset = 0; - curve_offset = 0; - curvekey_offset = 0; - patch_offset = 0; face_offset = 0; corner_offset = 0; - attr_map_offset = 0; - - prim_offset = 0; - num_subd_verts = 0; attributes.triangle_mesh = this; - curve_attributes.curve_mesh = this; subd_attributes.subd_mesh = this; - geometry_flags = GEOMETRY_NONE; - volume_isovalue = 0.001f; - has_volume = false; - has_surface_bssrdf = false; num_ngons = 0; @@ -457,7 +160,6 @@ Mesh::Mesh() : Node(node_type) Mesh::~Mesh() { - delete bvh; delete patch_table; delete subd_params; } @@ -493,26 +195,6 @@ void Mesh::reserve_mesh(int numverts, int numtris) attributes.resize(true); } -void Mesh::resize_curves(int numcurves, int numkeys) -{ - curve_keys.resize(numkeys); - curve_radius.resize(numkeys); - curve_first_key.resize(numcurves); - curve_shader.resize(numcurves); - - curve_attributes.resize(); -} - -void Mesh::reserve_curves(int numcurves, int numkeys) -{ - curve_keys.reserve(numkeys); - curve_radius.reserve(numkeys); - curve_first_key.reserve(numcurves); - curve_shader.reserve(numcurves); - - curve_attributes.resize(true); -} - void Mesh::resize_subd_faces(int numfaces, int num_ngons_, int numcorners) { subd_faces.resize(numfaces); @@ -533,6 +215,8 @@ void Mesh::reserve_subd_faces(int numfaces, int num_ngons_, int numcorners) void Mesh::clear(bool preserve_voxel_data) { + Geometry::clear(); + /* clear all verts and triangles */ verts.clear(); triangles.clear(); @@ -542,11 +226,6 @@ void Mesh::clear(bool preserve_voxel_data) triangle_patch.clear(); vert_patch_uv.clear(); - curve_keys.clear(); - curve_radius.clear(); - curve_first_key.clear(); - curve_shader.clear(); - subd_faces.clear(); subd_face_corners.clear(); @@ -554,27 +233,21 @@ void Mesh::clear(bool preserve_voxel_data) subd_creases.clear(); - curve_attributes.clear(); subd_attributes.clear(); attributes.clear(preserve_voxel_data); - used_shaders.clear(); - vert_to_stitching_key_map.clear(); vert_stitching_map.clear(); - if (!preserve_voxel_data) { - geometry_flags = GEOMETRY_NONE; - } - - transform_applied = false; - transform_negative_scaled = false; - transform_normal = transform_identity(); - delete patch_table; patch_table = NULL; } +void Mesh::clear() +{ + clear(false); +} + void Mesh::add_vertex(float3 P) { verts.push_back_reserved(P); @@ -606,18 +279,6 @@ void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_) } } -void Mesh::add_curve_key(float3 co, float radius) -{ - curve_keys.push_back_reserved(co); - curve_radius.push_back_reserved(radius); -} - -void Mesh::add_curve(int first_key, int shader) -{ - curve_first_key.push_back_reserved(first_key); - curve_shader.push_back_reserved(shader); -} - void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth_) { int start_corner = subd_face_corners.size(); @@ -637,47 +298,39 @@ void Mesh::add_subd_face(int *corners, int num_corners, int shader_, bool smooth subd_faces.push_back_reserved(face); } -static void get_uv_tiles_from_attribute(Attribute *attr, int num, unordered_set<int> &tiles) +void Mesh::copy_center_to_motion_step(const int motion_step) { - if (attr == NULL) { - return; - } - - const float2 *uv = attr->data_float2(); - for (int i = 0; i < num; i++, uv++) { - float u = uv->x, v = uv->y; - int x = (int)u, y = (int)v; - - if (x < 0 || y < 0 || x >= 10) { - continue; - } + Attribute *attr_mP = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - /* Be conservative in corners - precisely touching the right or upper edge of a tile - * should not load its right/upper neighbor as well. */ - if (x > 0 && (u < x + 1e-6f)) { - x--; - } - if (y > 0 && (v < y + 1e-6f)) { - y--; - } + if (attr_mP) { + Attribute *attr_mN = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + Attribute *attr_N = attributes.find(ATTR_STD_VERTEX_NORMAL); + float3 *P = &verts[0]; + float3 *N = (attr_N) ? attr_N->data_float3() : NULL; + size_t numverts = verts.size(); - tiles.insert(1001 + 10 * y + x); + memcpy(attr_mP->data_float3() + motion_step * numverts, P, sizeof(float3) * numverts); + if (attr_mN) + memcpy(attr_mN->data_float3() + motion_step * numverts, N, sizeof(float3) * numverts); } } void Mesh::get_uv_tiles(ustring map, unordered_set<int> &tiles) { + Attribute *attr, *subd_attr; + if (map.empty()) { - get_uv_tiles_from_attribute(attributes.find(ATTR_STD_UV), num_triangles() * 3, tiles); - get_uv_tiles_from_attribute( - subd_attributes.find(ATTR_STD_UV), subd_face_corners.size() + num_ngons, tiles); - get_uv_tiles_from_attribute(curve_attributes.find(ATTR_STD_UV), num_curves(), tiles); + attr = attributes.find(ATTR_STD_UV); + subd_attr = subd_attributes.find(ATTR_STD_UV); } else { - get_uv_tiles_from_attribute(attributes.find(map), num_triangles() * 3, tiles); - get_uv_tiles_from_attribute( - subd_attributes.find(map), subd_face_corners.size() + num_ngons, tiles); - get_uv_tiles_from_attribute(curve_attributes.find(map), num_curves(), tiles); + attr = attributes.find(map); + subd_attr = subd_attributes.find(map); + } + + if (attr) { + attr->get_uv_tiles(this, ATTR_PRIM_TRIANGLE, tiles); + subd_attr->get_uv_tiles(this, ATTR_PRIM_SUBD, tiles); } } @@ -685,15 +338,11 @@ void Mesh::compute_bounds() { BoundBox bnds = BoundBox::empty; size_t verts_size = verts.size(); - size_t curve_keys_size = curve_keys.size(); - if (verts_size + curve_keys_size > 0) { + if (verts_size > 0) { for (size_t i = 0; i < verts_size; i++) bnds.grow(verts[i]); - for (size_t i = 0; i < curve_keys_size; i++) - bnds.grow(curve_keys[i], curve_radius[i]); - Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); if (use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); @@ -703,15 +352,6 @@ void Mesh::compute_bounds() bnds.grow(vert_steps[i]); } - Attribute *curve_attr = curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - if (use_motion_blur && curve_attr) { - size_t steps_size = curve_keys.size() * (motion_steps - 1); - float3 *key_steps = curve_attr->data_float3(); - - for (size_t i = 0; i < steps_size; i++) - bnds.grow(key_steps[i]); - } - if (!bnds.valid()) { bnds = BoundBox::empty; @@ -719,9 +359,6 @@ void Mesh::compute_bounds() for (size_t i = 0; i < verts_size; i++) bnds.grow_safe(verts[i]); - for (size_t i = 0; i < curve_keys_size; i++) - bnds.grow_safe(curve_keys[i], curve_radius[i]); - if (use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); float3 *vert_steps = attr->data_float3(); @@ -729,14 +366,6 @@ void Mesh::compute_bounds() for (size_t i = 0; i < steps_size; i++) bnds.grow_safe(vert_steps[i]); } - - if (use_motion_blur && curve_attr) { - size_t steps_size = curve_keys.size() * (motion_steps - 1); - float3 *key_steps = curve_attr->data_float3(); - - for (size_t i = 0; i < steps_size; i++) - bnds.grow_safe(key_steps[i]); - } } } @@ -748,6 +377,38 @@ void Mesh::compute_bounds() bounds = bnds; } +void Mesh::apply_transform(const Transform &tfm, const bool apply_to_motion) +{ + transform_normal = transform_transposed_inverse(tfm); + + /* apply to mesh vertices */ + for (size_t i = 0; i < verts.size(); i++) + verts[i] = transform_point(&tfm, verts[i]); + + if (apply_to_motion) { + Attribute *attr = attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (attr) { + size_t steps_size = verts.size() * (motion_steps - 1); + float3 *vert_steps = attr->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + vert_steps[i] = transform_point(&tfm, vert_steps[i]); + } + + Attribute *attr_N = attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); + + if (attr_N) { + Transform ntfm = transform_normal; + size_t steps_size = verts.size() * (motion_steps - 1); + float3 *normal_steps = attr_N->data_float3(); + + for (size_t i = 0; i < steps_size; i++) + normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i])); + } + } +} + void Mesh::add_face_normals() { /* don't compute if already there */ @@ -975,39 +636,6 @@ void Mesh::pack_verts(const vector<uint> &tri_prim_index, } } -void Mesh::pack_curves(Scene *scene, - float4 *curve_key_co, - float4 *curve_data, - size_t curvekey_offset) -{ - size_t curve_keys_size = curve_keys.size(); - - /* pack curve keys */ - if (curve_keys_size) { - float3 *keys_ptr = curve_keys.data(); - float *radius_ptr = curve_radius.data(); - - for (size_t i = 0; i < curve_keys_size; i++) - curve_key_co[i] = make_float4(keys_ptr[i].x, keys_ptr[i].y, keys_ptr[i].z, radius_ptr[i]); - } - - /* pack curve segments */ - size_t curve_num = num_curves(); - - for (size_t i = 0; i < curve_num; i++) { - Curve curve = get_curve(i); - int shader_id = curve_shader[i]; - Shader *shader = (shader_id < used_shaders.size()) ? used_shaders[shader_id] : - scene->default_surface; - shader_id = scene->shader_manager->get_shader_id(shader, false); - - curve_data[i] = make_float4(__int_as_float(curve.first_key + curvekey_offset), - __int_as_float(curve.num_keys), - __int_as_float(shader_id), - 0.0f); - } -} - void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset) { size_t num_faces = subd_faces.size(); @@ -1054,1391 +682,4 @@ void Mesh::pack_patches(uint *patch_data, uint vert_offset, uint face_offset, ui } } -void Mesh::compute_bvh( - Device *device, DeviceScene *dscene, SceneParams *params, Progress *progress, int n, int total) -{ - if (progress->get_cancel()) - return; - - compute_bounds(); - - const BVHLayout bvh_layout = BVHParams::best_bvh_layout(params->bvh_layout, - device->get_bvh_layout_mask()); - if (need_build_bvh(bvh_layout)) { - string msg = "Updating Mesh BVH "; - if (name.empty()) - msg += string_printf("%u/%u", (uint)(n + 1), (uint)total); - else - msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total); - - Object object; - object.mesh = this; - - vector<Mesh *> meshes; - meshes.push_back(this); - vector<Object *> objects; - objects.push_back(&object); - - if (bvh && !need_update_rebuild) { - progress->set_status(msg, "Refitting BVH"); - - bvh->meshes = meshes; - bvh->objects = objects; - - bvh->refit(*progress); - } - else { - progress->set_status(msg, "Building BVH"); - - BVHParams bparams; - bparams.use_spatial_split = params->use_bvh_spatial_split; - bparams.bvh_layout = bvh_layout; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - params->use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = params->num_bvh_time_steps; - bparams.num_motion_curve_steps = params->num_bvh_time_steps; - bparams.bvh_type = params->bvh_type; - bparams.curve_flags = dscene->data.curve.curveflags; - bparams.curve_subdivisions = dscene->data.curve.subdivisions; - - delete bvh; - bvh = BVH::create(bparams, meshes, objects); - MEM_GUARDED_CALL(progress, bvh->build, *progress); - } - } - - need_update = false; - need_update_rebuild = false; -} - -void Mesh::tag_update(Scene *scene, bool rebuild) -{ - need_update = true; - - if (rebuild) { - need_update_rebuild = true; - scene->light_manager->need_update = true; - } - else { - foreach (Shader *shader, used_shaders) - if (shader->has_surface_emission) - scene->light_manager->need_update = true; - } - - scene->mesh_manager->need_update = true; - scene->object_manager->need_update = true; -} - -bool Mesh::has_motion_blur() const -{ - return (use_motion_blur && (attributes.find(ATTR_STD_MOTION_VERTEX_POSITION) || - curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION))); -} - -bool Mesh::has_true_displacement() const -{ - foreach (Shader *shader, used_shaders) { - if (shader->has_displacement && shader->displacement_method != DISPLACE_BUMP) { - return true; - } - } - - return false; -} - -bool Mesh::has_voxel_attributes() const -{ - foreach (const Attribute &attr, attributes.attributes) { - if (attr.element == ATTR_ELEMENT_VOXEL) { - return true; - } - } - - return false; -} - -float Mesh::motion_time(int step) const -{ - return (motion_steps > 1) ? 2.0f * step / (motion_steps - 1) - 1.0f : 0.0f; -} - -int Mesh::motion_step(float time) const -{ - if (motion_steps > 1) { - int attr_step = 0; - - for (int step = 0; step < motion_steps; step++) { - float step_time = motion_time(step); - if (step_time == time) { - return attr_step; - } - - /* Center step is stored in a separate attribute. */ - if (step != motion_steps / 2) { - attr_step++; - } - } - } - - return -1; -} - -bool Mesh::need_build_bvh(BVHLayout layout) const -{ - return !transform_applied || has_surface_bssrdf || layout == BVH_LAYOUT_OPTIX; -} - -bool Mesh::is_instanced() const -{ - /* Currently we treat subsurface objects as instanced. - * - * While it might be not very optimal for ray traversal, it avoids having - * duplicated BVH in the memory, saving quite some space. - */ - return !transform_applied || has_surface_bssrdf; -} - -/* Mesh Manager */ - -MeshManager::MeshManager() -{ - need_update = true; - need_flags_update = true; -} - -MeshManager::~MeshManager() -{ -} - -void MeshManager::update_osl_attributes(Device *device, - Scene *scene, - vector<AttributeRequestSet> &mesh_attributes) -{ -#ifdef WITH_OSL - /* for OSL, a hash map is used to lookup the attribute by name. */ - OSLGlobals *og = (OSLGlobals *)device->osl_memory(); - - og->object_name_map.clear(); - og->attribute_map.clear(); - og->object_names.clear(); - - og->attribute_map.resize(scene->objects.size() * ATTR_PRIM_TYPES); - - for (size_t i = 0; i < scene->objects.size(); i++) { - /* set object name to object index map */ - Object *object = scene->objects[i]; - og->object_name_map[object->name] = i; - og->object_names.push_back(object->name); - - /* set object attributes */ - foreach (ParamValue &attr, object->attributes) { - OSLGlobals::Attribute osl_attr; - - osl_attr.type = attr.type(); - osl_attr.desc.element = ATTR_ELEMENT_OBJECT; - osl_attr.value = attr; - osl_attr.desc.offset = 0; - osl_attr.desc.flags = 0; - - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][attr.name()] = osl_attr; - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][attr.name()] = osl_attr; - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][attr.name()] = osl_attr; - } - - /* find mesh attributes */ - size_t j; - - for (j = 0; j < scene->meshes.size(); j++) - if (scene->meshes[j] == object->mesh) - break; - - AttributeRequestSet &attributes = mesh_attributes[j]; - - /* set object attributes */ - foreach (AttributeRequest &req, attributes.requests) { - OSLGlobals::Attribute osl_attr; - - if (req.triangle_desc.element != ATTR_ELEMENT_NONE) { - osl_attr.desc = req.triangle_desc; - - if (req.triangle_type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else if (req.triangle_type == TypeDesc::TypeMatrix) - osl_attr.type = TypeDesc::TypeMatrix; - else if (req.triangle_type == TypeFloat2) - osl_attr.type = TypeFloat2; - else if (req.triangle_type == TypeRGBA) - osl_attr.type = TypeRGBA; - else - osl_attr.type = TypeDesc::TypeColor; - - if (req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][stdname] = osl_attr; - } - else if (req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_TRIANGLE][req.name] = osl_attr; - } - } - - if (req.curve_desc.element != ATTR_ELEMENT_NONE) { - osl_attr.desc = req.curve_desc; - - if (req.curve_type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else if (req.curve_type == TypeDesc::TypeMatrix) - osl_attr.type = TypeDesc::TypeMatrix; - else if (req.curve_type == TypeFloat2) - osl_attr.type = TypeFloat2; - else if (req.curve_type == TypeRGBA) - osl_attr.type = TypeRGBA; - else - osl_attr.type = TypeDesc::TypeColor; - - if (req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][stdname] = osl_attr; - } - else if (req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_CURVE][req.name] = osl_attr; - } - } - - if (req.subd_desc.element != ATTR_ELEMENT_NONE) { - osl_attr.desc = req.subd_desc; - - if (req.subd_type == TypeDesc::TypeFloat) - osl_attr.type = TypeDesc::TypeFloat; - else if (req.subd_type == TypeDesc::TypeMatrix) - osl_attr.type = TypeDesc::TypeMatrix; - else if (req.subd_type == TypeFloat2) - osl_attr.type = TypeFloat2; - else if (req.subd_type == TypeRGBA) - osl_attr.type = TypeRGBA; - else - osl_attr.type = TypeDesc::TypeColor; - - if (req.std != ATTR_STD_NONE) { - /* if standard attribute, add lookup by geom: name convention */ - ustring stdname(string("geom:") + string(Attribute::standard_name(req.std))); - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][stdname] = osl_attr; - } - else if (req.name != ustring()) { - /* add lookup by mesh attribute name */ - og->attribute_map[i * ATTR_PRIM_TYPES + ATTR_PRIM_SUBD][req.name] = osl_attr; - } - } - } - } -#else - (void)device; - (void)scene; - (void)mesh_attributes; -#endif -} - -void MeshManager::update_svm_attributes(Device *, - DeviceScene *dscene, - Scene *scene, - vector<AttributeRequestSet> &mesh_attributes) -{ - /* for SVM, the attributes_map table is used to lookup the offset of an - * attribute, based on a unique shader attribute id. */ - - /* compute array stride */ - int attr_map_size = 0; - - for (size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - mesh->attr_map_offset = attr_map_size; - attr_map_size += (mesh_attributes[i].size() + 1) * ATTR_PRIM_TYPES; - } - - if (attr_map_size == 0) - return; - - /* create attribute map */ - uint4 *attr_map = dscene->attributes_map.alloc(attr_map_size); - memset(attr_map, 0, dscene->attributes_map.size() * sizeof(uint)); - - for (size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - AttributeRequestSet &attributes = mesh_attributes[i]; - - /* set object attributes */ - int index = mesh->attr_map_offset; - - foreach (AttributeRequest &req, attributes.requests) { - uint id; - - if (req.std == ATTR_STD_NONE) - id = scene->shader_manager->get_attribute_id(req.name); - else - id = scene->shader_manager->get_attribute_id(req.std); - - if (mesh->num_triangles()) { - attr_map[index].x = id; - attr_map[index].y = req.triangle_desc.element; - attr_map[index].z = as_uint(req.triangle_desc.offset); - - if (req.triangle_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if (req.triangle_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if (req.triangle_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else if (req.triangle_type == TypeRGBA) - attr_map[index].w = NODE_ATTR_RGBA; - else - attr_map[index].w = NODE_ATTR_FLOAT3; - - attr_map[index].w |= req.triangle_desc.flags << 8; - } - - index++; - - if (mesh->num_curves()) { - attr_map[index].x = id; - attr_map[index].y = req.curve_desc.element; - attr_map[index].z = as_uint(req.curve_desc.offset); - - if (req.curve_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if (req.curve_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if (req.curve_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else - attr_map[index].w = NODE_ATTR_FLOAT3; - - attr_map[index].w |= req.curve_desc.flags << 8; - } - - index++; - - if (mesh->subd_faces.size()) { - attr_map[index].x = id; - attr_map[index].y = req.subd_desc.element; - attr_map[index].z = as_uint(req.subd_desc.offset); - - if (req.subd_type == TypeDesc::TypeFloat) - attr_map[index].w = NODE_ATTR_FLOAT; - else if (req.subd_type == TypeDesc::TypeMatrix) - attr_map[index].w = NODE_ATTR_MATRIX; - else if (req.subd_type == TypeFloat2) - attr_map[index].w = NODE_ATTR_FLOAT2; - else if (req.triangle_type == TypeRGBA) - attr_map[index].w = NODE_ATTR_RGBA; - else - attr_map[index].w = NODE_ATTR_FLOAT3; - - attr_map[index].w |= req.subd_desc.flags << 8; - } - - index++; - } - - /* terminator */ - for (int j = 0; j < ATTR_PRIM_TYPES; j++) { - attr_map[index].x = ATTR_STD_NONE; - attr_map[index].y = 0; - attr_map[index].z = 0; - attr_map[index].w = 0; - - index++; - } - } - - /* copy to device */ - dscene->attributes_map.copy_to_device(); -} - -static void update_attribute_element_size(Mesh *mesh, - Attribute *mattr, - AttributePrimitive prim, - size_t *attr_float_size, - size_t *attr_float2_size, - size_t *attr_float3_size, - size_t *attr_uchar4_size) -{ - if (mattr) { - size_t size = mattr->element_size(mesh, prim); - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* pass */ - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - *attr_uchar4_size += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - *attr_float_size += size; - } - else if (mattr->type == TypeFloat2) { - *attr_float2_size += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - *attr_float3_size += size * 4; - } - else { - *attr_float3_size += size; - } - } -} - -static void update_attribute_element_offset(Mesh *mesh, - device_vector<float> &attr_float, - size_t &attr_float_offset, - device_vector<float2> &attr_float2, - size_t &attr_float2_offset, - device_vector<float4> &attr_float3, - size_t &attr_float3_offset, - device_vector<uchar4> &attr_uchar4, - size_t &attr_uchar4_offset, - Attribute *mattr, - AttributePrimitive prim, - TypeDesc &type, - AttributeDescriptor &desc) -{ - if (mattr) { - /* store element and type */ - desc.element = mattr->element; - desc.flags = mattr->flags; - type = mattr->type; - - /* store attribute data in arrays */ - size_t size = mattr->element_size(mesh, prim); - - AttributeElement &element = desc.element; - int &offset = desc.offset; - - if (mattr->element == ATTR_ELEMENT_VOXEL) { - /* store slot in offset value */ - VoxelAttribute *voxel_data = mattr->data_voxel(); - offset = voxel_data->slot; - } - else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) { - uchar4 *data = mattr->data_uchar4(); - offset = attr_uchar4_offset; - - assert(attr_uchar4.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_uchar4[offset + k] = data[k]; - } - attr_uchar4_offset += size; - } - else if (mattr->type == TypeDesc::TypeFloat) { - float *data = mattr->data_float(); - offset = attr_float_offset; - - assert(attr_float.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_float[offset + k] = data[k]; - } - attr_float_offset += size; - } - else if (mattr->type == TypeFloat2) { - float2 *data = mattr->data_float2(); - offset = attr_float2_offset; - - assert(attr_float2.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_float2[offset + k] = data[k]; - } - attr_float2_offset += size; - } - else if (mattr->type == TypeDesc::TypeMatrix) { - Transform *tfm = mattr->data_transform(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size * 3); - for (size_t k = 0; k < size * 3; k++) { - attr_float3[offset + k] = (&tfm->x)[k]; - } - attr_float3_offset += size * 3; - } - else { - float4 *data = mattr->data_float4(); - offset = attr_float3_offset; - - assert(attr_float3.size() >= offset + size); - for (size_t k = 0; k < size; k++) { - attr_float3[offset + k] = data[k]; - } - attr_float3_offset += size; - } - - /* mesh vertex/curve index is global, not per object, so we sneak - * a correction for that in here */ - if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK && - desc.flags & ATTR_SUBDIVIDED) { - /* indices for subdivided attributes are retrieved - * from patch table so no need for correction here*/ - } - else if (element == ATTR_ELEMENT_VERTEX) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_VERTEX_MOTION) - offset -= mesh->vert_offset; - else if (element == ATTR_ELEMENT_FACE) { - if (prim == ATTR_PRIM_TRIANGLE) - offset -= mesh->tri_offset; - else - offset -= mesh->face_offset; - } - else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) { - if (prim == ATTR_PRIM_TRIANGLE) - offset -= 3 * mesh->tri_offset; - else - offset -= mesh->corner_offset; - } - else if (element == ATTR_ELEMENT_CURVE) - offset -= mesh->curve_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY) - offset -= mesh->curvekey_offset; - else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION) - offset -= mesh->curvekey_offset; - } - else { - /* attribute not found */ - desc.element = ATTR_ELEMENT_NONE; - desc.offset = 0; - } -} - -void MeshManager::device_update_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - progress.set_status("Updating Mesh", "Computing attributes"); - - /* gather per mesh requested attributes. as meshes may have multiple - * shaders assigned, this merges the requested attributes that have - * been set per shader by the shader manager */ - vector<AttributeRequestSet> mesh_attributes(scene->meshes.size()); - - for (size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - - scene->need_global_attributes(mesh_attributes[i]); - - foreach (Shader *shader, mesh->used_shaders) { - mesh_attributes[i].add(shader->attributes); - } - } - - /* mesh attribute are stored in a single array per data type. here we fill - * those arrays, and set the offset and element type to create attribute - * maps next */ - - /* Pre-allocate attributes to avoid arrays re-allocation which would - * take 2x of overall attribute memory usage. - */ - size_t attr_float_size = 0; - size_t attr_float2_size = 0; - size_t attr_float3_size = 0; - size_t attr_uchar4_size = 0; - for (size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - AttributeRequestSet &attributes = mesh_attributes[i]; - foreach (AttributeRequest &req, attributes.requests) { - Attribute *triangle_mattr = mesh->attributes.find(req); - Attribute *curve_mattr = mesh->curve_attributes.find(req); - Attribute *subd_mattr = mesh->subd_attributes.find(req); - - update_attribute_element_size(mesh, - triangle_mattr, - ATTR_PRIM_TRIANGLE, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_uchar4_size); - update_attribute_element_size(mesh, - curve_mattr, - ATTR_PRIM_CURVE, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_uchar4_size); - update_attribute_element_size(mesh, - subd_mattr, - ATTR_PRIM_SUBD, - &attr_float_size, - &attr_float2_size, - &attr_float3_size, - &attr_uchar4_size); - } - } - - dscene->attributes_float.alloc(attr_float_size); - dscene->attributes_float2.alloc(attr_float2_size); - dscene->attributes_float3.alloc(attr_float3_size); - dscene->attributes_uchar4.alloc(attr_uchar4_size); - - size_t attr_float_offset = 0; - size_t attr_float2_offset = 0; - size_t attr_float3_offset = 0; - size_t attr_uchar4_offset = 0; - - /* Fill in attributes. */ - for (size_t i = 0; i < scene->meshes.size(); i++) { - Mesh *mesh = scene->meshes[i]; - AttributeRequestSet &attributes = mesh_attributes[i]; - - /* todo: we now store std and name attributes from requests even if - * they actually refer to the same mesh attributes, optimize */ - foreach (AttributeRequest &req, attributes.requests) { - Attribute *triangle_mattr = mesh->attributes.find(req); - Attribute *curve_mattr = mesh->curve_attributes.find(req); - Attribute *subd_mattr = mesh->subd_attributes.find(req); - - update_attribute_element_offset(mesh, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - triangle_mattr, - ATTR_PRIM_TRIANGLE, - req.triangle_type, - req.triangle_desc); - - update_attribute_element_offset(mesh, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - curve_mattr, - ATTR_PRIM_CURVE, - req.curve_type, - req.curve_desc); - - update_attribute_element_offset(mesh, - dscene->attributes_float, - attr_float_offset, - dscene->attributes_float2, - attr_float2_offset, - dscene->attributes_float3, - attr_float3_offset, - dscene->attributes_uchar4, - attr_uchar4_offset, - subd_mattr, - ATTR_PRIM_SUBD, - req.subd_type, - req.subd_desc); - - if (progress.get_cancel()) - return; - } - } - - /* create attribute lookup maps */ - if (scene->shader_manager->use_osl()) - update_osl_attributes(device, scene, mesh_attributes); - - update_svm_attributes(device, dscene, scene, mesh_attributes); - - if (progress.get_cancel()) - return; - - /* copy to device */ - progress.set_status("Updating Mesh", "Copying Attributes to device"); - - if (dscene->attributes_float.size()) { - dscene->attributes_float.copy_to_device(); - } - if (dscene->attributes_float2.size()) { - dscene->attributes_float2.copy_to_device(); - } - if (dscene->attributes_float3.size()) { - dscene->attributes_float3.copy_to_device(); - } - if (dscene->attributes_uchar4.size()) { - dscene->attributes_uchar4.copy_to_device(); - } - - if (progress.get_cancel()) - return; - - /* After mesh attributes and patch tables have been copied to device memory, - * we need to update offsets in the objects. */ - scene->object_manager->device_update_mesh_offsets(device, dscene, scene); -} - -void MeshManager::mesh_calc_offset(Scene *scene) -{ - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - - size_t patch_size = 0; - size_t face_size = 0; - size_t corner_size = 0; - - size_t prim_size = 0; - - foreach (Mesh *mesh, scene->meshes) { - mesh->vert_offset = vert_size; - mesh->tri_offset = tri_size; - - mesh->curvekey_offset = curve_key_size; - mesh->curve_offset = curve_size; - - mesh->patch_offset = patch_size; - mesh->face_offset = face_size; - mesh->corner_offset = corner_size; - - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - curve_key_size += mesh->curve_keys.size(); - curve_size += mesh->num_curves(); - - if (mesh->subd_faces.size()) { - Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; - patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; - - /* patch tables are stored in same array so include them in patch_size */ - if (mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - face_size += mesh->subd_faces.size(); - corner_size += mesh->subd_face_corners.size(); - - mesh->prim_offset = prim_size; - prim_size += mesh->num_primitives(); - } -} - -void MeshManager::device_update_mesh( - Device *, DeviceScene *dscene, Scene *scene, bool for_displacement, Progress &progress) -{ - /* Count. */ - size_t vert_size = 0; - size_t tri_size = 0; - - size_t curve_key_size = 0; - size_t curve_size = 0; - - size_t patch_size = 0; - - foreach (Mesh *mesh, scene->meshes) { - vert_size += mesh->verts.size(); - tri_size += mesh->num_triangles(); - - curve_key_size += mesh->curve_keys.size(); - curve_size += mesh->num_curves(); - - if (mesh->subd_faces.size()) { - Mesh::SubdFace &last = mesh->subd_faces[mesh->subd_faces.size() - 1]; - patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8; - - /* patch tables are stored in same array so include them in patch_size */ - if (mesh->patch_table) { - mesh->patch_table_offset = patch_size; - patch_size += mesh->patch_table->total_size(); - } - } - } - - /* Create mapping from triangle to primitive triangle array. */ - vector<uint> tri_prim_index(tri_size); - if (for_displacement) { - /* For displacement kernels we do some trickery to make them believe - * we've got all required data ready. However, that data is different - * from final render kernels since we don't have BVH yet, so can't - * really use same semantic of arrays. - */ - foreach (Mesh *mesh, scene->meshes) { - for (size_t i = 0; i < mesh->num_triangles(); ++i) { - tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset); - } - } - } - else { - for (size_t i = 0; i < dscene->prim_index.size(); ++i) { - if ((dscene->prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { - tri_prim_index[dscene->prim_index[i]] = dscene->prim_tri_index[i]; - } - } - } - - /* Fill in all the arrays. */ - if (tri_size != 0) { - /* normals */ - progress.set_status("Updating Mesh", "Computing normals"); - - uint *tri_shader = dscene->tri_shader.alloc(tri_size); - float4 *vnormal = dscene->tri_vnormal.alloc(vert_size); - uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size); - uint *tri_patch = dscene->tri_patch.alloc(tri_size); - float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); - - foreach (Mesh *mesh, scene->meshes) { - mesh->pack_shaders(scene, &tri_shader[mesh->tri_offset]); - mesh->pack_normals(&vnormal[mesh->vert_offset]); - mesh->pack_verts(tri_prim_index, - &tri_vindex[mesh->tri_offset], - &tri_patch[mesh->tri_offset], - &tri_patch_uv[mesh->vert_offset], - mesh->vert_offset, - mesh->tri_offset); - if (progress.get_cancel()) - return; - } - - /* vertex coordinates */ - progress.set_status("Updating Mesh", "Copying Mesh to device"); - - dscene->tri_shader.copy_to_device(); - dscene->tri_vnormal.copy_to_device(); - dscene->tri_vindex.copy_to_device(); - dscene->tri_patch.copy_to_device(); - dscene->tri_patch_uv.copy_to_device(); - } - - if (curve_size != 0) { - progress.set_status("Updating Mesh", "Copying Strands to device"); - - float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size); - float4 *curves = dscene->curves.alloc(curve_size); - - foreach (Mesh *mesh, scene->meshes) { - mesh->pack_curves(scene, - &curve_keys[mesh->curvekey_offset], - &curves[mesh->curve_offset], - mesh->curvekey_offset); - if (progress.get_cancel()) - return; - } - - dscene->curve_keys.copy_to_device(); - dscene->curves.copy_to_device(); - } - - if (patch_size != 0) { - progress.set_status("Updating Mesh", "Copying Patches to device"); - - uint *patch_data = dscene->patches.alloc(patch_size); - - foreach (Mesh *mesh, scene->meshes) { - mesh->pack_patches(&patch_data[mesh->patch_offset], - mesh->vert_offset, - mesh->face_offset, - mesh->corner_offset); - - if (mesh->patch_table) { - mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset], - mesh->patch_table_offset); - } - - if (progress.get_cancel()) - return; - } - - dscene->patches.copy_to_device(); - } - - if (for_displacement) { - float4 *prim_tri_verts = dscene->prim_tri_verts.alloc(tri_size * 3); - foreach (Mesh *mesh, scene->meshes) { - for (size_t i = 0; i < mesh->num_triangles(); ++i) { - Mesh::Triangle t = mesh->get_triangle(i); - size_t offset = 3 * (i + mesh->tri_offset); - prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]); - prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]); - prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]); - } - } - dscene->prim_tri_verts.copy_to_device(); - } -} - -void MeshManager::device_update_bvh(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - /* bvh build */ - progress.set_status("Updating Scene BVH", "Building"); - - BVHParams bparams; - bparams.top_level = true; - bparams.bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, - device->get_bvh_layout_mask()); - bparams.use_spatial_split = scene->params.use_bvh_spatial_split; - bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && - scene->params.use_bvh_unaligned_nodes; - bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; - bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; - bparams.bvh_type = scene->params.bvh_type; - bparams.curve_flags = dscene->data.curve.curveflags; - bparams.curve_subdivisions = dscene->data.curve.subdivisions; - - VLOG(1) << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout."; - -#ifdef WITH_EMBREE - if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { - if (dscene->data.bvh.scene) { - BVHEmbree::destroy(dscene->data.bvh.scene); - } - } -#endif - - BVH *bvh = BVH::create(bparams, scene->meshes, scene->objects); - bvh->build(progress, &device->stats); - - if (progress.get_cancel()) { -#ifdef WITH_EMBREE - if (bparams.bvh_layout == BVH_LAYOUT_EMBREE) { - if (dscene->data.bvh.scene) { - BVHEmbree::destroy(dscene->data.bvh.scene); - } - } -#endif - delete bvh; - return; - } - - /* copy to device */ - progress.set_status("Updating Scene BVH", "Copying BVH to device"); - - PackedBVH &pack = bvh->pack; - - if (pack.nodes.size()) { - dscene->bvh_nodes.steal_data(pack.nodes); - dscene->bvh_nodes.copy_to_device(); - } - if (pack.leaf_nodes.size()) { - dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes); - dscene->bvh_leaf_nodes.copy_to_device(); - } - if (pack.object_node.size()) { - dscene->object_node.steal_data(pack.object_node); - dscene->object_node.copy_to_device(); - } - if (pack.prim_tri_index.size()) { - dscene->prim_tri_index.steal_data(pack.prim_tri_index); - dscene->prim_tri_index.copy_to_device(); - } - if (pack.prim_tri_verts.size()) { - dscene->prim_tri_verts.steal_data(pack.prim_tri_verts); - dscene->prim_tri_verts.copy_to_device(); - } - if (pack.prim_type.size()) { - dscene->prim_type.steal_data(pack.prim_type); - dscene->prim_type.copy_to_device(); - } - if (pack.prim_visibility.size()) { - dscene->prim_visibility.steal_data(pack.prim_visibility); - dscene->prim_visibility.copy_to_device(); - } - if (pack.prim_index.size()) { - dscene->prim_index.steal_data(pack.prim_index); - dscene->prim_index.copy_to_device(); - } - if (pack.prim_object.size()) { - dscene->prim_object.steal_data(pack.prim_object); - dscene->prim_object.copy_to_device(); - } - if (pack.prim_time.size()) { - dscene->prim_time.steal_data(pack.prim_time); - dscene->prim_time.copy_to_device(); - } - - dscene->data.bvh.root = pack.root_index; - dscene->data.bvh.bvh_layout = bparams.bvh_layout; - dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0); - - bvh->copy_to_device(progress, dscene); - - delete bvh; -} - -void MeshManager::device_update_preprocess(Device *device, Scene *scene, Progress &progress) -{ - if (!need_update && !need_flags_update) { - return; - } - - progress.set_status("Updating Meshes Flags"); - - /* Update flags. */ - bool volume_images_updated = false; - - foreach (Mesh *mesh, scene->meshes) { - mesh->has_volume = false; - - foreach (const Shader *shader, mesh->used_shaders) { - if (shader->has_volume) { - mesh->has_volume = true; - } - if (shader->has_surface_bssrdf) { - mesh->has_surface_bssrdf = true; - } - } - - if (need_update && mesh->has_volume) { - /* Create volume meshes if there is voxel data. */ - if (mesh->has_voxel_attributes()) { - if (!volume_images_updated) { - progress.set_status("Updating Meshes Volume Bounds"); - device_update_volume_images(device, scene, progress); - volume_images_updated = true; - } - - create_volume_mesh(scene, mesh, progress); - } - } - } - - need_flags_update = false; -} - -void MeshManager::device_update_displacement_images(Device *device, - Scene *scene, - Progress &progress) -{ - progress.set_status("Updating Displacement Images"); - TaskPool pool; - ImageManager *image_manager = scene->image_manager; - set<int> bump_images; - foreach (Mesh *mesh, scene->meshes) { - if (mesh->need_update) { - foreach (Shader *shader, mesh->used_shaders) { - if (!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) { - continue; - } - foreach (ShaderNode *node, shader->graph->nodes) { - if (node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) { - continue; - } - - ImageSlotTextureNode *image_node = static_cast<ImageSlotTextureNode *>(node); - foreach (int slot, image_node->slots) { - if (slot != -1) { - bump_images.insert(slot); - } - } - } - } - } - } - foreach (int slot, bump_images) { - pool.push(function_bind( - &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress)); - } - pool.wait_work(); -} - -void MeshManager::device_update_volume_images(Device *device, Scene *scene, Progress &progress) -{ - progress.set_status("Updating Volume Images"); - TaskPool pool; - ImageManager *image_manager = scene->image_manager; - set<int> volume_images; - - foreach (Mesh *mesh, scene->meshes) { - if (!mesh->need_update) { - continue; - } - - foreach (Attribute &attr, mesh->attributes.attributes) { - if (attr.element != ATTR_ELEMENT_VOXEL) { - continue; - } - - VoxelAttribute *voxel = attr.data_voxel(); - - if (voxel->slot != -1) { - volume_images.insert(voxel->slot); - } - } - } - - foreach (int slot, volume_images) { - pool.push(function_bind( - &ImageManager::device_update_slot, image_manager, device, scene, slot, &progress)); - } - pool.wait_work(); -} - -void MeshManager::device_update(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress) -{ - if (!need_update) - return; - - VLOG(1) << "Total " << scene->meshes.size() << " meshes."; - - bool true_displacement_used = false; - size_t total_tess_needed = 0; - - foreach (Mesh *mesh, scene->meshes) { - foreach (Shader *shader, mesh->used_shaders) { - if (shader->need_update_mesh) - mesh->need_update = true; - } - - if (mesh->need_update) { - /* Update normals. */ - mesh->add_face_normals(); - mesh->add_vertex_normals(); - - if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { - mesh->add_undisplaced(); - } - - /* Test if we need tessellation. */ - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE && mesh->num_subd_verts == 0 && - mesh->subd_params) { - total_tess_needed++; - } - - /* Test if we need displacement. */ - if (mesh->has_true_displacement()) { - true_displacement_used = true; - } - - if (progress.get_cancel()) - return; - } - } - - /* Tessellate meshes that are using subdivision */ - if (total_tess_needed) { - Camera *dicing_camera = scene->dicing_camera; - dicing_camera->update(scene); - - size_t i = 0; - foreach (Mesh *mesh, scene->meshes) { - if (mesh->need_update && mesh->subdivision_type != Mesh::SUBDIVISION_NONE && - mesh->num_subd_verts == 0 && mesh->subd_params) { - string msg = "Tessellating "; - if (mesh->name == "") - msg += string_printf("%u/%u", (uint)(i + 1), (uint)total_tess_needed); - else - msg += string_printf( - "%s %u/%u", mesh->name.c_str(), (uint)(i + 1), (uint)total_tess_needed); - - progress.set_status("Updating Mesh", msg); - - mesh->subd_params->camera = dicing_camera; - DiagSplit dsplit(*mesh->subd_params); - mesh->tessellate(&dsplit); - - i++; - - if (progress.get_cancel()) - return; - } - } - } - - /* Update images needed for true displacement. */ - bool old_need_object_flags_update = false; - if (true_displacement_used) { - VLOG(1) << "Updating images used for true displacement."; - device_update_displacement_images(device, scene, progress); - old_need_object_flags_update = scene->object_manager->need_flags_update; - scene->object_manager->device_update_flags(device, dscene, scene, progress, false); - } - - /* Device update. */ - device_free(device, dscene); - - mesh_calc_offset(scene); - if (true_displacement_used) { - device_update_mesh(device, dscene, scene, true, progress); - } - if (progress.get_cancel()) - return; - - device_update_attributes(device, dscene, scene, progress); - if (progress.get_cancel()) - return; - - /* Update displacement. */ - bool displacement_done = false; - size_t num_bvh = 0; - BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, - device->get_bvh_layout_mask()); - - foreach (Mesh *mesh, scene->meshes) { - if (mesh->need_update) { - if (displace(device, dscene, scene, mesh, progress)) { - displacement_done = true; - } - - if (mesh->need_build_bvh(bvh_layout)) { - num_bvh++; - } - } - - if (progress.get_cancel()) - return; - } - - /* Device re-update after displacement. */ - if (displacement_done) { - device_free(device, dscene); - - device_update_attributes(device, dscene, scene, progress); - if (progress.get_cancel()) - return; - } - - TaskPool pool; - - size_t i = 0; - foreach (Mesh *mesh, scene->meshes) { - if (mesh->need_update) { - pool.push(function_bind( - &Mesh::compute_bvh, mesh, device, dscene, &scene->params, &progress, i, num_bvh)); - if (mesh->need_build_bvh(bvh_layout)) { - i++; - } - } - } - - TaskPool::Summary summary; - pool.wait_work(&summary); - VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); - - foreach (Shader *shader, scene->shaders) { - shader->need_update_mesh = false; - } - - Scene::MotionType need_motion = scene->need_motion(); - bool motion_blur = need_motion == Scene::MOTION_BLUR; - - /* Update objects. */ - vector<Object *> volume_objects; - foreach (Object *object, scene->objects) { - object->compute_bounds(motion_blur); - } - - if (progress.get_cancel()) - return; - - device_update_bvh(device, dscene, scene, progress); - if (progress.get_cancel()) - return; - - device_update_mesh(device, dscene, scene, false, progress); - if (progress.get_cancel()) - return; - - need_update = false; - - if (true_displacement_used) { - /* Re-tag flags for update, so they're re-evaluated - * for meshes with correct bounding boxes. - * - * This wouldn't cause wrong results, just true - * displacement might be less optimal ot calculate. - */ - scene->object_manager->need_flags_update = old_need_object_flags_update; - } -} - -void MeshManager::device_free(Device *device, DeviceScene *dscene) -{ - dscene->bvh_nodes.free(); - dscene->bvh_leaf_nodes.free(); - dscene->object_node.free(); - dscene->prim_tri_verts.free(); - dscene->prim_tri_index.free(); - dscene->prim_type.free(); - dscene->prim_visibility.free(); - dscene->prim_index.free(); - dscene->prim_object.free(); - dscene->prim_time.free(); - dscene->tri_shader.free(); - dscene->tri_vnormal.free(); - dscene->tri_vindex.free(); - dscene->tri_patch.free(); - dscene->tri_patch_uv.free(); - dscene->curves.free(); - dscene->curve_keys.free(); - dscene->patches.free(); - dscene->attributes_map.free(); - dscene->attributes_float.free(); - dscene->attributes_float2.free(); - dscene->attributes_float3.free(); - dscene->attributes_uchar4.free(); - - /* Signal for shaders like displacement not to do ray tracing. */ - dscene->data.bvh.bvh_layout = BVH_LAYOUT_NONE; - -#ifdef WITH_OSL - OSLGlobals *og = (OSLGlobals *)device->osl_memory(); - - if (og) { - og->object_name_map.clear(); - og->attribute_map.clear(); - og->object_names.clear(); - } -#else - (void)device; -#endif -} - -void MeshManager::tag_update(Scene *scene) -{ - need_update = true; - scene->object_manager->need_update = true; -} - -void MeshManager::collect_statistics(const Scene *scene, RenderStats *stats) -{ - foreach (Mesh *mesh, scene->meshes) { - stats->mesh.geometry.add_entry( - NamedSizeEntry(string(mesh->name.c_str()), mesh->get_total_size_in_bytes())); - } -} - -bool Mesh::need_attribute(Scene *scene, AttributeStandard std) -{ - if (std == ATTR_STD_NONE) - return false; - - if (scene->need_global_attribute(std)) - return true; - - foreach (Shader *shader, used_shaders) - if (shader->attributes.find(std)) - return true; - - return false; -} - -bool Mesh::need_attribute(Scene * /*scene*/, ustring name) -{ - if (name == ustring()) - return false; - - foreach (Shader *shader, used_shaders) - if (shader->attributes.find(name)) - return true; - - return false; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index c5be0ba60b9..5583e9c0400 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -21,6 +21,7 @@ #include "bvh/bvh_params.h" #include "render/attribute.h" +#include "render/geometry.h" #include "render/shader.h" #include "util/util_array.h" @@ -29,7 +30,6 @@ #include "util/util_map.h" #include "util/util_param.h" #include "util/util_set.h" -#include "util/util_transform.h" #include "util/util_types.h" #include "util/util_vector.h" @@ -51,7 +51,7 @@ struct PackedPatchTable; /* Mesh */ -class Mesh : public Node { +class Mesh : public Geometry { public: NODE_DECLARE @@ -91,94 +91,6 @@ class Mesh : public Node { return triangles.size() / 3; } - /* Mesh Curve */ - struct Curve { - int first_key; - int num_keys; - - int num_segments() const - { - return num_keys - 1; - } - - void bounds_grow(const int k, - const float3 *curve_keys, - const float *curve_radius, - BoundBox &bounds) const; - void bounds_grow(float4 keys[4], BoundBox &bounds) const; - void bounds_grow(const int k, - const float3 *curve_keys, - const float *curve_radius, - const Transform &aligned_space, - BoundBox &bounds) const; - - void motion_keys(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - float time, - size_t k0, - size_t k1, - float4 r_keys[2]) const; - void cardinal_motion_keys(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - float time, - size_t k0, - size_t k1, - size_t k2, - size_t k3, - float4 r_keys[4]) const; - - void keys_for_step(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - size_t step, - size_t k0, - size_t k1, - float4 r_keys[2]) const; - void cardinal_keys_for_step(const float3 *curve_keys, - const float *curve_radius, - const float3 *key_steps, - size_t num_curve_keys, - size_t num_steps, - size_t step, - size_t k0, - size_t k1, - size_t k2, - size_t k3, - float4 r_keys[4]) const; - }; - - Curve get_curve(size_t i) const - { - int first = curve_first_key[i]; - int next_first = (i + 1 < curve_first_key.size()) ? curve_first_key[i + 1] : curve_keys.size(); - - Curve curve = {first, next_first - first}; - return curve; - } - - size_t num_curves() const - { - return curve_first_key.size(); - } - - size_t num_segments() const - { - return curve_keys.size() - curve_first_key.size(); - } - - size_t num_primitives() const - { - return num_triangles() + num_segments(); - } - /* Mesh SubdFace */ struct SubdFace { int start_corner; @@ -212,14 +124,6 @@ class Mesh : public Node { SubdivisionType subdivision_type; /* Mesh Data */ - enum GeometryFlags { - GEOMETRY_NONE = 0, - GEOMETRY_TRIANGLES = (1 << 0), - GEOMETRY_CURVES = (1 << 1), - }; - int geometry_flags; /* used to distinguish meshes with no verts - and meshed for which geometry is not created */ - array<int> triangles; array<float3> verts; array<int> shader; @@ -230,13 +134,6 @@ class Mesh : public Node { array<float2> vert_patch_uv; float volume_isovalue; - bool has_volume; /* Set in the device_update_flags(). */ - bool has_surface_bssrdf; /* Set in the device_update_flags(). */ - - array<float3> curve_keys; - array<float> curve_radius; - array<int> curve_first_key; - array<int> curve_shader; array<SubdFace> subd_faces; array<int> subd_face_corners; @@ -246,42 +143,18 @@ class Mesh : public Node { SubdParams *subd_params; - vector<Shader *> used_shaders; - AttributeSet attributes; - AttributeSet curve_attributes; AttributeSet subd_attributes; - BoundBox bounds; - bool transform_applied; - bool transform_negative_scaled; - Transform transform_normal; - PackedPatchTable *patch_table; - uint motion_steps; - bool use_motion_blur; - - /* Update Flags */ - bool need_update; - bool need_update_rebuild; - /* BVH */ - BVH *bvh; - size_t tri_offset; size_t vert_offset; - size_t curve_offset; - size_t curvekey_offset; - size_t patch_offset; size_t patch_table_offset; size_t face_offset; size_t corner_offset; - size_t attr_map_offset; - - size_t prim_offset; - size_t num_subd_verts; private: @@ -289,7 +162,7 @@ class Mesh : public Node { unordered_multimap<int, int> vert_stitching_map; /* stitching index -> multiple real vert indices */ friend class DiagSplit; - friend class MeshManager; + friend class GeometryManager; public: /* Functions */ @@ -298,24 +171,24 @@ class Mesh : public Node { void resize_mesh(int numverts, int numfaces); void reserve_mesh(int numverts, int numfaces); - void resize_curves(int numcurves, int numkeys); - void reserve_curves(int numcurves, int numkeys); void resize_subd_faces(int numfaces, int num_ngons, int numcorners); void reserve_subd_faces(int numfaces, int num_ngons, int numcorners); - void clear(bool preserve_voxel_data = false); + void clear(bool preserve_voxel_data); + void clear() override; void add_vertex(float3 P); void add_vertex_slow(float3 P); void add_triangle(int v0, int v1, int v2, int shader, bool smooth); - void add_curve_key(float3 loc, float radius); - void add_curve(int first_key, int shader); void add_subd_face(int *corners, int num_corners, int shader_, bool smooth_); - void compute_bounds(); + void copy_center_to_motion_step(const int motion_step); + + void compute_bounds() override; + void apply_transform(const Transform &tfm, const bool apply_to_motion) override; void add_face_normals(); void add_vertex_normals(); void add_undisplaced(); - void get_uv_tiles(ustring map, unordered_set<int> &tiles); + void get_uv_tiles(ustring map, unordered_set<int> &tiles) override; void pack_shaders(Scene *scene, uint *shader); void pack_normals(float4 *vnormal); @@ -325,103 +198,11 @@ class Mesh : public Node { float2 *tri_patch_uv, size_t vert_offset, size_t tri_offset); - void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); void pack_patches(uint *patch_data, uint vert_offset, uint face_offset, uint corner_offset); - void compute_bvh(Device *device, - DeviceScene *dscene, - SceneParams *params, - Progress *progress, - int n, - int total); - - bool need_attribute(Scene *scene, AttributeStandard std); - bool need_attribute(Scene *scene, ustring name); - - void tag_update(Scene *scene, bool rebuild); - - bool has_motion_blur() const; - bool has_true_displacement() const; - bool has_voxel_attributes() const; - - /* Convert between normalized -1..1 motion time and index - * in the VERTEX_MOTION attribute. */ - float motion_time(int step) const; - int motion_step(float time) const; - - /* Check whether the mesh should have own BVH built separately. Briefly, - * own BVH is needed for mesh, if: - * - * - It is instanced multiple times, so each instance object should share the - * same BVH tree. - * - Special ray intersection is needed, for example to limit subsurface rays - * to only the mesh itself. - * - The BVH layout requires the top level to only contain instances. - */ - bool need_build_bvh(BVHLayout layout) const; - - /* Check if the mesh should be treated as instanced. */ - bool is_instanced() const; - void tessellate(DiagSplit *split); }; -/* Mesh Manager */ - -class MeshManager { - public: - bool need_update; - bool need_flags_update; - - MeshManager(); - ~MeshManager(); - - bool displace(Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress); - - /* attributes */ - void update_osl_attributes(Device *device, - Scene *scene, - vector<AttributeRequestSet> &mesh_attributes); - void update_svm_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - vector<AttributeRequestSet> &mesh_attributes); - - void device_update_preprocess(Device *device, Scene *scene, Progress &progress); - void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); - - void device_free(Device *device, DeviceScene *dscene); - - void tag_update(Scene *scene); - - void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); - - void collect_statistics(const Scene *scene, RenderStats *stats); - - protected: - /* Calculate verts/triangles/curves offsets in global arrays. */ - void mesh_calc_offset(Scene *scene); - - void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); - - void device_update_mesh(Device *device, - DeviceScene *dscene, - Scene *scene, - bool for_displacement, - Progress &progress); - - void device_update_attributes(Device *device, - DeviceScene *dscene, - Scene *scene, - Progress &progress); - - void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); - - void device_update_displacement_images(Device *device, Scene *scene, Progress &progress); - - void device_update_volume_images(Device *device, Scene *scene, Progress &progress); -}; - CCL_NAMESPACE_END #endif /* __MESH_H__ */ diff --git a/intern/cycles/render/mesh_displace.cpp b/intern/cycles/render/mesh_displace.cpp index 6a6c2fbb3eb..467810f9273 100644 --- a/intern/cycles/render/mesh_displace.cpp +++ b/intern/cycles/render/mesh_displace.cpp @@ -43,7 +43,7 @@ static float3 compute_face_normal(const Mesh::Triangle &t, float3 *verts) return norm / normlen; } -bool MeshManager::displace( +bool GeometryManager::displace( Device *device, DeviceScene *dscene, Scene *scene, Mesh *mesh, Progress &progress) { /* verify if we have a displacement shader */ @@ -58,7 +58,7 @@ bool MeshManager::displace( size_t object_index = OBJECT_NONE; for (size_t i = 0; i < scene->objects.size(); i++) { - if (scene->objects[i]->mesh == mesh) { + if (scene->objects[i]->geometry == mesh) { object_index = i; break; } @@ -91,7 +91,7 @@ bool MeshManager::displace( /* set up object, primitive and barycentric coordinates */ int object = object_index; - int prim = mesh->tri_offset + i; + int prim = mesh->prim_offset + i; float u, v; switch (j) { diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index f451b58e92a..74c6a7759a6 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -362,7 +362,7 @@ struct VoxelAttributeGrid { int channels; }; -void MeshManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress) +void GeometryManager::create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress) { string msg = string_printf("Computing Volume Mesh %s", mesh->name.c_str()); progress.set_status("Updating Mesh", msg); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 00f4a7283bb..75e21e00dcf 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -333,10 +333,10 @@ void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph) /* TODO(lukas): This is quite inefficient. A fairly simple improvement would * be to have a cache in each mesh that is indexed by attribute. * Additionally, building a graph-to-meshes list once could help. */ - foreach (Mesh *mesh, scene->meshes) { - foreach (Shader *shader, mesh->used_shaders) { + foreach (Geometry *geom, scene->geometry) { + foreach (Shader *shader, geom->used_shaders) { if (shader->graph == graph) { - mesh->get_uv_tiles(attribute, used_tiles); + geom->get_uv_tiles(attribute, used_tiles); } } } diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 849329a086d..4987b6089d7 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -16,6 +16,7 @@ #include "render/camera.h" #include "device/device.h" +#include "render/hair.h" #include "render/light.h" #include "render/mesh.h" #include "render/curves.h" @@ -87,7 +88,7 @@ NODE_DEFINE(Object) { NodeType *type = NodeType::add("object", create); - SOCKET_NODE(mesh, "Mesh", &Mesh::node_type); + SOCKET_NODE(geometry, "Geometry", &Geometry::node_base_type); SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); SOCKET_UINT(visibility, "Visibility", ~0); SOCKET_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); @@ -152,7 +153,7 @@ void Object::update_motion() void Object::compute_bounds(bool motion_blur) { - BoundBox mbounds = mesh->bounds; + BoundBox mbounds = geometry->bounds; if (motion_blur && use_motion()) { array<DecomposedTransform> decomp(motion.size()); @@ -172,7 +173,7 @@ void Object::compute_bounds(bool motion_blur) } else { /* No motion blur case. */ - if (mesh->transform_applied) { + if (geometry->transform_applied) { bounds = mbounds; } else { @@ -183,89 +184,18 @@ void Object::compute_bounds(bool motion_blur) void Object::apply_transform(bool apply_to_motion) { - if (!mesh || tfm == transform_identity()) + if (!geometry || tfm == transform_identity()) return; - /* triangles */ - if (mesh->verts.size()) { - /* store matrix to transform later. when accessing these as attributes we - * do not want the transform to be applied for consistency between static - * and dynamic BVH, so we do it on packing. */ - mesh->transform_normal = transform_transposed_inverse(tfm); - - /* apply to mesh vertices */ - for (size_t i = 0; i < mesh->verts.size(); i++) - mesh->verts[i] = transform_point(&tfm, mesh->verts[i]); - - if (apply_to_motion) { - Attribute *attr = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (attr) { - size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); - float3 *vert_steps = attr->data_float3(); - - for (size_t i = 0; i < steps_size; i++) - vert_steps[i] = transform_point(&tfm, vert_steps[i]); - } - - Attribute *attr_N = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_NORMAL); - - if (attr_N) { - Transform ntfm = mesh->transform_normal; - size_t steps_size = mesh->verts.size() * (mesh->motion_steps - 1); - float3 *normal_steps = attr_N->data_float3(); - - for (size_t i = 0; i < steps_size; i++) - normal_steps[i] = normalize(transform_direction(&ntfm, normal_steps[i])); - } - } - } - - /* curves */ - if (mesh->curve_keys.size()) { - /* compute uniform scale */ - float3 c0 = transform_get_column(&tfm, 0); - float3 c1 = transform_get_column(&tfm, 1); - float3 c2 = transform_get_column(&tfm, 2); - float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f / 3.0f); - - /* apply transform to curve keys */ - for (size_t i = 0; i < mesh->curve_keys.size(); i++) { - float3 co = transform_point(&tfm, mesh->curve_keys[i]); - float radius = mesh->curve_radius[i] * scalar; - - /* scale for curve radius is only correct for uniform scale */ - mesh->curve_keys[i] = co; - mesh->curve_radius[i] = radius; - } - - if (apply_to_motion) { - Attribute *curve_attr = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - if (curve_attr) { - /* apply transform to motion curve keys */ - size_t steps_size = mesh->curve_keys.size() * (mesh->motion_steps - 1); - float4 *key_steps = curve_attr->data_float4(); - - for (size_t i = 0; i < steps_size; i++) { - float3 co = transform_point(&tfm, float4_to_float3(key_steps[i])); - float radius = key_steps[i].w * scalar; - - /* scale for curve radius is only correct for uniform scale */ - key_steps[i] = float3_to_float4(co); - key_steps[i].w = radius; - } - } - } - } + geometry->apply_transform(tfm, apply_to_motion); /* we keep normals pointing in same direction on negative scale, notify - * mesh about this in it (re)calculates normals */ + * geometry about this in it (re)calculates normals */ if (transform_negative_scale(tfm)) - mesh->transform_negative_scaled = true; + geometry->transform_negative_scaled = true; if (bounds.valid()) { - mesh->compute_bounds(); + geometry->compute_bounds(); compute_bounds(false); } @@ -275,11 +205,11 @@ void Object::apply_transform(bool apply_to_motion) void Object::tag_update(Scene *scene) { - if (mesh) { - if (mesh->transform_applied) - mesh->need_update = true; + if (geometry) { + if (geometry->transform_applied) + geometry->need_update = true; - foreach (Shader *shader, mesh->used_shaders) { + foreach (Shader *shader, geometry->used_shaders) { if (shader->use_mis && shader->has_surface_emission) scene->light_manager->need_update = true; } @@ -287,7 +217,7 @@ void Object::tag_update(Scene *scene) scene->camera->need_flags_update = true; scene->curve_system_manager->need_update = true; - scene->mesh_manager->need_update = true; + scene->geometry_manager->need_update = true; scene->object_manager->need_update = true; } @@ -353,32 +283,22 @@ ObjectManager::~ObjectManager() { } -void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob) +static float object_surface_area(UpdateObjectTransformState *state, + const Transform &tfm, + Geometry *geom) { - KernelObject &kobject = state->objects[ob->index]; - Transform *object_motion_pass = state->object_motion_pass; - - Mesh *mesh = ob->mesh; - uint flag = 0; - - /* Compute transformations. */ - Transform tfm = ob->tfm; - Transform itfm = transform_inverse(tfm); + if (geom->type != Geometry::MESH) { + return 0.0f; + } /* Compute surface area. for uniform scale we can do avoid the many * transform calls and share computation for instances. * * TODO(brecht): Correct for displacement, and move to a better place. */ - float uniform_scale; + Mesh *mesh = static_cast<Mesh *>(geom); float surface_area = 0.0f; - float3 color = ob->color; - float pass_id = ob->pass_id; - float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF); - int particle_index = (ob->particle_system) ? - ob->particle_index + state->particle_offset[ob->particle_system] : - 0; - + float uniform_scale; if (transform_uniform_scale(tfm, uniform_scale)) { map<Mesh *, float>::iterator it; @@ -424,9 +344,31 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s } } + return surface_area; +} + +void ObjectManager::device_update_object_transform(UpdateObjectTransformState *state, Object *ob) +{ + KernelObject &kobject = state->objects[ob->index]; + Transform *object_motion_pass = state->object_motion_pass; + + Geometry *geom = ob->geometry; + uint flag = 0; + + /* Compute transformations. */ + Transform tfm = ob->tfm; + Transform itfm = transform_inverse(tfm); + + float3 color = ob->color; + float pass_id = ob->pass_id; + float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF); + int particle_index = (ob->particle_system) ? + ob->particle_index + state->particle_offset[ob->particle_system] : + 0; + kobject.tfm = tfm; kobject.itfm = itfm; - kobject.surface_area = surface_area; + kobject.surface_area = object_surface_area(state, tfm, geom); kobject.color[0] = color.x; kobject.color[1] = color.y; kobject.color[2] = color.z; @@ -435,11 +377,16 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s kobject.particle_index = particle_index; kobject.motion_offset = 0; - if (mesh->use_motion_blur) { + if (geom->use_motion_blur) { state->have_motion = true; } - if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { - flag |= SD_OBJECT_HAS_VERTEX_MOTION; + + if (geom->type == Geometry::MESH) { + /* TODO: why only mesh? */ + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { + flag |= SD_OBJECT_HAS_VERTEX_MOTION; + } } if (state->need_motion == Scene::MOTION_PASS) { @@ -460,7 +407,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s /* Motion transformations, is world/object space depending if mesh * comes with deformed position in object space, or if we transform * the shading point in world space. */ - if (!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) { + if (!(flag & SD_OBJECT_HAS_VERTEX_MOTION)) { tfm_pre = tfm_pre * itfm; tfm_post = tfm_post * itfm; } @@ -485,12 +432,13 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s kobject.dupli_generated[0] = ob->dupli_generated[0]; kobject.dupli_generated[1] = ob->dupli_generated[1]; kobject.dupli_generated[2] = ob->dupli_generated[2]; - kobject.numkeys = mesh->curve_keys.size(); + kobject.numkeys = (geom->type == Geometry::HAIR) ? static_cast<Hair *>(geom)->curve_keys.size() : + 0; kobject.dupli_uv[0] = ob->dupli_uv[0]; kobject.dupli_uv[1] = ob->dupli_uv[1]; - int totalsteps = mesh->motion_steps; + int totalsteps = geom->motion_steps; kobject.numsteps = (totalsteps - 1) / 2; - kobject.numverts = mesh->verts.size(); + kobject.numverts = (geom->type == Geometry::MESH) ? static_cast<Mesh *>(geom)->verts.size() : 0; kobject.patch_map_offset = 0; kobject.attribute_map_offset = 0; uint32_t hash_name = util_murmur_hash3(ob->name.c_str(), ob->name.length(), 0); @@ -505,7 +453,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s state->object_flag[ob->index] = flag; /* Have curves. */ - if (mesh->num_curves()) { + if (geom->type == Geometry::HAIR) { state->have_curves = true; } } @@ -681,7 +629,7 @@ void ObjectManager::device_update_flags( vector<Object *> volume_objects; bool has_volume_objects = false; foreach (Object *object, scene->objects) { - if (object->mesh->has_volume) { + if (object->geometry->has_volume) { if (bounds_valid) { volume_objects.push_back(object); } @@ -690,11 +638,11 @@ void ObjectManager::device_update_flags( } foreach (Object *object, scene->objects) { - if (object->mesh->has_volume) { + if (object->geometry->has_volume) { object_flag[object->index] |= SD_OBJECT_HAS_VOLUME; object_flag[object->index] &= ~SD_OBJECT_HAS_VOLUME_ATTRIBUTES; - foreach (Attribute &attr, object->mesh->attributes.attributes) { + foreach (Attribute &attr, object->geometry->attributes.attributes) { if (attr.element == ATTR_ELEMENT_VOXEL) { object_flag[object->index] |= SD_OBJECT_HAS_VOLUME_ATTRIBUTES; } @@ -744,21 +692,24 @@ void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Sc bool update = false; foreach (Object *object, scene->objects) { - Mesh *mesh = object->mesh; - - if (mesh->patch_table) { - uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() - - mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - - mesh->patch_offset; - - if (kobjects[object->index].patch_map_offset != patch_map_offset) { - kobjects[object->index].patch_map_offset = patch_map_offset; - update = true; + Geometry *geom = object->geometry; + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + if (mesh->patch_table) { + uint patch_map_offset = 2 * (mesh->patch_table_offset + mesh->patch_table->total_size() - + mesh->patch_table->num_nodes * PATCH_NODE_SIZE) - + mesh->patch_offset; + + if (kobjects[object->index].patch_map_offset != patch_map_offset) { + kobjects[object->index].patch_map_offset = patch_map_offset; + update = true; + } } } - if (kobjects[object->index].attribute_map_offset != mesh->attr_map_offset) { - kobjects[object->index].attribute_map_offset = mesh->attr_map_offset; + if (kobjects[object->index].attribute_map_offset != geom->attr_map_offset) { + kobjects[object->index].attribute_map_offset = geom->attr_map_offset; update = true; } } @@ -779,10 +730,10 @@ void ObjectManager::device_free(Device *, DeviceScene *dscene) void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, Progress &progress) { /* todo: normals and displacement should be done before applying transform! */ - /* todo: create objects/meshes in right order! */ + /* todo: create objects/geometry in right order! */ - /* counter mesh users */ - map<Mesh *, int> mesh_users; + /* counter geometry users */ + map<Geometry *, int> geometry_users; Scene::MotionType need_motion = scene->need_motion(); bool motion_blur = need_motion == Scene::MOTION_BLUR; bool apply_to_motion = need_motion != Scene::MOTION_PASS; @@ -790,10 +741,10 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P bool have_instancing = false; foreach (Object *object, scene->objects) { - map<Mesh *, int>::iterator it = mesh_users.find(object->mesh); + map<Geometry *, int>::iterator it = geometry_users.find(object->geometry); - if (it == mesh_users.end()) - mesh_users[object->mesh] = 1; + if (it == geometry_users.end()) + geometry_users[object->geometry] = 1; else it->second++; } @@ -803,27 +754,34 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, P uint *object_flag = dscene->object_flag.data(); - /* apply transforms for objects with single user meshes */ + /* apply transforms for objects with single user geometry */ foreach (Object *object, scene->objects) { /* Annoying feedback loop here: we can't use is_instanced() because * it'll use uninitialized transform_applied flag. * - * Could be solved by moving reference counter to Mesh. + * Could be solved by moving reference counter to Geometry. */ - if ((mesh_users[object->mesh] == 1 && !object->mesh->has_surface_bssrdf) && - !object->mesh->has_true_displacement() && - object->mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { + Geometry *geom = object->geometry; + bool apply = (geometry_users[geom] == 1) && !geom->has_surface_bssrdf && + !geom->has_true_displacement(); + + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); + apply = apply && mesh->subdivision_type == Mesh::SUBDIVISION_NONE; + } + + if (apply) { if (!(motion_blur && object->use_motion())) { - if (!object->mesh->transform_applied) { + if (!geom->transform_applied) { object->apply_transform(apply_to_motion); - object->mesh->transform_applied = true; + geom->transform_applied = true; if (progress.get_cancel()) return; } object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; - if (object->mesh->transform_negative_scaled) + if (geom->transform_negative_scaled) object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; } else @@ -842,7 +800,7 @@ void ObjectManager::tag_update(Scene *scene) { need_update = true; scene->curve_system_manager->need_update = true; - scene->mesh_manager->need_update = true; + scene->geometry_manager->need_update = true; scene->light_manager->need_update = true; } diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index cbbff0d4c6d..c5d878ec938 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -32,7 +32,7 @@ CCL_NAMESPACE_BEGIN class Device; class DeviceScene; -class Mesh; +class Geometry; class ParticleSystem; class Progress; class Scene; @@ -46,7 +46,7 @@ class Object : public Node { public: NODE_DECLARE - Mesh *mesh; + Geometry *geometry; Transform tfm; BoundBox bounds; uint random_id; diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 1e75fa0f99b..4f7d886cb10 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -94,7 +94,7 @@ Scene::Scene(const SceneParams ¶ms_, Device *device) film = new Film(); background = new Background(); light_manager = new LightManager(); - mesh_manager = new MeshManager(); + geometry_manager = new GeometryManager(); object_manager = new ObjectManager(); integrator = new Integrator(); image_manager = new ImageManager(device->info); @@ -118,8 +118,8 @@ void Scene::free_memory(bool final) { foreach (Shader *s, shaders) delete s; - foreach (Mesh *m, meshes) - delete m; + foreach (Geometry *g, geometry) + delete g; foreach (Object *o, objects) delete o; foreach (Light *l, lights) @@ -128,7 +128,7 @@ void Scene::free_memory(bool final) delete p; shaders.clear(); - meshes.clear(); + geometry.clear(); objects.clear(); lights.clear(); particle_systems.clear(); @@ -140,7 +140,7 @@ void Scene::free_memory(bool final) integrator->device_free(device, &dscene); object_manager->device_free(device, &dscene); - mesh_manager->device_free(device, &dscene); + geometry_manager->device_free(device, &dscene); shader_manager->device_free(device, &dscene, this); light_manager->device_free(device, &dscene); @@ -165,7 +165,7 @@ void Scene::free_memory(bool final) delete background; delete integrator; delete object_manager; - delete mesh_manager; + delete geometry_manager; delete shader_manager; delete light_manager; delete particle_system_manager; @@ -211,7 +211,7 @@ void Scene::device_update(Device *device_, Progress &progress) if (progress.get_cancel() || device->have_error()) return; - mesh_manager->device_update_preprocess(device, this, progress); + geometry_manager->device_update_preprocess(device, this, progress); if (progress.get_cancel() || device->have_error()) return; @@ -235,7 +235,7 @@ void Scene::device_update(Device *device_, Progress &progress) return; progress.set_status("Updating Meshes"); - mesh_manager->device_update(device, &dscene, this, progress); + geometry_manager->device_update(device, &dscene, this, progress); if (progress.get_cancel() || device->have_error()) return; @@ -356,7 +356,7 @@ bool Scene::need_update() bool Scene::need_data_update() { return (background->need_update || image_manager->need_update || object_manager->need_update || - mesh_manager->need_update || light_manager->need_update || lookup_tables->need_update || + geometry_manager->need_update || light_manager->need_update || lookup_tables->need_update || integrator->need_update || shader_manager->need_update || particle_system_manager->need_update || curve_system_manager->need_update || bake_manager->need_update || film->need_update); @@ -379,7 +379,7 @@ void Scene::reset() background->tag_update(this); integrator->tag_update(this); object_manager->tag_update(this); - mesh_manager->tag_update(this); + geometry_manager->tag_update(this); light_manager->tag_update(this); particle_system_manager->tag_update(this); curve_system_manager->tag_update(this); @@ -392,7 +392,7 @@ void Scene::device_free() void Scene::collect_statistics(RenderStats *stats) { - mesh_manager->collect_statistics(this, stats); + geometry_manager->collect_statistics(this, stats); image_manager->collect_statistics(stats); } diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index f99510d2d42..ab30aaa1f43 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -44,8 +44,8 @@ class Integrator; class Light; class LightManager; class LookupTables; -class Mesh; -class MeshManager; +class Geometry; +class GeometryManager; class Object; class ObjectManager; class ParticleSystemManager; @@ -213,7 +213,7 @@ class Scene { /* data lists */ vector<Object *> objects; - vector<Mesh *> meshes; + vector<Geometry *> geometry; vector<Shader *> shaders; vector<Light *> lights; vector<ParticleSystem *> particle_systems; @@ -222,7 +222,7 @@ class Scene { ImageManager *image_manager; LightManager *light_manager; ShaderManager *shader_manager; - MeshManager *mesh_manager; + GeometryManager *geometry_manager; ObjectManager *object_manager; ParticleSystemManager *particle_system_manager; CurveSystemManager *curve_system_manager; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index c77a20787f5..dac7fbac806 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -701,23 +701,26 @@ DeviceRequestedFeatures Session::get_requested_device_features() requested_features.use_object_motion = false; requested_features.use_camera_motion = use_motion && scene->camera->use_motion(); foreach (Object *object, scene->objects) { - Mesh *mesh = object->mesh; - if (mesh->num_curves()) { - requested_features.use_hair = true; - } + Geometry *geom = object->geometry; if (use_motion) { - requested_features.use_object_motion |= object->use_motion() | mesh->use_motion_blur; - requested_features.use_camera_motion |= mesh->use_motion_blur; - } -#ifdef WITH_OPENSUBDIV - if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { - requested_features.use_patch_evaluation = true; + requested_features.use_object_motion |= object->use_motion() | geom->use_motion_blur; + requested_features.use_camera_motion |= geom->use_motion_blur; } -#endif if (object->is_shadow_catcher) { requested_features.use_shadow_tricks = true; } - requested_features.use_true_displacement |= mesh->has_true_displacement(); + if (geom->type == Geometry::MESH) { + Mesh *mesh = static_cast<Mesh *>(geom); +#ifdef WITH_OPENSUBDIV + if (mesh->subdivision_type != Mesh::SUBDIVISION_NONE) { + requested_features.use_patch_evaluation = true; + } +#endif + requested_features.use_true_displacement |= mesh->has_true_displacement(); + } + else if (geom->type == Geometry::HAIR) { + requested_features.use_hair = true; + } } requested_features.use_background_light = scene->light_manager->has_background_light(scene); diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 661208c6463..60f38aa14da 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -214,7 +214,7 @@ Shader::Shader() : Node(node_type) used = false; need_update = true; - need_update_mesh = true; + need_update_geometry = true; need_sync_object = false; } @@ -288,7 +288,7 @@ void Shader::set_graph(ShaderGraph *graph_) const char *new_hash = (graph_) ? graph_->displacement_hash.c_str() : ""; if (strcmp(old_hash, new_hash) != 0) { - need_update_mesh = true; + need_update_geometry = true; } } @@ -347,14 +347,14 @@ void Shader::tag_update(Scene *scene) } /* compare if the attributes changed, mesh manager will check - * need_update_mesh, update the relevant meshes and clear it. */ + * need_update_geometry, update the relevant meshes and clear it. */ if (attributes.modified(prev_attributes)) { - need_update_mesh = true; - scene->mesh_manager->need_update = true; + need_update_geometry = true; + scene->geometry_manager->need_update = true; } if (has_volume != prev_has_volume) { - scene->mesh_manager->need_flags_update = true; + scene->geometry_manager->need_flags_update = true; scene->object_manager->need_flags_update = true; } } @@ -489,8 +489,8 @@ void ShaderManager::device_update_shaders_used(Scene *scene) if (scene->background->shader) scene->background->shader->used = true; - foreach (Mesh *mesh, scene->meshes) - foreach (Shader *shader, mesh->used_shaders) + foreach (Geometry *geom, scene->geometry) + foreach (Shader *shader, geom->used_shaders) shader->used = true; foreach (Light *light, scene->lights) diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h index f74204df355..c6f40bb7833 100644 --- a/intern/cycles/render/shader.h +++ b/intern/cycles/render/shader.h @@ -95,7 +95,7 @@ class Shader : public Node { /* synchronization */ bool need_update; - bool need_update_mesh; + bool need_update_geometry; bool need_sync_object; /* If the shader has only volume components, the surface is assumed to |