Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
interaction [2020/05/25 11:43] – [On components] admin | interaction [2020/05/26 12:53] – [Gesture Interaction] admin | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Interaction ====== | ====== Interaction ====== | ||
- | In the following the implementation of mouse and keyboard interaction with default FMX methods will be described. | + | In the following the implementation of mouse, keyboard |
In case you'll need extended features, have a look at the InputController implementation: | In case you'll need extended features, have a look at the InputController implementation: | ||
Line 127: | Line 127: | ||
==== HitTest Property ==== | ==== HitTest Property ==== | ||
+ | The HitTest property is a very important value for user interaction and for performance. Because Firemonkey checks all controls on the form each time the mouse moves, many operations are caused. Especially ray cast operations on 3D objects are very costly! | ||
+ | |||
+ | So our intention should be, to reduce those operations to a minimum. Any object that is not important for user interaction or ray-casting, | ||
+ | |||
+ | <file pascal> | ||
+ | GorillaCube1.HitTest := false; | ||
+ | </ | ||
+ | |||
+ | But remember, if you disable intersection tests, no mouse events on that object will be called anymore! | ||
+ | |||
+ | ==== Bounding-Volume-History ==== | ||
+ | |||
+ | Gorilla3D offers an optimization for fast raycast intersection tests. This optimization is only available for derived classes of TGorillaMesh with a valid " | ||
+ | Take a further read for Bounding volume hierarchy at: [[https:// | ||
+ | |||
+ | <file pascal> | ||
+ | procedure TForm1.FormCreate(Sender: | ||
+ | var LMeshDef : TMeshDef; | ||
+ | begin | ||
+ | [...] | ||
+ | // setup bounding volume hierarchy | ||
+ | LMeshDef := GorillaMesh1.Def as TMeshDef; | ||
+ | LMeshDef.AcquireBVH(); | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | To destroy a bounding volume hierarchy again, we have to call ReleasBVH(). | ||
+ | <file pascal> | ||
+ | var LMeshDef : TMeshDef; | ||
+ | begin | ||
+ | // destroy bounding volume hierarchy | ||
+ | LMeshDef := GorillaMesh1.Def as TMeshDef; | ||
+ | LMeshDef.ReleaseBVH(); | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | Because setting up a bounding volume hierarchy causes some overhead data you should keep in mind to use this optimization only where it's useful. | ||
===== Keyboard Interaction ===== | ===== Keyboard Interaction ===== | ||
+ | In case you'll need keyboard interaction, | ||
+ | In the following example we setup a physics demo with a sphere. When cursor keys are down, an impulse will be applied to the sphere rigid body, which moves the object in space. | ||
+ | |||
+ | <file pascal> | ||
+ | uses | ||
+ | [...], | ||
+ | Gorilla.Sphere, | ||
+ | | ||
+ | type | ||
+ | TForm1 = class(TForm) | ||
+ | GorillaSphere1: | ||
+ | GorillaPhysicsSystem1: | ||
+ | | ||
+ | procedure FormKeyDown(Sender: | ||
+ | Shift: TShiftState); | ||
+ | | ||
+ | [...] | ||
+ | end; | ||
+ | |||
+ | [...] | ||
+ | | ||
+ | procedure TForm1.FormKeyDown(Sender: | ||
+ | Shift: TShiftState); | ||
+ | var LImpulse : TPoint3D; | ||
+ | LBody : TQ3Body; | ||
+ | begin | ||
+ | if (Key = vkLEFT) then | ||
+ | LImpulse := TPoint3D.Create(-1, | ||
+ | else if (Key = vkRIGHT) then | ||
+ | LImpulse := TPoint3D.Create(1, | ||
+ | else if (Key = vkUP) then | ||
+ | LImpulse := TPoint3D.Create(0, | ||
+ | else if (Key = vkDOWN) then | ||
+ | LImpulse := TPoint3D.Create(0, | ||
+ | |||
+ | // apply impulse on sphere | ||
+ | GorillaPhysicsSystem1.RemoteBodyImpulse(GorillaSphere1, | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | The usage of form key events is very rudimentary and may reach its limits very fast. | ||
+ | |||
+ | ===== Gesture Interaction ===== | ||
+ | |||
+ | Gesture handling is supported for Gorilla3D viewport. To allow gesture management you will need a TGestureManager component on your form and you have to link it to the TGorillaViewport component. | ||
+ | |||
+ | In the example below it is described, how to rotate and zoom a model. Therefor we use the interactive gestures: ZOOM and PAN. | ||
+ | In the // | ||
+ | And execute the very simple //DoZoom// and // | ||
+ | |||
+ | <file pascal> | ||
+ | type | ||
+ | TForm1 = class(TForm) | ||
+ | GorillaViewport1: | ||
+ | GestureManager1: | ||
+ | GorillaModel1: | ||
+ | | ||
+ | procedure GorillaViewport1Gesture(Sender: | ||
+ | const EventInfo: TGestureEventInfo; | ||
+ | | ||
+ | protected | ||
+ | FLastPos : TPointF; | ||
+ | | ||
+ | [...] | ||
+ | end; | ||
+ | | ||
+ | procedure TForm1.FormCreate(Sender : TObject); | ||
+ | begin | ||
+ | GorillaViewport1.Touch.GestureManager := GestureManager1; | ||
+ | GorillaViewport1.Touch.InteractiveGestures := [Zoom, Pan]; | ||
+ | GorillaViewport1.OnGesture := GorillaViewport1Gesture; | ||
+ | [...] | ||
+ | end; | ||
+ | |||
+ | procedure TForm1.GorillaViewport1Gesture(Sender: | ||
+ | const EventInfo: TGestureEventInfo; | ||
+ | |||
+ | procedure DoZoom(); | ||
+ | var LScale : Single; | ||
+ | begin | ||
+ | if not (TInteractiveGestureFlag.gfBegin in EventInfo.Flags) | ||
+ | and not (TInteractiveGestureFlag.gfEnd in EventInfo.Flags) then | ||
+ | begin | ||
+ | LScale := EventInfo.Distance / 100; | ||
+ | GorillaModel1.Scale.Point := Point3D(LScale, | ||
+ | end; | ||
+ | end; | ||
+ | |||
+ | procedure DoRotate(); | ||
+ | var LDist : Single; | ||
+ | LDiff, | ||
+ | LNew, | ||
+ | LPos : TPointF; | ||
+ | begin | ||
+ | LNew := EventInfo.Location; | ||
+ | |||
+ | if not Assigned(GorillaModel1) then | ||
+ | begin | ||
+ | FLastPos := LNew; | ||
+ | Exit; | ||
+ | end; | ||
+ | |||
+ | if not (TInteractiveGestureFlag.gfBegin in EventInfo.Flags) | ||
+ | and not (TInteractiveGestureFlag.gfEnd in EventInfo.Flags) then | ||
+ | begin | ||
+ | LPos := EventInfo.Location; | ||
+ | LDiff := FLastPos - LPos; | ||
+ | |||
+ | LDist := LDiff.X / 5; | ||
+ | |||
+ | GorillaModel1.RotationAngle.Y := GorillaModel1.RotationAngle.Y + LDist; | ||
+ | end; | ||
+ | |||
+ | FLastPos := LNew; | ||
+ | end; | ||
+ | |||
+ | begin | ||
+ | // just a dirty and quick solution for gesture handling | ||
+ | case EventInfo.GestureID of | ||
+ | igiZoom : | ||
+ | begin | ||
+ | // zoom | ||
+ | DoZoom(); | ||
+ | Handled := true; | ||
+ | end; | ||
+ | |||
+ | igiPan : | ||
+ | begin | ||
+ | // rotate model | ||
+ | DoRotate(); | ||
+ | Handled := true; | ||
+ | end; | ||
+ | |||
+ | else | ||
+ | begin | ||
+ | Handled := false; | ||
+ | end; | ||
+ | end; | ||
+ | end; | ||
+ | </ | ||
+ | ===== GamePad Interaction ===== | ||
+ | |||
+ | Interacting with gamepads in Firemonkey is not possible out of the box. But of course you can build your own component. | ||
+ | Gorilla3D already provides support for gamepads in the TGorillaInputController and is very easy to use. Also combination of mouse and keyboard input is managable. | ||
+ | |||
+ | ===== Input-Controller ===== | ||
+ | Because most games and applications use hotkeys and sequences to interact with the 3D world. | ||
+ | But handling all keyboard and mouse | ||
+ | |||
+ | Read more: [[inputpolling|Input Polling]] | ||
+ | |||
+ | Next step: [[android|Android]] |