Exemplo n.º 1
0
        void CheckCamera()
        {
            Camera cam = currentCamera;

            if (cam == null)
            {
                return;
            }

            currentCamPos   = cam.transform.position;
            currentCamRot   = cam.transform.rotation;
            _cameraHasMoved = (lastCamPos != currentCamPos || lastCamRot != currentCamRot);
            if (_cameraHasMoved)
            {
                lastCamPos = currentCamPos;
                lastCamRot = currentCamRot;
                if (frustumPlanes == null)
                {
                    frustumPlanes          = new Plane[6];
                    frustumPlanesDistances = new float[6];
                    frustumPlanesNormals   = new Vector3[6];
                }
#if UNITY_IOS || UNITY_WEBGL
                                #if UNITY_2017_3_OR_NEWER
                GeometryUtility.CalculateFrustumPlanes(cam.projectionMatrix * cam.worldToCameraMatrix, frustumPlanes);
                                #else
                frustumPlanes = GeometryUtility.CalculateFrustumPlanes(cam.projectionMatrix * cam.worldToCameraMatrix);
                                #endif
#else
                GeometryUtilityNonAlloc.CalculateFrustumPlanes(frustumPlanes, cam.projectionMatrix * cam.worldToCameraMatrix);
#endif
                for (int k = 0; k < 6; k++)
                {
                    frustumPlanesDistances [k] = frustumPlanes [k].distance;
                    frustumPlanesNormals [k]   = frustumPlanes [k].normal;
                }

                if (frustumCorners == null || frustumCorners.Length != 4)
                {
                    frustumCorners = new Vector3[4];
                }
                cam.CalculateFrustumCorners(Misc.rectFullViewport, cam.farClipPlane, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
                for (int i = 0; i < 4; i++)
                {
                    frustumCorners [i] = cam.transform.position + cam.transform.TransformVector(frustumCorners [i]);
                }
                shouldCheckChunksInFrustum = true;
            }
        }
        VoxelChunk PopNearestChunk(int frustumCheckIteration, float acceptedDistanceSqr, float forceChunkSqrDistance, out float chunkDist)
        {
            chunkDist = 1e8f;
            int   nearestNode = 0;
            float minDist     = float.MaxValue;
            int   node        = chunkQueueRoot;

            while (node > 0)
            {
                VoxelChunk chunk = linkedChunks [node].chunk;
                float      cdx   = chunk.position.x - currentCamPos.x;
                float      cdz   = chunk.position.z - currentCamPos.z;
                float      dist  = cdx * cdx + cdz * cdz;

                // if chunk is within forced visible distance, return it immediately
                if (dist <= forceChunkSqrDistance)
                {
                    chunkDist   = dist;
                    nearestNode = node;
                    break;
                }

                // otherwise, prioritize by distance and frustum
                if (frustumCheckIteration != chunk.frustumCheckIteration)
                {
                    chunk.frustumCheckIteration = frustumCheckIteration;
                    Vector3 boundsMin;
                    boundsMin.x = chunk.position.x - 8;
                    boundsMin.y = chunk.position.y - 8;
                    boundsMin.z = chunk.position.z - 8;
                    Vector3 boundsMax;
                    boundsMax.x            = chunk.position.x + 8;
                    boundsMax.y            = chunk.position.y + 8;
                    boundsMax.z            = chunk.position.z + 8;
                    chunk.visibleInFrustum = GeometryUtilityNonAlloc.TestPlanesAABB(frustumPlanesNormals, frustumPlanesDistances, ref boundsMin, ref boundsMax);
                }

                float frontDist = dist;
                if (!chunk.visibleInFrustum && !chunk.ignoreFrustum)
                {
                    bool inDistance = frontDist <= acceptedDistanceSqr;
                    if (onlyRenderInFrustum && !inDistance)
                    {
                        node = linkedChunks [node].next;
                        continue;
                    }
                    frontDist += 1000000000;
                }
                if (frontDist < minDist)
                {
                    minDist     = frontDist;
                    chunkDist   = dist;
                    nearestNode = node;
                    if (frontDist < acceptedDistanceSqr)
                    {
                        break;
                    }
                }
                node = linkedChunks [node].next;
            }
            if (nearestNode > 0)
            {
                if (nearestNode == chunkQueueRoot)
                {
                    chunkQueueRoot = linkedChunks [nearestNode].next;
                    linkedChunks [chunkQueueRoot].prev = 0;
                }
                else
                {
                    if (linkedChunks [nearestNode].prev > 0)
                    {
                        linkedChunks [linkedChunks [nearestNode].prev].next = linkedChunks [nearestNode].next;
                    }
                    if (linkedChunks [nearestNode].next > 0)
                    {
                        linkedChunks [linkedChunks [nearestNode].next].prev = linkedChunks [nearestNode].prev;
                    }
                }
                linkedChunks [nearestNode].used = false;
                VoxelChunk chunk = linkedChunks [nearestNode].chunk;
                return(chunk);
            }
            return(null);
        }
        void CheckCuboidVisibility(Octree cuboid)
        {
            if (cuboid.exploredChildren >= 8)
            {
                return;
            }

            Vector3 cuboidCenter = cuboid.center;
            float   dx           = cuboidCenter.x - currentCamPos.x;

            if (dx < 0)
            {
                dx = -dx;                 // simple abs()
            }
            dx -= cuboid.extents;
            dx /= 16f;
            if (dx > _visibleChunksDistance)
            {
                return;
            }
            float dy = cuboidCenter.y - currentCamPos.y;

            if (dy < 0)
            {
                dy = -dy;
            }
            dy -= cuboid.extents;
            dy /= 16f;
            int chunksYDistance = _visibleChunksDistance >= 8 ? 8 : _visibleChunksDistance;

            if (dy > chunksYDistance)
            {
                return;
            }
            float dz = cuboidCenter.z - currentCamPos.z;

            if (dz < 0)
            {
                dz = -dz;
            }
            dz -= cuboid.extents;
            dz /= 16f;
            if (dz > _visibleChunksDistance)
            {
                return;
            }

            Vector3 cuboidMin, cuboidMax;

            cuboidMin.x = cuboidCenter.x - cuboid.extents;
            cuboidMin.y = cuboidCenter.y - cuboid.extents;
            cuboidMin.z = cuboidCenter.z - cuboid.extents;
            cuboidMax.x = cuboidCenter.x + cuboid.extents;
            cuboidMax.y = cuboidCenter.y + cuboid.extents;
            cuboidMax.z = cuboidCenter.z + cuboid.extents;

            bool inFrustum;

            if (onlyRenderInFrustum)
            {
                inFrustum = GeometryUtilityNonAlloc.TestPlanesAABB(frustumPlanesNormals, frustumPlanesDistances, ref cuboidMin, ref cuboidMax);
            }
            else
            {
                inFrustum = true;
            }
            if (inFrustum)
            {
                int cuboidSize = cuboid.extents * 2;
                if (cuboidSize > 16)
                {
                    if (cuboid.children == null)
                    {
                        cuboid.Explode();
                    }
                    for (int k = 0; k < 8; k++)
                    {
                        if (!cuboid.children [k].explored)
                        {
                            PushCuboid(cuboid.children [k]);
                        }
                    }
                    return;
                }

                // cuboid is less than a chunk - use that chunk
                int chunkX, chunkY, chunkZ;
                GetChunkCoordinates(cuboid.center, out chunkX, out chunkY, out chunkZ);
                int hash = GetChunkHash(chunkX, chunkY, chunkZ);

                CachedChunk cachedChunk;
                if (cachedChunks.TryGetValue(hash, out cachedChunk))
                {
                    cachedChunk.octree = cuboid;
                    cuboid.parent.exploredChildren++;
                    cuboid.explored = true;
                    VoxelChunk chunk = cachedChunk.chunk;
                    if (chunk == null)
                    {
                        return;
                    }
                    if (chunk.isPopulated)
                    {
                        // If this chunk has been created but not rendered yet, request it
                        //	if (chunk.renderState == ChunkRenderState.Pending && !chunk.inqueue) {
                        if (chunk.renderState != ChunkRenderState.RenderingComplete || !chunk.mr.enabled)
                        {
                            if (chunk.inqueue)
                            {
                                chunk.needsMeshRebuild = true;
                            }
                            else
                            {
                                ChunkRequestRefresh(chunk, false, true);
                            }
                        }
                        return;
                    }
                }

                CreateChunk(hash, chunkX, chunkY, chunkZ, false);
                chunkCreationCountThisFrame++;
            }
        }