コード例 #1
0
        /// <summary>
        /// Calculate collision
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="sphereCollider"></param>
        /// <param name="result"></param>
        private static void CalculateCollision(ref Ray ray, ref SphereCollider3D sphereCollider, out RayCastResult result)
        {
            Vector3 sphereCenter = sphereCollider.Transform3D.Position;
            float   sphereRadius = sphereCollider.Radius * sphereCollider.Transform3D.Scale.X / 2;

            Vector3 m = ray.Position - sphereCenter;
            float   b = Vector3.Dot(m, ray.Direction);
            float   c = Vector3.Dot(m, m) - sphereRadius * sphereRadius;

            // Exit if r’s origin outside s (c > 0) and r pointing away from s (b > 0)
            if (c > 0.0f && b > 0.0f)
            {
                result = new RayCastResult();
                return;
            }

            float discr = b * b - c;

            // A negative discriminant corresponds to ray missing sphere
            if (discr < 0.0f)
            {
                result = new RayCastResult();
                return;
            }

            // Ray now found to intersect sphere, compute smallest t value of intersection
            float t = -b - (float)Math.Sqrt(discr);

            // If t is negative, ray started inside sphere so clamp t to zero
            if (t < 0.0f)
            {
                t = 0.0f;
            }

            Vector3 q      = ray.Position + t * ray.Direction;
            Vector3 normal = (q - sphereCenter);

            normal.Normalize();

            result = new RayCastResult()
            {
                HitBody = sphereCollider.Owner,
                HitData = new RayHit3D()
                {
                    Location = q,
                    Normal   = normal,
                    T        = t,
                }
            };
        }
        private AxisManipulationHelper CreateHandle(AxisManipulationHelperType amhType, AxisType axisType, Prefab prefab, Material idleMaterial, Material grabbedMaterial, Material focusedMaterial, Quaternion orientation, AxisManipulationHelper[] relatedHandlers)
        {
            // Entity name suffix
            var suffix = $"{amhType}_{axisType}";

            // Handle root
            var handle = new Entity($"handle_{suffix}")
                         .AddComponent(new Transform3D()
            {
                LocalScale = Vector3.One * this.HandleScale,
            });

            this.rigRootEntity.AddChild(handle);

            if (prefab != null)
            {
                // Instantiate prefab
                var prefabInstance = prefab.Instantiate();

                var prefabTransform = prefabInstance.FindComponent <Transform3D>();
                prefabTransform.LocalOrientation = orientation;

                handle.AddChild(prefabInstance);
            }
            else
            {
                // Generate default look for the handle
                Vector3   position = Vector3.Zero;
                Vector3   size     = Vector3.One;
                Component mesh     = null;
                Component collider = null;

                switch (amhType)
                {
                case AxisManipulationHelperType.Center:
                    var sphereDiameter = 1f;

                    mesh = new SphereMesh()
                    {
                        Diameter = sphereDiameter,
                    };
                    collider = new SphereCollider3D()
                    {
                        Margin = 0.0001f,
                        Radius = sphereDiameter,
                    };
                    break;

                case AxisManipulationHelperType.Axis:
                    var axisLength    = 4f;
                    var axisThickness = 0.5f;

                    size = new Vector3(axisLength, axisThickness, axisThickness);

                    mesh     = new CubeMesh();
                    collider = new BoxCollider3D()
                    {
                        Margin = 0.0001f,
                        Size   = size + Vector3.One,
                        Offset = Vector3.UnitX,
                    };

                    position = 0.5f * Vector3.UnitX * (axisLength + 2f);
                    break;

                case AxisManipulationHelperType.Plane:
                    var planeLength    = 2f;
                    var planeThickness = 0.25f;

                    size = new Vector3(planeLength, planeThickness, planeLength);

                    mesh     = new CubeMesh();
                    collider = new BoxCollider3D()
                    {
                        Margin = 0.0001f,
                        Size   = size + Vector3.One,
                        Offset = Vector3.UnitX + Vector3.UnitZ,
                    };

                    position = 0.5f * Vector3.Normalize(Vector3.UnitX + Vector3.UnitZ) * (planeLength + 2f);
                    break;
                }

                // Collider entity
                var handleCollider = new Entity($"collider_{suffix}")
                                     .AddComponent(new Transform3D()
                {
                    LocalPosition    = Vector3.Transform(position, orientation),
                    LocalOrientation = orientation,
                })
                                     .AddComponent(collider)
                                     .AddComponent(new StaticBody3D()
                {
                    CollisionCategories = this.CollisionCategory,
                    IsSensor            = true,
                })
                                     .AddComponent(new NearInteractionGrabbable());

                // Visual entity
                var handleVisual = new Entity($"visuals_{suffix}")
                                   .AddComponent(new Transform3D()
                {
                    LocalScale = size,
                })
                                   .AddComponent(mesh)
                                   .AddComponent(new MeshRenderer())
                                   .AddComponent(new MaterialComponent());

                // Build hierarchy
                handle.AddChild(handleCollider);
                handleCollider.AddChild(handleVisual);
            }

            // Apply material
            var materialComponents = handle.FindComponentsInChildren <MaterialComponent>().ToArray();

            this.ApplyMaterialToAllComponents(materialComponents, idleMaterial);

            // Register helper object
            var helperTargetEntity = handle.FindComponentInChildren <NearInteractionGrabbable>()?.Owner;

            if (helperTargetEntity == null)
            {
                throw new Exception($"The handle entity needs to have a {nameof(NearInteractionGrabbable)} component.");
            }

            var handleHelper = new AxisManipulationHelper()
            {
                Type               = amhType,
                AxisType           = axisType,
                BaseEntity         = handle,
                MaterialComponents = materialComponents,
                IdleMaterial       = idleMaterial,
                GrabbedMaterial    = grabbedMaterial,
                FocusedMaterial    = focusedMaterial,
                RelatedHandles     = relatedHandlers,
            };

            this.helpers.Add(helperTargetEntity, handleHelper);

            return(handleHelper);
        }