/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using Leap.Unity.Drawing; using Leap.Unity.RuntimeGizmos; using UnityEngine; namespace Leap.Unity.Geometry { public struct Box { public Transform transform; public Vector3 center; public Vector3 radii; public Matrix4x4? overrideMatrix; private Box(LocalBox localBox) { this.center = localBox.center; this.radii = localBox.radii; this.transform = null; this.overrideMatrix = null; } public Box(LocalBox localBox, Transform withTransform) : this(localBox) { this.transform = withTransform; } public Box(Vector3 center, Vector3 radii, Component transformSource = null) { this.center = center; this.radii = radii; if (transformSource != null) { this.transform = transformSource.transform; } else { this.transform = null; } this.overrideMatrix = null; } public Box(Vector3 radii) : this(Vector3.zero, radii) { } public Box(Vector3 radii, Component transformSource) : this(Vector3.zero, radii, transformSource) { } public Box(float radius) : this(Vector3.one * radius) { } public Box(float radius, Component transformSource) : this(Vector3.one * radius, transformSource) { } public static Box unit { get { return new Box(1f); } } /// /// Local-to-world matrix for this Box. /// public Matrix4x4 matrix { get { if (overrideMatrix != null) { return overrideMatrix.Value * Matrix4x4.Translate(center); } if (transform == null) { return Matrix4x4.Translate(center); } return transform.localToWorldMatrix * Matrix4x4.Translate(center); } } private Vector3 corner000 { get { return matrix.MultiplyPoint3x4(-radii); } } private Vector3 corner100 { get { return matrix.MultiplyPoint3x4(new Vector3( radii.x, -radii.y, -radii.z )); } } private Vector3 corner010 { get { return matrix.MultiplyPoint3x4(new Vector3( -radii.x, radii.y, -radii.z )); } } private Vector3 corner110 { get { return matrix.MultiplyPoint3x4(new Vector3( radii.x, radii.y, -radii.z )); } } private Vector3 corner001 { get { return matrix.MultiplyPoint3x4(new Vector3( -radii.x, -radii.y, radii.z )); } } private Vector3 corner101 { get { return matrix.MultiplyPoint3x4(new Vector3( radii.x, -radii.y, radii.z )); } } private Vector3 corner011 { get { return matrix.MultiplyPoint3x4(new Vector3( -radii.x, radii.y, radii.z )); } } private Vector3 corner111 { get { return matrix.MultiplyPoint3x4(radii); } } /// Returns the world-space position of the normalized coordinates /// (X, Y, Z each from 0 to 1) given this box's radii and attached transform. /// public Vector3 Sample(Vector3 coords01) { var coordsN1to1 = coords01.CompWise(f => Mathf.Clamp01(f) * 2 - 1); return matrix.MultiplyPoint3x4(this.radii.CompMul(coordsN1to1)); } public void DrawLines(System.Action drawLineFunc, int divisions = 0) { divisions = Mathf.Max(1, divisions); var frac = 1f / divisions; drawDividedLines(draw: drawLineFunc, step: frac, a: corner000, b: corner100); drawDividedLines(draw: drawLineFunc, step: frac, a: corner000, b: corner010); drawDividedLines(draw: drawLineFunc, step: frac, a: corner110, b: corner100); drawDividedLines(draw: drawLineFunc, step: frac, a: corner110, b: corner010); drawDividedLines(draw: drawLineFunc, step: frac, a: corner000, b: corner001); drawDividedLines(draw: drawLineFunc, step: frac, a: corner100, b: corner101); drawDividedLines(draw: drawLineFunc, step: frac, a: corner010, b: corner011); drawDividedLines(draw: drawLineFunc, step: frac, a: corner110, b: corner111); drawDividedLines(draw: drawLineFunc, step: frac, a: corner001, b: corner101); drawDividedLines(draw: drawLineFunc, step: frac, a: corner001, b: corner011); drawDividedLines(draw: drawLineFunc, step: frac, a: corner111, b: corner101); drawDividedLines(draw: drawLineFunc, step: frac, a: corner111, b: corner011); } private void drawDividedLines(System.Action draw, float step, Vector3 a, Vector3 b) { step = Mathf.Max(0.01f, step); var a_t = a; for (var t = step; t <= 1f; t += step) { var b_t = Vector3.Lerp(a, b, t); draw(a_t, b_t); a_t = b_t; } } public void Draw(Drawer drawer, Color? color = null) { if (color != null) { drawer.color = color.Value; } DrawLines(drawer.Line); } public void DrawRuntimeGizmos(RuntimeGizmoDrawer drawer) { if (transform != null) { drawer.PushMatrix(); drawer.matrix = Matrix4x4.TRS(transform.TransformPoint(center), transform.rotation, Quaternion.Inverse(transform.rotation) * transform.TransformVector(radii)); drawBoxGizmos(drawer, Vector3.zero, Vector3.one); drawer.PopMatrix(); } else { drawBoxGizmos(drawer, center, radii); } } private void drawBoxGizmos(RuntimeGizmoDrawer drawer, Vector3 center, Vector3 radii) { drawer.DrawWireCube(center, radii * 2f); drawer.color = drawer.color.WithAlpha(0.05f); int div = 3; float invDiv = 1f / div; for (int i = 0; i < div; i++) { for (int j = 0; j < div; j++) { for (int k = 0; k < div; k++) { drawer.DrawWireCube((center + (new Vector3(i, j, k) - radii) * invDiv * 2), radii * invDiv * 2f); } } } drawer.color = drawer.color.WithAlpha(0.04f); drawer.DrawCube(center, radii * 2f); } } }