Chanc opened this issue on Apr 11, 2020 ยท 40 posts
an0malaus posted Mon, 13 April 2020 at 5:13 AM
Just an observation on Point At, the pointAt dials can themselves be controlled by valueOperations (ERC) and will take intermediate settings between 0 and 1, where they act accordingly: at 0, rotation dials are in full control, at 0.5, rotation and pointAt have equal, reduced influence, and at 1.0, pointAt operates along.
The PointAt feature really is missing some required functionality, as in actually adding its influence to the actor's rotation dials, as though it were another form of ERC/valueOperation. In such a scenario, pointAt strength could then be dialled back when an eyeball reaches the end of its rotation limits (if applied).
I've used a similar pointAt operation to simulate gravity, by having a magnet rotate a ponytail or hair part and point at a nadir prop set at 0, -maxint, 0. The difficulty is imposing limits on pointAt, so I used a python callback instead, to extract the Euler angles and apply them to set rotation keyframes instead. For each frame that needs the gravity/pointAt effect, the script will set rotations, then when completed, Another script will kill the callback and the dial rotations take sole effect.
Save this as .py in the same folder as the hair prop .pp2 file
# HamptonGravity.py
# (c) 2018-2020 Geoff Hicks (an0malaus|GeoffIX|gwhicks)
#
# Callback function to apply gravity to HamptonHair prop.
# Pitch is applied to CTRLSwing.
# Roll is applied to CTRLSway.
# Script should be co-located with the Hair Prop.
#
# v1.0 20181101 Initial version based on ParisHairGravity.py v1.1
# Added kEventCodeACTORSELECTIONCHANGED and kEventCodePARMCHANGED to watchCode
# Look a bit harder for the 'HamptonHair' prop, in case it's parented to the current figure, but not
# actually selected.
# v1.1 20190114 Add copysign to math module explicit imports
# v1.2 20200408 Added Side and Back deformers and overall Control parameters to HamptonHair instead of just Bangs.
########################################################################################################################
version = '1.2'
debug = False
pitchParmName = 'CTRLSwing'#'CTRLBangsSwing'
rollParmName = 'CTRLSway'#'CTRLBangsSway'
import poser
from math import atan2, asin, degrees, copysign
def getAngle( actor, bScale ):
WM = actor.WorldMatrix()
## Define required cells of matrix. Note: bScale is propagating scale of the figure to which the prop is parented.
WM12 = WM[0][1]/bScale
WM22 = WM[1][1]/bScale
WM31 = WM[2][0]/bScale
WM32 = WM[2][1]/bScale
WM33 = WM[2][2]/bScale
if abs( WM32 ) > 1.0: # Out of [ -1 .. +1 ] range for arcsine, so crop to valid range
if debug:
print 'WARNING: WM32 out of valid arcsine range [-1..1] ({})'.format( WM32 )
WM32 = copysign( 1.0, WM32 )
AngleX = degrees( asin( WM32*-1 ) )
AngleY = degrees( atan2( WM31, WM33 ) )
AngleZ = degrees( atan2( WM12, WM22 ) )
if debug:
print 'Euler Angles {}, {}, {}'.format( AngleX, AngleY, AngleZ )
return ( AngleX, AngleY, AngleZ )
def HamptonActor():
actor = poser.Scene().CurrentActor()
if actor:
if actor.IsProp() and 'Hampton' in actor.Name():
return actor
else:
figure = actor.ItsFigure()
if figure:
for actor in figure.Actors():
if actor.IsProp() and 'Hampton' in actor.Name():
break
else:
return None
else:
return None
return actor
def HamptonUpdate():
scene = poser.Scene()
actor = HamptonActor()
if not actor:
return
pitch = actor.Parameter( pitchParmName )
roll = actor.Parameter( rollParmName )
if not ( pitch and roll ):
return
bScale = 1.0
figure = actor.ItsFigure()
if figure:
body = figure.RootActor()
if body:
bScaleParm = body.ParameterByCode( poser.kParmCodeASCALE )
if bScaleParm:
bScale = bScaleParm.Value()
( aX, aY, aZ ) = getAngle( actor, bScale ) # We only care about the pitch (aX) and roll (aZ)
newPitch = -aX
newRoll = -aZ
needDraw = False
if pitch.Value() != newPitch:
pitch.SetValue( newPitch )
needDraw = True
if roll.Value() != newRoll:
roll.SetValue( newRoll )
needDraw = True
if needDraw:
scene.DrawAll()
scene = poser.Scene()
watchCode = poser.kEventCodeKEYSCHANGED | poser.kEventCodePARMCHANGED | poser.kEventCodeACTORSELECTIONCHANGED
def HamptonCallback( iScene, iEventType ):
if ( iEventType & watchCode ) != 0:
HamptonUpdate()
scene.SetEventCallback( HamptonCallback )
### END ###
You can replicate this for any hair prop with a magnet set to move a ponytail, or even an eye/multiple eyes simply by adjusting which parameters get the Euler angles assigned.
The StopGravityUpdates.py script below stops all callbacks.
# StopGravityUpdates.py
# (c) 2018 Geoff Hicks (an0malaus|GeoffIX|gwhicks)
#
# Clear the Callback function installed by any Hair Gravity scripts.
# This is literally the shortest Poser Python Script I have ever written!
#
# v1.0 20180926 Initial version to match ParisHairGravity.py
########################################################################################################################
version = '1.0'
debug = False
import poser
poser.Scene().ClearEventCallback()
### END ###
Verbosity: Profusely promulgating Graham's number epics of complete and utter verbiage by the metric monkey barrel.