1
$\begingroup$

I've been following CGCookie's Voxelize Art tutorial on YT and everything has been smooth sailing until pretty much the last step. The tutorial was made using 2.8 so I obviously some of the code has been updated/changed since, but since I'm learning I'd like to know how to fix it. I'm adding the Octree Depth panel that pops up once it Voxelizes your mesh, to make it have more or less resolution and I get this error message:

AttributeError: 'OBJECT_OT_voxelize' object has no attribute 'voxelizedResolution'.

Not sure if it makes sense out of context since these are specific commands. I'm still new to Python and am not sure what I'm missing here. What do I defy the attribute as and where to place it in the text editor? I've included a screenshot for reference. Any help/explanation would be great. Thank you!

        import bpy
from bpy.types import (
    AddonPreferences,
    Operator,
    Panel,
    PropertyGroup,
)
from bpy.props import (IntProperty)

class OBJECT_OT_voxelize(Operator):
    bl_label = "Voxelize"
    bl_idname = "object.voxelize"
    bl_description = "Converts any object into a voxel mesh"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_options = {'REGISTER', 'UNDO'}
    
    voxelizeResolution: bpy.props.IntProperty(
        name = "Voxel Resolution",
        default = 6,
        min = 1,
        max = 15,
        description = "Octree Depth used in the Remesh Modifier",
    )
    
    @classmethod
    def poll(cls, context):
        return context.active_object and context.object.select_get() and context.object.type in ['MESH', 'CURVE']

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)
    
    def execute(self, context):
        #set source and create target
        sourceName = bpy.context.object.name
        source = bpy.data.objects[sourceName]

        bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'})
        bpy.context.object.name = sourceName + "_Voxelized"
        bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
        bpy.ops.object.convert(target='MESH')

        source.hide_render = True
        source.hide_viewport = True


        targetName = bpy.context.object.name
        target = bpy.data.objects[sourceName]

        #turn the target object into blocks
        bpy.ops.object.modifier_add(type='REMESH')
        bpy.context.object.modifiers["Remesh"].mode = 'BLOCKS'
        bpy.context.object.modifiers["Remesh"].octree_depth = self.voxelizedResolution
        bpy.context.object.modifiers["Remesh"].use_remove_disconnected = False
        bpy.ops.object.modifier_apply(modifier="Remesh")

        #transfer UVs to target
        bpy.ops.object.modifier_add(type='DATA_TRANSFER')
        bpy.context.object.modifiers["DataTransfer"].use_loop_data = True
        bpy.context.object.modifiers["DataTransfer"].data_types_loops = {'UV'}
        bpy.context.object.modifiers["DataTransfer"].loop_mapping = 'POLYINTERP_NEAREST'
        bpy.context.object.modifiers["DataTransfer"].object = source
        bpy.ops.object.datalayout_transfer(modifier="DataTransfer")
        bpy.ops.object.modifier_apply(modifier="DataTransfer")

        #reduce faces to single color
        bpy.ops.object.editmode_toggle()
        bpy.ops.mesh.select_mode(type='FACE')
        bpy.context.area.ui_type = 'UV'
        bpy.context.scene.tool_settings.use_uv_select_sync = False
        bpy.context.space_data.uv_editor.sticky_select_mode = 'DISABLED'
        bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
        bpy.context.scene.tool_settings.transform_pivot_point = 'INDIVIDUAL_ORIGINS'
        bpy.ops.mesh.select_all(action='DESELECT')

        count = 0
        while count < 100:
            bpy.ops.mesh.select_random(ratio=count + 1, seed=count)
            bpy.ops.uv.select_all(action='SELECT')
            bpy.ops.transform.resize(value=(0.001, 0.001, 0.001))
            bpy.ops.mesh.hide(unselected=False)
            count +=1
            
        #return to previous context
        bpy.context.area.ui_type = 'VIEW_3D'
        bpy.ops.mesh.reveal()
        bpy.ops.object.editmode_toggle()
            
        return {'FINISHED'}         

def menu_func(self, context):
    self.layout.operator(OBJECT_OT_voxelize.bl_idname)
    
def register():
    bpy.utils.register_class(OBJECT_OT_voxelize)
    bpy.types.VIEW3D_MT_object.append(menu_func)
    
def unregister():
    bpy.utils.unregister_class(OBJECT_OT_voxelize)
    bpy.types.VIEW3D_MT_object.remove(menu_func)

if __name__ == "__main__":
    register()    

blend file:

$\endgroup$
3
  • 1
    $\begingroup$ For future reference, always post code you need help with directly in the question, don't use screenshots. It's easier to troubleshoot and answer your question if we can copy your code and paste in into our own Blender text editor, can't easily do that with an image! $\endgroup$
    – Jakemoyo
    Aug 17, 2022 at 9:20
  • $\begingroup$ oops deleted my answer. crantisz spotted it first XD $\endgroup$ Aug 17, 2022 at 9:34
  • $\begingroup$ thank you! I haven't posted here before, I'll be sure to copy paste next time. $\endgroup$ Aug 17, 2022 at 22:58

1 Answer 1

2
$\begingroup$

You just mess up the names. Here is voxelizeResolution

voxelizeResolution: bpy.props.IntProperty(
    name = "Voxel Resolution",
    default = 6,
    min = 1,
    max = 15,
    description = "Octree Depth used in the Remesh Modifier",
)

And here is voxelizedResolution:

bpy.context.object.modifiers["Remesh"].octree_depth = self.voxelizedResolution
$\endgroup$
1
  • $\begingroup$ Hi @crantisz , thank you for your help. Sorry, I've been trying to use your code corrections and run it but I'm still getting the same error. I edited my question to include the code as it's too many characters to fit in here. Any help would be greatly appreciated. $\endgroup$ Aug 18, 2022 at 21:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .