Esempio n. 1
0
 private void Update()
 {
     //Rate Limit it to doing a cull-calculation every 10 physics-second frames, which should be plenty.  These are very heavy.
     counter++;
     if (counter > 500)
     {
         counter = 0;
         if (maxdistance == -1)
         {
             maxdistance = Kopernicus.RuntimeUtility.RuntimeUtility.KopernicusConfig.ScatterCullDistance;
         }
         //if 0 abort.
         if (maxdistance == 0)
         {
             return;
         }
         surfaceObjectQuad = GetComponentInParent <PQSMod_LandClassScatterQuad>();
         kopSurfaceObjects = surfaceObjectQuad.GetComponentsInChildren <KopernicusSurfaceObject>(true);
         if (kopSurfaceObjects.Length == 0)
         {
             return;
         }
         int distance = 15000;
         if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ActiveVessel)
         {
             distance = (int)Vector3.Distance(FlightGlobals.ActiveVessel.transform.position, surfaceObjectQuad.transform.position);
         }
         else
         {
             distance = 0;
         }
         //Optimization checks
         if ((distance > maxdistance) && (kopSurfaceObjects[0].GetComponent <MeshRenderer>().enabled == false))
         {
             return;
         }
         if ((distance <= maxdistance) && (kopSurfaceObjects[0].GetComponent <MeshRenderer>().enabled == true))
         {
             return;
         }
         for (int i = 0; i < kopSurfaceObjects.Length; i++)
         {
             MeshRenderer surfaceObject = kopSurfaceObjects[i].GetComponent <MeshRenderer>();
             if (distance > maxdistance)
             {
                 surfaceObject.enabled = false;
             }
             else
             {
                 surfaceObject.enabled = true;
             }
         }
     }
     else
     {
         return;
     }
 }
Esempio n. 2
0
 private void Update()
 {
     //Rate Limit it to doing a cull-calculation every 120 frames, which should be plenty since we don't update more anyways.  These are very heavy.
     counter++;
     if (counter > 120)
     {
         if (!init)
         {
             init        = true;
             maxdistance = Kopernicus.RuntimeUtility.RuntimeUtility.KopernicusConfig.ScatterCullDistance;
         }
         surfaceObjectQuad = GetComponentInParent <PQSMod_LandClassScatterQuad>();
         surfaceObjects    = surfaceObjectQuad.GetComponentsInChildren <MeshRenderer>(true);
         counter           = 0;
         int distance = 15000;
         if (HighLogic.LoadedSceneIsFlight)
         {
             distance = (int)Vector3.Distance(Camera.current.transform.position, surfaceObjectQuad.transform.position);
         }
         else
         {
             distance = 0;
         }
         for (int i = 0; i < surfaceObjects.Length; i++)
         {
             MeshRenderer surfaceObject = surfaceObjects[i];
             if (distance > maxdistance)
             {
                 surfaceObject.enabled = false;
             }
             else
             {
                 surfaceObject.enabled = true;
             }
         }
     }
     else
     {
         return;
     }
 }
Esempio n. 3
0
        /// <summary>
        ///   Recalculates the distance to a hit item, or -1f if nothing
        ///   was hit by the laser.
        /// </summary>
        /// <returns></returns>
        private void castUpdate()
        {
            if (resetHitThisUpdate)
            {
                updateForcedResultAge = 0;
            }
            else
            {
                ++updateForcedResultAge;
            }

            float newDist = -1f;

            // The location of origin is different in LateUpdate than it is
            // in Update, so it has to be reset in both:
            origin   = this.part.transform.TransformPoint(relLaserOrigin);
            pointing = this.part.transform.rotation * Vector3d.down;
            HitName  = "<none>";
            if (hasPower && Activated && origin != null && pointing != null)
            {
                // the points on the map-space corresponding to these points is different:
                mapOrigin   = ScaledSpace.LocalToScaledSpace(origin);
                mapPointing = pointing;

                if (bestLateUpdateHit.distance >= 0)
                {
                    Debug.Log("  using local raycast result.");
                    UpdateAge = updateForcedResultAge;

                    RaycastHit hit = bestLateUpdateHit;

                    newDist = hit.distance;

                    // Walk up the UnityGameObject tree trying to find an object that is
                    // something the user will be familiar with:
                    GameObject hitObject = hit.transform.gameObject;
                    if (hitObject != null)
                    {
                        HitName = hitObject.name; // default if the checks below don't work.

                        // Despite the name and what the Unity documentation says,
                        // GetComponentInParent actually looks all the way up the
                        // ancestor list, not just in Parents, so these following
                        // checks are walking up the ancestors to find the one that
                        // has a KSP component assigned to it:
                        if (hitObject.layer == 15)
                        {
                            // Support Kopernicus scatter colliders
                            // - no more crashing into boulders
                            // - shoot them with lasers! (and then drive around them)
                            PQSMod_LandClassScatterQuad scatter = hitObject.GetComponentInParent <PQSMod_LandClassScatterQuad>();
                            if (scatter != null)
                            {
                                HitName = scatter.transform.parent.name; // the name of the Scatter, eg. "Scatter boulder".
                            }
                            else
                            {
                                // Fallback to the body.
                                CelestialBody body = hitObject.GetComponentInParent <CelestialBody>();
                                if (body != null)
                                {
                                    HitName = body.name;
                                }
                            }
                        }
                        else
                        {
                            Part part = hitObject.GetComponentInParent <Part>();
                            if (part != null)
                            {
                                HitName = part.name;
                            }
                        }
                        UpdateAge = 0;
                    }
                }
                // If the hit is not found, or it is found but is far enough
                // away that it might be on the other side of the planet, seen
                // through the ocean (which has no collider so raycasts pass
                // through it), then try the more expensive pqs ray cast solver.
                if (newDist < 0 || newDist > 100000)
                {
                    Debug.Log("  numeric solver starting:.");
                    double        pqsDist;
                    CelestialBody pqsBody;
                    bool          success = pqsTool.RayCast(origin, pointing, out pqsBody, out pqsDist);
                    if (pqsTool.UpdateAge == 0)
                    {
                        Debug.Log("    UpdateAge == 0.");
                        if (success)
                        {
                            Debug.Log("      success.");
                            // If it's a closer hit than we have already, then use it:
                            if (pqsDist < newDist || newDist < 0)
                            {
                                HitName = pqsBody.name;
                                newDist = (float)pqsDist;
                            }
                        }
                    }
                    else
                    {
                        Debug.Log("    UpdateAge != 0.");
                        if (pqsTool.PrevSuccess)
                        {
                            Debug.Log("      prevsuccess.");
                            // If it's a closer hit than we have already, then use it:
                            if (pqsTool.PrevDist < newDist || newDist < 0)
                            {
                                Debug.Log("      prevsuccess.");
                                HitName = pqsTool.PrevBodyName;
                                newDist = (float)pqsTool.PrevDist;
                            }
                        }
                    }
                    UpdateAge = pqsTool.UpdateAge;
                }
            }
            Distance = newDist;
            Debug.Log("Distance = " + Distance);
            resetHitThisUpdate = false;
        }
Esempio n. 4
0
        /// <summary>
        /// By default, KSP merges all scatters that are on one quad into one gigantic mesh that is then rendered.
        /// Because Kopernicus wants to know where each scatter actually is, we have to create our own scatter objects
        /// </summary>
        private void CreateScatterMeshes(PQSMod_LandClassScatterQuad quad)
        {
            Random.InitState(quad.seed);

            // Redo the density calculation
            if (useBetterDensity)
            {
                Dictionary <String, Double> densities = quad.quad.GetComponent <DensityContainer>().densities;
                if (densities.ContainsKey(quad.scatter.scatterName))
                {
                    Double density = densities[quad.scatter.scatterName];
                    if (ignoreDensityGameSetting && PQS.Global_ScatterFactor > 0)
                    {
                        density /= PQS.Global_ScatterFactor;
                    }
                    Double scatterN = density * quad.scatter.densityFactor *
                                      (quad.quad.quadArea / quad.quad.sphereRoot.radius / 1000.0) *
                                      quad.scatter.maxScatter;
                    scatterN  += Random.Range(-0.5f, 0.5f);
                    quad.count = Math.Min((Int32)Math.Round(scatterN), quad.scatter.maxScatter);
                }
            }

            for (Int32 i = 0; i < quad.count; i++)
            {
                if (useBetterDensity)
                {
                    // Generate a random number between 0 and 1. If it is above the spawn chance, abort
                    if (Random.value > spawnChance)
                    {
                        continue;
                    }
                }

                Int32 num2 = -1;
                Int32 num3 = -1;
                while (num3 == num2)
                {
                    Int32 num4 = Random.Range(1, PQS.cacheRes + 1);
                    Int32 num5 = Random.Range(1, PQS.cacheRes + 1);
                    Int32 x    = num4 + Random.Range(-1, 1);
                    Int32 z    = num5 + Random.Range(-1, 1);
                    num3 = PQS.vi(num4, num5);
                    num2 = PQS.vi(x, z);
                }

                Vector3 scatterPos = Vector3.Lerp(quad.quad.verts[num3], quad.quad.verts[num2], Random.value);
                Vector3 scatterUp  = quad.quad.sphereRoot.surfaceRelativeQuads
                    ? (Vector3)(scatterPos + quad.quad.positionPlanet).normalized
                    : scatterPos.normalized;

                scatterPos += scatterUp * quad.scatter.verticalOffset;
                Single     scatterAngle = Random.Range(rotation[0], rotation[1]);
                Quaternion scatterRot   = QuaternionD.AngleAxis(scatterAngle, scatterUp) * quad.quad.quadRotation;
                Single     scatterScale = Random.Range(quad.scatter.minScale, quad.scatter.maxScale);

                // Create a new object for the scatter
                GameObject scatterObject = new GameObject("Scatter");
                scatterObject.transform.parent        = quad.obj.transform;
                scatterObject.transform.localPosition = scatterPos;
                scatterObject.transform.localRotation = scatterRot;
                scatterObject.transform.localScale    = Vector3.one * scatterScale;
                scatterObject.AddComponent <KopernicusSurfaceObject>().objectName = quad.scatter.scatterName;
                MeshFilter filter = scatterObject.AddComponent <MeshFilter>();
                filter.sharedMesh = meshes.Count > 0 ? meshes[Random.Range(0, meshes.Count)] : baseMesh;
                MeshRenderer renderer = scatterObject.AddComponent <MeshRenderer>();
                renderer.sharedMaterial    = quad.scatter.material;
                renderer.shadowCastingMode = quad.scatter.castShadows ? ShadowCastingMode.On : ShadowCastingMode.Off;
                renderer.receiveShadows    = quad.scatter.recieveShadows;
                scatterObject.layer        = GameLayers.LOCAL_SPACE;
                scatterObjects.Add(scatterObject);
            }

            quad.obj.name = "Kopernicus-" + quad.scatter.scatterName;
        }
Esempio n. 5
0
        /// <summary>
        ///   Recalculates the distance to a hit item, or -1f if nothing
        ///   was hit by the laser.
        /// </summary>
        /// <returns></returns>
        private void castUpdate()
        {
            if (resetHitThisUpdate)
            {
                updateForcedResultAge = 0;
            }
            else
            {
                ++updateForcedResultAge;
            }
            float newDist = -1f;

            // The location of origin is different in LateUpdate than it is
            // in Update, so it has to be reset in both:
            UpdatePointing();

            HitName  = "<none>";
            HitLayer = "<none>";
            if (hasPower && Activated && origin != null && pointing != null)
            {
                // the points on the map-space corresponding to these points is different:
                mapOrigin   = ScaledSpace.LocalToScaledSpace(origin);
                mapPointing = pointing;

                if (bestLateUpdateHit.distance >= 0)
                {
                    DebugMsg("  using local raycast result.");
                    UpdateAge = updateForcedResultAge;

                    RaycastHit hit = bestLateUpdateHit;
                    newDist = hit.distance;

                    // Walk up the UnityGameObject tree trying to find an object that is
                    // something the user will be familiar with:
                    GameObject hitObject = (hit.transform == null ? null : hit.transform.gameObject);
                    if (hitObject != null)
                    {
                        HitLayer = LayerMask.LayerToName(hitObject.layer); // for debug reasons

                        HitName = hitObject.name;                          // default if the checks below don't work.

                        // Despite the name and what the Unity documentation says,
                        // GetComponentInParent actually looks all the way up the
                        // ancestor list, not just in Parents, so these following
                        // checks are walking up the ancestors to find the one that
                        // has a KSP component assigned to it:
                        if (hitObject.layer == 15)
                        {
                            // Support Kopernicus scatter colliders
                            // - no more crashing into boulders
                            // - shoot them with lasers! (and then drive around them)
                            PQSMod_LandClassScatterQuad scatter = hitObject.GetComponentInParent <PQSMod_LandClassScatterQuad>();
                            if (scatter != null)
                            {
                                HitName = scatter.transform.parent.name; // the name of the Scatter, eg. "Scatter boulder".
                            }
                            else
                            {
                                // Fallback to the body.
                                CelestialBody body = hitObject.GetComponentInParent <CelestialBody>();
                                if (body != null)
                                {
                                    HitName = body.name;
                                }
                            }
                        }
                        else
                        {
                            Part part = hitObject.GetComponentInParent <Part>();
                            if (part != null)
                            {
                                HitName = part.name;
                            }
                        }
                        UpdateAge = 0;
                    }
                }
                // If the hit is not found, or it is found but is far enough
                // away that it might be on the other side of the planet, seen
                // through the ocean (which has no collider so raycasts pass
                // through it), then try the more expensive pqs ray cast solver.
                if (newDist < 0 || newDist > 100000)
                {
                    DebugMsg("  numeric solver starting:.");
                    double        pqsDist;
                    CelestialBody pqsBody;
                    bool          success = pqsTool.RayCast(origin, pointing, out pqsBody, out pqsDist);
                    if (pqsTool.UpdateAge == 0)
                    {
                        DebugMsg("    UpdateAge == 0.");
                        if (success)
                        {
                            DebugMsg("      success.");
                            // If it's a closer hit than we have already, then use it:
                            if (pqsDist < newDist || newDist < 0)
                            {
                                HitName = pqsBody.name;
                                // Ignore any hit closer than 2km as probably bogus "vessel below PQS" hit:
                                // (it's possible for the actual terrain polygons to approximate the PQS curve
                                // in a way where the vessel sits "under" the PQS predicted altitude despite
                                // being above the polygon - that generates a bogus "hit terrain" false positive
                                // as the line goes from "under" the terrain to "above" it.  The PQS systen should
                                // not need to be queried for nearby terrain, so if there isn't a nearby real raycast
                                // hit, then don't believe it when PQS claims there is one:
                                if (pqsDist >= 2000)
                                {
                                    newDist = (float)pqsDist;
                                }
                            }
                        }
                    }
                    else
                    {
                        DebugMsg("    UpdateAge != 0.");
                        if (pqsTool.PrevSuccess)
                        {
                            DebugMsg("      prevsuccess.");
                            // If it's a closer hit than we have already, then use it:
                            if (pqsTool.PrevDist < newDist || newDist < 0)
                            {
                                DebugMsg("      prevsuccess.");
                                HitName = pqsTool.PrevBodyName;
                                // Ignore any hit closer than 2km as probably bogus "vessel below PQS" hit:
                                // (see comment above in the "if" about this.)
                                if (pqsTool.PrevDist >= 2000)
                                {
                                    newDist = (float)pqsTool.PrevDist;
                                }
                            }
                        }
                    }
                    UpdateAge = pqsTool.UpdateAge;
                }
            }
            Distance = newDist;
            DebugMsg("Distance = " + Distance);
            resetHitThisUpdate = false;
        }