Page MenuHome

Decimate modifier not working in operator settings
Closed, ResolvedPublic

Description

System Information
Windows 10 x64
GTX 950M

Blender Version
Broken:
Date: 2019-01-18
Hash: c59370bf643f

Looks like the decimate modifier doesn't work when used in operator settings. Every other modifier seems to work fine.

Exact steps for others to reproduce the error
1: Select a mesh object
2: Run script, run operator, and enable Decimate.
3: Increase Subsurf Amount and watch it change.
4: Adjust Decimate Amount (Nothing happens other than number changing on modifier).
5: Adjust Iterations under modifier settings and watch it work like it should.

import bpy

			
def main(context, strip_surf_amount, strip_decimate_amount):
	
	ACT_OBJ = bpy.context.active_object
			
	#Subsurf Modifier
	SUB_MOD = ACT_OBJ.modifiers.new(name="Subsurf_Strips", type='SUBSURF')
	SUB_MOD.levels = strip_surf_amount
	SUB_MOD.subdivision_type = 'CATMULL_CLARK'
	bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Subsurf_Strips")

	#Decimate Modifier
	DECIMATE_MOD = ACT_OBJ.modifiers.new(name="Decimate_Strips", type='DECIMATE')
	DECIMATE_MOD.decimate_type = 'UNSUBDIV'
	DECIMATE_MOD.iterations = strip_decimate_amount

	#smooth modifier
	SMOOTH_MOD_1 = ACT_OBJ.modifiers.new("Smooth_Strips_1", 'SMOOTH')
	SMOOTH_MOD_1.use_x = True
	SMOOTH_MOD_1.use_y = True
	SMOOTH_MOD_1.use_z = True
	SMOOTH_MOD_1.factor = 0.5
	SMOOTH_MOD_1.iterations = 2 #4


class SimpleOperator(bpy.types.Operator):
	"""Tooltip"""
	bl_idname = "object.simple_operator"
	bl_label = "Simple Object Operator"
	bl_options = {'REGISTER', 'UNDO'}
	

	strip_surf_amount: bpy.props.IntProperty(
			name="Subsurf Amount",
			description="Amount of subsurf",
			default=1,
			)

	strip_decimate: bpy.props.BoolProperty(
			name="Decimate",
			description="Decimate",
			default=False,
			)

	strip_decimate_amount: bpy.props.IntProperty(
			name="Decimate Amount",
			description="Amount to decimate",
			default=2, 		
			)


	def draw(self, context):
		layout = self.layout

		#Topology
		box = layout.box()  	  
		col = box.column(align=True)
		col.label(text="Topology")
		col.prop(self, "strip_surf_amount", text="Subsurf Amount")
		col.prop(self, "strip_decimate", text="Decimate")
		if self.strip_decimate: 	   
			col.prop(self, "strip_decimate_amount", text="Decimate Amount")


	def execute(self, context):
		main(context, self.strip_surf_amount, self.strip_decimate_amount)
		return {'FINISHED'}


def register():
	bpy.utils.register_class(SimpleOperator)


def unregister():
	bpy.utils.unregister_class(SimpleOperator)


if __name__ == "__main__":
	register()

Event Timeline

Philipp Oeser (lichtwerk) triaged this task as Confirmed, Medium priority.Jan 22 2019, 10:31 AM

Something up front:
I guess it might be good practice to not make new modifiers on redo but instead look for existing ones and change settings on those.
I would also make sure you cap subsurf levels to a reasonable max [just had the case where the UI hang and I had to reboot because I apparently went into insane amount of subdivisions...]

That being said there was rB2ca4f4f0cb8d that made a change here that might be the reason...
Prior to this commit both original DecimateModifierData facecount and evaluated DecimateModifierData facecount were updated, after rB2ca4f4f0cb8d only the original is.
With that happening, I am getting the modifier error (at least with the setup in your script, not sure how to reproduce otherwise):

Modifier requires more than 3 input faces

That somehow results in undo/redo not doing a clean job and undesired things happen:

  • a new subdiv modifier gets added after the existing decimate / smooth
  • this subdiv modifier cannot be applied cleanly (it is not the first in the list anymore)
  • additional decimate / smooth modifiers get added (see above comment about not adding new ones but looking for existing ones...)

anyways: regarding the change in rB2ca4f4f0cb8d, I am drpping this here [not 100% sure this is neccesary]:

1
2
3diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
4index fff94e0d836..8068ef4ea09 100644
5--- a/source/blender/modifiers/intern/MOD_decimate.c
6+++ b/source/blender/modifiers/intern/MOD_decimate.c
7@@ -89,13 +89,14 @@ static DecimateModifierData *getOriginalModifierData(
8 }
9
10 static void updateFaceCount(
11- const ModifierEvalContext *ctx, const DecimateModifierData *dmd, int face_count)
12+ const ModifierEvalContext *ctx, DecimateModifierData *dmd, int face_count)
13 {
14 if (DEG_is_active(ctx->depsgraph)) {
15 /* update for display only */
16 DecimateModifierData *dmd_orig = getOriginalModifierData(dmd, ctx);
17 dmd_orig->face_count = face_count;
18 }
19+ dmd->face_count = face_count;
20 }
21
22 static Mesh *applyModifier(

@Brecht Van Lommel (brecht): confirming for now, mind checking?

You can also remove everything ,but the decimate modifier and you still get the same results and error.

import bpy

			
def main(context, strip_decimate_amount):
	
	ACT_OBJ = bpy.context.active_object

	#Decimate Modifier
	DECIMATE_MOD = ACT_OBJ.modifiers.new(name="Decimate_Strips", type='DECIMATE')
	DECIMATE_MOD.decimate_type = 'UNSUBDIV'
	DECIMATE_MOD.iterations = strip_decimate_amount


class SimpleOperator(bpy.types.Operator):
	"""Tooltip"""
	bl_idname = "object.simple_operator"
	bl_label = "Simple Object Operator"
	bl_options = {'REGISTER', 'UNDO'}
	

	strip_decimate: bpy.props.BoolProperty(
			name="Decimate",
			description="Decimate",
			default=False,
			)

	strip_decimate_amount: bpy.props.IntProperty(
			name="Decimate Amount",
			description="Amount to decimate",
			default=2, 		
			)


	def draw(self, context):
		layout = self.layout

		#Topology
		box = layout.box()  	  
		col = box.column(align=True)
		col.label(text="Topology")
		col.prop(self, "strip_decimate", text="Decimate")
		if self.strip_decimate: 	   
			col.prop(self, "strip_decimate_amount", text="Decimate Amount")


	def execute(self, context):
		main(context, self.strip_decimate_amount)
		return {'FINISHED'}


def register():
	bpy.utils.register_class(SimpleOperator)


def unregister():
	bpy.utils.unregister_class(SimpleOperator)


if __name__ == "__main__":
	register()