From e068d09a4bc8cee957e3cfee90fb852180b6be5f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 14:34:56 +0100 Subject: [PATCH 01/13] Cycles: Improve logging of cases when motion blur is disabled Next logical step is to expose this somehow to the interface. --- intern/cycles/blender/blender_mesh.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index fab03c7659b..ab909c4527f 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1157,10 +1157,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, { /* no motion, remove attributes again */ if(b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, disabling motion blur."; + VLOG(1) << "Topology differs, disabling motion blur for object " + << b_ob.name(); } else { - VLOG(1) << "No actual deformation motion for object " << b_ob.name(); + VLOG(1) << "No actual deformation motion for object " + << b_ob.name(); } mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_mN) From 7bbb2292dc3ed997abd98ea17e2d66df6cd83ddc Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 15:16:22 +0100 Subject: [PATCH 02/13] Cycles: Cleanup, whitespace around operator --- intern/cycles/blender/blender_mesh.cpp | 4 ++-- intern/cycles/blender/blender_session.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index ab909c4527f..c3676ea5de6 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -597,8 +597,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector& used_shaders, - bool subdivision=false, - bool subdivide_uvs=true) + bool subdivision = false, + bool subdivide_uvs = true) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 71c1eefe65f..21166b2f155 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -580,7 +580,7 @@ static void populate_bake_data(BakeData *data, const BL::BakePixel bp = pixel_array; int i; - for(i=0; i < num_pixels; i++) { + for(i = 0; i < num_pixels; i++) { if(bp.object_id() == object_id) { data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy()); } else { From 8576efc98a8f84eded32c406e83de3fe5f17f3e6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 15:59:32 +0100 Subject: [PATCH 03/13] RNA: Expose autosmooth face splitting This way render engine can request mesh to be auto-split and not worry about implementing this functionality on it's own. Please note that this split is to be performed prior to tessellation. --- source/blender/makesrna/intern/rna_mesh_api.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 4a078ef9182..cd48bc1a3df 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -240,6 +240,9 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split"); RNA_def_function_ui_description(func, "Free split vertex normals"); + func = RNA_def_function(srna, "split_faces", "BKE_mesh_split_faces"); + RNA_def_function_ui_description(func, "Spli faces based on the edge angle"); + func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, From 2b66a17e50ce1971977630b3493fb198dcd9cfef Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 16:04:39 +0100 Subject: [PATCH 04/13] Copy autosmooth mesh settings BKE_mesh_new_from_object This way render engine can first apply all modifiers on the new mesh and then optionally perform autosmooth face splitting on it. --- source/blender/blenkernel/intern/mesh.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index d21f43ac484..af02e02b017 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2346,6 +2346,11 @@ Mesh *BKE_mesh_new_from_object( tmpmesh = BKE_mesh_add(bmain, "Mesh"); DM_to_mesh(dm, tmpmesh, ob, mask, true); + + /* Copy autosmooth settings from original mesh. */ + Mesh *me = (Mesh *)ob->data; + tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH); + tmpmesh->smoothresh = me->smoothresh; } /* BKE_mesh_add/copy gives us a user count we don't need */ From 38b01415546f2530ced77e91ac2d57b37b576b07 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 16:23:54 +0100 Subject: [PATCH 05/13] Cycles: Pass explicit subdivision type to object_to_mesh This allows us to do some extra logic checks there based on particular subdivision type. Additionally avoids implicit cast of enum to bool. --- intern/cycles/blender/blender_mesh.cpp | 16 ++++++++++++++-- intern/cycles/blender/blender_util.h | 8 ++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c3676ea5de6..a83e756de91 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -961,7 +961,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); - BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type); + BL::Mesh b_mesh = object_to_mesh(b_data, + b_ob, + b_scene, + true, + !preview, + need_undeformed, + mesh->subdivision_type); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { @@ -1086,7 +1092,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ - b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false); + b_mesh = object_to_mesh(b_data, + b_ob, + b_scene, + true, + !preview, + false, + Mesh::SUBDIVISION_NONE); } if(!b_mesh) { diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index f17a61f0ac8..92db5fdfd45 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -48,12 +48,12 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, bool apply_modifiers, bool render, bool calc_undeformed, - bool subdivision) + Mesh::SubdivisionType subdivision_type) { bool subsurf_mod_show_render; bool subsurf_mod_show_viewport; - if(subdivision) { + if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; subsurf_mod_show_render = subsurf_mod.show_render(); @@ -65,7 +65,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); - if(subdivision) { + if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; subsurf_mod.show_render(subsurf_mod_show_render); @@ -76,7 +76,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, if(me.use_auto_smooth()) { me.calc_normals_split(); } - if(!subdivision) { + if(subdivision_type == Mesh::SUBDIVISION_NONE) { me.calc_tessface(true); } } From 394fa07d41bf403920806522e6ca09a9531bca29 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 16:32:57 +0100 Subject: [PATCH 06/13] Cycles: Fix wrong motion blur when combining deformation motion blur with autosplit The issue was that we used to compare number of vertices for mesh after the auto smooth was applied (at the center of the shutter time) with number of vertices prior to the auto smooth applied. This caused false-positive consideration of a mesh as changing topology. Now we do autosplit as early as possible and do it from blender side, so Cycles does not need to re-implement splitting on it's side. --- intern/cycles/blender/blender_mesh.cpp | 42 +++----------------------- intern/cycles/blender/blender_util.h | 7 ++++- 2 files changed, 10 insertions(+), 39 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index a83e756de91..66893d4d668 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -671,28 +671,10 @@ static void create_mesh(Scene *scene, int shader = clamp(f->material_index(), 0, used_shaders.size()-1); bool smooth = f->use_smooth() || use_loop_normals; - /* split vertices if normal is different + /* Create triangles. * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - BL::Array loop_normals = f->split_normals(); - - for(int i = 0; i < n; i++) { - float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; - } - } - } - - /* create triangles */ + * NOTE: Autosmooth is already taken care about. + */ if(n == 4) { if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) @@ -724,24 +706,8 @@ static void create_mesh(Scene *scene, vi.reserve(n); for(int i = 0; i < n; i++) { + /* NOTE: Autosmooth is already taken care about. */ vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); - - /* split vertices if normal is different - * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal()); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; - } - } } /* create subd faces */ diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 92db5fdfd45..b67834cdea3 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -74,7 +74,12 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, if((bool)me) { if(me.use_auto_smooth()) { - me.calc_normals_split(); + if(subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK) { + me.calc_normals_split(); + } + else { + me.split_faces(); + } } if(subdivision_type == Mesh::SUBDIVISION_NONE) { me.calc_tessface(true); From 0507b3e4c41ff058c00b7a45d937d82939b4e0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 11 Jan 2017 18:47:06 +0100 Subject: [PATCH 07/13] Viewport SSAO: Fix normals not normalized --- source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index 054a2f795ee..50c8e255162 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -27,8 +27,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition) { vec3 normal = cross(normalize(dFdx(viewposition)), ssao_params.w * normalize(dFdy(viewposition))); - normalize(normal); - return normal; + return normalize(normal); } float calculate_ssao_factor(float depth) From c910beaa2133989150cdafa556ca11ddc9fffc92 Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Wed, 11 Jan 2017 15:15:54 -0200 Subject: [PATCH 08/13] Split interp_weights_face_v3 into specific functions for tris and quads This splits `interp_weights_face_v3` into `interp_weights_tri_v3` and `interp_weights_quad_v3`, in order to properly handle three sided polygons without needing a useless extra index in your weight array. This also improves clarity and consistency with other math_geom functions, thus reducing potential future errors. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2461 --- source/blender/blenkernel/intern/collision.c | 6 +-- .../blender/blenkernel/intern/dynamicpaint.c | 4 +- source/blender/blenkernel/intern/smoke.c | 9 ++-- source/blender/blenlib/BLI_math_geom.h | 6 +-- source/blender/blenlib/intern/math_geom.c | 47 +++++++++---------- .../render/intern/source/convertblender.c | 15 ++++-- .../blender/render/intern/source/occlusion.c | 9 +++- 7 files changed, 50 insertions(+), 46 deletions(-) diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 18ca1407ba0..ee25be36855 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1014,7 +1014,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll } BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], - float r_nor[3], float *r_lambda, float r_w[4]) + float r_nor[3], float *r_lambda, float r_w[3]) { float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3]; float nor_v0p2, nor_p1p2; @@ -1026,7 +1026,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float nor_v0p2 = dot_v3v3(v0p2, r_nor); madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2); - interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face); + interp_weights_tri_v3(r_w, v0, v1, v2, p2face); sub_v3_v3v3(p1p2, p2, p1); sub_v3_v3v3(v0p2, p2, v0); @@ -1085,7 +1085,7 @@ static CollPair *cloth_point_collpair( const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co; float lambda /*, distance1 */, distance2; float facenor[3], v1p1[3], v1p2[3]; - float w[4]; + float w[3]; if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) return collpair; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 4d9e314afc4..1d198e36e05 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3739,7 +3739,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( /* velocity brush, only do on main sample */ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) { - float weights[4]; + float weights[3]; float brushPointVelocity[3]; float velocity[3]; @@ -3748,7 +3748,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( const int v3 = mloop[mlooptri[hitTri].tri[2]].v; /* calculate barycentric weights for hit point */ - interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord); + interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord); /* simple check based on brush surface velocity, * todo: perhaps implement something that handles volume movement as well */ diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index e8970d416e9..d0ef5cfc092 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -758,15 +758,14 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z) /* find the nearest point on the mesh */ if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) { const MLoopTri *lt = &data->looptri[nearest.index]; - float weights[4]; + float weights[3]; int v1, v2, v3; /* calculate barycentric weights for nearest point */ v1 = data->mloop[lt->tri[0]].v; v2 = data->mloop[lt->tri[1]].v; v3 = data->mloop[lt->tri[2]].v; - interp_weights_face_v3( - weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co); + interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co); // DG TODO if (data->has_velocity) @@ -1454,7 +1453,7 @@ static void sample_derivedmesh( /* find the nearest point on the mesh */ if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) { - float weights[4]; + float weights[3]; int v1, v2, v3, f_index = nearest.index; float n1[3], n2[3], n3[3], hit_normal[3]; @@ -1471,7 +1470,7 @@ static void sample_derivedmesh( v1 = mloop[mlooptri[f_index].tri[0]].v; v2 = mloop[mlooptri[f_index].tri[1]].v; v3 = mloop[mlooptri[f_index].tri[2]].v; - interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co); + interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { /* apply normal directional velocity */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index b5007b29f4c..d33c2cb3279 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -323,10 +323,8 @@ bool clip_segment_v3_plane_n( float r_p1[3], float r_p2[3]); /****************************** Interpolation ********************************/ - -/* tri or quad, d can be NULL */ -void interp_weights_face_v3(float w[4], - const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]); +void interp_weights_tri_v3(float w[3], const float a[3], const float b[3], const float c[3], const float p[3]); +void interp_weights_quad_v3(float w[4], const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]); void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]); void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 76dac5487f2..74ede1e7559 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2950,7 +2950,15 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa } } -void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]) +void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3]) +{ + float n[3]; + + normal_tri_v3(n, v1, v2, v3); + barycentric_weights(v1, v2, v3, co, n, w); +} + +void interp_weights_quad_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]) { float w2[3]; @@ -2963,7 +2971,7 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co w[1] = 1.0f; else if (equals_v3v3(co, v3)) w[2] = 1.0f; - else if (v4 && equals_v3v3(co, v4)) + else if (equals_v3v3(co, v4)) w[3] = 1.0f; else { /* otherwise compute barycentric interpolation weights */ @@ -2971,35 +2979,24 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co bool degenerate; sub_v3_v3v3(n1, v1, v3); - if (v4) { - sub_v3_v3v3(n2, v2, v4); - } - else { - sub_v3_v3v3(n2, v2, v3); - } + sub_v3_v3v3(n2, v2, v4); cross_v3_v3v3(n, n1, n2); - /* OpenGL seems to split this way, so we do too */ - if (v4) { - degenerate = barycentric_weights(v1, v2, v4, co, n, w); - SWAP(float, w[2], w[3]); + degenerate = barycentric_weights(v1, v2, v4, co, n, w); + SWAP(float, w[2], w[3]); - if (degenerate || (w[0] < 0.0f)) { - /* if w[1] is negative, co is on the other side of the v1-v3 edge, - * so we interpolate using the other triangle */ - degenerate = barycentric_weights(v2, v3, v4, co, n, w2); + if (degenerate || (w[0] < 0.0f)) { + /* if w[1] is negative, co is on the other side of the v1-v3 edge, + * so we interpolate using the other triangle */ + degenerate = barycentric_weights(v2, v3, v4, co, n, w2); - if (!degenerate) { - w[0] = 0.0f; - w[1] = w2[0]; - w[2] = w2[1]; - w[3] = w2[2]; - } + if (!degenerate) { + w[0] = 0.0f; + w[1] = w2[0]; + w[2] = w2[1]; + w[3] = w2[2]; } } - else { - barycentric_weights(v1, v2, v3, co, n, w); - } } } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 86961cdd169..263ea3d4ef2 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -5569,12 +5569,17 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve /* interpolate speed vectors from strand surface */ face= mesh->face[*index]; - co1= mesh->co[face[0]]; - co2= mesh->co[face[1]]; - co3= mesh->co[face[2]]; - co4= (face[3])? mesh->co[face[3]]: NULL; + co1 = mesh->co[face[0]]; + co2 = mesh->co[face[1]]; + co3 = mesh->co[face[2]]; - interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); + if (face[3]) { + co4 = mesh->co[face[3]]; + interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co); + } + else { + interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co); + } zero_v4(speed); madd_v4_v4fl(speed, winspeed[face[0]], w[0]); diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index ddcd2e84520..cd93898d846 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -1190,9 +1190,14 @@ static void sample_occ_surface(ShadeInput *shi) co1 = mesh->co[face[0]]; co2 = mesh->co[face[1]]; co3 = mesh->co[face[2]]; - co4 = (face[3]) ? mesh->co[face[3]] : NULL; - interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); + if (face[3]) { + co4 = mesh->co[face[3]]; + interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co); + } + else { + interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co); + } zero_v3(shi->ao); zero_v3(shi->env); From c4f60319d1709723d8076429c13965b0c94dc88b Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 11 Jan 2017 22:11:13 +0100 Subject: [PATCH 09/13] UI: Try limiting 'x' icon to search buttons Reusing PROP_TEXTEDIT_UPDATE instead of adding a new property flag just for search strings. Currently it's only used for search strings anyway so seems fine for now. Fixes T50336. --- source/blender/editors/interface/interface_utils.c | 8 +++----- source/blender/makesrna/RNA_types.h | 6 ++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 8dfbbdd02eb..df6f098ee81 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -119,12 +119,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind else but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); - PropertySubType subtype = RNA_property_subtype(prop); - if (!(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME) || (block->flag & UI_BLOCK_LIST_ITEM))) { - UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR); - } if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { - UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); + /* TEXTEDIT_UPDATE is usally used for search buttons. For these we also want + * the 'x' icon to clear search string, so setting VALUE_CLEAR flag, too. */ + UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE | UI_BUT_VALUE_CLEAR); } break; case PROP_POINTER: diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 1a191a68668..dee8df7d933 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -174,8 +174,10 @@ typedef enum PropertyFlag { * and collections */ PROP_ANIMATABLE = (1 << 1), - /* This flag means when the property's widget is in 'textedit' mode, it will be updated after every typed char, - * instead of waiting final validation. Used e.g. for text searchbox. */ + /* This flag means when the property's widget is in 'textedit' mode, it will be updated + * after every typed char, instead of waiting final validation. Used e.g. for text searchbox. + * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag + * for search/filter properties, but this works just fine for now. */ PROP_TEXTEDIT_UPDATE = (1 << 31), /* icon */ From 092cbcd1d2c31b10af31ce326bdf4efc2819a5fa Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 11 Jan 2017 23:01:07 +0100 Subject: [PATCH 10/13] Fix T50056: Dyntopo brush size shortcut broken using constant detail setting. --- source/blender/editors/sculpt_paint/sculpt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 47f0220726b..84e98181dfb 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5693,11 +5693,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) WM_operator_properties_create_ptr(&props_ptr, ot); if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) { - set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0); - RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail"); + set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0); + RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution"); } else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) { - set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0); + set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0); RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent"); } else { From 65c8937f7ed815c74203dddc8d41429e0185744e Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 12 Jan 2017 01:03:23 -0500 Subject: [PATCH 11/13] Add Add Modifiers tab to the NLA & VSE editors This is a follow up to rBca935ab Differential Revision: https://developer.blender.org/D2442 --- .../scripts/startup/bl_ui/space_sequencer.py | 10 ++++++++++ source/blender/editors/space_nla/nla_buttons.c | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 26136a8e024..0648db3746d 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -497,6 +497,7 @@ class SequencerButtonsPanel_Output: class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): bl_label = "Edit Strip" + bl_category = "Strip" def draw(self, context): layout = self.layout @@ -563,6 +564,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): bl_label = "Effect Strip" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -701,6 +703,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): bl_label = "Strip Input" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -795,6 +798,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): bl_label = "Sound" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -848,6 +852,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel): bl_label = "Scene" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -894,6 +899,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel): class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel): bl_label = "Mask" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -923,6 +929,7 @@ class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel): class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): bl_label = "Filter" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -977,6 +984,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): bl_label = "Proxy/Timecode" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -1109,6 +1117,7 @@ class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel): class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel): bl_label = "Modifiers" + bl_category = "Modifiers" def draw(self, context): layout = self.layout @@ -1211,6 +1220,7 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "scene.sequence_editor.active_strip" _property_type = (bpy.types.Sequence,) + bl_category = "Strip" if __name__ == "__main__": # only for live edit. diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 3243579f7d0..5355b8012db 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -502,51 +502,57 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa) void nla_buttons_register(ARegionType *art) { PanelType *pt; - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata"); strcpy(pt->idname, "NLA_PT_animdata"); strcpy(pt->label, N_("Animation Data")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_animdata; pt->poll = nla_animdata_panel_poll; pt->flag = PNL_DEFAULT_CLOSED; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track"); strcpy(pt->idname, "NLA_PT_track"); strcpy(pt->label, N_("Active Track")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_track; pt->poll = nla_track_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_properties"); strcpy(pt->label, N_("Active Strip")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_properties; pt->poll = nla_strip_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_actionclip"); strcpy(pt->label, N_("Action Clip")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_actclip; pt->poll = nla_strip_actclip_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation"); strcpy(pt->idname, "NLA_PT_evaluation"); strcpy(pt->label, N_("Evaluation")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_evaluation; pt->poll = nla_strip_eval_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers"); strcpy(pt->idname, "NLA_PT_modifiers"); strcpy(pt->label, N_("Modifiers")); + strcpy(pt->category, "Modifiers"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_modifiers; pt->poll = nla_strip_eval_panel_poll; From 67f68295be523d0dca5343db68352441f9e58d92 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 09:45:04 +0100 Subject: [PATCH 12/13] Cycles tests: Rework output messages Made them closer to how GTest shows the output, so reading test logs is easier now (at least feels more uniform). Additionally now we know how much time tests are taking so can tweak samples/resolution to reduce render time of slow tests. It is now also possible to enable colored messages using magic CYCLESTEST_COLOR environment variable. This makes it even easier to visually grep failed/passed tests using `ctest -R cycles -V`. --- tests/python/cycles_render_tests.py | 99 ++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 78b4b346f24..ae8848570f0 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -6,9 +6,46 @@ import os import shutil import subprocess import sys +import time import tempfile +class COLORS_ANSI: + RED = '\033[00;31m' + GREEN = '\033[00;32m' + ENDC = '\033[0m' + + +class COLORS_DUMMY: + RED = '' + GREEN = '' + ENDC = '' + +COLORS = COLORS_DUMMY + + +def printMessage(type, status, message): + if type == 'SUCCESS': + print(COLORS.GREEN, end="") + elif type == 'FAILURE': + print(COLORS.RED, end="") + status_text = ... + if status == 'RUN': + status_text = " RUN " + elif status == 'OK': + status_text = " OK " + elif status == 'PASSED': + status_text = " PASSED " + elif status == 'FAILED': + status_text = " FAILED " + else: + status_text = status + print("[{}]" . format(status_text), end="") + print(COLORS.ENDC, end="") + print(" {}" . format(message)) + sys.stdout.flush() + + def render_file(filepath): command = ( BLENDER, @@ -83,16 +120,32 @@ def verify_output(filepath): def run_test(filepath): testname = test_get_name(filepath) spacer = "." * (32 - len(testname)) - print(testname, spacer, end="") - sys.stdout.flush() + printMessage('SUCCESS', 'RUN', testname) + time_start = time.time() error = render_file(filepath) + status = "FAIL" if not error: - if verify_output(filepath): - print("PASS") - else: + if not verify_output(filepath): error = "VERIFY" - if error: - print("FAIL", error) + time_end = time.time() + elapsed_ms = int((time_end - time_start) * 1000) + if not error: + printMessage('SUCCESS', 'OK', "{} ({} ms)" . + format(testname, elapsed_ms)) + else: + if error == "NO_CYCLES": + print("Can't perform tests because Cycles failed to load!") + return False + elif error == "NO_START": + print('Can not perform tests because blender fails to start.', + 'Make sure INSTALL target was run.') + return False + elif error == 'VERIFY': + print("Rendered result is different from reference image") + else: + print("Unknown error %r" % error) + printMessage('FAILURE', 'FAILED', "{} ({} ms)" . + format(testname, elapsed_ms)) return error @@ -105,30 +158,38 @@ def blend_list(path): def run_all_tests(dirpath): + passed_tests = [] failed_tests = [] all_files = list(blend_list(dirpath)) all_files.sort() + printMessage('SUCCESS', "==========", + "Running {} tests from 1 test case." . format(len(all_files))) + time_start = time.time() for filepath in all_files: error = run_test(filepath) + testname = test_get_name(filepath) if error: if error == "NO_CYCLES": - print("Can't perform tests because Cycles failed to load!") return False elif error == "NO_START": - print('Can not perform tests because blender fails to start.', - 'Make sure INSTALL target was run.') return False - elif error == 'VERIFY': - pass - else: - print("Unknown error %r" % error) - testname = test_get_name(filepath) failed_tests.append(testname) + else: + passed_tests.append(testname) + time_end = time.time() + elapsed_ms = int((time_end - time_start) * 1000) + print("") + printMessage('SUCCESS', "==========", + "{} tests from 1 test case ran. ({} ms total)" . + format(len(all_files), elapsed_ms)) + printMessage('SUCCESS', 'PASSED', "{} tests." . + format(len(passed_tests))) if failed_tests: + printMessage('FAILURE', 'FAILED', "{} tests, listed below:" . + format(len(failed_tests))) failed_tests.sort() - print("\n\nFAILED tests:") for test in failed_tests: - print(" ", test) + printMessage('FAILURE', "FAILED", "{}" . format(test)) return False return True @@ -145,10 +206,14 @@ def main(): parser = create_argparse() args = parser.parse_args() + global COLORS global BLENDER, ROOT, IDIFF global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT global VERBOSE + if os.environ.get("CYCLESTEST_COLOR") is not None: + COLORS = COLORS_ANSI + BLENDER = args.blender[0] ROOT = args.testdir[0] IDIFF = args.idiff[0] From 554024e08e7855685446b33d8bdbde5cacc196a5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 11 Oct 2016 16:33:07 +0200 Subject: [PATCH 13/13] Cycles: move hair particle settings to scene context Since the beginning of times hair settings in cycles were global for the whole scene but were located in the particle context. This causes quite some trickery to get shots set up for the movies here in the studio by forcing artists to create dummy particle system to change settings of hair on the shot. While ideally this settings should be properly become per-particle system for the time being it will save sweat and blood to move the settings to scene context. Reviewers: brecht Subscribers: jtheninja, eyecandy, venomgfx, Blendify Differential Revision: https://developer.blender.org/D2287 --- intern/cycles/blender/addon/ui.py | 57 +++++++++++-------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 3f7730efbb0..925f923dd41 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -226,6 +226,7 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel): scene = context.scene cscene = scene.cycles + ccscene = scene.cycles_curves if cscene.feature_set == 'EXPERIMENTAL': split = layout.split() @@ -252,6 +253,25 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel): row.prop(cscene, "volume_step_size") row.prop(cscene, "volume_max_steps") + layout.prop(ccscene, "use_curves", text="Use Hair") + col = layout.column() + col.active = ccscene.use_curves + + col.prop(ccscene, "primitive", text="Primitive") + col.prop(ccscene, "shape", text="Shape") + + if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'): + col.prop(ccscene, "cull_backfacing", text="Cull back-faces") + + if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK': + col.prop(ccscene, "resolution", text="Resolution") + elif ccscene.primitive == 'CURVE_SEGMENTS': + col.prop(ccscene, "subdivisions", text="Curve subdivisions") + + row = col.row() + row.prop(ccscene, "minimum_width", text="Min Pixels") + row.prop(ccscene, "maximum_width", text="Max Ext.") + class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): bl_label = "Light Paths" @@ -1391,43 +1411,6 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): layout.template_ID(slot, "texture", new="texture.new") -class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel): - bl_label = "Cycles Hair Rendering" - bl_context = "particle" - - @classmethod - def poll(cls, context): - psys = context.particle_system - return CyclesButtonsPanel.poll(context) and psys and psys.settings.type == 'HAIR' - - def draw_header(self, context): - ccscene = context.scene.cycles_curves - self.layout.prop(ccscene, "use_curves", text="") - - def draw(self, context): - layout = self.layout - - scene = context.scene - ccscene = scene.cycles_curves - - layout.active = ccscene.use_curves - - layout.prop(ccscene, "primitive", text="Primitive") - layout.prop(ccscene, "shape", text="Shape") - - if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'): - layout.prop(ccscene, "cull_backfacing", text="Cull back-faces") - - if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK': - layout.prop(ccscene, "resolution", text="Resolution") - elif ccscene.primitive == 'CURVE_SEGMENTS': - layout.prop(ccscene, "subdivisions", text="Curve subdivisions") - - row = layout.row() - row.prop(ccscene, "minimum_width", text="Min Pixels") - row.prop(ccscene, "maximum_width", text="Max Ext.") - - class CyclesRender_PT_bake(CyclesButtonsPanel, Panel): bl_label = "Bake" bl_context = "render"