Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2014-10-03 17:10:05 +0400
committerCampbell Barton <ideasman42@gmail.com>2014-10-03 17:10:05 +0400
commit65acb7b3ee44befaad0d7744816e52b24f970924 (patch)
tree019cfcd0e00c4637aa06f1eef04e879ae14788a2
parentb39b6c7fdaf1827334b9945a3c3383dbf9e78d36 (diff)
parent4c43fcf791c3c26fe5f729ffe5e96bae2957e88a (diff)
Merge branch 'master' into dyntopo_holes
-rw-r--r--intern/cycles/blender/blender_camera.cpp2
-rw-r--r--intern/cycles/device/device_memory.h5
-rw-r--r--intern/cycles/kernel/closure/bsdf_microfacet.h145
-rw-r--r--intern/cycles/kernel/geom/geom_bvh.h75
-rw-r--r--intern/cycles/kernel/geom/geom_bvh_volume.h322
-rw-r--r--intern/cycles/kernel/kernel_path.h8
-rw-r--r--intern/cycles/kernel/kernel_types.h6
-rw-r--r--intern/cycles/kernel/kernel_volume.h4
-rw-r--r--intern/cycles/render/camera.cpp20
-rw-r--r--intern/cycles/render/camera.h7
-rw-r--r--intern/cycles/render/image.cpp8
-rw-r--r--intern/cycles/render/mesh.cpp4
-rw-r--r--intern/cycles/render/object.cpp52
-rw-r--r--intern/cycles/render/object.h1
-rw-r--r--intern/cycles/render/scene.cpp5
-rw-r--r--release/scripts/startup/bl_ui/space_view3d_toolbar.py13
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c7
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h7
-rw-r--r--source/blender/blenloader/intern/versioning_270.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4
-rw-r--r--source/blender/makesrna/intern/rna_brush.c4
-rw-r--r--source/blender/modifiers/intern/MOD_array.c26
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c9
24 files changed, 569 insertions, 175 deletions
diff --git a/intern/cycles/blender/blender_camera.cpp b/intern/cycles/blender/blender_camera.cpp
index 016f6637b3c..ce8c64c4819 100644
--- a/intern/cycles/blender/blender_camera.cpp
+++ b/intern/cycles/blender/blender_camera.cpp
@@ -390,7 +390,6 @@ void BlenderSync::sync_camera(BL::RenderSettings b_render, BL::Object b_override
/* sync */
Camera *cam = scene->camera;
blender_camera_sync(cam, &bcam, width, height);
- scene->camera->use_camera_in_volume = experimental;
}
void BlenderSync::sync_camera_motion(BL::Object b_ob, float motion_time)
@@ -555,7 +554,6 @@ void BlenderSync::sync_view(BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int
blender_camera_border(&bcam, b_scene.render(), b_scene, b_v3d, b_rv3d, width, height);
blender_camera_sync(scene->camera, &bcam, width, height);
- scene->camera->use_camera_in_volume = experimental;
}
BufferParams BlenderSync::get_buffer_params(BL::RenderSettings b_render, BL::Scene b_scene, BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, Camera *cam, int width, int height)
diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h
index 8eee6a2c79e..07a6eb36a3c 100644
--- a/intern/cycles/device/device_memory.h
+++ b/intern/cycles/device/device_memory.h
@@ -260,6 +260,11 @@ public:
return data.size();
}
+ T* get_data()
+ {
+ return &data[0];
+ }
+
private:
array<T> data;
};
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index a0c59e6cbc0..c6aed1205e0 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -35,139 +35,38 @@
CCL_NAMESPACE_BEGIN
-/* Approximate erf and erfinv implementations
+/* Approximate erf and erfinv implementations.
+ * Implementation comes stright from the wikipedia:
*
- * Adapted from code (C) Copyright John Maddock 2006.
- * Use, modification and distribution are subject to the
- * Boost Software License, Version 1.0. (See accompanying file
- * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
-
-ccl_device float approx_erff_impl(float z)
-{
- float result;
-
- if(z < 0.5f) {
- if(z < 1e-10f) {
- if(z == 0) {
- result = 0;
- }
- else {
- float c = 0.0033791670f;
- result = z * 1.125f + z * c;
- }
- }
- else {
- float Y = 1.044948577f;
-
- float zz = z * z;
- float num = (((-0.007727583f * zz) + -0.050999073f)*zz + -0.338165134f)*zz + 0.083430589f;
- float denom = (((0.000370900f * zz) + 0.008585719f)*zz + 0.087522260f)*zz + 0.455004033f;
- result = z * (Y + num / denom);
- }
- }
- else if(z < 2.5f) {
- if(z < 1.5f) {
- float Y = 0.4059357643f;
- float fz = z - 0.5f;
-
- float num = (((0.088890036f * fz) + 0.191003695f)*fz + 0.178114665f)*fz + -0.098090592f;
- float denom = (((0.123850974f * fz) + 0.578052804f)*fz + 1.426280048f)*fz + 1.847590709f;
-
- result = Y + num / denom;
- result *= expf(-z * z) / z;
- }
- else {
- float Y = 0.506728172f;
- float fz = z - 1.5f;
- float num = (((0.017567943f * fz) + 0.043948189f)*fz + 0.038654037f)*fz + -0.024350047f;
- float denom = (((0.325732924f * fz) + 0.982403709f)*fz + 1.539914949f)*fz + 1;
-
- result = Y + num / denom;
- result *= expf(-z * z) / z;
- }
-
- result = 1 - result;
- }
- else {
- result = 1;
- }
-
- return result;
-}
+ * http://en.wikipedia.org/wiki/Error_function
+ *
+ * Some constants are baked into the code.
+ */
-ccl_device float approx_erff(float z)
+ccl_device_inline float approx_erff(float x)
{
float s = 1.0f;
-
- if(z < 0.0f) {
+ if(x < 0.0f) {
s = -1.0f;
- z = -z;
- }
-
- return s * approx_erff_impl(z);
-}
-
-ccl_device float approx_erfinvf_impl(float p, float q)
-{
- float result = 0;
-
- if(p <= 0.5f) {
- float Y = 0.089131474f;
- float g = p * (p + 10);
- float num = (((-0.012692614f * p) + 0.033480662f)*p + -0.008368748f)*p + -0.000508781f;
- float denom = (((1.562215583f * p) + -1.565745582f)*p + -0.970005043f)*p + 1.0f;
- float r = num / denom;
- result = g * Y + g * r;
+ x = -x;
}
- else if(q >= 0.25f) {
- float Y = 2.249481201f;
- float g = sqrtf(-2 * logf(q));
- float xs = q - 0.25f;
- float num = (((17.644729840f * xs) + 8.370503283f)*xs + 0.105264680f)*xs + -0.202433508f;
- float denom = (((-28.660818049f * xs) + 3.971343795f)*xs + 6.242641248f)*xs + 1.0f;
- float r = num / denom;
- result = g / (Y + r);
+ /* Such a clamp doesn't give much distortion to the output value
+ * and gives quite a few of the speedup.
+ */
+ if(x > 3.0f) {
+ return s;
}
- else {
- float x = sqrtf(-logf(q));
-
- if(x < 3) {
- float Y = 0.807220458f;
- float xs = x - 1.125f;
- float num = (((0.387079738f * xs) + 0.117030156f)*xs + -0.163794047f)*xs + -0.131102781f;
- float denom = (((4.778465929f * xs) + 5.381683457f)*xs + 3.466254072f)*xs + 1.0f;
- float R = num / denom;
- result = Y * x + R * x;
- }
- else {
- float Y = 0.939955711f;
- float xs = x - 3;
- float num = (((0.009508047f * xs) + 0.018557330f)*xs + -0.002224265f)*xs + -0.035035378f;
- float denom = (((0.220091105f * xs) + 0.762059164f)*xs + 1.365334981f)*xs + 1.0f;
- float R = num / denom;
- result = Y * x + R * x;
- }
- }
-
- return result;
+ float t = 1.0f / (1.0f + 0.47047f*x);
+ return s * (1.0f -
+ t*(0.3480242f + t*(-0.0958798f + t*0.7478556f)) * expf(-x*x));
}
-ccl_device float approx_erfinvf(float z)
+ccl_device_inline float approx_erfinvf(float x)
{
- float p, q, s;
-
- if(z < 0) {
- p = -z;
- q = 1 - p;
- s = -1;
- }
- else {
- p = z;
- q = 1 - z;
- s = 1;
- }
-
- return s * approx_erfinvf_impl(p, q);
+ float ln1_x2 = logf(1.0f - x*x);
+ float term = 4.546884979448f + ln1_x2 * 0.5f;
+ return copysignf(1.0f, x) *
+ sqrtf(sqrtf(term*term - ln1_x2 * 7.142230224076f) - term);
}
/* Beckmann and GGX microfacet importance sampling from:
diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/geom/geom_bvh.h
index dd6abe32fec..59e811fa97e 100644
--- a/intern/cycles/kernel/geom/geom_bvh.h
+++ b/intern/cycles/kernel/geom/geom_bvh.h
@@ -123,6 +123,36 @@ CCL_NAMESPACE_BEGIN
#include "geom_bvh_shadow.h"
#endif
+#if defined(__VOLUME__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume
+#define BVH_FUNCTION_FEATURES 0
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__INSTANCING__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_instancing
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__HAIR__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_hair
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__OBJECT_MOTION__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_motion
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION
+#include "geom_bvh_volume.h"
+#endif
+
+#if defined(__VOLUME__) && defined(__HAIR__) && defined(__OBJECT_MOTION__)
+#define BVH_FUNCTION_NAME bvh_intersect_volume_hair_motion
+#define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION
+#include "geom_bvh_volume.h"
+#endif
+
/* to work around titan bug when using arrays instead of textures */
#if !defined(__KERNEL_CUDA__) || defined(__KERNEL_CUDA_TEX_STORAGE__)
ccl_device_inline
@@ -311,5 +341,50 @@ ccl_device_inline float3 ray_offset(float3 P, float3 Ng)
#endif
}
+/* to work around titan bug when using arrays instead of textures */
+#if !defined(__KERNEL_CUDA__) || defined(__KERNEL_CUDA_TEX_STORAGE__)
+ccl_device_inline
+#else
+ccl_device_noinline
+#endif
+bool scene_intersect_volume(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect)
+{
+#ifdef __OBJECT_MOTION__
+ if(kernel_data.bvh.have_motion) {
+#ifdef __HAIR__
+ if(kernel_data.bvh.have_curves)
+ return bvh_intersect_volume_hair_motion(kg, ray, isect);
+#endif /* __HAIR__ */
+
+ return bvh_intersect_volume_motion(kg, ray, isect);
+ }
+#endif /* __OBJECT_MOTION__ */
+
+#ifdef __HAIR__
+ if(kernel_data.bvh.have_curves)
+ return bvh_intersect_volume_hair(kg, ray, isect);
+#endif /* __HAIR__ */
+
+#ifdef __KERNEL_CPU__
+
+#ifdef __INSTANCING__
+ if(kernel_data.bvh.have_instancing)
+ return bvh_intersect_volume_instancing(kg, ray, isect);
+#endif /* __INSTANCING__ */
+
+ return bvh_intersect_volume(kg, ray, isect);
+#else /* __KERNEL_CPU__ */
+
+#ifdef __INSTANCING__
+ return bvh_intersect_volume_instancing(kg, ray, isect);
+#else
+ return bvh_intersect_volume(kg, ray, isect);
+#endif /* __INSTANCING__ */
+
+#endif /* __KERNEL_CPU__ */
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/geom/geom_bvh_volume.h
new file mode 100644
index 00000000000..aac0a18647a
--- /dev/null
+++ b/intern/cycles/kernel/geom/geom_bvh_volume.h
@@ -0,0 +1,322 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
+ * and code copyright 2009-2012 Intel Corporation
+ *
+ * Modifications Copyright 2011-2014, 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.
+ */
+
+/* This is a template BVH traversal function for volumes, where
+ * various features can be enabled/disabled. This way we can compile optimized
+ * versions for each case without new features slowing things down.
+ *
+ * BVH_INSTANCING: object instancing
+ * BVH_HAIR: hair curve rendering
+ * BVH_MOTION: motion blur rendering
+ *
+ */
+
+#define FEATURE(f) (((BVH_FUNCTION_FEATURES) & (f)) != 0)
+
+ccl_device bool BVH_FUNCTION_NAME(KernelGlobals *kg,
+ const Ray *ray,
+ Intersection *isect)
+{
+ /* todo:
+ * - test if pushing distance on the stack helps (for non shadow rays)
+ * - separate version for shadow rays
+ * - likely and unlikely for if() statements
+ * - test restrict attribute for pointers
+ */
+
+ /* traversal stack in CUDA thread-local memory */
+ int traversalStack[BVH_STACK_SIZE];
+ traversalStack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stackPtr = 0;
+ int nodeAddr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ float3 P = ray->P;
+ float3 dir = bvh_clamp_direction(ray->D);
+ float3 idir = bvh_inverse_direction(dir);
+ int object = OBJECT_NONE;
+
+ const uint visibility = PATH_RAY_ALL_VISIBILITY;
+
+#if FEATURE(BVH_MOTION)
+ Transform ob_tfm;
+#endif
+
+ isect->t = ray->t;
+ isect->object = OBJECT_NONE;
+ isect->prim = PRIM_NONE;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+
+#if defined(__KERNEL_SSE2__)
+ const shuffle_swap_t shuf_identity = shuffle_swap_identity();
+ const shuffle_swap_t shuf_swap = shuffle_swap_swap();
+
+ const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000));
+ ssef Psplat[3], idirsplat[3];
+ shuffle_swap_t shufflexyz[3];
+
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ ssef tsplat(0.0f, 0.0f, -isect->t, -isect->t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ /* traversal loop */
+ do {
+ do {
+ /* traverse internal nodes */
+ while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) {
+ bool traverseChild0, traverseChild1;
+ int nodeAddrChild1;
+
+#if !defined(__KERNEL_SSE2__)
+ /* Intersect two child bounding boxes, non-SSE version */
+ float t = isect->t;
+
+ /* fetch node data */
+ float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
+ float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
+ float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
+
+ /* intersect ray against child nodes */
+ NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f);
+ NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+
+ NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x;
+ NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y;
+ NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z;
+ NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ /* decide which nodes to traverse next */
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & visibility);
+ traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & visibility);
+#else
+ traverseChild0 = (c0max >= c0min);
+ traverseChild1 = (c1max >= c1min);
+#endif
+
+#else // __KERNEL_SSE2__
+ /* Intersect two child bounding boxes, SSE3 version adapted from Embree */
+
+ /* fetch node data */
+ const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE;
+ const float4 cnodes = ((float4*)bvh_nodes)[3];
+
+ /* intersect ray against child nodes */
+ const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0];
+ const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1];
+ const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2];
+
+ /* calculate { c0min, c1min, -c0max, -c1max} */
+ ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat));
+ const ssef tminmax = minmax ^ pn;
+
+ const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax);
+
+ /* decide which nodes to traverse next */
+#ifdef __VISIBILITY_FLAG__
+ /* this visibility test gives a 5% performance hit, how to solve? */
+ traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & visibility);
+ traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & visibility);
+#else
+ traverseChild0 = (movemask(lrhit) & 1);
+ traverseChild1 = (movemask(lrhit) & 2);
+#endif
+#endif // __KERNEL_SSE2__
+
+ nodeAddr = __float_as_int(cnodes.x);
+ nodeAddrChild1 = __float_as_int(cnodes.y);
+
+ if(traverseChild0 && traverseChild1) {
+ /* both children were intersected, push the farther one */
+#if !defined(__KERNEL_SSE2__)
+ bool closestChild1 = (c1min < c0min);
+#else
+ bool closestChild1 = tminmax[1] < tminmax[0];
+#endif
+
+ if(closestChild1) {
+ int tmp = nodeAddr;
+ nodeAddr = nodeAddrChild1;
+ nodeAddrChild1 = tmp;
+ }
+
+ ++stackPtr;
+ traversalStack[stackPtr] = nodeAddrChild1;
+ }
+ else {
+ /* one child was intersected */
+ if(traverseChild1) {
+ nodeAddr = nodeAddrChild1;
+ }
+ else if(!traverseChild0) {
+ /* neither child was intersected */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if(nodeAddr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
+ int primAddr = __float_as_int(leaf.x);
+
+#if FEATURE(BVH_INSTANCING)
+ if(primAddr >= 0) {
+#endif
+ int primAddr2 = __float_as_int(leaf.y);
+
+ /* pop */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+
+ /* primitive intersection */
+ for(; primAddr < primAddr2; primAddr++) {
+ /* only primitives from volume object */
+ uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object;
+ int object_flag = kernel_tex_fetch(__object_flag, tri_object);
+
+ if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
+ continue;
+ }
+
+ /* intersect ray against primitive */
+ uint type = kernel_tex_fetch(__prim_type, primAddr);
+
+ switch(type & PRIMITIVE_ALL) {
+ case PRIMITIVE_TRIANGLE: {
+ triangle_intersect(kg, isect, P, dir, visibility, object, primAddr);
+ break;
+ }
+#if FEATURE(BVH_MOTION)
+ case PRIMITIVE_MOTION_TRIANGLE: {
+ motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr);
+ break;
+ }
+#endif
+#if FEATURE(BVH_HAIR)
+ case PRIMITIVE_CURVE:
+ case PRIMITIVE_MOTION_CURVE: {
+ if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE)
+ bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
+ else
+ bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, NULL, 0, 0);
+ break;
+ }
+#endif
+ default: {
+ break;
+ }
+ }
+ }
+ }
+#if FEATURE(BVH_INSTANCING)
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -primAddr-1);
+ int object_flag = kernel_tex_fetch(__object_flag, object);
+
+ if(object_flag & SD_OBJECT_HAS_VOLUME) {
+
+#if FEATURE(BVH_MOTION)
+ bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
+#else
+ bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t);
+#endif
+
+#if defined(__KERNEL_SSE2__)
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ ++stackPtr;
+ traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+
+ nodeAddr = kernel_tex_fetch(__object_node, object);
+ }
+ else {
+ /* pop */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+ }
+ }
+#endif
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+#if FEATURE(BVH_INSTANCING)
+ if(stackPtr >= 0) {
+ kernel_assert(object != OBJECT_NONE);
+
+ /* instance pop */
+#if FEATURE(BVH_MOTION)
+ bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_tfm);
+#else
+ bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t);
+#endif
+
+#if defined(__KERNEL_SSE2__)
+ Psplat[0] = ssef(P.x);
+ Psplat[1] = ssef(P.y);
+ Psplat[2] = ssef(P.z);
+
+ tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t);
+
+ gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz);
+#endif
+
+ object = OBJECT_NONE;
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+#endif
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != PRIM_NONE);
+}
+
+#undef FEATURE
+#undef BVH_FUNCTION_NAME
+#undef BVH_FUNCTION_FEATURES
+
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 29077a8886c..e68a8370012 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -411,6 +411,8 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd
int num_hits = subsurface_scatter_multi_step(kg, sd, bssrdf_sd, state->flag, sc, &lcg_state, bssrdf_u, bssrdf_v, false);
#ifdef __VOLUME__
Ray volume_ray = *ray;
+ bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
+ sd->flag & SD_OBJECT_INTERSECTS_VOLUME;
#endif
/* compute lighting with the BSDF closure */
@@ -430,7 +432,7 @@ ccl_device bool kernel_path_subsurface_scatter(KernelGlobals *kg, ShaderData *sd
#endif
#ifdef __VOLUME__
- if(kernel_data.integrator.use_volumes) {
+ if(need_update_volume_stack) {
/* Setup ray from previous surface point to the new one. */
volume_ray.D = normalize_len(hit_ray.P - volume_ray.P,
&volume_ray.t);
@@ -802,6 +804,8 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
int num_hits = subsurface_scatter_multi_step(kg, sd, bssrdf_sd, state->flag, sc, &lcg_state, bssrdf_u, bssrdf_v, true);
#ifdef __VOLUME__
Ray volume_ray = *ray;
+ bool need_update_volume_stack = kernel_data.integrator.use_volumes &&
+ sd->flag & SD_OBJECT_INTERSECTS_VOLUME;
#endif
/* compute lighting with the BSDF closure */
@@ -811,7 +815,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg,
path_state_branch(&hit_state, j, num_samples);
#ifdef __VOLUME__
- if(kernel_data.integrator.use_volumes) {
+ if(need_update_volume_stack) {
/* Setup ray from previous surface point to the new one. */
float3 P = ray_offset(bssrdf_sd[hit].P, -bssrdf_sd[hit].Ng);
volume_ray.D = normalize_len(P - volume_ray.P,
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 7c95f8cf14a..2fe1cd87072 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -615,8 +615,12 @@ enum ShaderDataFlag {
SD_OBJECT_MOTION = 1048576, /* has object motion blur */
SD_TRANSFORM_APPLIED = 2097152, /* vertices have transform applied */
SD_NEGATIVE_SCALE_APPLIED = 4194304, /* vertices have negative scale applied */
+ SD_OBJECT_HAS_VOLUME = 8388608, /* object has a volume shader */
+ SD_OBJECT_INTERSECTS_VOLUME = 16777216, /* object intersects AABB of an object with volume shader */
- SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|SD_NEGATIVE_SCALE_APPLIED)
+ SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
+ SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
+ SD_OBJECT_INTERSECTS_VOLUME)
};
struct KernelGlobals;
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 794ce925777..dd947a54530 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -985,9 +985,7 @@ ccl_device void kernel_volume_stack_init(KernelGlobals *kg,
enclosed_index < VOLUME_STACK_SIZE - 1)
{
Intersection isect;
- if(!scene_intersect(kg, &volume_ray, PATH_RAY_ALL_VISIBILITY,
- &isect, NULL, 0.0f, 0.0f))
- {
+ if(!scene_intersect_volume(kg, &volume_ray, &isect)) {
break;
}
diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp
index 28b6c994568..110adb4d036 100644
--- a/intern/cycles/render/camera.cpp
+++ b/intern/cycles/render/camera.cpp
@@ -276,17 +276,15 @@ void Camera::device_update(Device *device, DeviceScene *dscene, Scene *scene)
/* Camera in volume. */
kcam->is_inside_volume = 0;
- if(use_camera_in_volume) {
- 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))
- {
- /* TODO(sergey): Consider adding more grained check. */
- kcam->is_inside_volume = 1;
- break;
- }
+ 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))
+ {
+ /* TODO(sergey): Consider adding more grained check. */
+ kcam->is_inside_volume = 1;
+ break;
}
}
}
diff --git a/intern/cycles/render/camera.h b/intern/cycles/render/camera.h
index 3054137309d..788ae7b9bb6 100644
--- a/intern/cycles/render/camera.h
+++ b/intern/cycles/render/camera.h
@@ -102,13 +102,6 @@ public:
bool need_device_update;
int previous_need_motion;
- /* Camera in volume. */
- /* TODO(sergey): Get rid of this argument once
- * cameras in volume considered fast enough for
- * the regular kernel.
- */
- bool use_camera_in_volume;
-
/* functions */
Camera();
~Camera();
diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp
index 076cc3d8b63..eb2c3333c44 100644
--- a/intern/cycles/render/image.cpp
+++ b/intern/cycles/render/image.cpp
@@ -176,6 +176,10 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
img->frame = frame;
img->need_load = true;
}
+ if(img->use_alpha != use_alpha) {
+ img->use_alpha = use_alpha;
+ img->need_load = true;
+ }
img->users++;
return slot;
}
@@ -219,6 +223,10 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani
img->frame = frame;
img->need_load = true;
}
+ if(img->use_alpha != use_alpha) {
+ img->use_alpha = use_alpha;
+ img->need_load = true;
+ }
img->users++;
return slot+tex_image_byte_start;
}
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 54cfab42a97..42103396b53 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -1032,7 +1032,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
if(!need_update)
return;
- /* update normals */
+ /* update normals and flags */
foreach(Mesh *mesh, scene->meshes) {
mesh->has_volume = false;
foreach(uint shader, mesh->used_shaders) {
@@ -1109,6 +1109,8 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
bool motion_blur = false;
#endif
+ /* update obejcts */
+ vector<Object *> volume_objects;
foreach(Object *object, scene->objects)
object->compute_bounds(motion_blur);
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index 1f148d34ea6..46ddab235d9 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -75,8 +75,14 @@ void Object::compute_bounds(bool motion_blur)
bounds.grow(mbounds.transformed(&ttfm));
}
}
- else
- bounds = mbounds.transformed(&tfm);
+ else {
+ if(mesh->transform_applied) {
+ bounds = mbounds;
+ }
+ else {
+ bounds = mbounds.transformed(&tfm);
+ }
+ }
}
void Object::apply_transform(bool apply_to_motion)
@@ -372,8 +378,6 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
device_free(device, dscene);
- need_update = false;
-
if(scene->objects.size() == 0)
return;
@@ -392,6 +396,46 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
progress.set_status("Updating Objects", "Applying Static Transformations");
apply_static_transforms(dscene, scene, object_flag, progress);
}
+}
+
+void ObjectManager::device_update_flags(Device *device, DeviceScene *dscene,
+ Scene *scene, Progress& progress)
+{
+ if(!need_update)
+ return;
+
+ need_update = false;
+
+ if(scene->objects.size() == 0)
+ return;
+
+ /* object info flag */
+ uint *object_flag = dscene->object_flag.get_data();
+
+ vector<Object *> volume_objects;
+ foreach(Object *object, scene->objects) {
+ if(object->mesh->has_volume) {
+ volume_objects.push_back(object);
+ }
+ }
+
+ int object_index = 0;
+ foreach(Object *object, scene->objects) {
+ if(object->mesh->has_volume) {
+ object_flag[object_index] |= SD_OBJECT_HAS_VOLUME;
+ }
+
+ foreach(Object *volume_object, volume_objects) {
+ if(object == volume_object) {
+ continue;
+ }
+ if(object->bounds.intersects(volume_object->bounds)) {
+ object_flag[object_index] |= SD_OBJECT_INTERSECTS_VOLUME;
+ break;
+ }
+ }
+ ++object_index;
+ }
/* allocate object flag */
device->tex_alloc("__object_flag", dscene->object_flag);
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index 677526b715f..2c69b83a2e9 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -76,6 +76,7 @@ public:
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
+ void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index d0de8c51300..6c3f98bc9b0 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -175,6 +175,11 @@ void Scene::device_update(Device *device_, Progress& progress)
if(progress.get_cancel()) return;
+ progress.set_status("Updating Objects Flags");
+ object_manager->device_update_flags(device, &dscene, this, progress);
+
+ if(progress.get_cancel()) return;
+
progress.set_status("Updating Hair Systems");
curve_system_manager->device_update(device, &dscene, this, progress);
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
index 1969572530d..ffd4299bc39 100644
--- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py
+++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py
@@ -844,14 +844,15 @@ class VIEW3D_PT_tools_brush(Panel, View3DPaintPanel):
self.prop_unified_size(row, context, brush, "use_pressure_size")
# strength, use_strength_pressure, and use_strength_attenuation
- if capabilities.has_strength:
- col.separator()
- row = col.row(align=True)
+ col.separator()
+ row = col.row(align=True)
+
+ if capabilities.has_space_attenuation:
+ row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
- if capabilities.has_space_attenuation:
- row.prop(brush, "use_space_attenuation", toggle=True, icon_only=True)
+ self.prop_unified_strength(row, context, brush, "strength", text="Strength")
- self.prop_unified_strength(row, context, brush, "strength", text="Strength")
+ if capabilities.has_strength_pressure:
self.prop_unified_strength(row, context, brush, "use_pressure_strength")
# auto_smooth_factor and use_inverse_smooth_pressure
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 661fe03912f..105c83f9864 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 272
-#define BLENDER_SUBVERSION 0
+#define BLENDER_SUBVERSION 1
/* 262 was the last editmesh release but it has compatibility code for bmesh data */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 399bea1b610..cad062ac63d 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -3014,10 +3014,17 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
if (UNLIKELY(c == 0)) {
continue;
}
+ else if (UNLIKELY(c < 3)) {
+ STACK_DISCARD(oldl, c);
+ STACK_DISCARD(mloop, c);
+ continue;
+ }
+
mp_new = STACK_PUSH_RET_PTR(mpoly);
*mp_new = *mp;
mp_new->totloop = c;
+ BLI_assert(mp_new->totloop >= 3);
mp_new->loopstart = STACK_SIZE(mloop) - c;
STACK_PUSH(oldp, i);
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
index da9bf5ea04c..864a7704aa9 100644
--- a/source/blender/blenlib/BLI_stackdefines.h
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -64,6 +64,13 @@
stack[_i] = stack[_##stack##_index]; \
} \
} (void)0
+#define STACK_DISCARD(stack, n) \
+ { \
+ const unsigned int _n = n; \
+ BLI_assert(_##stack##_index >= _n); \
+ (void)stack; \
+ _##stack##_index -= _n; \
+ } (void)0
#ifdef __GNUC__
#define STACK_SWAP(stack_a, stack_b) { \
SWAP(typeof(stack_a), stack_a, stack_b); \
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 22868035a13..d8da0a12b50 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -390,6 +390,14 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
}
+
+ if (!MAIN_VERSION_ATLEAST(main, 272, 1)) {
+ Brush *br;
+ for (br = main->brush.first; br; br = br->id.next) {
+ if ((br->ob_mode & OB_MODE_SCULPT) && ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
+ br->alpha = 1.0f;
+ }
+ }
if (!DNA_struct_elem_find(fd->filesdna, "Image", "float", "gen_color")) {
Image *image;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 9c8c3c29b9c..e024f837feb 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -809,10 +809,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, Unifi
return alpha * pressure * feather;
case SCULPT_TOOL_SNAKE_HOOK:
- return feather;
+ return root_alpha * feather;
case SCULPT_TOOL_GRAB:
- return feather;
+ return root_alpha * feather;
case SCULPT_TOOL_ROTATE:
return alpha * pressure * feather;
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 1ff99271146..bbc2e0572fa 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -264,7 +264,7 @@ static int rna_BrushCapabilities_has_spacing_get(PointerRNA *ptr)
return (!(br->flag & BRUSH_ANCHORED));
}
-static int rna_SculptToolCapabilities_has_strength_get(PointerRNA *ptr)
+static int rna_SculptToolCapabilities_has_strength_pressure_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
return !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK);
@@ -689,7 +689,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna)
SCULPT_TOOL_CAPABILITY(has_secondary_color, "Has Secondary Color");
SCULPT_TOOL_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke");
SCULPT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation");
- SCULPT_TOOL_CAPABILITY(has_strength, "Has Strength");
+ SCULPT_TOOL_CAPABILITY(has_strength_pressure, "Has Strength Pressure");
SCULPT_TOOL_CAPABILITY(has_gravity, "Has Gravity");
#undef SCULPT_CAPABILITY
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 66796480542..bae75d8693f 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -406,6 +406,9 @@ static DerivedMesh *arrayModifier_doArray(
const bool use_merge = amd->flags & MOD_ARR_MERGE;
const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge;
+ const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob);
+ /* allow pole vertices to be used by many faces */
+ const bool with_follow = use_offset_ob;
int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
@@ -454,7 +457,7 @@ static DerivedMesh *arrayModifier_doArray(
offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j);
}
- if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
+ if (use_offset_ob) {
float obinv[4][4];
float result_mat[4][4];
@@ -606,10 +609,12 @@ static DerivedMesh *arrayModifier_doArray(
int target = full_doubles_map[prev_chunk_index];
if (target != -1) {
target += chunk_nverts; /* translate mapping */
- /* The rule here is to not follow mapping to chunk N-2, which could be too far
- * so if target vertex was itself mapped, then this vertex is not mapped */
- if (full_doubles_map[target] != -1) {
- target = -1;
+ if (!with_follow) {
+ /* The rule here is to not follow mapping to chunk N-2, which could be too far
+ * so if target vertex was itself mapped, then this vertex is not mapped */
+ if (full_doubles_map[target] != -1) {
+ target = -1;
+ }
}
}
full_doubles_map[this_chunk_index] = target;
@@ -624,7 +629,7 @@ static DerivedMesh *arrayModifier_doArray(
c * chunk_nverts,
chunk_nverts,
amd->merge_dist,
- false);
+ with_follow);
}
}
}
@@ -644,7 +649,7 @@ static DerivedMesh *arrayModifier_doArray(
first_chunk_start,
first_chunk_nverts,
amd->merge_dist,
- false);
+ with_follow);
}
/* start capping */
@@ -711,7 +716,12 @@ static DerivedMesh *arrayModifier_doArray(
if (use_merge) {
for (i = 0; i < result_nverts; i++) {
if (full_doubles_map[i] != -1) {
- tot_doubles++;
+ if (i == full_doubles_map[i]) {
+ full_doubles_map[i] = -1;
+ }
+ else {
+ tot_doubles++;
+ }
}
}
if (tot_doubles > 0) {
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 76986583ef5..7349ca9f9ef 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -60,7 +60,7 @@ static void copyData(ModifierData *md, ModifierData *target)
static bool isDisabled(ModifierData *UNUSED(md), int UNUSED(useRenderParams))
{
- return 0;
+ return false;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -75,6 +75,11 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
}
+static bool dependsOnNormals(ModifierData *UNUSED(md))
+{
+ return true;
+}
+
static DerivedMesh *WireframeModifier_do( WireframeModifierData *wmd, Object *ob, DerivedMesh *dm)
{
DerivedMesh *result;
@@ -135,7 +140,7 @@ ModifierTypeInfo modifierType_Wireframe = {
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
/* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
+ /* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,