This page has been translated automatically.
Видеоуроки
Interface
Essentials
Advanced
Подсказки и советы
Основы
Программирование на C#
Рендеринг
Professional (SIM)
Принципы работы
Свойства (properties)
Компонентная Система
Рендер
Физика
Редактор UnigineEditor
Обзор интерфейса
Работа с ассетами
Настройки и предпочтения
Работа с проектами
Настройка параметров ноды
Setting Up Materials
Настройка свойств
Освещение
Sandworm
Использование инструментов редактора для конкретных задач
Расширение функционала редактора
Встроенные объекты
Ноды (Nodes)
Объекты (Objects)
Эффекты
Декали
Источники света
Geodetics
World-ноды
Звуковые объекты
Объекты поиска пути
Players
Программирование
Основы
Настройка среды разработки
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Плагины
Форматы файлов
Materials and Shaders
Rebuilding the Engine Tools
Интерфейс пользователя (GUI)
Двойная точность координат
API
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
Работа с контентом
Оптимизация контента
Материалы
Визуальный редактор материалов
Сэмплы материалов
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials
Внимание! Эта версия документация УСТАРЕЛА, поскольку относится к более ранней версии SDK! Пожалуйста, переключитесь на самую актуальную документацию для последней версии SDK.
Внимание! Эта версия документации описывает устаревшую версию SDK, которая больше не поддерживается! Пожалуйста, обновитесь до последней версии SDK.

Using Manipulators to Transform Objects

After adding an object to the scene in Unigine Editor, you can control object transformations with control devices. But sometimes transformations are supposed to be made at application runtime. For example, when you create your own game with a world editor, where you can place objects in the world and move them around.

This usage example will teach you how to:

  1. Select an object on the screen with the mouse using Intersections.
  2. Use manipulator widgets to modify the object transform matrix.
  3. Switch between different manipulator widgets using the keyboard.

See Also#

Creating Manipulators to Control Object Transformations#

There are 3 types of manipulator widgets used for object transforming:

All these manipulators work the same way, each of them visually represents a part of the transformation matrix that you can change by dragging the control elements of the widget. Use the CHANGED callback of the widget to make the selected object follow manipulators transformations.

Source code (C#)
public class Manipulator : Component
{
	// declare object and translator widget manipulator variables
    Unigine.Node obj;
	WidgetManipulator ObjManTranslator;
	
    private void Init()
    {
        // write here code to be called on component initialization
		
		// create a manipulator class instance and add it to the UI
        gui = Gui.GetCurrent();
        ObjManTranslator = new WidgetManipulatorTranslator(gui);
        gui.AddChild(ObjManTranslator);
		
		// setting the ApplyTransform method as a callback on changing the widget state
		ObjManTranslator.AddCallback(Gui.CALLBACK_INDEX.CHANGED, ApplyTransform);
    }
	
	// a callback method used to transform an object
	private void ApplyTransform()
	{
		if(obj != null)
			obj.WorldTransform = ObjManTranslator.Transform;
	}
}

Selecting Objects Using Mouse Cursor#

To select an object under the mouse cursor we should cast a ray from the cursor location in the view direction of the camera using the World.GetIntersection() method, that returns an intersected object (if any).

Source code (C#)
// find an object under the cursor
private Unigine.Node GetNodeUnderCursor()
{
	ivec2 mouse = Input.MousePosition;

	// find a point 100 units away in front of the camera
	Vec3 p0 = Game.Player.WorldPosition;
		
	EngineWindow main_window = WindowManager.MainWindow;
	if (main_window)
	{
		ivec2 main_pos = main_window.Position;
		mouse.x += main_pos.x;
		mouse.y += main_pos.y;
	}
	Vec3 p1 = p0 + new vec3(Game.Player.GetDirectionFromMainWindow(mouse.x, mouse.y)) * 100;
		
	// cast a ray, that will detect an object within 100 units in front of the camera
	return World.GetIntersection(p0, p1, 1, intersection);
}

Putting it All Together#

Now let's put it all together and add a keyboard handler to switch the current manipulator. For example, let's use Z, X, C keys to select Translator, Rotator, Scaler Manipulators accordingly. The selected widget will be displayed on the screen where the object is located (i.e. it will have the same transformation).

  1. Create a new C# componentManipulator. Double-click it in the Asset Browser to edit code in your IDE.
  2. Copy the code below and paste it to your component.
  3. Assign Manipulator to any enabled node in the world and click Play.
Source code (C#)
#region Math Variables
#if UNIGINE_DOUBLE
using Scalar = System.Double;
using Vec2 = Unigine.dvec2;
using Vec3 = Unigine.dvec3;
using Vec4 = Unigine.dvec4;
using Mat4 = Unigine.dmat4;
#else
using Scalar = System.Single;
using Vec2 = Unigine.vec2;
using Vec3 = Unigine.vec3;
using Vec4 = Unigine.vec4;
using Mat4 = Unigine.mat4;
using WorldBoundBox = Unigine.BoundBox;
using WorldBoundSphere = Unigine.BoundSphere;
using WorldBoundFrustum = Unigine.BoundFrustum;
#endif
#endregion

using System;
using System.Collections;
using System.Collections.Generic;
using Unigine;

[Component(PropertyGuid = "AUTOGENERATED_GUID")] // <-- this line is generated automatically for a new component
public class Manipulator : Component
{
	// WorldIntersection object to store the information about the intersection 
	WorldIntersection intersection = new WorldIntersection();
 
	// Unigine.Object object to gain access to a selected object's transform in Unigine 
	Unigine.Node obj;
 
	// create manipulators for each type of transform(Translating, Scaling, Rotating) 
	WidgetManipulator ObjManTranslator;
	WidgetManipulator ObjManScaler;
	WidgetManipulator ObjManRotator;
	
	// create widget manipulator used to store transformation matrix of an active widget
	WidgetManipulator CurrentObjectManipulator;
	Gui gui;

	[Method(Order=2)] private void Init()
	{
		// write here code to be called on component initialization 
		gui = Gui.GetCurrent();

		// create widget for each transformation type
		ObjManTranslator = new WidgetManipulatorTranslator(gui);
		ObjManScaler = new WidgetManipulatorScaler(gui);
		ObjManRotator = new WidgetManipulatorRotator(gui);
		
		// set projection for the widgets
		ObjManTranslator.Projection= Game.Player.Camera.Projection;
		ObjManScaler.Projection = Game.Player.Camera.Projection;
		ObjManRotator.Projection = Game.Player.Camera.Projection;

		// add widgets to UI
		gui.AddChild(ObjManTranslator);
		gui.AddChild(ObjManScaler);
		gui.AddChild(ObjManRotator);

		// add a callback for each widget   
		ObjManTranslator.AddCallback(Gui.CALLBACK_INDEX.CHANGED, ApplyTransform);
		ObjManRotator.AddCallback(Gui.CALLBACK_INDEX.CHANGED, ApplyTransform);
		ObjManScaler.AddCallback(Gui.CALLBACK_INDEX.CHANGED, ApplyTransform);

		// hide created widgets
		ObjManScaler.Hidden = true;
		ObjManRotator.Hidden = true;
		ObjManTranslator.Hidden = true;
	}
 
	private void Update()
	{
		// write here code to be called before updating each render frame
		 if (!Game.Player)
			return;
	
		// set modelview for each widget manipulator every frame
		ObjManTranslator.Modelview = Game.Player.Camera.Modelview;
		ObjManScaler.Modelview = Game.Player.Camera.Modelview;
		ObjManRotator.Modelview = Game.Player.Camera.Modelview;

		// select an object with right-click
		if (Input.IsMouseButtonDown(Input.MOUSE_BUTTON.RIGHT))
		{
			obj = GetNodeUnderCursor();
			CurrentObjectManipulator.Transform = obj.WorldTransform;
		}

		// choose manipulator with Z,X,C keys
		if(obj)
		{
			if(Input.IsKeyDown(Input.KEY.Z))
				SwitchManipulator(ObjManTranslator);
			if(Input.IsKeyDown(Input.KEY.X))
				SwitchManipulator(ObjManRotator);
			if(Input.IsKeyDown(Input.KEY.C))
				SwitchManipulator(ObjManScaler);
			if (!Input.IsMouseButtonPressed(Input.MOUSE_BUTTON.LEFT))
				CurrentObjectManipulator.Transform = obj.WorldTransform;
		}
	}
 
	// transform an object
	private void ApplyTransform()
	{
		if(obj != null && Input.IsMouseButtonPressed(Input.MOUSE_BUTTON.LEFT))
			obj.WorldTransform = CurrentObjectManipulator.Transform;
	}
 
	// find an object under the cursor
	private Unigine.Node GetNodeUnderCursor()
	{
		ivec2 mouse = Input.MousePosition;

		// find a point 100 units away in front of the camera
		Vec3 p0 = Game.Player.WorldPosition;
		
		EngineWindow main_window = WindowManager.MainWindow;
		if (main_window)
		{
			ivec2 main_pos = main_window.Position;
			mouse.x += main_pos.x;
			mouse.y += main_pos.y;
		}
		Vec3 p1 = p0 + new vec3(Game.Player.GetDirectionFromMainWindow(mouse.x, mouse.y)) * 100;
		
		// cast a ray, that will detect an object within 100 units in front of the camera
		return World.GetIntersection(p0, p1, 1, intersection);
	}

	// relocate chosen manipulator to the position of selected object and make it visible
	void SwitchManipulator(WidgetManipulator CurrentManipulator)
	{
		// relocate a widget and making it visible
		CurrentManipulator.Transform = obj.WorldTransform;
		CurrentManipulator.Hidden = false;
		
		// make other widgets hidden
		CurrentObjectManipulator = CurrentManipulator;
		if(ObjManTranslator != CurrentManipulator)
			ObjManTranslator.Hidden = true;
		if(ObjManRotator != CurrentManipulator)
			ObjManRotator.Hidden = true;
		if(ObjManScaler != CurrentManipulator)
			ObjManScaler.Hidden = true;
	}
}
Last update: 14.12.2022
Build: ()