ZBrushCentral

Human readable canvas stroke

I don’t suppose there’s anyway to reverse the canvas stroke recordings to something human readable?

[CanvasStroke,(ZObjStrokeV02n82=YH36CV1B3p23H36CV1B4p2CH371V1C7p4CH372V1CAp50H373V1CEp53H375V1D2p57H376V1D6p5AH377V1DBp5EH378V1E0p62H379V1E4p66H37BV1EAp69H37CV1EFp6CH37EV1F5p6FH37FV1FAp73H381V200p78H383V206p7DH385V20Cp81H387V212p85H38AV218p8AH38CV21Ep8DH38FV224p90H392V229p94H395V22Fp97H397V235p99H39AV23Bp9CH39DV241p9DH3A0V247p9EH3A2V24Dp9FXH3A5V252YH3A8V258pA1XH3ACV25DYH3AFV263pA3H3B2V268pA5H3B5V26DpA6H3B8V272pA8H3BCV276pA9H3BFV27BpABH3C2V280pACH3C5V284pADH3C9V289pAEXH3CCV28DYH3CFV292pADXH3D2V296YH3D5V29ApACXH3D9V29EH3DCV2A2YH3DFV2A6pABH3E2V2A9pACXH3E5V2ADH3E8V2B0H3EAV2B3H3EDV2B6YH3EFV2B8pADH3F1V2BApAEXH3F3V2BCYH3F4V2BEpAFXH3F6V2C0YH3F7V2C2pB0H3F8V2C3pB1XH3F8V2C5YH3F9V2C6pB2H3FAV2C8pB3H3FBV2C9pB4H3FBV2CApB5XH3FCV2CCH3FCV2CDYH3FCV2CEpB6XH3FDV2CFH3FDV2D0H3FDV2D1H3FDV2D2YH3FEV2D4pB7H3FEV2D5pB8
H3FEV2D6pB9XH3FEV2D7YH3FEV2D8pBAXH3FEV2D9YH3FEV2DApBBH3FEV2D9pB9H3FEV2D7p88H3FEV2D4PXH3FEV2D4)]

to

[CanvasStroke,(x1, y1, x2, y2)]

and
where x1, y1 and x2, y2 are the start and end of a stroke, ignoring pen pressure and direction for now.

Yes, Strokes can be “decipher”… and actually I did at some point. Sadly I lost most of my notes in a recent move but I think I can remember most of it. This is how I was able to write strokes that react to the terrain for the TerrainTools plugin.
Essentially Strokes have a header (ZObjStrokeV02), the number of points (n=82), and then the Horizontal and Vertical coordinates in hexadecimal for each point; they also store pressure information but this is optional… Strokes also record when you press ALT, SHIFT, CONTROL. It wasn’t too complicated to figure out but it would be great if it would be properly documented.

CanvasStroke isn’t as powerful as using Strokes encoded in the ZobjStrokev02 way and it has a length limitation… also CanvasStroke was a bit buggy if I remember correctly(?). I do remember trying to use it but decided to go for the more complicated path so there must be a reason.

Why exactly do you need to translate ZobjStrokes to CanvasStroke? if you just need the start and end points then you could write a script that
1- writes the stroke to a file.
2- parses the file to get the first and the last point coordinates.
3- convert them from hexadecimal and store them as a variable you can use for CanvasStroke.

If you just want to be able to read it yourself then find the first H, in your example 36C, in decimal 876. So Horizonal coordinate x1=876… then the first V (1b3), convert it to decimal (y1=435). do the same for the last H and V and you get x2=1022 and y2=724 .

I’ll add something about this to the online docs. I’ll also post a zscript here in a day or two that might help. In the meantime, this information was originally from Pixolator:

The information that is contained within a ZObjStroke is the H,V position of the mouse as well as tablet pressure and key press. In order to use the stroke command, you do not need to know how to actually enter the stroke data points, you simply allow ZBrush to record your brush strokes and ZBrush will create the appropriate stroke command. If, however, you do want to get better understanding of the stroke command, here is a brief explanation…

*(ZobjStroke: specifies that the following is a ZBrush stroke data
*V02n2: Specifies a version 02 stroke data with 2 data points

  • H followed by a number is the H position of the cursor. value is integer and in Hex format

  • h followed by a number is the H position of the cursor. value is 2 digits* integer and 2 digits fraction in Hex format

  • V and v are similar to the H and h and are specifying the V position

  • P = Full pressure

  • p= 2 digits hex pressure value (0x00 to 0xff)

  • K is for keypress values:

    K (no value) = no keys pressed (only appears when keys have been used) K1 = Shift K2 = Ctrl K3 = Shift+Ctrl K4 = Alt K5 = Shift+Alt K6 = Ctrl+Alt K7 = Shift+Ctrl+Alt

*I think this is probably now out-of-date and should be up to 4 digits, with two remaining for the fraction part.

A note about converting the fraction part. Each digit is treated separately, the first is 16ths and the second is 256ths. So, for example:

for a Hex value of 8F

Hex 8= decimal 8
8 divided by 16 = 0.5
Hex F = decimal 15
15 divided by 256 = 0.05859375
Adding two results together gives the final fraction = 0.55859375

Thanks fellas, that makes perfect sense. However, what does the first character Y actually do?

I’ve delineated it here with comma spaces

ZObjStrokeV02, n82 = Y, H36C, V1B3, p23, H36C, V1B4, p2C …

It looks like Y indicates a change in tablet pressure or keypress.

If both pressure and keypress are changed then Z is used.

X , which will follow a changed value, indicates that for the current point and those following, the pressure or the keypress remain the same as the previous point, so no values are included for those points.

I’ve seen a keypress change not preceded by Y or Z, so treat this explanation with caution!

OK, I looked into a command I’d forgotten about - [StrokeGetInfo]. This provides a whole lot of information from a Stroke. For example, you can get the point count of the last Stroke like this:

[StrokeGetInfo,[StrokeGetLast],0]

Attached is a zscript that will write out all the values to a text file. Instead of using the last Stroke you select a Stroke file from disk, so you need to save one out first using Stroke>Inventory>ExportLast.

The text file it writes to is called “output.txt” and will be written in the same location as the zscript. It will be overwritten if you choose another Stroke file, so rename the file first if you want to keep it!

For each point the end value K= is the Keypress. This value is recorded for each point as a modifier key can be depressed during a Stroke (for example Shift when snapping to vertical). The values are 256 = Shift, 512 = Ctrl, 1024 = Alt, with the values added together for combinations.

P= is pressure. This value is normalized from 256 levels, so a value of 0.171875 is equal to level 44 and a value of 1 will indicate full pressure.

Note: you’ll see that [StrokeLoad,fileName] is used repeatedly. It has to be done this way because a zscript string variable can only hold a maximum of 255 characters which would not be enough for most brush strokes. However, I think ZBrush actually only loads the stroke once, and keeps it in memory until the next StrokeLoad has a different file name. So there is no additional overhead writing the code this way. But this is something to be aware of if you write code that repeatedly saves a stroke to the same file name, because StrokeLoad won’t update.

Get_Stroke_Info.txt (3.47 KB)

Have fun!Get_Stroke_Info.txt (3.47 KB)

Very nice, Thanks Marcus.

You’re welcome, dargelos! And yes, [CanvasStroke] is a bit buggy, I think. I tend to use [IClick,1004,…] instead.