2
$\begingroup$

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. enter image description here

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

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.

Thank you in advance!

$\endgroup$
  • $\begingroup$ 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 $\endgroup$ – batFINGER Mar 31 at 10:49
  • $\begingroup$ 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. $\endgroup$ – aura Mar 31 at 10:54
1
$\begingroup$

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)

enter image description here 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.

$\endgroup$
  • $\begingroup$ This is what i want. Thank you so much!!! $\endgroup$ – aura Mar 31 at 12:18
  • $\begingroup$ 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! $\endgroup$ – batFINGER Mar 31 at 12:47

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.