예제 #1
0
 // Start is called before the first frame update
 void Start()
 {
     print("Spawned Particle system");
     _sourceHandler = sourceLight.GetComponent <IncorporatedParticleImage>();
     // _sourceHandler = sourceLight.GetComponent<RefractionBlockFromPointLight>();
     // _sourceHandlerTest = sourceLight.GetComponent<VirtualImageProblem>();
 }
        // Update is called once per frame
        void Update()
        {
            switch (_status)
            {
            case Status.SeekingPoints:     // Look for points to render to
                _postComplete = false;
                // Change how this is done depending on the image type
                if (imageType == ImageType.OriginalObject || imageType == ImageType.MirrorRealImage)
                {
                    // Generate corresponding particle system
                    _seekParticleSystem =
                        Instantiate(Resources.Load <GameObject>("Simulations/SphericalSurfaceSeekPS"));

                    if (_seekParticleSystem != null)
                    {
                        // Set transforms to match this object
                        _seekParticleSystem.transform.position   = _myPos;
                        _seekParticleSystem.transform.localScale = transform.localScale;

                        // set it's source to this object
                        SeekParticleSystemHandler seekHandler =
                            _seekParticleSystem.AddComponent <SeekParticleSystemHandler>();
                        seekHandler.myParticleSystem =
                            _seekParticleSystem.GetComponent <ParticleSystem>();
                        seekHandler.sourceLight = gameObject;
                        if (imageType == ImageType.MirrorRealImage)
                        {
                            seekHandler.sourceImageObject = sourceSceneObject;
                        }
                    }
                }
                else if (imageType == ImageType.MirrorVirtualImage)
                {
                    // SECTION: get border verts
                    Mesh      sourceMirrorMesh = sourceSceneObject.GetComponent <MeshFilter>().mesh;
                    Vector3[] verts            = sourceMirrorMesh.vertices;

                    // print("Full list of Verts (" + verts.Length + "):\n");
                    // VertListToString(verts);

                    // SECTION: only unique
                    verts = verts.ToList().Distinct().ToArray();

                    // print("Only unique verts (" + verts.Length + "):\n");
                    // VertListToString(verts);

                    // SECTION: convert to world space
                    for (int i = 0; i < verts.Length; i++)
                    {
                        verts[i] = sourceSceneObject.transform.TransformPoint(verts[i]);
                    }

                    // print("Transformed unique verts (" + verts.Length + "):\n");
                    // VertListToString(verts);

                    // SECTION: Debug with rays
                    // foreach (Vector3 vert in verts)
                    // {
                    //     Debug.DrawRay(_myPos, (vert - _myPos).normalized * 15, Color.cyan, Mathf.Infinity);
                    // }

                    // SECTION: create seek mesh verts, set 0 -> myPos
                    Vector3[] newVerts = new Vector3[verts.Length + 1];

                    newVerts[0] = _myPos;

                    for (int i = 1; i < newVerts.Length; i++)
                    {
                        newVerts[i] = _myPos + (verts[i - 1] - _myPos).normalized * 15;
                    }

                    // print("New mesh verts:");
                    // VertListToString(newVerts);

                    // SECTION: Debug new verts with lines
                    // foreach (Vector3 vert in newVerts)
                    // {
                    //     Debug.DrawLine(_myPos, vert, Color.magenta, Mathf.Infinity);
                    // }

                    // SECTION: assign triangles from newVerts
                    int[] tris = new int[(newVerts.Length - 1) * 3];
                    for (int i = 0; i < newVerts.Length - 1; i++)
                    {
                        tris[i * 3] = i + 1;

                        if (i + 2 == newVerts.Length)
                        {
                            tris[i * 3 + 1] = 1;
                        }
                        else
                        {
                            tris[i * 3 + 1] = i + 2;
                        }

                        tris[i * 3 + 2] = 0;
                    }

                    // print("Tris list:");
                    // IntListToString(tris);

                    // SECTION: create gameobject from verts and tris
                    GameObject seekObject = new GameObject(gameObject.name + "VirtualImageSeekCast");
                    Mesh       seekMesh   = new Mesh();

                    seekMesh.vertices  = newVerts;
                    seekMesh.triangles = tris;
                    seekMesh.RecalculateNormals();
                    seekMesh.RecalculateBounds();

                    // seekObject.AddComponent<MeshRenderer>();

                    MeshFilter meshFilter = seekObject.AddComponent <MeshFilter>();
                    meshFilter.mesh = seekMesh;

                    MeshCollider meshCollider = seekObject.AddComponent <MeshCollider>();
                    meshCollider.convex = true;
                    // meshCollider.sharedMesh = seekMesh;

                    // SECTION: create particle system and check for points
                    _seekParticleSystem =
                        Instantiate(Resources.Load <GameObject>("Simulations/SemiSphericalSurfaceSeekPS"));

                    if (_seekParticleSystem != null)
                    {
                        Vector3 sourceSceneObjectPos = sourceSceneObject.transform.position;

                        Vector3 sourceSceneObjectForward = sourceSceneObject.transform.forward;
                        Vector3 dirToSourceObject        =
                            (sourceSceneObjectPos - _myPos).normalized;
                        float dot = Vector3.Dot(dirToSourceObject, sourceSceneObjectForward);
                        dot = dot > 0 ? 1 : -1;
                        _seekParticleSystem.transform.rotation =
                            Quaternion.LookRotation(sourceSceneObjectForward * dot);

                        _seekParticleSystem.transform.position =
                            sourceSceneObjectPos + sourceSceneObjectForward * (dot * 0.05f);

                        Vector3 sourceMirrorTransformLocalScale = sourceSceneObject.transform.localScale;
                        _seekParticleSystem.transform.localScale = new Vector3(
                            sourceMirrorTransformLocalScale.x / 100,
                            sourceMirrorTransformLocalScale.y / 100,
                            sourceMirrorTransformLocalScale.z / 300);

                        SeekParticleSystemHandler particleSystemHandler =
                            _seekParticleSystem.AddComponent <SeekParticleSystemHandler>();

                        particleSystemHandler.myParticleSystem =
                            _seekParticleSystem.GetComponent <ParticleSystem>();
                        particleSystemHandler.sourceLight       = gameObject;
                        particleSystemHandler.sourceImageObject = sourceSceneObject;
                        particleSystemHandler.validVolume       = meshCollider;
                    }
                }
                else
                {
                    print(_myName + ": has unknown imageType: " + imageType);
                }

                _status            = Status.WaitingForPointSeek;
                _objectPointsIndex = 0;

                break;

            case Status.PreRendering:     // collect data and render with appropriate method
                // Destroy seek particle system (it's done with its work)
                Destroy(_seekParticleSystem);
                // Complete this object's job is it is done
                if (_objectPointsIndex.Equals(_objectPointsToRender.Count))
                {
                    print(_myName + ": completed all points to render! Status is now COMPLETE");
                    _status = Status.Complete;
                    break;
                }

                // Get the appropriate data for the current object indexed
                _curTargetObject     = _objectsInScene[_objectPointsIndex];
                _curInteractionPoint = _objectPointsToRender[_objectPointsIndex];
                print(_myName + ": Rendering point: " + _curInteractionPoint);

                // Check the type of object, and render
                if (_curTargetObject.GetComponent <PlaneMirrorDef>() != null)
                {
                    print(_myName + ": point " + _curInteractionPoint + " is a plane mirror! Rendering...");
                    _status = Status.PlaneMirrorRendering;
                }
                else if (_curTargetObject.GetComponent <SphericalMirrorDef>() != null)
                {
                    print(_myName + ": point " + _curInteractionPoint + " is a spherical mirror! Rendering...");
                    _status = Status.SphericalMirrorRendering;
                }
                else if (_curTargetObject.GetComponent <ThinLensDef>() != null)
                {
                    print(_myName + ": point " + _curInteractionPoint + " is a thin lens! Rendering...");
                    _status = Status.ThinLensRendering;
                }
                else     // WTF?
                {
                    print(_myName + ": Encountered unknown object: " + _curTargetObject.name);
                    _curTargetObject.GetComponent <Renderer>().material.color = Color.red;
                }

                break;

            case Status.PlaneMirrorRendering:
                ObjectSeekHits curSeekHit = _objectSeekHits[_objectPointsIndex];

                print(_myName + ": rendering a plane mirror from " + _myPos + " to " + _curInteractionPoint +
                      " on mirror " + curSeekHit.ObjName);

                Vector3 mirrorNorm = curSeekHit.HitNormal;

                Vector3 exitDir = Quaternion.AngleAxis(180, mirrorNorm) *
                                  -(_curInteractionPoint - _myPos).normalized;
                float imageDistance = Vector3.Distance(_myPos, _curInteractionPoint);

                Debug.DrawLine(_myPos, _curInteractionPoint, Color.cyan, Mathf.Infinity);
                Debug.DrawRay(_curInteractionPoint, mirrorNorm, Color.red, Mathf.Infinity);
                Debug.DrawRay(_curInteractionPoint, exitDir, Color.green, Mathf.Infinity);
                Debug.DrawRay(_curInteractionPoint, -exitDir * imageDistance, Color.yellow,
                              Mathf.Infinity);

                Vector3 outputImagePos = _curInteractionPoint - exitDir * imageDistance;

                print(_myName + ": Found image location at " + outputImagePos);

                GameObject image = Instantiate(Resources.Load <GameObject>("Objects/ParticleImagePoint"),
                                               outputImagePos,
                                               Quaternion.identity);

                // Give this new virtual image a unique name to be identified by
                image.name = _myName + " (Virtual image) " + _generatedImageId;
                _generatedImageId++;

                IncorporatedParticleImage incorporatedParticleImage =
                    image.GetComponent <IncorporatedParticleImage>();
                incorporatedParticleImage.imageType         = ImageType.MirrorVirtualImage;
                incorporatedParticleImage.sourceSceneObject = _curTargetObject;

                print(_myName + ": created virtual image of " + _curTargetObject.name + " with name " + image.name);

                // Return to prerendering for the next point
                _objectPointsIndex++;
                _status = Status.PreRendering;
                print(_myName + ": moving to work on point index " + _objectPointsIndex +
                      ". going back to prerendering");

                break;

            case Status.SphericalMirrorRendering:
                curSeekHit = _objectSeekHits[_objectPointsIndex];
                print(_myName + ": rendering a spherical mirror from " + _myPos + " to " + curSeekHit.ObjName);
                // Get target spherical mirror def
                SphericalMirrorDef sphericalMirrorDef = _curTargetObject.GetComponent <SphericalMirrorDef>();

                // Get direction to mirror origin
                Vector3 rayToOrigin = (sphericalMirrorDef.GetPos() - _myPos).normalized;

                // Get direction to mirror center of curvature
                Vector3 rayToCenterOfCurvature = (sphericalMirrorDef.GetCenter() - _myPos).normalized;

                //// Calculate reflection vector
                // Get which side object is on
                Vector3 targetForward = _curTargetObject.transform.forward;
                float   objectDot     = Vector3.Dot(targetForward, rayToOrigin);
                int     clampDot      = objectDot > 0 ? 1 : -1;

                // Calculate exit dir
                Vector3 hitNormal = targetForward * clampDot;

                exitDir = Quaternion.AngleAxis(180, hitNormal) * -rayToOrigin;

                // Calculate intersection point between
                if (Math3d.ClosestPointsOnTwoLines(out Vector3 cp1, out Vector3 cp2, sphericalMirrorDef.GetPos(),
                                                   exitDir.normalized, _myPos, rayToCenterOfCurvature))
                {
                    float distanceBetween = Vector3.Distance(cp1, cp2);
                    if (distanceBetween < 0.1f)
                    {
                        Vector3 avgPoint = (cp1 + cp2) / 2;
                        print(_myName + ": Found spherical image loc at " + avgPoint);

                        // Generate new image from point
                        image = Instantiate(Resources.Load <GameObject>("Objects/ParticleImagePoint"),
                                            avgPoint,
                                            Quaternion.identity);

                        // Give this new virtual image a unique name to be identified by
                        image.name = _myName + " (Virtual image) " + _generatedImageId;
                        _generatedImageId++;

                        incorporatedParticleImage =
                            image.GetComponent <IncorporatedParticleImage>();

                        // Detect if it is a virtual or real image
                        float imagePointDot = Vector3.Dot(targetForward,
                                                          (sphericalMirrorDef.GetCenter() - avgPoint).normalized);
                        incorporatedParticleImage.imageType = imagePointDot > 0
                                ? ImageType.MirrorRealImage
                                : ImageType.MirrorVirtualImage;

                        incorporatedParticleImage.sourceSceneObject = _curTargetObject;

                        print(_myName + ": created virtual image of " + _curTargetObject.name + " with name " +
                              image.name);

                        // Return to prerendering for the next point
                        _objectPointsIndex++;
                        _status = Status.PreRendering;
                        print(_myName + ": moving to work on point index " + _objectPointsIndex +
                              ". going back to prerendering");
                    }
                    else
                    {
                        print(_myName + ": Points are not close! Distance: " + distanceBetween);
                    }
                }
                else
                {
                    print(_myName + "Handle image straight on");
                }

                break;