123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- package h2d;
- /**
- Follows the 3D object position in current 3D camera, synchronizing the follower position to projected 2D position of the followed object.
- **/
- @:uiNoComponent
- class ObjectFollower extends Object {
- /**
- Reference to target 3D object to follow.
- **/
- public var follow : h3d.scene.Object;
- /**
- Rounds the resulting 2d position of follower aligning it to s2d pixel grid.
- **/
- public var pixelSnap = true;
- /**
- If enabled, follower will mirror visibility of target object.
- **/
- public var followVisibility = false;
- /**
- Extra camera projection offset along X-axis to which follower will attach to.
- **/
- public var offsetX = 0.;
- /**
- Extra camera projection offset along Y-axis to which follower will attach to.
- **/
- public var offsetY = 0.;
- /**
- Extra camera projection offset along Z-axis to which follower will attach to.
- **/
- public var offsetZ = 0.;
- /**
- Horizontal object alignment relative to anchoring point.
- **/
- public var horizontalAlign : h2d.Flow.FlowAlign = Left;
- /**
- Vertical object alignment relative to anchoring point.
- **/
- public var verticalAlign : h2d.Flow.FlowAlign = Top;
- /**
- Mask with current depth buffer
- **/
- public var depthMask : Bool = false;
- /**
- Calculate the depth for masking with the given bias in 3D position units, relative to current camera.
- **/
- public var depthBias : Float = 0.;
- /**
- Express the offset in terms of the current camera direction.
- **/
- public var cameraRelative : Bool = false;
- var zValue : Float = 0.;
- var outputScale : Float = 1.;
- var tmpPos = new h3d.Vector();
- var tmpSize : h2d.col.Bounds;
- /**
- Create a new ObjectFollower instance.
- @param obj The 3D object to follow.
- @param parent An optional parent `h2d.Object` instance to which ObjectFollower adds itself if set.
- **/
- public function new( obj, ?parent ) {
- super(parent);
- this.follow = obj;
- }
- function followObject() {
- if( follow == null )
- return;
- var scene = @:privateAccess follow.getScene();
- if( scene == null )
- return;
- var s2d = getScene();
- var width = s2d == null ? h3d.Engine.getCurrent().width : s2d.width;
- var height = s2d == null ? h3d.Engine.getCurrent().height : s2d.height;
- var absPos = follow.getAbsPos();
- var pos = new h3d.Vector();
- if( cameraRelative ) {
- var m = new h3d.Matrix();
- inline m.load(scene.camera.mcam);
- inline m.transpose();
- var tmp = new h3d.Vector(offsetX, offsetZ, offsetY);
- tmp.transform3x3(m);
- pos.set(absPos._41 + tmp.x, absPos._42 + tmp.y, absPos._43 + tmp.z);
- } else {
- pos.set(absPos._41 + offsetX, absPos._42 + offsetY, absPos._43 + offsetZ);
- }
- var p = scene.camera.project(pos.x, pos.y, pos.z, width * outputScale, height * outputScale, tmpPos);
- zValue = p.z;
- if( horizontalAlign != Left || verticalAlign != Top ) {
- if( tmpSize == null ) tmpSize = new h2d.col.Bounds();
- var prev = follow;
- follow = null;
- var b = getSize(tmpSize); // prevent recursive
- follow = prev;
- var w = b.width, h = b.height;
- switch( horizontalAlign ) {
- case Middle: p.x -= w * 0.5;
- case Right: p.x -= w;
- default:
- }
- switch( verticalAlign ) {
- case Middle: p.y -= h * 0.5;
- case Bottom: p.y -= h;
- default:
- }
- }
- if( pixelSnap ) {
- p.x = Math.round(p.x);
- p.y = Math.round(p.y);
- }
- x = p.x;
- y = p.y;
- if( depthBias != 0 ) {
- var move = scene.camera.pos.sub(pos).normalized();
- pos.x += move.x * depthBias;
- pos.y += move.y * depthBias;
- pos.z += move.z * depthBias;
- var p2 = scene.camera.project(pos.x, pos.y, pos.z, width, height, tmpPos);
- zValue = p2.z;
- }
- }
- override function calcAbsPos() {
- super.calcAbsPos();
- absX = x;
- absY = y;
- }
- override function syncPos() {
- if( follow == null ) {
- if( posChanged ) {
- calcAbsPos();
- for( c in children )
- c.posChanged = true;
- posChanged = false;
- }
- return;
- }
- followObject();
- super.syncPos();
- }
- override function sync(ctx) {
- followObject();
- super.sync(ctx);
- }
- override function drawRec(ctx:RenderContext) {
- if( !visible || zValue < 0 || zValue > 1 )
- return;
- if( followVisibility ) {
- var parent = follow;
- while(parent != null) {
- if( !parent.visible )
- return;
- parent = parent.parent;
- }
- }
- if( !depthMask ) {
- super.drawRec(ctx);
- return;
- }
- @:privateAccess {
- var prev = ctx.baseShader.zValue;
- var prevMode = ctx.pass.depthTest, prevWrite = ctx.pass.depthWrite;
- if( prevMode != LessEqual ) {
- ctx.pass.depth(true, LessEqual);
- ctx.engine.selectMaterial(ctx.pass);
- }
- ctx.baseShader.zValue = zValue;
- super.drawRec(ctx);
- ctx.baseShader.zValue = prev;
- if( prevMode != LessEqual ) {
- ctx.pass.depth(prevWrite, prevMode);
- ctx.engine.selectMaterial(ctx.pass);
- }
- }
- }
- }
|