Alternative to WorldToScreen?

Moho allows users to write new tools and plugins. Discuss scripting ideas and problems here.

Moderators: Víctor Paredes, Belgarath, slowtiger

User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Alternative to WorldToScreen?

Post by Rai López »

Hi. I'm trying to get a point always follow the exact position of another point in a different layer no matter what layer (or camera) transformations have been applied, IOW, like if they where "joined" across space, but since I need it to work from an embedded script I've no way to access functions like i.e. "LM_Graphics:WorldToScreen(pt, where)", due to as you know embedded scripts can not get access to any function dependent on view/LM_Graphics.

I think this is one of those things that would be super easy to solve if it weren't for that, but trying to figure out how it could be done by kind of inverse engineering and dealing with all the possible matrix transformations instead simply blows my head...

So to start with... does someone here think that is even possible? Or should I better try to get it out of my head? :roll: Well, thanks in advance for any help.
...
User avatar
hayasidist
Posts: 3525
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Alternative to WorldToScreen?

Post by hayasidist »

just to make sure I understand what you're asking...
for example:
layer 1 is not transformed in any way, and has a point at {0,0}
layer 2 is shifted to be at {-.6, -.3} so to be visually coincident with the layer 1 point, it would have to have a point at {.6, .3}

to generalise, then, in (say) layer 2 you want a layerscript that will find the layer 1 reference point(s) and shift layer 2's point(s) so they line up taking into account the layer transforms.

is that the idea?
User avatar
synthsin75
Posts: 9975
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Alternative to WorldToScreen?

Post by synthsin75 »

Doesn't account for layer z-depth and doesn't stay aligned with XY rotation:

Code: Select all

function LayerScript(moho)
	local layer, layer2 = moho:LayerAsVector(moho.layer), moho:LayerAsVector(moho.document:Layer(0))
	local mesh, mesh2 = layer:Mesh(), layer2:Mesh()
   
	local layerGlobal = AE_GetGlobalLayerMatrix(moho, layer, moho.frame)
	local pt = mesh:Point(0)
	local pt2 = mesh2:Point(0)
	pt2.fPos = pt.fPos
	layerGlobal:Transform(pt2.fPos)
end

-- **************************************************
-- Alexandra Evseeva @ http://ae.revival.ru/
-- http://www.lostmarble.com/forum/viewtopic.php?p=196232#p196232
-- http://mohoscripts.com/script/ae_utilities
-- **************************************************
function AE_GetGlobalLayerMatrix(moho, layer, frame) 
	local prevMatrix = LM.Matrix:new_local()
	prevMatrix:Identity()
	local nextLayer = layer
	repeat
		local prevLayer = nextLayer
		local matrix = LM.Matrix:new_local()
		nextLayer:GetLayerTransform(frame, matrix, moho.document)
		matrix:Multiply(prevMatrix)
		prevMatrix:Set(matrix)
		if nextLayer:Parent() then nextLayer = nextLayer:Parent() end
	until nextLayer == prevLayer
	local cameraMatrix = LM.Matrix:new_local()
	moho.document:GetCameraMatrix(frame, cameraMatrix)
	cameraMatrix:Invert()
	cameraMatrix:Multiply(prevMatrix)
	return cameraMatrix
end
-- **************************************************
Testing with more than one point:

Code: Select all

	local layer, layer2 = moho:LayerAsVector(moho.layer), moho:LayerAsVector(moho.document:Layer(0))
	local mesh, mesh2 = layer:Mesh(), layer2:Mesh()
	
	for i = 0, 1 do
		local layerGlobal = AE_GetGlobalLayerMatrix(moho, layer, moho.frame)
		local pt = mesh:Point(i)
		local pt2 = mesh2:Point(i)
		pt2.fPos = pt.fPos
		layerGlobal:Transform(pt2.fPos)
	end
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: Alternative to WorldToScreen?

Post by Rai López »

Thanks for the responses, guys. I'll try to clarify as much as much as I can with words, but I think/hope the testing file be more eloquent...
hayasidist wrote: Mon Jan 10, 2022 9:57 pm layer 1 is not transformed in any way, and has a point at {0,0}
Well, if that assumption was for simplifying reasons I think I understand, but Layer 1 (o master layer) would be indeed transformed in almost all ways, and points would be at any point (although, for the use I have in mind at least, not too far from layer's Origin).
hayasidist wrote: Mon Jan 10, 2022 9:57 pm layer 2 is shifted to be at {-.6, -.3} so to be visually coincident with the layer 1 point, it would have to have a point at {.6, .3}
Yes, but I think what is causing the gaps when layer/camera transformations take place is preciselly the fact that the affected points are indeed not at [0, 0]. I mean, it seems easy to get the layer's Origin full matrix transformation, but as soon as you try to apply it to a displaced point's position is where things seems to start mismatching if there are any camera or layer transforms.

synthsin75 wrote: Mon Jan 10, 2022 11:03 pm Doesn't account for layer z-depth and doesn't stay aligned with XY rotation:
I do need z-depth and (very specially) XY rotation, but thanks. Indeed I already tried to study some of the A.Evseeva scripts, but I admit they exceed my matrices understanding among other things... Although thanks to it and some trial an error I got a very basic starting point:
It relays on Layer's and Point's IDs, and only works over one point (left side of the neck) for simplicity and quick testing, the idea is to work over named point groups for easy setup and flexibility, but all that would come later. Well, as you can see by playing (or directly manipulating XY rotation of HEAD layer for example), as long as there are no camera or layer transforms (frame 0 to 50) the slave point follows master point as expected and without gaps (there is a little Line Width mismatching but that's another issue), but as soon as camera or layer is translated (so 3D perspective comes into play) the slave point doesn't remain "joined" anymore... I've been tryin to apply camera matrix in different ways without success yet, but I'm afraid even I got counteract camera displacements, I would still get gaps due to layer transformations, and very specially XY rotations. But, OTOH, something tells me that there must be a way to get a certain vector position in a layer and subtract every layer and/or camera transformation since there is access to all the involved matrices after all, isn't it? Or maybe a way to somehow fake the longed WorldToScreen/ScreenToWorld methods? Who knows... but, well, I hope so :roll:
Last edited by Rai López on Tue Jan 11, 2022 2:42 am, edited 1 time in total.
...
User avatar
synthsin75
Posts: 9975
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Alternative to WorldToScreen?

Post by synthsin75 »

I think I've suggested MohoView:Point2Vec(where, layerM) as an alternative to WorldToScreen before. Don't know if it would help in this instance, off hand.


EDIT: No, doesn't look like layerscripts have access to moho.view.
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: Alternative to WorldToScreen?

Post by Rai López »

synthsin75 wrote: Tue Jan 11, 2022 2:42 am I think I've suggested MohoView:Point2Vec(where, layerM) as an alternative to WorldToScreen before. Don't know if it would help in this instance, off hand.
I thought about that at some point, too... but sadly we would be in the same, since it depends on LM_Graphics/MohoView as well :cry:

EDIT: Yeah... Clearly, the best outcome here is we could have access to moho.view from embedded scripts (an old dream), but that's how things are...
...
User avatar
synthsin75
Posts: 9975
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Alternative to WorldToScreen?

Post by synthsin75 »

Not perfect, but this almost handles XY rotation:

Code: Select all

function LayerScript(moho, view)
	local layer, layer2 = moho:LayerAsVector(moho.layer), moho:LayerAsVector(moho.document:Layer(0))
	local mesh, mesh2 = layer:Mesh(), layer2:Mesh()
	
	local rotX = layer.fRotationX
	local rotY = layer.fRotationY
	
	for i = 0, 1 do
		local layerGlobal = AE_GetGlobalLayerMatrix(moho, layer, moho.frame)
		local pt = mesh:Point(i)
		local pt2 = mesh2:Point(i)
		pt2.fPos = pt.fPos
		
		layerGlobal:Rotate(0, rotX)
		layerGlobal:Rotate(1, rotY)
		
		layerGlobal:Transform(pt2.fPos)
	end
end
User avatar
synthsin75
Posts: 9975
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Alternative to WorldToScreen?

Post by synthsin75 »

But if you remove the camera matrix, it also handles z-translation:

Code: Select all

function LayerScript(moho, view)
	local layer, layer2 = moho:LayerAsVector(moho.layer), moho:LayerAsVector(moho.document:Layer(0))
	local mesh, mesh2 = layer:Mesh(), layer2:Mesh()
	
	local rotX = layer.fRotationX
	local rotY = layer.fRotationY
	
	for i = 0, 1 do
		local layerGlobal = AE_GetGlobalLayerMatrix(moho, layer, moho.frame)
		local pt = mesh:Point(i)
		local pt2 = mesh2:Point(i)
		pt2.fPos = pt.fPos
		
		--layerGlobal:Rotate(0, rotX)
		--layerGlobal:Rotate(1, rotY)
		
		layerGlobal:Transform(pt2.fPos)
	end
end

-- **************************************************
-- Alexandra Evseeva @ http://ae.revival.ru/
-- http://www.lostmarble.com/forum/viewtopic.php?p=196232#p196232
-- http://mohoscripts.com/script/ae_utilities
-- **************************************************
function AE_GetGlobalLayerMatrix(moho, layer, frame) 
	local prevMatrix = LM.Matrix:new_local()
	prevMatrix:Identity()
	local nextLayer = layer
	repeat
		local prevLayer = nextLayer
		local matrix = LM.Matrix:new_local()
		nextLayer:GetLayerTransform(frame, matrix, moho.document)
		matrix:Multiply(prevMatrix)
		prevMatrix:Set(matrix)
		if nextLayer:Parent() then nextLayer = nextLayer:Parent() end
	until nextLayer == prevLayer
--[=[
	local cameraMatrix = LM.Matrix:new_local()
	moho.document:GetCameraMatrix(frame, cameraMatrix)
	cameraMatrix:Invert()
	cameraMatrix:Multiply(prevMatrix)
	return cameraMatrix
--]=]
	return prevMatrix
end
-- **************************************************
Removing the camera matrix also makes XY rotation accurate. :D

EDIT: Don't need to append the x and y rotations without the camera matrix.
Last edited by synthsin75 on Tue Jan 11, 2022 4:06 am, edited 1 time in total.
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: Alternative to WorldToScreen?

Post by Rai López »

synthsin75 wrote: Tue Jan 11, 2022 3:05 am Not perfect, but this almost handles XY rotation:
Hmm... So do you think not all the transformations can be obtained by means of involved transformation matrices? I also started to have my doubts abou that, but I hoped not have to deal with separated values because matices sounded to me like the most straightforward and precise way... But anyway I'll take a look to it tomorrow, of course. Thanks!
...
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: Alternative to WorldToScreen?

Post by Rai López »

synthsin75 wrote: Tue Jan 11, 2022 3:32 am Removing the camera matrix also makes XY rotation accurate. :D
Crossed post... Really?? Then really I can't wait to try it out tomorrow and see! Thanks (THANKS) again!
...
User avatar
synthsin75
Posts: 9975
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Alternative to WorldToScreen?

Post by synthsin75 »

Yeah, it works perfectly for z-translation, XY rotation, and layer shear, but the downside is that it breaks with any camera animation.
Don't know if that can be done as well.
User avatar
synthsin75
Posts: 9975
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Alternative to WorldToScreen?

Post by synthsin75 »

Way simpler version of the above:

Code: Select all

function LayerScript(moho)
	local doc = moho.document
	local layer, layer2 = moho:LayerAsVector(moho.layer), moho:LayerAsVector(moho.document:Layer(0))
	local mesh, mesh2 = layer:Mesh(), layer2:Mesh()
	
	for i = 0, 1 do
		local pt = mesh:Point(i)
		local pt2 = mesh2:Point(i)
		pt2.fPos = pt.fPos
		
		local matrix = LM.Matrix:new_local()
		layer:GetFullTransform(moho.frame, matrix, doc)
		matrix:Transform(pt2.fPos)
	end
end
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: Alternative to WorldToScreen?

Post by Rai López »

Hi again! I've tried the three versions but, sadly, none of them seem to work to me as soon as any camera OR layer translations take place... It's easy to see this by means of the testing Moho file from my first post if you put A.Evseeva's function first of all and simply change these lines of your codes:

Code: Select all

	local layer, layer2 = moho.document:LayerByAbsoluteID(4), moho.document:LayerByAbsoluteID(2)
	local mesh, mesh2 = moho:LayerAsVector(layer):Mesh(), moho:LayerAsVector(layer2):Mesh()
	
	local rotX = layer:Parent().fRotationX
	local rotY = layer:Parent().fRotationY
	
	for i = 1, 1 do

I hope I'm not missing something, but I always get some kind of different point position mismatching from frame 50 on if I try, for example, this:

Code: Select all

function LayerScript(moho)
-- **************************************************
-- Alexandra Evseeva @ http://ae.revival.ru/
-- http://www.lostmarble.com/forum/viewtopic.php?p=196232#p196232
-- http://mohoscripts.com/script/ae_utilities
-- **************************************************
	function AE_GetGlobalLayerMatrix(moho, layer, frame) 
		local prevMatrix = LM.Matrix:new_local()
		prevMatrix:Identity()
		local nextLayer = layer
		repeat
			local prevLayer = nextLayer
			local matrix = LM.Matrix:new_local()
			nextLayer:GetLayerTransform(frame, matrix, moho.document)
			matrix:Multiply(prevMatrix)
			prevMatrix:Set(matrix)
			if nextLayer:Parent() then nextLayer = nextLayer:Parent() end
		until nextLayer == prevLayer
	--[=[
		local cameraMatrix = LM.Matrix:new_local()
		moho.document:GetCameraMatrix(frame, cameraMatrix)
		cameraMatrix:Invert()
		cameraMatrix:Multiply(prevMatrix)
		return cameraMatrix
	--]=]
		return prevMatrix
	end
-- **************************************************
	local layer, layer2 = moho.document:LayerByAbsoluteID(4), moho.document:LayerByAbsoluteID(2)
	local mesh, mesh2 = moho:LayerAsVector(layer):Mesh(), moho:LayerAsVector(layer2):Mesh()
	
	local rotX = layer:Parent().fRotationX
	local rotY = layer:Parent().fRotationY
	
	for i = 1, 1 do
		local layerGlobal = AE_GetGlobalLayerMatrix(moho, layer, moho.frame)
		local pt = mesh:Point(i)
		local pt2 = mesh2:Point(i)
		pt2.fPos = pt.fPos
		
		--layerGlobal:Rotate(0, rotX)
		--layerGlobal:Rotate(1, rotY)
		
		layerGlobal:Transform(pt2.fPos)
	end
end

No matter if I uncomment and return from the function cameraMatrix instead prevMatrix or both, multiply them or whatever... I'm starting to think all this could be (even) trickier than expected and I wonder if shouldn't I start thinking another approaches? But to can turn the page, it's important to me try to use up all the bullets this way before ruling out because in theory (if it worked) it would bring the most perfect results under all circumstances, so for now I think I'll continue trial-and-erroring a little more with all these ma(d)trices thing :roll:
Last edited by Rai López on Tue Jan 11, 2022 3:20 pm, edited 1 time in total.
...
User avatar
hayasidist
Posts: 3525
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Alternative to WorldToScreen?

Post by hayasidist »

Take a look at this:

http://www.lostmarble.com/forum/viewtop ... 9&p=180070

My "bake vector" script takes all the points in a vector layer and applies all the transforms to them so that the resulting position is as though there were no transforms - i.e. all the layer / bone / camera actions are wiped out but the points are left VISUALLY where they were. (see "local function bakeVector" in the .LUA)

to do this, I convert the vec2 that is fPos to a vec3 - and its the vec3 that needs to be the subject of the matrix transform - which is then converted back to a vec2 using some fairly straightforward maths to project the vec3 onto the plane that is the vector layer.

===

I have not gone any further than thinking about what I'm about to describe, so please treat it as me thinking out loud...

What is, I think, needed is as you've done - to find the "difference" between the master and slave transform matrices and use that where I've used just the layer transform.

And, just in case you're not aware, matrix multiplication is not commutative - IOW A:Mult(B) is not the same as B:Mult(A)

The bottom line of all that is that I'm not sure whether the matrix you want is

Slave:Invert()
Slave:Mult(Master)

or

Master:Invert
Master:Mult(Slave)

or

Slave:Invert()
Master:Mult(Slave)

or

Master:Invert
Slave:Mult(Master)

==

hope that is at least stepping forward....
User avatar
Rai López
Posts: 2243
Joined: Sun Aug 08, 2004 1:41 pm
Location: Spain
Contact:

Re: Alternative to WorldToScreen?

Post by Rai López »

This all sounds very interesting, hayasidist! At some point passed through my mind try to somehow include vec3 into the equation, but I didn't now even where to start off, so I'll study your script as soon as possible and see...
hayasidist wrote: Tue Jan 11, 2022 3:19 pm And, just in case you're not aware, matrix multiplication is not commutative - IOW A:Mult(B) is not the same as B:Mult(A)
Yeah, I think I kinda imagined that, but I must admit for all the other things I have to play trial and error almost all the time because matrix interaction concepts are beyond my capabilities (I got kind of used to it when I worked on some tools that drew a lot of widgets in viewport, but that simply was too long ago...), I mean, for example, I use :Invert() and :Multiply() because I imagine it's the way to counteract upper/inner layer transformations to avoid unwanted feedbacks, but I'm not totally sure about the involved math and what it really does under the hood (OK: IHaveNoIdeaWhatI'mDoingDogWithTie.jpg) :oops:

hayasidist wrote: Tue Jan 11, 2022 3:19 pm What is, I think, needed is as you've done - to find the "difference" between the master and slave transform matrices and use that where I've used just the layer transform.
Yeah, I think try to use that "difference" and get they somehow cancel each other, is more or less what I've always had in mind about this subject, but not taking into account real point's position in vec3 well could be the key of getting unwanted point translations when they are not at [0, 0]. So let's see what I can get once/if I'm able to apply all this... Thanks!
...
Post Reply