# Change Object's Location on local Z-Axis using Slider

I have a problem with moving the object on its local z axis.

import bpy, mathutils
from bpy.types import Panel, Operator
from bpy.props import FloatProperty
from mathutils import Matrix, Vector

#get, set methods of the floatproperty
def get_locationZ(self):
return self['locationZ']

def set_locationZ(self, value):
obj = bpy.context.object
loc = Matrix.Translation((0.0, 0.0, value))
obj.matrix_basis *= loc
self['locationZ'] = value

class ToolPanel(Panel):
bl_space_type='VIEW_3D'
bl_region_type='TOOLS'
bl_label='Cylinder'
bl_context='objectmode'
bl_category='Cylinder'

#floatproperty
bpy.types.Object.myFloat = FloatProperty(
name = "locationZ",
description = "Set the location on local z axis",
min = -100,
max = 100,
get = get_locationZ,
set = set_locationZ)

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

row = layout.row()
row.template_ID(context.scene.objects, "active")

split=layout.split()
col=split.column(align=True)

if obj is not None:
col.prop(obj, 'myFloat')

#Register
def register():
bpy.utils.register_class(ToolPanel)
#Unregister
def unregister():
bpy.utils.unregister_class(ToolPanel)

if __name__== '__main__':
register()


The problem is: If I increase the value of the slider, the cylinder moves in positive direction on the local Z axis.

But when I start to reduce the value, the cylinder moves in positive direction until the value reaches zero.

And then it turns and moves in negative directon. I want to move it to negavite direction immediately I start to reduce the value of the slider.

• Quick way to paste codeblock. If you have code in blender, text editor ctrl-A select all, hit tab, copy, paste here, shift tab in blender. You are applying a translation, like pressing g1 g0.9 g0.8 will move 2.7 . Need to set an absolute value. Pretty much want same as col.prop(obj, "location", index=2, slider=True) ie set obj.location.z = value wheras even with the matrix math you are simply obj.location.z += value – batFINGER Mar 31 at 10:49
• Thats not what i want, because thats moves the object on the global z axis. So if i change for example the rotation X and then i want to move the object on the LOCAL Z axis, not on the global/or ont the parentobject's. So obj.location.z += value dont do what i'd like to. – aura Mar 31 at 10:54

Applying rotation accumulates

As I was poorly trying to point out in comment applying the translation matrix from value will have a cumulative effect. (no matter what direction)

Use the delta value calculated from previous value.

Other minor changes, use self in the setter getter, rather than relying on bpy.context.object is self If you want context possibly better to use an update method instead.

Using ob.get("propname", default) gives a default value even when the property hasn't been set.

EDIT. Changed this to moving "locally globally" this way our slider value is global and won't be affected by local scale. (Move 1 unit globally in local z, akin to translate operator)

Example below working in 2.8. (Minor change @ to * or back).

import bpy, mathutils
from bpy.types import Panel, Operator
from bpy.props import FloatProperty
from mathutils import Matrix, Vector

#get, set methods of the floatproperty
def get_locationZ(self):
return self.get('locationZ', 0)

def set_locationZ(self, value):
z_axis = Vector((0, 0, 1))
delta = value - self.get('locationZ', 0)
v = (self.matrix_world.to_3x3() @ z_axis).normalized()

self.matrix_world.translation += delta * v
self['locationZ'] = value

class VIEW3D_PT_ToolPanel(Panel):
bl_space_type='VIEW_3D'
bl_region_type='TOOLS'
bl_label='Cylinder'
bl_context='objectmode'

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

row = layout.row()
row.template_ID(context.view_layer.objects, "active") # context.scene.objects (2.7x)

split=layout.split()
col=split.column(align=True)

if obj is not None:
col.prop(obj, 'myFloat', slider=True)

#floatproperty
bpy.types.Object.myFloat = FloatProperty(
name = "locationZ",
description = "Set the location on local z axis",
min = -100,
max = 100,
soft_min=-10,
soft_max=10,
step=1,
subtype='DISTANCE',
get = get_locationZ,
set = set_locationZ)

#Register
def register():
bpy.utils.register_class(VIEW3D_PT_ToolPanel)
#Unregister
def unregister():
bpy.utils.unregister_class(VIEW3D_PT_ToolPanel)

if __name__== '__main__':
register()


As a side note the new elementwise @ multiplier works as expected for M @= T For 2.7x found using M = T * M a more reliable option.

• This is what i want. Thank you so much!!! – aura Mar 31 at 12:18
• Thankyou. Changed it up a bit such that a global value can be used on value to move value times a unit global vector in the z local axis direction. See revisions for older version blender.stackexchange.com/posts/135801/revisions Good questions are appreciated too! – batFINGER Mar 31 at 12:47