0
$\begingroup$

First: I'm new to Python programming in Blender.

I already know how add a row to scale one single axis of an object by using a slider in the tools panel e.g. I'm using this code snippet to do this:

import bpy # Python API for Blender
from bpy.types import Panel, Operator

# Class for the panel, derived by Panel
class SimpleToolPanel(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'CW Tools'
    bl_context = 'objectmode'
    bl_category = 'CW Tools' # Where the Panel have to appear. In this case in the Tools cetegory.

    # Add UI elements here
    def draw(self, context):
        layout = self.layout

        # New row
        row = layout.row()

        # get the selected object
        obj = context.object

        #Let's display the scale of the object
        str_scale = 'Object: ' + obj.name + ' scale: ' + str(obj.scale)

        row.label(text=str_scale)

        #Add scale slider property
        row = layout.row()
        row.prop(obj, 'scale', index=0, text='Scale x:')

        row = layout.row()
        row.prop(obj, 'scale', index=1, text='Scale y:')

        row = layout.row()
        row.prop(obj, 'scale', index=2, text='Scale z:')

# Register
def register():
    bpy.utils.register_class(SimpleToolPanel)

# Unregister
def unregister():
    bpy.utils.unregister_class(SimpleToolPanel)

# Run in text editor
if __name__ == "__main__":
    register()

My question:

How is the code to resize a complete active object via one single slider, please?

$\endgroup$
4
  • $\begingroup$ What happens if you don't mention the index? Will it scale the whole object then? $\endgroup$ Nov 19 '18 at 15:47
  • $\begingroup$ Sorry. The row scales the x-axis only. I would like to scale all three axis together e.g. $\endgroup$ Nov 19 '18 at 15:52
  • $\begingroup$ I've replaced the whole code to show you my current version. At the moment I'm able to scale every single axis of an active object. But I would like to scale the whole object by using one single slider only. $\endgroup$ Nov 19 '18 at 15:57
  • $\begingroup$ @CraigDJones To answer your question: No. I see all three axes at once side by side then. $\endgroup$ Nov 19 '18 at 16:02
1
$\begingroup$

Make the current scale "unity" for the scale_factor.

This is a bit of an old chestnut, if a simple scale factor is added such that

ob.scale *= scale_factor

which is how the scale operator works somewhat, everything turns to zero once the scale hits zero... And it also acts geometrically making it very unmanageable very quickly.

As a workaround I've added a boolean to copy the current scale to a vector property and set the scale factor to 1. To reset click the boolean back on and off. (prob should be an operator instead but you get the idea.)

enter image description here

import bpy
from mathutils import Vector
from bpy.types import Panel, Operator
from bpy.props import (FloatProperty,
        FloatVectorProperty,
        BoolProperty)

class SimpleToolPanel(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'CW Tools'
    bl_context = 'objectmode'
    bl_category = 'Tools'

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        obj = context.object
        row.prop(obj, "scale_set", toggle=True)
        if obj.scale_set:
            row = layout.row()
            row.prop(obj, 'scale_factor')

def scale_set(self, context):
    if self.scale_set:
        self.scale_vector = self.scale.copy()
        self["scale_factor"] = 1

def scale_obj(self, context):
    self.scale = self.scale_factor * Vector(self.scale_vector)

def register():
    bpy.types.Object.scale_vector = FloatVectorProperty()
    bpy.types.Object.scale_set = BoolProperty(
            default=False,
            update=scale_set)

    bpy.types.Object.scale_factor = FloatProperty(
            name="Scale Factor",
            default=1,
            update=scale_obj
            )
    bpy.utils.register_class(SimpleToolPanel)


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

if __name__ == "__main__":
    register()
$\endgroup$
3
  • $\begingroup$ This is a nice solution too. Thank you for your efforts. See my answer above to know what I miss in your code. $\endgroup$ Nov 20 '18 at 12:32
  • 1
    $\begingroup$ IMO the accepted answer is not the way to go.... unless the question is how to make the y and z scale the value of x scale. It scales an object to scale.x * (1, 1, 1,) taking into no account if the object already has non-uniform scale. Eg If the object already has scale.x = 0, then the object becomes scaled to zero. (0, 0, 0) . If an object has scale (3, 0, 0) it gets scaled to (3, 3, 3) If the initial scale is (1, 1, 1) my answer will do same. But if the initial scale is (1, 2, 3) and I scale it by 2 I get (2, 4, 6) which makes sense to me, (2, 2, 2) not so sure. Anyway your question.. $\endgroup$
    – batFINGER
    Nov 20 '18 at 12:59
  • $\begingroup$ You are completely right. Your solution answers my basic question and scales an object the right way. But both solutions here are a good foundation for myself to work with and learn more. Thank you. $\endgroup$ Nov 21 '18 at 17:07
2
$\begingroup$

Here's the script to do this (open to corrections):

[Edit: Added getVal to reflect current X scale]

import bpy # Python API for Blender
from bpy.types import Panel, Operator

# Class for the panel, derived by Panel
class SimpleToolPanel(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'CW Tools'
    bl_context = 'objectmode'
    bl_category = 'CW Tools' # Where the Panel have to appear. In this case in the Tools cetegory.

    def setVal(self, val):
        self.objects.active.scale[0] = val
        self.objects.active.scale[1] = val
        self.objects.active.scale[2] = val

    #Edit: Pick the value from the X scale, assuming all scale values are the same
    def getVal(self):
        return self.objects.active.scale[0]

    bpy.types.Scene.scaleVal = bpy.props.FloatProperty(set = setVal, get = getVal)

    # Add UI elements here
    def draw(self, context):
        layout = self.layout

        # New row
        row = layout.row()

        # get the selected object
        obj = context.object

        #Let's display the scale of the object
        str_scale = 'Object: ' + obj.name + ' scale: ' + str(obj.scale)

        row.label(text=str_scale)

        #Add scale slider property

        row = layout.row()
        row.prop(bpy.context.scene, 'scaleVal', text='Scale:')

# Register
def register():
    bpy.utils.register_class(SimpleToolPanel)

# Unregister
def unregister():
    bpy.utils.unregister_class(SimpleToolPanel)

# Run in text editor
if __name__ == "__main__":
    register()
$\endgroup$
3
  • $\begingroup$ Thank you! It's nearly what I was looking for. Now I have to check out how to set the current object scale value before adjusting it with the slider. In your version the slider is always zero and does not read the active object scale before adjusting it. $\endgroup$ Nov 20 '18 at 8:09
  • 1
    $\begingroup$ You are welcome. It's trivial to read the active objects scale. You need to just have another function getVal(self) and set it to get parameter of FloatProperty constructor. But there are going to be three different values. How would you like to combine them? In the edit I am setting it to the first scale value. Assuming all three would be the same. $\endgroup$ Nov 20 '18 at 9:03
  • $\begingroup$ Exactly. I need just one same value for all parameters (x,y,z). Thank you! $\endgroup$ Nov 20 '18 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.