Get top left screen position of layer with ScreenToWorld ?

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

Moderators: Víctor Paredes, Belgarath, slowtiger

Post Reply
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Get top left screen position of layer with ScreenToWorld ?

Post by Lukas »

Does anyone have a clue how to get the position on a layer of the top left screen pixel of the viewport?

I've tried lots of things but can't figure it out. Especially when the camera is tracked on the Z axis it's getting very complicated.

Code: Select all

TopLeftVector2 = LM.Vector2:new()
local graphics = view:Graphics()
local pt = LM.Point:new_local()
pt:Set(0, 0)
graphics:ScreenToWorld(pt, TopLeftVector2)
-- ??????
matrix:Transform(TopLeftVector2)
User avatar
SimplSam
Posts: 1060
Joined: Thu Mar 13, 2014 5:09 pm
Location: London, UK
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by SimplSam »

I started to answer this twice and stopped (twice) because I figured out - I don't actually understand the question.

Subject says:: "Get top left screen position of layer with ScreenToWorld ?"
- That suggests you want the vector screen position of the top,left corner of a Layer.

Body says:: "Get the position on a layer of the top left screen pixel of the viewport?"
- That suggests you want the position (not sure pix or vec?) of the top,left corner of the screen viewport relative to a layer.

Can you clarify?
Moho 14.1 » Win 11 Pro 64GB » NVIDIA GTX 1080ti 11GB
Moho 14.1 » Mac mini 2012 8GB » macOS 10.15 Catalina
Tube: SimplSam


Sam
User avatar
synthsin75
Posts: 10007
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by synthsin75 »

You might check out how Stan does it in this tool: http://mohoscripts.com/script/lm_transf ... r_modified
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by Lukas »

SimplSam wrote: Tue Oct 26, 2021 4:12 pmCan you clarify?
Ah sorry, it's difficult to express myself with all these technical things that I don't completely understand myself.

Basically what I'm trying to do is set a bone's position to the top-left of the screen, independent of viewport/camera/layer position.

Here's some code, which is probably doing things weirdly/inefficient/completely the wrong approach. It works in some situations, but not when the camera is placed in specific ways. I'm running the function from within "DrawMe" and the 'guiBone' is a global bone variable.

Code: Select all

function FO_Draw:DockGUIbone(moho, view)
	if guiBone ~= nil then
		-- * Fix GUI-bone settings:
		guiBone.fConstraints = false
		-- * Get layer:
		local layer = FO_Utilities:RigLayer(moho)
		-- * Get top left position:
		TopLeftVector2 = LM.Vector2:new()
		local graphics = view:Graphics()
		local pt = LM.Point:new_local()
		pt:Set(0, 0)
		graphics:ScreenToWorld(pt, TopLeftVector2)
		-- * Flip GUI bone if nessecary:
		local flippedH = false
		local flipLayer = layer
		local timesFlipped = 0
		local totalXScale = 1
		while flipLayer ~= nil do
			totalXScale = totalXScale * flipLayer.fScale.value.x
			if flipLayer.fFlipH:GetValue(moho.frame) or flipLayer.fScale.value.x < 0 then
				timesFlipped = timesFlipped + 1
			end
			flipLayer = flipLayer:Parent()
		end
		if totalXScale < 0 then
			totalXScale = totalXScale * -1
		end
		guiBone.fFlipH:Clear()
		if (timesFlipped % 2 ~= 0) then
    		-- * Flipped an odd amount fo times
			guiBone.fFlipH:SetValue(1, true)
		end
		-- * Get View rotation:
		local viewRotation = graphics:ViewRotation()
		-- * Get View zoom:
		local viewZoom = graphics:ViewZoom()
		-- * Get Camera zoom:
		local cameraZoom = (moho.document.fCameraTrack:GetValue(moho.frame).z / 3.7321) / (moho.document.fCameraZoom:GetValue(moho.frame) / 2)
		-- * Layer matrix without camera: (write down why...?)
		local matrix = FO_Utilities:LayerMatrix(moho, moho.layer, moho.frame)
		matrix:Invert()
		-- * Camera Matrix: (Doesn't work for Z value or zoom?)
		local cameraMatrix = LM.Matrix:new_local()
		moho.document:GetCameraMatrix(moho.frame, cameraMatrix)
		local cameraScale = cameraMatrix:ScaleValue()

		-- * What the hell was I thinking here?
		-- *********************
		-- * Remember:
		local camT = moho.document.fCameraTrack:GetValue(0)
		local camZ = moho.document.fCameraZoom:GetValue(0)
		local camR = moho.document.fCameraRoll:GetValue(0)
		local camP = moho.document.fCameraPanTilt:GetValue(0)
		-- * Reset:
		local vec3 = LM.Vector3:new()
		vec3:Set(0, 0, 3.7321)
		moho.document.fCameraTrack:SetValue(0, vec3)
		moho.document.fCameraZoom:SetValue(0, 2)
		local vec2 = LM.Vector2:new()
		vec2:Set(0, 0)
		moho.document.fCameraRoll:SetValue(0, 0)
		moho.document.fCameraPanTilt:SetValue(0, vec2)
		-- * Get REST camera matrix:
		local cameraRestMatrix = LM.Matrix:new_local()
		moho.document:GetCameraMatrix(0, cameraRestMatrix)
		-- * Revert:
		moho.document.fCameraTrack:SetValue(0, camT)
		moho.document.fCameraZoom:SetValue(0, camZ)
		moho.document.fCameraRoll:SetValue(0, camR)
		moho.document.fCameraPanTilt:SetValue(0, camP)
		-- *********************

		-- * What?
		cameraMatrix:Invert()
		cameraMatrix:Multiply(cameraRestMatrix)
		matrix:Multiply(cameraMatrix)

		-- * Topleft vec2 position:
		matrix:Transform(TopLeftVector2)
		
		-- * Add layer transform rotation to view rotation:
		translation, rotationZ, scale, flip, pString, rString, sString, fString = AE_Utilities:Matrix2transform(matrix)
		if flippedH then
			viewRotation = -viewRotation
		end
		local rotation = viewRotation - rotationZ

		-- * Key GUI-bone position:
		guiBone.fAnimPos:Clear()
		guiBone.fAnimPos:SetValue(1, TopLeftVector2)
		guiBone.fPos = TopLeftVector2
		-- * Key GUI-bone angle:
		guiBone.fAnimAngle:Clear()
		guiBone.fAnimAngle:SetValue(1, -rotation)
		guiBone.fAngle = -rotation
		-- * Key GUI-bone scale:
		local scale = 1/totalXScale / viewZoom/3 * cameraZoom
		guiBone.fAnimScale:Clear()
		guiBone.fAnimScale:SetValue(1, scale)
		-- * Dials:
		--[[
		for i = 1, #smartBoneDials do
			local dial = smartBoneDials[i]
			-- * dial Scale:
			dial.fAnimScale:Clear()
			dial.fAnimScale:SetValue(1, scale*dial.fAnimScale:GetValue(0))
			-- * Dial Pos:
			-- dial.fAnimPos:Clear()
			local dialPos = dial.fAnimPos:GetValue(0)
			dialPos:Set(dialPos.x, dialPos.y * scale)
			dial.fAnimPos:SetValue(1, dialPos)
		end
		--]]
		-- * Update viewport:
		moho.layer:UpdateCurFrame()
	end
end
Here's a video showing the WIP tool. The docked 'guiBone' kind of stays put, but it's because the camera is in the default z-position. (In reality, in my scenes the camera is rarely in the default z-position)


synthsin75 wrote: Tue Oct 26, 2021 5:41 pm You might check out how Stan does it in this tool: http://mohoscripts.com/script/lm_transf ... r_modified
I will look into it, thanks for the tip!
User avatar
synthsin75
Posts: 10007
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by synthsin75 »

Personally, I would go with a solution that's completely independent of the camera. For example, you can make a reference of the smart bone layer, delete the original's sublayers, and set it immune to camera. The original will still control the smart bones in the reference (where the rendered art is), but as long as you break the layer transform sync, you can now place your controls anywhere.

Then it's just a matter of sticking this original bone layer to the workspace, like my dock layers script: http://www.lostmarble.com/forum/viewtopic.php?t=32740
User avatar
hayasidist
Posts: 3557
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Get top left screen position of layer with ScreenToWorld ?

Post by hayasidist »

I looked at this from the opposite direction having failed to get my ideas for the asked question to work.

starting with a mesh point (i.e. M_Point, not LM_Point) in the top left I got the point's fPos and did a world-to-screen on that - and that gave me a crazy result for the screen pixel location; but transforming the fPos with the full document matrix and then doing a world-to-screen on that gave the "right answer". IOW the vec2 you put in to world-to-screen is not the actual "world" vec2 you need... That worked for all the cases I tried - even with the orbit view and multiple camera and layer movements...

so I tried that in reverse: screen-to-world of a point then transform the world result with the inverted document matrix (which is more or less what's in the Transform layer tool that Stan modified) but that didn't work at all.

at this point I decided that I must have been doing something really dumb, so I repeated the concept with the mouse - trying to do a W-T-S on mouseEvent.vec to match mouseEvent.pt -- abject failure on my part!!


===
where I am on this:

what works:
>> W-T-S on a transformed (vec) gives the correct LM Point.
>> S-T-W on that LM Point gives a result that is tolerably equal to the transformed(vec) (+/- quantising because of screen resolution??)

What doesn't want to work: any transformation - most notably using the Invert() of the matrix used to do the transform - that I've tried so far on the transformed vec in an attempt to retrieve the original vec

any ideas?
User avatar
synthsin75
Posts: 10007
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by synthsin75 »

As a very simplified example, try this:

Code: Select all

		local pt = LM.Point:new_local()
		local m = LM.Matrix:new_local()
		m:Identity()
		moho.layer:GetFullTransform(moho.frame, m, moho.document)
		pt:Set(0, 0)
		local vec2 = view:Point2Vec(pt, m)
		mesh:AddLonePoint(vec2, 0)
		mesh:AppendPoint(vec2, 0)
User avatar
hayasidist
Posts: 3557
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Get top left screen position of layer with ScreenToWorld ?

Post by hayasidist »

Point2Vec!! well I never knew that was there -- that's cracked it!

Code: Select all

	local v1 = LM.Vector2:new_local()
	local p1 = LM.Point:new_local()
	local mDoc = LM.Matrix:new_local()
	
	p1:Set(0, 0)
	layer:GetFullTransform(frame, mDoc, doc)
	v1 = view:Point2Vec(p1, mDoc)

which leaves me wondering what purpose ScreenToWorld has?!
User avatar
SimplSam
Posts: 1060
Joined: Thu Mar 13, 2014 5:09 pm
Location: London, UK
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by SimplSam »

Funny thing (due to a earlier typo in your post 'mat') - it looks like it does not even need the matrix transform.

Code: Select all

local p1 = LM.Point:new_local()
p1:Set(0,0)
local v1 = view:Point2Vec(p1)
p.s. I guess ScreenToWorld is when you are drawing on the screen with Graphics - which is independent of Layer transforms and Camera.
Moho 14.1 » Win 11 Pro 64GB » NVIDIA GTX 1080ti 11GB
Moho 14.1 » Mac mini 2012 8GB » macOS 10.15 Catalina
Tube: SimplSam


Sam
User avatar
hayasidist
Posts: 3557
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Get top left screen position of layer with ScreenToWorld ?

Post by hayasidist »

the typo (well spotted BTW!) was because the code is actually gathered from a long sequence of failed attempts - much of which is commented out along with the reason for its failures -- and the intervening stuff I deleted left me with an inconsistent pair of get and use the matrix! (I actually had many different matrices in there - graphics, camera only, layer, doc, inverts ...) a slip of the clip! ;-)
User avatar
Lukas
Posts: 1297
Joined: Fri Apr 09, 2010 9:00 am
Location: Netherlands
Contact:

Re: Get top left screen position of layer with ScreenToWorld ?

Post by Lukas »

Wow, thanks a lot everyone!

I was looking in all the wrong places. I would have never figured that out unless I somehow stumbled upon view:Point2Vec(). It looks like is going to work after all 😳
Post Reply