Răsfoiți Sursa

Sources for new XRComponents for VR (#903)

Signed-off-by: VladimirLagutin <[email protected]>
VladimirLagutin 2 luni în urmă
părinte
comite
b924917e5a

+ 192 - 0
Gems/OpenXRVk/Assets/OpenXRVk/default.xractions

@@ -79,6 +79,198 @@
 							</Class>
 						</Class>
 					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_aim_pose" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Aim Pose" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Aim Pose" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_aim_pose" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Right Aim Pose" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Aim Pose" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_grip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Grip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Squeeze" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_grip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Right Grip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Squeeze" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_trigger" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Trigger" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Trigger Value" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_trigger" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Right Trigger" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Trigger Value" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_button_a" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Button A" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="A Click" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_button_b" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Button B" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="B Click" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_button_menu" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="right_button_menu" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Thumbrest Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_stick_x" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Horizontal Stick" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Thumbstick X" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="right_stick_y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Vertical Stick" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(R)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Thumbstick Y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_button_x" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Button X" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="X Click" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_button_y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Button Y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Y Click" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_button_menu" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Button Menu" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Menu Click" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_stick_x" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Thumbstick X" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Thumbstick X" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
+					<Class name="OpenXRActionDescriptor" field="element" version="1" type="{90BBF6F6-C7D6-4F64-B784-CE03F86DC36B}">
+						<Class name="AZStd::string" field="Name" value="left_stick_y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="LocalizedName" value="Left Thumbstick Y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::string" field="Comment" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+						<Class name="AZStd::vector&lt;OpenXRActionPathDescriptor, allocator&gt;" field="ActionPathDescriptors" type="{6A1AA49C-7A58-5B23-8B25-30B162E65135}">
+							<Class name="OpenXRActionPathDescriptor" field="element" version="1" type="{F25D6382-C9E0-414B-A542-1758F5477D03}">
+								<Class name="AZStd::string" field="InteractionProfile" value="Oculus Touch" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="UserPath" value="(L)" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+								<Class name="AZStd::string" field="ComponentPath" value="Thumbstick Y" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
+							</Class>
+						</Class>
+					</Class>
 				</Class>
 			</Class>
 		</Class>

+ 7 - 1
Gems/OpenXRVk/Code/CMakeLists.txt

@@ -64,6 +64,11 @@ ly_add_target(
             Gem::Atom_RHI_Vulkan.Reflect
             Gem::Atom_RHI_Vulkan.Glad.Static
             Gem::XR.Static
+            Gem::PhysX.Static			
+            Gem::Atom_Feature_Common.Public			
+            Gem::CommonFeaturesAtom.Static
+            Gem::EMotionFXStaticLib
+            Gem::EMotionFX
 )
 
 ly_add_target(
@@ -114,10 +119,11 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
         BUILD_DEPENDENCIES
             PUBLIC
                 AZ::AzCore
-                AZ::AzFramework
                 AZ::AssetBuilderSDK
                 ${openxr_dependency}
                 Gem::${gem_name}.Static
+                Gem::EMotionFXStaticLib
+                Gem::EMotionFX
     )
 
     ly_add_target(

+ 148 - 0
Gems/OpenXRVk/Code/Source/Devices/Common/XRControllerAnimationsComponent.cpp

@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include "XRControllerAnimationsComponent.h"
+
+#include <AzCore/Component/TransformBus.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+
+#include <Integration/ActorComponentBus.h>
+
+#include <Integration/AnimGraphComponentBus.h>
+
+namespace OpenXRVk
+{
+    void XRControllerAnimationsComponent::Reflect(AZ::ReflectContext* context)
+    {
+        XRControllersConfig::Reflect(context);
+
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->RegisterGenericType<XRControllersConfig>();
+
+            serializeContext->Class<XRControllerAnimationsComponent, AZ::Component>()
+                ->Version(1)
+                ->Field("Controller Items config", &XRControllerAnimationsComponent::m_controllersConfig)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<XRControllerAnimationsComponent>("XR Controller Animation", "Provides animations for controls on VR controller")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Category, "XR")
+                    ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
+                    ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &XRControllerAnimationsComponent::m_controllersConfig, "Controller Items config", "Configuration for each item of the controller")
+                    ;
+            }
+        }
+
+        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<XRControllerAnimationsComponent>("XR Component Animation Group")
+                ->Attribute(AZ::Script::Attributes::Category, "OpenXRVk Gem Group")
+                ;
+        }
+    }
+
+    void XRControllerAnimationsComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("XRControllerAnimationService"));
+    }
+
+    void XRControllerAnimationsComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("XRControllerAnimationService"));
+    }
+
+    void XRControllerAnimationsComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        required.push_back(AZ_CRC_CE("TransformService"));
+    }
+
+    void XRControllerAnimationsComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+    }
+
+    void XRControllerAnimationsComponent::Activate()
+    {
+        AZ::TickBus::Handler::BusConnect();
+    }
+
+    void XRControllerAnimationsComponent::Deactivate()
+    {
+        if (AZ::TickBus::Handler::BusIsConnected())
+        {
+            AZ::TickBus::Handler::BusDisconnect();
+        }
+    }
+
+    extern AZ::Transform ReadActionHandlePose(IOpenXRActions* iface, IOpenXRActions::ActionHandle actionHandle);
+    extern float ReadActionHandleFloat(IOpenXRActions* iface, IOpenXRActions::ActionHandle actionHandle, float deadZone);
+
+    void XRControllerAnimationsComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
+    {
+        auto actionsIFace = OpenXRActionsInterface::Get();
+        if (!actionsIFace)
+        {
+            return;
+        }
+
+        for (XRControllersConfig& cfg : m_controllersConfig)
+        {
+            if (!cfg.m_actionHandle.IsValid())
+            {
+                cfg.m_actionHandle = actionsIFace->GetActionHandle("main_action_set", cfg.m_actionName);
+                if (!cfg.m_actionHandle.IsValid())
+                {
+                    continue;
+                }
+            }
+            switch (cfg.m_controlItemType)
+            {
+                case XRControllersConfig::ControlItemType::Boolean:
+                {
+                    auto outcome = actionsIFace->GetActionStateBoolean(cfg.m_actionHandle);
+                    if (outcome.IsSuccess())
+                    {
+                        bool res = outcome.GetValue();
+                        if (res != cfg.m_prevBoolean)
+                        {
+                            EMotionFX::Integration::AnimGraphComponentRequestBus::Event(GetEntityId(), &EMotionFX::Integration::AnimGraphComponentRequestBus::Events::SetNamedParameterBool, cfg.m_animGraphParameter.c_str(), res);
+                            cfg.m_prevBoolean = res;
+                        }
+                    }
+                    break;
+                }
+                case XRControllersConfig::ControlItemType::Float:
+                {
+                    float res = ReadActionHandleFloat(actionsIFace, cfg.m_actionHandle, 0.001f);
+                    if (res != cfg.m_prevFloat)
+                    {
+                        EMotionFX::Integration::AnimGraphComponentRequestBus::Event(GetEntityId(), &EMotionFX::Integration::AnimGraphComponentRequestBus::Events::SetNamedParameterFloat, cfg.m_animGraphParameter.c_str(), res);
+                        cfg.m_prevFloat = res;
+                    }
+                    break;
+                }
+                case XRControllersConfig::ControlItemType::Vector2:
+                {
+                    float res = (ReadActionHandleFloat(actionsIFace, cfg.m_actionHandle, 0.001f) + 1.0f) / 2.0f;
+                    if (res != cfg.m_prevFloat)
+                    {
+                        EMotionFX::Integration::AnimGraphComponentRequestBus::Event(GetEntityId(), &EMotionFX::Integration::AnimGraphComponentRequestBus::Events::SetNamedParameterFloat, cfg.m_animGraphParameter.c_str(), res);
+                        cfg.m_prevFloat = res;
+                    }
+                    break;
+                }
+            }
+        }
+    }
+} // namespace OpenXRVk

+ 48 - 0
Gems/OpenXRVk/Code/Source/Devices/Common/XRControllerAnimationsComponent.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/Component/TickBus.h>
+#include <AzCore/Asset/AssetCommon.h>
+
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+#include "XRControllersConfig.h"
+
+namespace OpenXRVk
+{
+    //! XRControllerAnimationsComponent uses the OpenXRVk::OpenXRActionsInterface to read user input to animate a XR controller.
+    class XRControllerAnimationsComponent
+        : public AZ::Component
+        , public AZ::TickBus::Handler
+    {
+    public:
+        AZ_COMPONENT(XRControllerAnimationsComponent, "{A57B8F98-39A0-4B70-B7F7-2331E62A3276}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+    protected:
+        // AZ::Component
+        void Activate() override;
+        void Deactivate() override;
+
+        // AZ::TickBus::Handler
+        void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
+
+    private:
+        // Serialized data...
+		AZStd::vector<XRControllersConfig> m_controllersConfig;
+    };
+
+} // namespace OpenXRVk

+ 155 - 0
Gems/OpenXRVk/Code/Source/Devices/Common/XRControllerComponent.cpp

@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include "XRControllerComponent.h"
+
+#include <AzCore/Component/TransformBus.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzFramework/Components/CameraBus.h>
+
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+
+#include <AzCore/Math/Color.h>
+
+namespace OpenXRVk
+{
+    void XRControllerComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<XRControllerComponent, AZ::Component>()
+                ->Version(1)
+                ->Field("Label of Pose Label", &XRControllerComponent::m_controllerPoseActionLabel)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<XRControllerComponent>("XR Controller", "Provides movement/orientation of VR controller")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Category, "XR")
+                    ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
+                    ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &XRControllerComponent::m_controllerPoseActionLabel, "Action name of pose", "OpenXRActionsInterface ActionHandle label of pose")
+                    ;
+            }
+        }
+
+        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<XRControllerComponent>("XR Component Group")
+                ->Attribute(AZ::Script::Attributes::Category, "OpenXRVk Gem Group")
+                ;
+        }
+    }
+
+    void XRControllerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("XRControllerMovementService"));
+    }
+
+    void XRControllerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("XRControllerMovementService"));
+    }
+
+    void XRControllerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        required.push_back(AZ_CRC_CE("TransformService"));
+    }
+
+    void XRControllerComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+    }
+
+    void XRControllerComponent::Activate()
+    {
+        Camera::CameraNotificationBus::Handler::BusConnect();
+        AZ::TickBus::Handler::BusConnect();
+    }
+
+    void XRControllerComponent::Deactivate()
+    {
+        if (AZ::TickBus::Handler::BusIsConnected())
+        {
+            AZ::TickBus::Handler::BusDisconnect();
+        }
+        Camera::CameraNotificationBus::Handler::BusDisconnect();
+    }
+
+    void XRControllerComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
+    {
+        if (m_cameraEntity == AZ::EntityId())
+        {
+            return;
+        }
+        ProcessOpenXRActions();
+
+        // Get the camera's transform
+        AZ::Transform cameraTransform;
+        AZ::TransformBus::EventResult(cameraTransform, m_cameraEntity, &AZ::TransformBus::Events::GetWorldTM);
+
+        // Current transform of the controller (in local space relative to the camera)
+        AZ::Transform controllerLocalTransform = m_movement;
+
+        // Convert the controller's local transform to world space by multiplying with the camera's transform
+        // Ensure correct order of multiplication: local transform first, then camera transform
+        AZ::Transform controllerWorldTransform = cameraTransform * controllerLocalTransform;
+
+        // Apply the new world transform to the controller's render object
+        AZ::TransformBus::Event(GetEntityId(), &AZ::TransformBus::Events::SetWorldTM, controllerWorldTransform);
+    }
+
+    static AZ::Transform ReadActionHandlePose(IOpenXRActions* iface, IOpenXRActions::ActionHandle actionHandle)
+    {
+        auto outcome = iface->GetActionStatePose(actionHandle);
+        if (!outcome.IsSuccess())
+        {
+            AZ::Transform value = AZ::Transform::CreateIdentity();
+            value.SetTranslation(AZ::Vector3(-1000, -1000, -1000));
+            // Most likely the controller went to sleep.
+            return value;
+        }
+        AZ::Transform value = outcome.GetValue();
+        if (value.GetTranslation().IsClose(AZ::Vector3::CreateZero()))
+        {
+            // To avoid rendering controllers when the camera is inside of them
+            value.SetTranslation(AZ::Vector3(-1000, -1000, -1000));
+        }
+        return value;
+    }
+
+    void XRControllerComponent::ProcessOpenXRActions()
+    {
+        auto actionsIFace = OpenXRActionsInterface::Get();
+        if (!actionsIFace)
+        {
+            return;
+        }
+
+        if (!m_controllerPoseHandle.IsValid())
+        {
+            // Try to cache all handles.
+            m_controllerPoseHandle = actionsIFace->GetActionHandle("main_action_set", m_controllerPoseActionLabel);
+            if (!m_controllerPoseHandle.IsValid())
+            {
+                // Most likely the Action System failed to load the ActionSets asset.
+                return;
+            }
+        }
+
+        m_movement = ReadActionHandlePose(actionsIFace, m_controllerPoseHandle);
+    }
+
+
+    // Camera::CameraNotificationBus::Handler overrides
+    void XRControllerComponent::OnActiveViewChanged(const AZ::EntityId& activeEntityId)
+    {
+        m_cameraEntity = activeEntityId;
+    }
+} // namespace OpenXRVk

+ 62 - 0
Gems/OpenXRVk/Code/Source/Devices/Common/XRControllerComponent.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/Component/TickBus.h>
+#include <AzFramework/Components/CameraBus.h>
+
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+
+namespace OpenXRVk
+{
+    //! XRControllerComponent uses the OpenXRVk::OpenXRActionsInterface to read user input to control an VR controller.
+    class XRControllerComponent
+        : public AZ::Component
+        , public AZ::TickBus::Handler
+        , public Camera::CameraNotificationBus::Handler
+    {
+    public:
+        AZ_COMPONENT(XRControllerComponent, "{5DA45A04-A900-345C-23DE-23BD03BC3820}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+    protected:
+        // AZ::Component
+        void Activate() override;
+        void Deactivate() override;
+
+        // Camera::CameraNotificationBus::Handler overrides
+        void OnActiveViewChanged(const AZ::EntityId&) override;
+
+        // AZ::TickBus::Handler
+        void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
+
+    private:
+        void ProcessOpenXRActions();
+
+        AZ::EntityId m_cameraEntity;
+
+        // Transient data...
+        AZ::Transform m_movement = AZ::Transform::CreateIdentity();
+
+        // Serialized data...
+        AZStd::string m_controllerPoseActionLabel;
+
+        //! A cache of OpenXRVk Action Handles that provide straight
+        //! access into the user's input.
+        IOpenXRActions::ActionHandle m_controllerPoseHandle;
+    };
+
+} // namespace OpenXRVk

+ 41 - 0
Gems/OpenXRVk/Code/Source/Devices/Common/XRControllersConfig.cpp

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/Json/RegistrationContext.h>
+
+#include "XRControllersConfig.h"
+
+namespace OpenXRVk
+{
+        void XRControllersConfig::Reflect(AZ::ReflectContext* context)
+        {
+            if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+            {
+                serializeContext->Class<XRControllersConfig>()
+                    ->Field("controlItemType", &XRControllersConfig::m_controlItemType)
+                    ->Field("parameterControlLabel", &XRControllersConfig::m_animGraphParameter)
+                    ->Field("controlActionLabel", &XRControllersConfig::m_actionName)
+                ;
+
+                if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+                {
+                    editContext->Class<XRControllersConfig>("XRControllersConfig", "")
+                        ->DataElement(AZ::Edit::UIHandlers::ComboBox, &XRControllersConfig::m_controlItemType, "Type of the item", "Is it button or grip slider or thumbstick")
+                            ->EnumAttribute(XRControllersConfig::ControlItemType::Boolean, "Button (boolean)")
+                            ->EnumAttribute(XRControllersConfig::ControlItemType::Float, "Trigger (float)")
+                            ->EnumAttribute(XRControllersConfig::ControlItemType::Vector2, "Thumbstick (360 degrees)")
+                        ->DataElement(AZ::Edit::UIHandlers::Default, &XRControllersConfig::m_animGraphParameter, "AnimGraph parameter", "Name of parameter that controls an animation of the control item in AnimGraph")
+                        ->DataElement(AZ::Edit::UIHandlers::Default, &XRControllersConfig::m_actionName, "Action name", "OpenXRActionsInterface ActionHandle label")
+                    ;
+                }
+            }
+        }
+
+} // namespace OpenXRVk

+ 45 - 0
Gems/OpenXRVk/Code/Source/Devices/Common/XRControllersConfig.h

@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/RTTI/ReflectContext.h>
+#include <AzCore/std/containers/vector.h>
+#include <AzCore/std/string/string.h>
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+
+namespace OpenXRVk
+{
+	//! Configuration that is used by XRControllerAnimationsComponent to animate an VR controller.
+	struct XRControllersConfig final
+	{
+		enum class ControlItemType : AZ::u32 {
+			Boolean,
+			Float,
+			Vector2
+		};
+
+		AZ_RTTI(XRControllersConfig, "{A32512BD-124A-723B-AA24-214BCD02CCAA}");
+		AZ_CLASS_ALLOCATOR(XRControllersConfig, AZ::SystemAllocator);
+
+		static void Reflect(AZ::ReflectContext* context);
+		
+		// Editor configuration properties
+		ControlItemType m_controlItemType;
+		AZStd::string m_animGraphParameter;
+		AZStd::string m_actionName;
+
+		// Runtime variables
+		IOpenXRActions::ActionHandle m_actionHandle;
+		bool m_prevBoolean = false;
+		float m_prevFloat = 0;
+	};	
+
+} // namespace OpenXRVk

+ 8 - 0
Gems/OpenXRVk/Code/Source/OpenXRVkModule.cpp

@@ -10,6 +10,10 @@
 #include <AzCore/Module/Module.h>
 #include <OpenXRVk/OpenXRVkSystemComponent.h>
 #include <XRCameraMovementComponent.h>
+#include "Devices/Common/XRControllerComponent.h"
+#include "Devices/Common/XRControllerAnimationsComponent.h"
+#include <XRRayInteractorComponent.h>
+#include <XRInteractableComponent.h>
 
 #if defined (OPENXRVK_BUILDERS)
 #include "Builders/OpenXRVkAssetsBuilderSystemComponent.h"
@@ -31,6 +35,10 @@ namespace OpenXRVk
             m_descriptors.insert(m_descriptors.end(), {
                 SystemComponent::CreateDescriptor(),
                 XRCameraMovementComponent::CreateDescriptor(),
+                XRControllerComponent::CreateDescriptor(),
+				XRRayInteractorComponent::CreateDescriptor(),
+				XRInteractableComponent::CreateDescriptor(),
+                XRControllerAnimationsComponent::CreateDescriptor(),
                 #if defined (OPENXRVK_BUILDERS)
                 OpenXRVkBuilders::OpenXRAssetsBuilderSystemComponent::CreateDescriptor(),
                 #endif

+ 6 - 0
Gems/OpenXRVk/Code/Source/Platform/Android/platform_private_android_files.cmake

@@ -13,4 +13,10 @@ set(FILES
     ../Common/Default/InputDeviceXRController_Default.cpp
     ../Common/Default/OculusTouch_Default.cpp
     ../Common/Default/OculusTouch_Default.h
+    ../../Devices/Common/XRControllerComponent.cpp
+    ../../Devices/Common/XRControllerComponent.h
+	../../Devices/Common/XRControllerAnimationsComponent.cpp
+	../../Devices/Common/XRControllerAnimationsComponent.h
+	../../Devices/Common/XRControllersConfig.cpp
+	../../Devices/Common/XRControllersConfig.h
 )

+ 4 - 0
Gems/OpenXRVk/Code/Source/Platform/Linux/platform_private_linux_files.cmake

@@ -12,5 +12,9 @@ set(FILES
     ../Common/Default/InputDeviceXRController_Default.cpp
     ../Common/Default/OculusTouch_Default.cpp
     ../Common/Default/OculusTouch_Default.h
+    ../Common/Default/XRControllerComponent.cpp
+    ../Common/Default/XRControllerComponent.h
+    ../Common/Default/XRControllerAnimationsComponent.cpp
+    ../Common/Default/XRControllerAnimationsComponent.h
     ../Common/Unimplemented/OpenXRVkCommon_Unimplemented.cpp
 )

+ 6 - 0
Gems/OpenXRVk/Code/Source/Platform/Windows/platform_private_windows_files.cmake

@@ -13,4 +13,10 @@ set(FILES
     ../Common/Default/OculusTouch_Default.cpp
     ../Common/Default/OculusTouch_Default.h
     ../Common/Unimplemented/OpenXRVkCommon_Unimplemented.cpp
+    ../../Devices/Common/XRControllerComponent.cpp
+    ../../Devices/Common/XRControllerComponent.h
+	../../Devices/Common/XRControllerAnimationsComponent.cpp
+	../../Devices/Common/XRControllerAnimationsComponent.h
+	../../Devices/Common/XRControllersConfig.cpp
+	../../Devices/Common/XRControllersConfig.h
 )

+ 1 - 1
Gems/OpenXRVk/Code/Source/XRCameraMovementComponent.cpp

@@ -39,7 +39,7 @@ namespace OpenXRVk
             {
                 editContext->Class<XRCameraMovementComponent>("XR Camera Movement", "Provides XR controller input to control the camera")
                     ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
-                    ->Attribute(AZ::Edit::Attributes::Category, "Gameplay")
+                    ->Attribute(AZ::Edit::Attributes::Category, "XR")
                     ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
                     ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
                     ->DataElement(AZ::Edit::UIHandlers::Default, &XRCameraMovementComponent::m_moveSpeed, "Move Speed", "Speed of camera movement")

+ 213 - 0
Gems/OpenXRVk/Code/Source/XRInteractableComponent.cpp

@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <XRInteractableComponent.h>
+
+#include <AzCore/Component/TransformBus.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/RTTI/BehaviorContext.h>
+
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+
+#include <Atom/RPI.Public/ViewProviderBus.h>
+#include <Atom/RPI.Public/View.h>
+#include <Atom/RPI.Public/ViewportContext.h>
+#include <Atom/RPI.Public/ViewportContextBus.h>
+#include <Atom/RPI.Public/Pass/PassFilter.h>
+#include <Atom/RPI.Public/ViewportContextManager.h>
+#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
+#include <AzFramework/Components/CameraBus.h>
+#include <AzCore/Component/NonUniformScaleBus.h>
+
+#include <AzFramework/Physics/PhysicsScene.h>
+#include <AzFramework/Physics/PhysicsSystem.h>
+#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
+#include <AzFramework/Physics/Shape.h>
+
+#include <Source/RigidBodyComponent.h>
+#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
+
+namespace OpenXRVk
+{
+    void XRInteractableComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<XRInteractableComponent, AZ::Component>()
+                ->Version(1)
+                ->Field("Type of the interactable", &XRInteractableComponent::m_XRInteractableType)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<XRInteractableComponent>("XR Interactable", "Reacts on Ray Interactor from the XR controller")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Category, "XR")
+                    ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
+                    ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
+                    ->DataElement(AZ::Edit::UIHandlers::ComboBox, &XRInteractableComponent::m_XRInteractableType, "Type of the interactable", "Type of the interactable")
+                      ->EnumAttribute(XRInteractableComponent::XRInteractableType::Simple, "Simple")
+                    ;
+            }
+        }
+
+        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<XRInteractableComponent>("XRInteractable Component Group")
+                ->Attribute(AZ::Script::Attributes::Category, "OpenXRVk Gem Group")
+                ;
+        }
+    }
+
+    void XRInteractableComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("XRInteractableService"));
+    }
+
+    void XRInteractableComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("XRInteractableService"));
+    }
+
+    void XRInteractableComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        required.push_back(AZ_CRC_CE("TransformService"));
+        required.push_back(AZ_CRC_CE("PhysicsRigidBodyService"));
+    }
+
+    void XRInteractableComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+    }
+
+    void XRInteractableComponent::Init()
+    {
+        
+    }
+
+    void XRInteractableComponent::Activate()
+    {
+        AZ::TickBus::Handler::BusConnect();
+        Physics::RigidBodyNotificationBus::Handler::BusConnect(GetEntityId());
+
+        m_cachedRigidBodyComponent = GetEntity()->FindComponent<PhysX::RigidBodyComponent>();
+    }
+
+    void XRInteractableComponent::Deactivate()
+    {
+        if (AZ::TickBus::Handler::BusIsConnected())
+        {
+            AZ::TickBus::Handler::BusDisconnect();
+        }
+        Physics::RigidBodyNotificationBus::Handler::BusDisconnect();
+    }
+
+    static float SmoothStep(float edge0, float edge1, float t)
+    {
+        t = AZ::GetClamp((t - edge0) / (edge1 - edge0), 0.0f, 1.0f);
+        return t * t * (3.0f - 2.0f * t);
+    }
+
+    void XRInteractableComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
+    {
+        if (!m_hovering)
+            return;
+
+        constexpr float animationDuration = 0.25f;
+        constexpr float increaseScaleFactor = 0.3f;
+
+        m_hoverTime += deltaTime;
+        float t = AZ::GetClamp(m_hoverTime / animationDuration, 0.0f, 1.0f);
+
+        float factor = m_scalingUp
+            ? SmoothStep(0.0f, 1.0f, t) * increaseScaleFactor + 1.0f  // 1.0 -> 1.increaseScaleFactor
+            : 1 + increaseScaleFactor - SmoothStep(0.0f, 1.0f, t) * increaseScaleFactor;  // 1.increaseScaleFactor -> 1.0
+
+        AZ::Vector3 newScale = m_originalScale * factor;
+        if (t >= 1.0f)
+        {
+            if (m_scalingUp)
+            {
+                m_scalingUp = false;
+                m_hoverTime = 0.0f;
+            }
+            else
+            {
+                newScale = m_originalScale;
+                m_hovering = false;
+            }
+        }
+
+        if (m_hasNonUniform)
+        {
+            AZ::NonUniformScaleRequestBus::Event(GetEntityId(), &AZ::NonUniformScaleRequests::SetScale, newScale);
+        }
+        else
+        {
+            AZ::TransformBus::Event(GetEntityId(), &AZ::TransformInterface::SetLocalUniformScale, newScale.GetX());
+        }
+    }
+
+    // Called when the pointer is hovering over this object
+    void XRInteractableComponent::OnHoverStart()
+    {
+        if (m_hovering)
+        {
+            return;
+        }
+        m_hoverTime = 0.0f;
+        m_hovering = true;
+        m_scalingUp = true;
+
+        if (!m_originalScaleCached)
+        {
+            CacheOriginalScale();
+        }
+    }
+
+    // Called when the pointer stops hovering over this object
+    void XRInteractableComponent::OnHoverEnd()
+    {
+    }
+
+    void XRInteractableComponent::CacheOriginalScale()
+    {
+        m_originalScale = AZ::Vector3::CreateOne();
+        m_hasNonUniform = false;
+
+        AZ::Vector3 testScale = AZ::Vector3::CreateOne();
+        AZ::NonUniformScaleRequestBus::EventResult(testScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
+
+        if (!testScale.IsClose(AZ::Vector3::CreateOne()))
+        {
+            m_hasNonUniform = true;
+            m_originalScale = testScale;
+        }
+        else
+        {
+            float uniform = 1.0f;
+            AZ::TransformBus::EventResult(uniform, GetEntityId(), &AZ::TransformInterface::GetLocalUniformScale);
+            m_originalScale = AZ::Vector3(uniform);
+        }
+        m_originalScaleCached = true;
+    }
+
+    void XRInteractableComponent::OnGrab()
+    {
+        m_isGrabbing = true;
+        m_cachedRigidBodyComponent->DisablePhysics();
+    }
+
+    void XRInteractableComponent::OnRelease(const AZ::Vector3& impulse)
+    {
+        m_cachedRigidBodyComponent->EnablePhysics();
+        m_cachedRigidBodyComponent->ApplyLinearImpulse(impulse * m_cachedRigidBodyComponent->GetMass());
+        m_isGrabbing = false;
+    }
+
+} // namespace OpenXRVk

+ 87 - 0
Gems/OpenXRVk/Code/Source/XRInteractableComponent.h

@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/Component/TickBus.h>
+#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
+#include <AzCore/Component/Entity.h>
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+#include <AzFramework/Components/CameraBus.h>
+#include <AzFramework/Physics/RigidBodyBus.h>
+#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
+#include <Source/RigidBodyComponent.h>
+
+namespace OpenXRVk
+{
+    //! XRInteractableComponent defines that the object can be taken using the RayInteractor
+    class XRInteractableComponent
+        : public AZ::Component
+        , public AZ::TickBus::Handler
+        , public Physics::RigidBodyNotificationBus::Handler
+    {
+    public:
+
+        enum class XRInteractableType : AZ::u32 {
+            Simple
+        };
+
+        AZ_COMPONENT(OpenXRVk::XRInteractableComponent, "{9234ABCD-234B-12AB-242D-6436DEFC38BB}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+
+        // Called when the pointer is hovering over this object
+        virtual void OnHoverStart();
+
+        // Called when the pointer stops hovering over this object
+        virtual void OnHoverEnd();
+
+        virtual void OnGrab();
+        virtual void OnRelease(const AZ::Vector3& impulse);
+
+        bool IsHovering() { return m_isHovering; }
+        bool IsGrabbing() { return m_isGrabbing; }
+
+    protected:
+        // AZ::Component
+        void Init() override;
+        void Activate() override;
+        void Deactivate() override;
+
+        // AZ::TickBus::Handler
+        void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
+
+    private:
+        bool m_isHovering = false;
+        XRInteractableType m_XRInteractableType = XRInteractableType::Simple;
+
+        // Animation state
+        float m_hoverTime = 0.0f;
+        bool m_hovering = false;
+        bool m_scalingUp = true;
+
+        // Scale state
+        AZ::Vector3 m_originalScale = AZ::Vector3::CreateOne();
+        bool m_hasNonUniform = false;
+
+        bool m_originalScaleCached = false;
+        void CacheOriginalScale();
+
+        bool m_isGrabbing = false;
+
+        PhysX::RigidBodyComponent* m_cachedRigidBodyComponent = nullptr;
+    };
+
+} // namespace OpenXRVk

+ 364 - 0
Gems/OpenXRVk/Code/Source/XRRayInteractorComponent.cpp

@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <XRRayInteractorComponent.h>
+#include <XRInteractableComponent.h>
+
+#include <AzCore/Component/TransformBus.h>
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/RTTI/BehaviorContext.h>
+
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+
+#include <Atom/RPI.Public/ViewProviderBus.h>
+#include <Atom/RPI.Public/View.h>
+#include <Atom/RPI.Public/ViewportContext.h>
+#include <Atom/RPI.Public/ViewportContextBus.h>
+#include <Atom/RPI.Public/Pass/PassFilter.h>
+#include <Atom/RPI.Public/ViewportContextManager.h>
+#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
+#include <AzFramework/Components/CameraBus.h>
+#include <AzCore/Component/NonUniformScaleBus.h>
+
+#include <AzFramework/Physics/PhysicsScene.h>
+#include <AzFramework/Physics/PhysicsSystem.h>
+#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
+#include <AzFramework/Physics/Shape.h>
+
+#include <Atom/RPI.Public/Material/Material.h>
+
+#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
+#include <AzCore/Name/Name.h>
+
+#include <AzFramework/Physics/RigidBodyBus.h>
+#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
+
+namespace OpenXRVk
+{
+    const AZStd::string baseColorPropertyName = "baseColor.color";
+    const float translationToYScaleCoefficent = 100;
+    const float hoveringXZScaleCoefficient = 4;
+
+    void XRRayInteractorComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<XRRayInteractorComponent, AZ::Component>()
+                ->Version(1)
+                ->Field("Max length of the ray", &XRRayInteractorComponent::m_maxLength)
+                ->Field("The default color of the ray", &XRRayInteractorComponent::m_initialRayColor)
+                ->Field("The color when the ray hovers over some interactable object", &XRRayInteractorComponent::m_hoveringRayColor)
+                ->Field("Label of the grip button", &XRRayInteractorComponent::m_gripControlActionLabel)
+                ;
+
+            if (AZ::EditContext* editContext = serializeContext->GetEditContext())
+            {
+                editContext->Class<XRRayInteractorComponent>("XR Ray Interactor", "Draws ray interactor from the XR controller")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                    ->Attribute(AZ::Edit::Attributes::Category, "XR")
+                    ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Component_Placeholder.svg")
+                    ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &XRRayInteractorComponent::m_maxLength, "Max length of the ray", "Max length of the ray in meters")
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &XRRayInteractorComponent::m_initialRayColor, "Default color", "The default color of the ray")
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &XRRayInteractorComponent::m_hoveringRayColor, "Hovering color", "The color when the ray hovers over some interactable object")
+                    ->DataElement(AZ::Edit::UIHandlers::Default, &XRRayInteractorComponent::m_gripControlActionLabel, "Action name of the grip", "Action Handle Label of OpenXRActionsInterface")
+                    ;
+            }
+        }
+
+        if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
+        {
+            behaviorContext->Class<XRRayInteractorComponent>("XRRayInteractor Component Group")
+                ->Attribute(AZ::Script::Attributes::Category, "OpenXRVk Gem Group")
+                ;
+        }
+    }
+
+    void XRRayInteractorComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC_CE("XRRayInteractorService"));
+    }
+
+    void XRRayInteractorComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC_CE("XRRayInteractorService"));
+    }
+
+    void XRRayInteractorComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        required.push_back(AZ_CRC_CE("TransformService"));
+    }
+
+    void XRRayInteractorComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+    }
+
+    void XRRayInteractorComponent::Init()
+    {
+    }
+
+    void XRRayInteractorComponent::Activate()
+    {
+        AZ::TickBus::Handler::BusConnect();
+    }
+
+    void XRRayInteractorComponent::Deactivate()
+    {
+        if (AZ::TickBus::Handler::BusIsConnected())
+        {
+            AZ::TickBus::Handler::BusDisconnect();
+        }
+    }
+
+    void XRRayInteractorComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint timePoint)
+    {
+        if (!m_colorDefined)
+        {
+            AZ::Render::MaterialAssignmentMap originalMaterials;
+            AZ::Render::MaterialComponentRequestBus::EventResult(
+                originalMaterials, GetEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::GetMaterialMap);
+
+            if (!originalMaterials.empty())
+            {
+                for (const auto& [materialId, assignment] : originalMaterials)
+                {
+                    auto materialAsset = assignment.m_materialAsset;
+                    if (!materialAsset.IsReady())
+                        continue;
+                    // Waiting when the asset is ready
+                    auto const pIndex = assignment.m_materialInstance->FindPropertyIndex(AZ::Name("baseColor.color"));
+                    if (!pIndex.IsValid())
+                        continue;
+                    // Let's find the right material
+                    assignmentId = AZ::Render::MaterialAssignmentId::CreateDefault();
+
+                    AZ::Render::MaterialComponentRequestBus::Event(
+                        GetEntityId(),
+                        &AZ::Render::MaterialComponentRequestBus::Events::SetPropertyValueT<AZ::Color>, 
+                        assignmentId, baseColorPropertyName, m_initialRayColor);
+                    m_colorDefined = true;
+                }
+            }
+        }
+
+        ProcessOpenXRActions();
+
+        if (m_heldEntity.IsValid())
+        {
+            // Update held object's position relative to ray
+            AZ::Transform rayTransform;
+            AZ::TransformBus::EventResult(rayTransform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
+            AZ::Transform targetTransform = rayTransform * m_grabOffset;
+            AZ::TransformBus::Event(m_heldEntity, &AZ::TransformBus::Events::SetWorldTM, targetTransform);
+
+            // Track velocity
+            AZ::Vector3 currentPosition = targetTransform.GetTranslation();
+            m_currentVelocity = (currentPosition - m_lastFramePosition) / deltaTime;
+            m_lastFramePosition = currentPosition;
+
+            // Release object when button is released
+            if (m_currentSqueezeValue < 0.1f)
+            {
+                ReleaseHeldEntity();
+            }
+            return;
+        }
+        else if (m_currentSqueezeValue > 0.9f && m_currentlyHoveredEntity.IsValid())
+        {
+            GrabHoveredEntity();
+            return;
+        }
+        else {
+            m_heldEntity.SetInvalid();
+        }
+
+        // Store initial nonUniform scale X and Z
+        AZ::Vector3 nonUniformScale;
+        AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequestBus::Events::GetScale);
+        if (m_XZnonUniformScale == 0 && nonUniformScale.GetX() > 0)
+        {
+            m_XZnonUniformScale = nonUniformScale.GetX();
+        }
+
+        // Get the world transform of the current entity (typically the controller)
+        AZ::Transform rayOriginTransform;
+        AZ::TransformBus::EventResult(rayOriginTransform, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
+
+        // Define the ray start position and normalized direction
+        AZ::Vector3 start = rayOriginTransform.GetTranslation();
+        AZ::Vector3 direction = rayOriginTransform.GetBasisY().GetNormalized();
+
+        // Maximum ray length
+        float maxDistance = m_maxLength;
+
+        // Get the default physics scene
+        auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
+        AzPhysics::SceneHandle sceneHandle = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
+
+        if (sceneHandle == AzPhysics::InvalidSceneHandle)
+        {
+            AZ_Warning("XRRayInteractorComponent", false, "Invalid physics scene.");
+            return;
+        }
+
+        // Prepare the raycast request
+        AzPhysics::RayCastRequest request;
+        request.m_start = start;
+        request.m_direction = direction;
+        request.m_distance = maxDistance;
+        request.m_reportMultipleHits = false;
+
+        // Perform the raycast query
+        AzPhysics::SceneQueryHits hitResult;
+        sceneInterface->QueryScene(sceneHandle, &request, hitResult);
+
+        // Handle the result of the raycast
+        if (!hitResult.m_hits.empty())
+        {
+            AzPhysics::SceneQueryHit &hit = hitResult.m_hits[0];
+
+            // You can use hitResult.m_position or hitResult.m_entityId for further logic
+            if (hit.m_entityId.IsValid())
+            {
+                if (m_currentlyHoveredEntity != hit.m_entityId)
+                {
+                    CheckEndHovering();
+
+                    XRInteractableComponent* xrInteractableComponent = GetXRInterctableComponent(hit.m_entityId);
+                    if (xrInteractableComponent)     // Interactable component has changed
+                    {
+                        AZ::Render::MaterialComponentRequestBus::Event(
+                            GetEntityId(),
+                            &AZ::Render::MaterialComponentRequestBus::Events::SetPropertyValueT<AZ::Color>,
+                            assignmentId, baseColorPropertyName, m_hoveringRayColor);
+
+                        xrInteractableComponent->OnHoverStart();
+                        m_currentlyHoveredEntity = hit.m_entityId;
+                    }
+                }
+            }
+            else
+            {
+                CheckEndHovering();
+            }
+
+            float xzScale = m_currentlyHoveredEntity.IsValid() ? m_XZnonUniformScale * hoveringXZScaleCoefficient : m_XZnonUniformScale;
+            nonUniformScale.Set(xzScale, hit.m_distance * translationToYScaleCoefficent, xzScale);
+            AZ::NonUniformScaleRequestBus::Event(GetEntityId(), &AZ::NonUniformScaleRequestBus::Events::SetScale, nonUniformScale);
+        }
+        else
+        {
+            // Restore initial scale of the ray
+            nonUniformScale.Set(m_XZnonUniformScale, m_maxLength* translationToYScaleCoefficent, m_XZnonUniformScale);
+            AZ::NonUniformScaleRequestBus::Event(GetEntityId(), &AZ::NonUniformScaleRequestBus::Events::SetScale, nonUniformScale);
+            CheckEndHovering();
+        }
+    }
+
+    void XRRayInteractorComponent::CheckEndHovering()
+    {
+        if (m_currentlyHoveredEntity.IsValid())
+        {
+            XRInteractableComponent* oldCRInteractableComponent = GetXRInterctableComponent(m_currentlyHoveredEntity);
+            if (oldCRInteractableComponent)
+            {
+                oldCRInteractableComponent->OnHoverEnd();
+                m_currentlyHoveredEntity.SetInvalid();
+                AZ::Render::MaterialComponentRequestBus::Event(
+                    GetEntityId(),
+                    &AZ::Render::MaterialComponentRequestBus::Events::SetPropertyValueT<AZ::Color>,
+                    assignmentId, baseColorPropertyName, m_initialRayColor);
+            }
+        }
+    }
+
+    static float ReadActionHandleFloat(IOpenXRActions* iface, IOpenXRActions::ActionHandle actionHandle, float deadZone = 0.05f)
+    {
+        auto outcome = iface->GetActionStateFloat(actionHandle);
+        if (!outcome.IsSuccess())
+        {
+            // Most likely the controller went to sleep.
+            return 0.0f;
+        }
+        float value = outcome.GetValue();
+        if (fabsf(value) < deadZone)
+        {
+            return 0.0f;
+        }
+        return value;
+    }
+
+    void XRRayInteractorComponent::ProcessOpenXRActions()
+    {
+        m_currentSqueezeValue = 0;
+        auto actionsIFace = OpenXRActionsInterface::Get();
+        if (!actionsIFace)
+        {
+            return;
+        }
+
+        if (!m_controllerSqueezeHandle.IsValid())
+        {
+            // Try to cache all handles.
+            m_controllerSqueezeHandle = actionsIFace->GetActionHandle("main_action_set", m_gripControlActionLabel);
+            if (!m_controllerSqueezeHandle.IsValid())
+            {
+                // Most likely the Action System failed to load the ActionSets asset.
+                return;
+            }
+
+        }
+        m_currentSqueezeValue = ReadActionHandleFloat(actionsIFace, m_controllerSqueezeHandle);
+    }
+
+    void XRRayInteractorComponent::GrabHoveredEntity()
+    {
+        m_heldEntity = m_currentlyHoveredEntity;
+
+        AZ::Transform controllerWorldTM;
+        AZ::Transform objectWorldTM;
+        AZ::TransformBus::EventResult(controllerWorldTM, GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
+        AZ::TransformBus::EventResult(objectWorldTM, m_heldEntity, &AZ::TransformBus::Events::GetWorldTM);
+        m_grabOffset = controllerWorldTM.GetInverse() * objectWorldTM;
+
+        m_lastFramePosition = objectWorldTM.GetTranslation();
+        m_currentVelocity = AZ::Vector3::CreateZero();
+
+        XRInteractableComponent* xrInteractableComponent = GetXRInterctableComponent(m_heldEntity);
+        if (xrInteractableComponent)
+        {
+            xrInteractableComponent->OnGrab();
+        }
+    }
+
+    void XRRayInteractorComponent::ReleaseHeldEntity()
+    {
+        // Call OnRelease on the XRInteractableComponent if available
+        XRInteractableComponent* xrInteractableComponent = GetXRInterctableComponent(m_heldEntity);
+        if (xrInteractableComponent)
+        {
+            xrInteractableComponent->OnRelease(m_currentVelocity);
+        }
+
+        m_heldEntity.SetInvalid();
+    }
+
+    XRInteractableComponent* XRRayInteractorComponent::GetXRInterctableComponent(AZ::EntityId entityId)
+    {
+        AZ::Entity* entity = nullptr;
+        AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
+        if (entity)
+        {
+            return entity->FindComponent<XRInteractableComponent>();
+        }
+        return nullptr;
+    }
+
+
+} // namespace OpenXRVk

+ 79 - 0
Gems/OpenXRVk/Code/Source/XRRayInteractorComponent.h

@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/Component/TickBus.h>
+#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
+#include <AzCore/Component/Entity.h>
+#include <OpenXRVk/OpenXRVkActionsInterface.h>
+#include <AzFramework/Components/CameraBus.h>
+#include <AtomLyIntegration/CommonFeatures/Material/MaterialAssignmentId.h>
+#include <XRInteractableComponent.h>
+
+namespace OpenXRVk
+{
+    //! XRRayInteractorComponent draws line from controller
+    class XRRayInteractorComponent
+        : public AZ::Component
+        , public AZ::TickBus::Handler
+    {
+    public:
+        AZ_COMPONENT(OpenXRVk::XRRayInteractorComponent, "{ABD92123-AB30-233B-23AA-123BDEFC3821}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+    protected:
+        // AZ::Component
+        void Init() override;
+        void Activate() override;
+        void Deactivate() override;
+
+        // AZ::TickBus::Handler
+        void OnTick(float deltaTime, AZ::ScriptTimePoint timePoint) override;
+
+    private:
+		AZ::EntityId m_currentlyHoveredEntity = AZ::EntityId();
+        float m_maxLength = 10;
+        AZStd::string m_gripControlActionLabel;
+
+        AZ::Color m_initialRayColor = AZ::Color(0.2f, 0.8f, 0.1f, 1.0f);
+        AZ::Color m_hoveringRayColor = AZ::Color(0.2f, 0.2f, 0.8f, 1.0f);
+        AZ::Render::MaterialAssignmentId assignmentId;
+        bool m_colorDefined = false;
+
+        float m_XZnonUniformScale = 0;
+
+        void CheckEndHovering();
+
+        void ProcessOpenXRActions();
+        //! A cache of OpenXRVk Action Handles that provide straight
+        //! access into the user's input.
+        IOpenXRActions::ActionHandle m_controllerSqueezeHandle;
+
+        float m_currentSqueezeValue = 0;
+
+        // Grab functionality
+        AZ::EntityId m_heldEntity = AZ::EntityId();
+        AZ::Transform m_grabOffset = AZ::Transform::CreateIdentity();
+        AZ::Vector3 m_lastFramePosition = AZ::Vector3::CreateZero();
+        AZ::Vector3 m_currentVelocity = AZ::Vector3::CreateZero();
+
+        XRInteractableComponent* GetXRInterctableComponent(AZ::EntityId entityId);
+        void GrabHoveredEntity();
+        void ReleaseHeldEntity();
+
+    };
+
+} // namespace OpenXRVk

+ 4 - 0
Gems/OpenXRVk/Code/openxrvk_static_common_files.cmake

@@ -44,4 +44,8 @@ set(FILES
     Source/OpenXRVkActionsManager.h
     Source/OpenXRVkBehaviorReflection.cpp
     Source/OpenXRVkBehaviorReflection.h
+	Source/XRRayInteractorComponent.h
+	Source/XRRayInteractorComponent.cpp
+	Source/XRInteractableComponent.h
+	Source/XRInteractableComponent.cpp
 )

+ 63 - 0
Gems/OpenXRVk_README_EN.md

@@ -0,0 +1,63 @@
+# Controller Models and Animations Setup in O3DE
+
+There are many VR devices on the market, each with different controllers, so developers are responsible for integrating the appropriate 3D models into their applications.
+
+This Gem provides asset templates that can help you implement your own 3D controller models more easily.
+
+The prefab at  
+`OpenXRVk\Assets\Devices\Generic\Prefabs\Controllers.prefab`  
+includes both left and right controllers:  
+- `OpenXRVk\Assets\Devices\Generic\Prefabs\LeftController.prefab`  
+- `OpenXRVk\Assets\Devices\Generic\Prefabs\RightController.prefab`
+
+We recommend copying the entire folder  
+`OpenXRVk\Assets\Devices\Generic\`  
+into your own project. Then, place your controller `.fbx` models (which contain `.motion` data and animations) into the appropriate subfolders.
+
+For example, Oculus Quest models can be downloaded from the official site:  
+https://developers.meta.com/horizon/downloads/package/oculus-controller-art/
+
+You will need to:
+- Convert the `.fbx` files from ASCII to binary format (e.g., using Autodesk FBX Converter).
+- Use Blender to split out individual animations for each button and joystick on the controller.
+
+Animations can be as short as one frame (e.g., to represent a "pressed" state).  
+For thumbsticks, you’ll need 4 separate animations: forward, backward, left, and right.
+
+Here is an example animation list for Oculus Quest Pro/3:
+
+```
+left_b_button_menu.fbx  
+left_b_button_x.fbx  
+left_b_button_y.fbx  
+left_b_thumbstick_000.fbx  
+left_b_thumbstick_090.fbx  
+left_b_thumbstick_180.fbx  
+left_b_thumbstick_270.fbx  
+left_b_trigger_front.fbx  
+left_b_trigger_grip.fbx  
+right_b_button_a.fbx  
+right_b_button_b.fbx  
+right_b_button_oculus.fbx  
+right_b_thumbstick_000.fbx  
+right_b_thumbstick_090.fbx  
+right_b_thumbstick_180.fbx  
+right_b_thumbstick_270.fbx  
+right_b_trigger_front.fbx  
+right_b_trigger_grip.fbx  
+```
+
+After loading the controller prefabs into the O3DE Editor, you may see missing or invalid property references.  
+You will need to assign the appropriate `Actor Asset`, `Material`, and `AnimGraph`.
+
+If you add new actions to `OpenXRVk\Assets\OpenXRVk\default.xractions` or create your own `.xractions` file, you must update the `XRControllerAnimation` component to match the correct action paths to the corresponding animations.
+
+---
+
+## Licensing and Distribution Notice
+
+Due to licensing restrictions, official controller 3D models (such as those for Oculus/Meta devices) are **not** included in this repository.  
+You must download them yourself from official sources and ensure your usage complies with their respective license agreements.
+
+Only template assets and instructions for integration are provided here.  
+Do **not** redistribute downloaded or proprietary models with your project unless explicitly permitted by the original license.