private IEnumerator BuildTerrain(ElevationData elevation, Texture2D[] textures)
        {
            GameObject tc = GameObject.Find("terrain");

            if (tc != null)
            {
                GameObject.Destroy(tc);
            }
            yield return(null);

            // Center position of terrain.
            var position = this.transform.position;

            position -= new Vector3(SIZE / 2, 0, SIZE / 2);

            // Create terrain game object.
            GameObject terrainObject = new GameObject("terrain");

            terrainObject.transform.position = position;
            terrainObject.transform.parent   = this.transform;
            yield return(null);

            // Create terrain data.
            TerrainData terrainData = new TerrainData();

            terrainData.heightmapResolution = 33;
            terrainData.size = new Vector3(SIZE, HEIGHT, SIZE);
            terrainData.alphamapResolution = 32;
            terrainData.baseMapResolution  = 1024;
            terrainData.SetDetailResolution(1024, 8);
            yield return(null);

            // Tiles per side.
            var dimension = (int)Math.Sqrt(textures.Length);

            // Splat maps.
            var splats = new List <SplatPrototype>();

            foreach (var texture in textures)
            {
                splats.Add(new SplatPrototype()
                {
                    tileOffset = new Vector2(0, 0),
                    tileSize   = new Vector2(
                        SIZE / dimension,
                        SIZE / dimension
                        ),
                    texture = texture
                });
                yield return(null);
            }
            terrainData.splatPrototypes = splats.ToArray();
            terrainData.RefreshPrototypes();
            yield return(null);

            // Get tile
            var tile = this._place.Location.ToTile(this._place.Level);

            // Construct height map.
            float[,] data = new float[
                terrainData.heightmapWidth,
                terrainData.heightmapHeight
                            ];
            for (int x = 0; x < terrainData.heightmapWidth; x++)
            {
                for (int y = 0; y < terrainData.heightmapHeight; y++)
                {
                    // Scale elevation from 257x257 to 33x33
                    var x2 = Convert.ToInt32((double)x * 256 / (terrainData.heightmapWidth - 1));
                    var y2 = Convert.ToInt32((double)y * 256 / (terrainData.heightmapHeight - 1));

                    // Find index in Esri elevation array
                    var id = y2 * 257 + x2;

                    // Absolute height in map units.
                    var h1 = elevation.Heights[id];

                    // Height in model units.
                    var h2 = SIZE * (h1 - elevation.Min) / tile.Size;

                    // Apply exaggeration.
                    var h3 = h2 * VERTICAL_EXAGGERATION;

                    // Apply base offset.
                    var h4 = h3 + TERRAIN_BASE_HEIGHT;

                    // Final height.
                    data[terrainData.heightmapHeight - 1 - y, x] = h4;
                }
            }
            terrainData.SetHeights(0, 0, data);
            yield return(null);

            // Add alpha mapping
            //float[,,] maps = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight);
            var maps = new float[
                terrainData.alphamapWidth,
                terrainData.alphamapHeight,
                textures.Length
                       ];

            for (int y = 0; y < terrainData.alphamapHeight; y++)
            {
                for (int x = 0; x < terrainData.alphamapWidth; x++)
                {
                    // Convert alpha coordinates into tile index. Left to right, bottom to top.
                    var tilex = x / (terrainData.alphamapWidth / dimension);
                    var tiley = y / (terrainData.alphamapHeight / dimension);
                    var index = (dimension - tiley - 1) * dimension + tilex;
                    for (int t = 0; t < textures.Length; t++)
                    {
                        maps[y, x, t] = index == t ? 1f : 0f;
                    }
                }
            }
            terrainData.SetAlphamaps(0, 0, maps);
            yield return(null);

            // Create terrain collider.
            TerrainCollider terrainCollider = terrainObject.AddComponent <TerrainCollider>();

            terrainCollider.terrainData = terrainData;
            yield return(null);

            // Add terrain component.
            Terrain terrain = terrainObject.AddComponent <Terrain>();

            terrain.terrainData = terrainData;
            yield return(null);

            // Calculate mesh vertices and triangles.
            List <Vector3> vertices  = new List <Vector3>();
            List <int>     triangles = new List <int>();

            // Distance between vertices
            var step = SIZE / 32f;

            // Front
            for (int x = 0; x < terrainData.heightmapWidth; x++)
            {
                vertices.Add(new Vector3(x * step, 0f, 0f));
                vertices.Add(new Vector3(x * step, data[0, x], 0f));
            }
            yield return(null);

            // Right
            for (int z = 0; z < terrainData.heightmapHeight; z++)
            {
                vertices.Add(new Vector3(SIZE, 0f, z * step));
                vertices.Add(new Vector3(SIZE, data[z, terrainData.heightmapWidth - 1], z * step));
            }
            yield return(null);

            // Back
            for (int x = 0; x < terrainData.heightmapWidth; x++)
            {
                var xr = terrainData.heightmapWidth - 1 - x;
                vertices.Add(new Vector3(xr * step, 0f, SIZE));
                vertices.Add(new Vector3(xr * step, data[terrainData.heightmapHeight - 1, xr], SIZE));
            }
            yield return(null);

            // Left
            for (int z = 0; z < terrainData.heightmapHeight; z++)
            {
                var zr = terrainData.heightmapHeight - 1 - z;
                vertices.Add(new Vector3(0f, 0f, zr * step));
                vertices.Add(new Vector3(0f, data[zr, 0], zr * step));
            }
            yield return(null);

            // Quads
            for (int i = 0; i < vertices.Count / 2 - 1; i++)
            {
                triangles.AddRange(new int[] {
                    2 * i + 0,
                    2 * i + 1,
                    2 * i + 2,
                    2 * i + 2,
                    2 * i + 1,
                    2 * i + 3
                });
            }

            // Create single mesh for all four sides
            GameObject side = new GameObject("side");

            side.transform.position = position;
            side.transform.parent   = terrainObject.transform;
            yield return(null);

            // Create mesh
            Mesh mesh = new Mesh()
            {
                vertices  = vertices.ToArray(),
                triangles = triangles.ToArray()
            };

            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            yield return(null);

            MeshFilter meshFilter = side.AddComponent <MeshFilter>();

            meshFilter.mesh = mesh;
            yield return(null);

            MeshRenderer meshRenderer = side.AddComponent <MeshRenderer>();

            meshRenderer.material = new Material(Shader.Find("Standard"))
            {
                color = new Color32(0, 128, 128, 100)
            };
            yield return(null);

            MeshCollider meshCollider = side.AddComponent <MeshCollider>();

            yield return(null);

            buttonObject = Instantiate(buttonZoomPrefab, terrainObject.transform.position + new Vector3(0, 0.2f, 0), Quaternion.Euler(0, -90, 0)) as StableMenu;
            buttonObject.transform.parent = terrain.transform;
            yield return(null);
        }
Exemplo n.º 2
0
        public List <GameObjectRayHit> RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion)
        {
            var nodeHits = _objectTree.RaycastAll(ray);

            if (nodeHits.Count == 0)
            {
                return(new List <GameObjectRayHit>());
            }

            var boundsQConfig = new ObjectBounds.QueryConfig();

            boundsQConfig.ObjectTypes  = GameObjectTypeHelper.AllCombined;
            boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize;

            if (raycastPresicion == SceneRaycastPrecision.BestFit)
            {
                var hitList = new List <GameObjectRayHit>(10);
                foreach (var nodeHit in nodeHits)
                {
                    GameObject sceneObject = nodeHit.HitNode.Data;
                    if (sceneObject == null || !sceneObject.activeInHierarchy)
                    {
                        continue;
                    }

                    Renderer renderer = sceneObject.GetComponent <Renderer>();
                    if (renderer != null && !renderer.isVisible)
                    {
                        continue;
                    }

                    GameObjectType objectType = sceneObject.GetGameObjectType();
                    if (objectType == GameObjectType.Mesh)
                    {
                        GameObjectRayHit objectHit = RaycastMeshObject(ray, sceneObject);
                        if (objectHit != null)
                        {
                            hitList.Add(objectHit);
                        }
                    }
                    else
                    if (objectType == GameObjectType.Terrain)
                    {
                        TerrainCollider terrainCollider = sceneObject.GetComponent <TerrainCollider>();
                        if (terrainCollider != null)
                        {
                            RaycastHit hitInfo;
                            if (terrainCollider.Raycast(ray, out hitInfo, float.MaxValue))
                            {
                                hitList.Add(new GameObjectRayHit(ray, hitInfo));
                            }
                        }
                    }
                    else
                    if (objectType == GameObjectType.Sprite)
                    {
                        GameObjectRayHit objectHit = RaycastSpriteObject(ray, sceneObject);
                        if (objectHit != null)
                        {
                            hitList.Add(objectHit);
                        }
                    }
                    else
                    {
                        OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig);
                        if (worldOOBB.IsValid)
                        {
                            float t;
                            if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation))
                            {
                                var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation);
                                var hit      = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t);
                                hitList.Add(hit);
                            }
                        }
                    }
                }

                return(hitList);
            }
            else
            if (raycastPresicion == SceneRaycastPrecision.Box)
            {
                var hitList = new List <GameObjectRayHit>(10);
                foreach (var nodeHit in nodeHits)
                {
                    GameObject sceneObject = nodeHit.HitNode.Data;
                    if (sceneObject == null || !sceneObject.activeInHierarchy)
                    {
                        continue;
                    }

                    Renderer renderer = sceneObject.GetComponent <Renderer>();
                    if (renderer != null && !renderer.isVisible)
                    {
                        continue;
                    }

                    OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig);
                    if (worldOOBB.IsValid)
                    {
                        float t;
                        if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation))
                        {
                            var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation);
                            var hit      = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t);
                            hitList.Add(hit);
                        }
                    }
                }

                return(hitList);
            }

            return(new List <GameObjectRayHit>());
        }
Exemplo n.º 3
0
 public RasterTerrainMesh(TerrainCollider collider) : base(collider.transform)
 {
     SetpUpTerrainMesh(collider.terrainData, out _vertices, out _triangles);
     RecalcBounds();
 }
Exemplo n.º 4
0
        private void GenerateTerrain(List <HEU_LoadBufferVolume> terrainBuffers)
        {
            Transform parent = this.gameObject.transform;

            // Directory to store generated terrain files.
            string outputTerrainpath = GetOutputCacheDirectory();

            outputTerrainpath = HEU_Platform.BuildPath(outputTerrainpath, "Terrain");

            int numVolumes = terrainBuffers.Count;

            for (int t = 0; t < numVolumes; ++t)
            {
                if (terrainBuffers[t]._heightMap != null)
                {
                    GameObject newGameObject = new GameObject("heightfield_" + terrainBuffers[t]._tileIndex);
                    Transform  newTransform  = newGameObject.transform;
                    newTransform.parent = parent;

                    HEU_GeneratedOutput generatedOutput = new HEU_GeneratedOutput();
                    generatedOutput._outputData._gameObject = newGameObject;

                    Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent <Terrain>(newGameObject);

#if !HEU_TERRAIN_COLLIDER_DISABLED
                    TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent <TerrainCollider>(newGameObject);
#endif
                    // The TerrainData and TerrainLayer files needs to be saved out if we create them.
                    // Try user specified path, otherwise use the cache folder
                    string exportTerrainDataPath = terrainBuffers[t]._terrainDataExportPath;
                    if (string.IsNullOrEmpty(exportTerrainDataPath))
                    {
                        // This creates the relative folder path from the Asset's cache folder: {assetCache}/{geo name}/Terrain/Tile{tileIndex}/...
                        exportTerrainDataPath = HEU_Platform.BuildPath(outputTerrainpath, HEU_Defines.HEU_FOLDER_TERRAIN, HEU_Defines.HEU_FOLDER_TILE + terrainBuffers[t]._tileIndex);
                    }

                    bool bFullExportTerrainDataPath = HEU_Platform.DoesFileExist(exportTerrainDataPath);

                    if (!string.IsNullOrEmpty(terrainBuffers[t]._terrainDataPath))
                    {
                        // Load the source TerrainData, then make a unique copy of it in the cache folder

                        TerrainData sourceTerrainData = HEU_AssetDatabase.LoadAssetAtPath(terrainBuffers[t]._terrainDataPath, typeof(TerrainData)) as TerrainData;
                        if (sourceTerrainData == null)
                        {
                            Debug.LogWarningFormat("TerrainData, set via attribute, not found at: {0}", terrainBuffers[t]._terrainDataPath);
                        }

                        if (bFullExportTerrainDataPath)
                        {
                            terrain.terrainData = HEU_AssetDatabase.CopyAndLoadAssetAtGivenPath(sourceTerrainData, exportTerrainDataPath, typeof(TerrainData)) as TerrainData;
                        }
                        else
                        {
                            terrain.terrainData = HEU_AssetDatabase.CopyUniqueAndLoadAssetAtAnyPath(sourceTerrainData, exportTerrainDataPath, typeof(TerrainData)) as TerrainData;
                        }

                        if (terrain.terrainData != null)
                        {
                            // Store path so that it can be deleted on clean up
                            AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrain.terrainData));
                        }
                    }

                    if (terrain.terrainData == null)
                    {
                        terrain.terrainData = new TerrainData();

                        if (bFullExportTerrainDataPath)
                        {
                            string folderPath = HEU_Platform.GetFolderPath(exportTerrainDataPath, true);
                            HEU_AssetDatabase.CreatePathWithFolders(folderPath);
                            HEU_AssetDatabase.CreateAsset(terrain.terrainData, exportTerrainDataPath);
                        }
                        else
                        {
                            string assetPathName = "TerrainData" + HEU_Defines.HEU_EXT_ASSET;
                            HEU_AssetDatabase.CreateObjectInAssetCacheFolder(terrain.terrainData, exportTerrainDataPath, null, assetPathName, typeof(TerrainData));
                        }
                    }
                    TerrainData terrainData = terrain.terrainData;

#if !HEU_TERRAIN_COLLIDER_DISABLED
                    collider.terrainData = terrainData;
#endif

                    HEU_TerrainUtility.SetTerrainMaterial(terrain, terrainBuffers[t]._specifiedTerrainMaterialName);

#if UNITY_2018_3_OR_NEWER
                    terrain.allowAutoConnect = true;
                    // This has to be set after setting material
                    terrain.drawInstanced = true;
#endif

                    int heightMapSize = terrainBuffers[t]._heightMapWidth;

                    terrainData.heightmapResolution = heightMapSize;
                    if (terrainData.heightmapResolution != heightMapSize)
                    {
                        Debug.LogErrorFormat("Unsupported terrain size: {0}", heightMapSize);
                        continue;
                    }

                    // The terrainData.baseMapResolution is not set here, but rather left to whatever default Unity uses
                    // The terrainData.alphamapResolution is set later when setting the alphamaps.

                    // 32 is the default for resolutionPerPatch
                    const int detailResolution   = 1024;
                    const int resolutionPerPatch = 32;
                    terrainData.SetDetailResolution(detailResolution, resolutionPerPatch);

                    terrainData.SetHeights(0, 0, terrainBuffers[t]._heightMap);

                    // Note that Unity uses a default height range of 600 when a flat terrain is created.
                    // Without a non-zero value for the height range, user isn't able to draw heights.
                    // Therefore, set 600 as the value if height range is currently 0 (due to flat heightfield).
                    float heightRange = terrainBuffers[t]._heightRange;
                    if (heightRange == 0)
                    {
                        heightRange = 600;
                    }

                    terrainData.size = new Vector3(terrainBuffers[t]._terrainSizeX, heightRange, terrainBuffers[t]._terrainSizeY);

                    terrain.Flush();

                    // Set position
                    HAPI_Transform hapiTransformVolume = new HAPI_Transform(true);
                    hapiTransformVolume.position[0] += terrainBuffers[t]._position[0];
                    hapiTransformVolume.position[1] += terrainBuffers[t]._position[1];
                    hapiTransformVolume.position[2] += terrainBuffers[t]._position[2];
                    HEU_HAPIUtility.ApplyLocalTransfromFromHoudiniToUnity(ref hapiTransformVolume, newTransform);

                    // Set layers
                    Texture2D defaultTexture = HEU_VolumeCache.LoadDefaultSplatTexture();
                    int       numLayers      = terrainBuffers[t]._splatLayers.Count;

#if UNITY_2018_3_OR_NEWER
                    // Create TerrainLayer for each heightfield layer.
                    // Note that height and mask layers are ignored (i.e. not created as TerrainLayers).
                    // Since height layer is first, only process layers from 2nd index onwards.
                    if (numLayers > 1)
                    {
                        // Keep existing TerrainLayers, and either update or append to them
                        TerrainLayer[] existingTerrainLayers = terrainData.terrainLayers;

                        // Total layers are existing layers + new alpha maps
                        List <TerrainLayer> finalTerrainLayers = new List <TerrainLayer>(existingTerrainLayers);

                        for (int m = 1; m < numLayers; ++m)
                        {
                            TerrainLayer terrainlayer = null;

                            int terrainLayerIndex = -1;

                            bool bSetTerrainLayerProperties = true;

                            HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._splatLayers[m];

                            // Look up TerrainLayer file via attribute if user has set it
                            if (!string.IsNullOrEmpty(layer._layerPath))
                            {
                                terrainlayer = HEU_AssetDatabase.LoadAssetAtPath(layer._layerPath, typeof(TerrainLayer)) as TerrainLayer;
                                if (terrainlayer == null)
                                {
                                    Debug.LogWarningFormat("TerrainLayer, set via attribute, not found at: {0}", layer._layerPath);
                                    continue;
                                }
                                else
                                {
                                    // Always check if its part of existing list so as not to add it again
                                    terrainLayerIndex = HEU_TerrainUtility.GetTerrainLayerIndex(terrainlayer, existingTerrainLayers);
                                }
                            }

                            if (terrainlayer == null)
                            {
                                terrainlayer      = new TerrainLayer();
                                terrainLayerIndex = finalTerrainLayers.Count;
                                finalTerrainLayers.Add(terrainlayer);
                            }
                            else
                            {
                                // For existing TerrainLayer, make a copy of it if it has custom layer attributes
                                // because we don't want to change the original TerrainLayer.
                                if (layer._hasLayerAttributes)
                                {
                                    // Copy the TerrainLayer file
                                    TerrainLayer prevTerrainLayer = terrainlayer;
                                    terrainlayer = HEU_AssetDatabase.CopyAndLoadAssetAtAnyPath(terrainlayer, outputTerrainpath, typeof(TerrainLayer), true) as TerrainLayer;
                                    if (terrainlayer != null)
                                    {
                                        if (terrainLayerIndex >= 0)
                                        {
                                            // Update the TerrainLayer reference in the list with this copy
                                            finalTerrainLayers[terrainLayerIndex] = terrainlayer;
                                        }
                                        else
                                        {
                                            // Newly added
                                            terrainLayerIndex = finalTerrainLayers.Count;
                                            finalTerrainLayers.Add(terrainlayer);
                                        }

                                        // Store path for clean up later
                                        AddGeneratedOutputFilePath(HEU_AssetDatabase.GetAssetPath(terrainlayer));
                                    }
                                    else
                                    {
                                        Debug.LogErrorFormat("Unable to copy TerrainLayer '{0}' for generating Terrain. "
                                                             + "Using original TerrainLayer. Will not be able to set any TerrainLayer properties.", layer._layerName);
                                        terrainlayer = prevTerrainLayer;
                                        bSetTerrainLayerProperties = false;
                                        // Again, continuing on to keep proper indexing.
                                    }
                                }
                                else
                                {
                                    // Could be a layer in Assets/ but not part of existing layers in TerrainData
                                    terrainLayerIndex = finalTerrainLayers.Count;
                                    finalTerrainLayers.Add(terrainlayer);
                                    bSetTerrainLayerProperties = false;
                                }
                            }

                            if (bSetTerrainLayerProperties)
                            {
                                if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
                                {
                                    terrainlayer.diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
                                }
                                if (terrainlayer.diffuseTexture == null)
                                {
                                    terrainlayer.diffuseTexture = defaultTexture;
                                }

                                terrainlayer.diffuseRemapMin = Vector4.zero;
                                terrainlayer.diffuseRemapMax = Vector4.one;

                                if (!string.IsNullOrEmpty(layer._maskTexturePath))
                                {
                                    terrainlayer.maskMapTexture = HEU_MaterialFactory.LoadTexture(layer._maskTexturePath);
                                }

                                terrainlayer.maskMapRemapMin = Vector4.zero;
                                terrainlayer.maskMapRemapMax = Vector4.one;

                                terrainlayer.metallic = layer._metallic;

                                if (!string.IsNullOrEmpty(layer._normalTexturePath))
                                {
                                    terrainlayer.normalMapTexture = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
                                }

                                terrainlayer.normalScale = layer._normalScale;

                                terrainlayer.smoothness = layer._smoothness;
                                terrainlayer.specular   = layer._specularColor;
                                terrainlayer.tileOffset = layer._tileOffset;

                                if (layer._tileSize.magnitude == 0f && terrainlayer.diffuseTexture != null)
                                {
                                    // Use texture size if tile size is 0
                                    layer._tileSize = new Vector2(terrainlayer.diffuseTexture.width, terrainlayer.diffuseTexture.height);
                                }
                                terrainlayer.tileSize = layer._tileSize;
                            }
                        }
                        terrainData.terrainLayers = finalTerrainLayers.ToArray();
                    }
#else
                    // Need to create SplatPrototype for each layer in heightfield, representing the textures.
                    SplatPrototype[] splatPrototypes = new SplatPrototype[numLayers];
                    for (int m = 0; m < numLayers; ++m)
                    {
                        splatPrototypes[m] = new SplatPrototype();

                        HEU_LoadBufferVolumeLayer layer = terrainBuffers[t]._splatLayers[m];

                        Texture2D diffuseTexture = null;
                        if (!string.IsNullOrEmpty(layer._diffuseTexturePath))
                        {
                            diffuseTexture = HEU_MaterialFactory.LoadTexture(layer._diffuseTexturePath);
                        }
                        if (diffuseTexture == null)
                        {
                            diffuseTexture = defaultTexture;
                        }
                        splatPrototypes[m].texture = diffuseTexture;

                        splatPrototypes[m].tileOffset = layer._tileOffset;
                        if (layer._tileSize.magnitude == 0f && diffuseTexture != null)
                        {
                            // Use texture size if tile size is 0
                            layer._tileSize = new Vector2(diffuseTexture.width, diffuseTexture.height);
                        }
                        splatPrototypes[m].tileSize = layer._tileSize;

                        splatPrototypes[m].metallic   = layer._metallic;
                        splatPrototypes[m].smoothness = layer._smoothness;

                        if (!string.IsNullOrEmpty(layer._normalTexturePath))
                        {
                            splatPrototypes[m].normalMap = HEU_MaterialFactory.LoadTexture(layer._normalTexturePath);
                        }
                    }
                    terrainData.splatPrototypes = splatPrototypes;
#endif

                    // Set the splatmaps
                    if (terrainBuffers[t]._splatMaps != null)
                    {
                        // Set the alphamap size before setting the alphamaps to get correct scaling
                        // The alphamap size comes from the first alphamap layer
                        int alphamapResolution = terrainBuffers[t]._heightMapWidth;
                        if (numLayers > 1)
                        {
                            alphamapResolution = terrainBuffers[t]._splatLayers[1]._heightMapWidth;
                        }
                        terrainData.alphamapResolution = alphamapResolution;

                        terrainData.SetAlphamaps(0, 0, terrainBuffers[t]._splatMaps);
                    }

                    // Set the tree scattering
                    if (terrainBuffers[t]._scatterTrees != null)
                    {
                        HEU_TerrainUtility.ApplyScatterTrees(terrainData, terrainBuffers[t]._scatterTrees);
                    }

                    // Set the detail layers
                    if (terrainBuffers[t]._detailPrototypes != null)
                    {
                        HEU_TerrainUtility.ApplyDetailLayers(terrain, terrainData, terrainBuffers[t]._detailProperties,
                                                             terrainBuffers[t]._detailPrototypes, terrainBuffers[t]._detailMaps);
                    }

                    terrainBuffers[t]._generatedOutput = generatedOutput;
                    _generatedOutputs.Add(generatedOutput);

                    SetOutputVisiblity(terrainBuffers[t]);
                }
            }
        }
Exemplo n.º 5
0
    public static void GenerateTerrainMesh(GameObject terrainGO, string path, int sizeorg, int height, int fullsize, int terrainCount, int id)
    {
        int size = sizeorg + 1;

        byte[] orgBuffer = new byte[(size * size) * 2];
        byte[] buffer    = new byte[(size * size) * 2];
        using (BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read))) {
            int headerLength = Util.GetTerrainHeaderLength(path);



            reader.ReadBytes(headerLength);

            int lineoffset    = 0;
            int terrainOffset = 0;

            while (lineoffset < sizeorg)               // Resize the image to (power of 2) + 1
            {
                int fileOffset = 0;

                while (fileOffset < sizeorg * 2)                   // read one line
                {
                    orgBuffer [terrainOffset] = reader.ReadByte();
                    terrainOffset++;
                    fileOffset++;
                }
                orgBuffer [fileOffset + 1] = buffer [fileOffset - 1];
                orgBuffer [fileOffset + 2] = buffer [fileOffset];
                terrainOffset += 2;
                lineoffset++;
            }

            int lastLine = 0;

            while (lastLine < (size * 2))
            {
                int offset = (((size * size) * 2) - (size * 2));
                orgBuffer [offset + lastLine] = orgBuffer [((offset - (size * 2)) + lastLine)];
                lastLine++;
            }


            for (int y = 0; y < (size * 2); y++)
            {
                for (int x = 0; x < (size * 2); x++)
                {
                    int newOffset = (x * size) + y;
                    int orgOffset = (y * size) + x;

                    buffer [newOffset]     = orgBuffer [orgOffset];
                    buffer [newOffset + 1] = orgBuffer [orgOffset + 1];
                    x++;
                }
                y++;
            }

            for (int x = 0; x < size * 2; x++)
            {
                int offset = ((size * size) * 2) - (size * 2);
                buffer [offset + x]     = buffer [offset - (size * 2) + x];
                buffer [offset + x + 1] = buffer [offset - (size * 2) + x + 1];
                x++;
            }



            reader.Close();
        }


        Terrain         terrain     = terrainGO.AddComponent <Terrain>();
        TerrainCollider tc          = terrainGO.AddComponent <TerrainCollider>();
        TerrainData     terrainData = new TerrainData();

        tc.terrainData = terrainData;
        terrainData.heightmapResolution = size;
        if (size < 512)
        {
            int otSize = (fullsize) / 2;
            if (terrainCount == 48 && !(id == 10 || id == 11 || id == 12 || id == 19 || id == 20 || id == 21 || id == 28 || id == 29 || id == 30 || id == 37 || id == 38 || id == 39))
            {
                otSize = otSize / 2;
            }

            terrainData.size = new Vector3(otSize, height, otSize);
        }
        else
        {
            terrainData.size = new Vector3(size - 1, height, size - 1);
        }

        terrain.terrainData = terrainData;

        int heightmapWidth  = terrain.terrainData.heightmapWidth;
        int heightmapHeight = terrain.terrainData.heightmapHeight;

        float[,] heights = new float[heightmapHeight, heightmapWidth];
        float num3 = 1.525879E-05f;

        for (int i = 0; i < heightmapHeight; i++)
        {
            for (int j = 0; j < heightmapWidth; j++)
            {
                int num6 = Mathf.Clamp(j, 0, size - 1) + (Mathf.Clamp(i, 0, size - 1) * size);
//				byte num7 = buffer[num6 * 2];
//				buffer[num6 * 2] = buffer[(num6 * 2) + 1];
//				buffer[(num6 * 2) + 1] = num7;

                float num9 = System.BitConverter.ToUInt16(buffer, num6 * 2) * num3;
                heights[i, j] = num9;
            }
        }
        terrain.terrainData.SetHeights(0, 0, heights);
        terrain.heightmapPixelError = 1;
    }
 private void Start()
 {
     rend            = GetComponent <ParentBuilding>().MeshRenderer;
     boxCollider     = GetComponent <BoxCollider>();
     terrainCollider = Terrain.activeTerrain.GetComponent <TerrainCollider>();
 }
    protected override void Start()
    {
        base.init();

        // Make heightfield data
        NativeArray <float> heights;
        int2   size;
        float3 scale;
        bool   simple = false;

#if UNITY_ANDROID || UNITY_IOS
        simple = true;
#endif
        bool flat     = false;
        bool mountain = false;
        if (simple)
        {
            size       = new int2(2, 2);
            scale      = new float3(25, 0.1f, 25);
            heights    = new NativeArray <float>(size.x * size.y * UnsafeUtility.SizeOf <float>(), Allocator.Temp);
            heights[0] = 1;
            heights[1] = 0;
            heights[2] = 0;
            heights[3] = 1;
        }
        else
        {
            size  = new int2(SizeX, SizeZ);
            scale = new float3(ScaleX, ScaleY, ScaleZ);
            float period = 50.0f;
            heights = new NativeArray <float>(size.x * size.y * UnsafeUtility.SizeOf <float>(), Allocator.Temp);
            for (int j = 0; j < size.y; j++)
            {
                for (int i = 0; i < size.x; i++)
                {
                    float a = (i + j) * 2.0f * (float)math.PI / period;
                    heights[i + j * size.x] = flat ? 0.0f : math.sin(a);
                    if (mountain)
                    {
                        float fractionFromCenter = 1.0f - math.min(math.length(new float2(i - size.x / 2, j - size.y / 2)) / (math.min(size.x, size.y) / 2), 1.0f);
                        float mountainHeight     = math.smoothstep(0.0f, 1, fractionFromCenter) * 25.0f;
                        heights[i + j * size.x] += mountainHeight;
                    }
                }
            }
        }

        // static terrain
        Entity staticEntity;
        {
            bool createMesh = false;
            var  collider   = createMesh
                ? CreateMeshTerrain(heights, new int2(SizeX, SizeZ), new float3(ScaleX, ScaleY, ScaleZ))
                : TerrainCollider.Create(heights, size, scale, Method);

            bool compound = false;
            if (compound)
            {
                var instances = new NativeArray <CompoundCollider.ColliderBlobInstance>(4, Allocator.Temp);
                for (int i = 0; i < 4; i++)
                {
                    instances[i] = new CompoundCollider.ColliderBlobInstance
                    {
                        Collider          = collider,
                        CompoundFromChild = new RigidTransform
                        {
                            pos = new float3((i % 2) * scale.x * (size.x - 1), 0.0f, (i / 2) * scale.z * (size.y - 1)),
                            rot = quaternion.identity
                        }
                    };
                }
                collider = Unity.Physics.CompoundCollider.Create(instances);
                instances.Dispose();
            }

            float3 position = new float3(size.x - 1, 0.0f, size.y - 1) * scale * -0.5f;
            staticEntity = CreateStaticBody(position, quaternion.identity, collider);
        }
    }
Exemplo n.º 8
0
 public HeightData(TerrainCollider source)
 {
     this.dataHandle = new GCHandle();
     this.source     = source;
     UpdateHeightData();
 }
Exemplo n.º 9
0
        public void UpdateBounds()
        {
            if (setBoundsManually)
            {
                //mBounds = new Bounds(customBounds * 0.5f, customBounds);
                mBounds.size   = customBounds;
                mBounds.center = customBoundsCenter;
                mBounds.Expand(new Vector3(boundsOffset, 0, boundsOffset));
                bounds = mBounds;
                return;
            }

            bool flag = false;
            int  i, imax = 0;

            mTerrains = FindObjectsOfType(typeof(Terrain)) as Terrain[];
            bool multiTerrain = mTerrains != null;

            if (multiTerrain)
            {
                multiTerrain = mTerrains.Length > 1;
            }

            // First lets see if there is more than one terrain. Multi-terrain handling
            if (multiTerrain)
            {
#if UNITY_EDITOR
                //	Debug.Log("NJGMap: Calculating bounds for multiple terrains ("+mTerrains.Length+")");
#endif
                for (i = 0, imax = mTerrains.Length; i < imax; i++)
                {
                    Terrain      t             = mTerrains[i];
                    MeshRenderer mMeshRenderer = t.GetComponent <MeshRenderer>();

                    if (!flag)
                    {
                        //t.transform.position, new Vector3(1f, 1f, 1f)
                        mBounds = new Bounds();
                        flag    = true;
                    }

                    if (mMeshRenderer != null)
                    {
                        //Debug.Log("Terrain Mesh Renderer " + i + " : " + mMeshRenderer.bounds.size + " / " + t.name);
                        mBounds.Encapsulate(mMeshRenderer.bounds);
                    }
                    else
                    {
                        TerrainCollider mTerrainCollider = t.GetComponent <TerrainCollider>();
                        if (mTerrainCollider != null)
                        {
                            //Debug.Log("Terrain Collider " + i + " : " + mTerrainCollider.bounds.size+" / "+t.name);
                            mBounds.Encapsulate(mTerrainCollider.bounds);
                        }
                        else
                        {
                            Debug.LogError("Could not get measure bounds of terrain.", this);
                            return;
                        }
                    }
                }
            }
            // If not then check if there is one activeTerrain
            else if (Terrain.activeTerrain != null)
            {
#if UNITY_EDITOR
                //Debug.Log("NJGMap: Calculating bounds for active terrain");
#endif
                Terrain      t             = Terrain.activeTerrain;
                MeshRenderer mMeshRenderer = t.GetComponent <MeshRenderer>();

                if (!flag)
                {
                    //t.transform.position, new Vector3(1f, 1f, 1f)
                    mBounds = new Bounds();
                    flag    = true;
                }

                if (mMeshRenderer != null)
                {
                    //Debug.Log("Terrain Mesh Renderer " + i + " : " + mMeshRenderer.bounds.size + " / " + t.name);
                    mBounds.Encapsulate(mMeshRenderer.bounds);
                }
                else
                {
                    TerrainCollider mTerrainCollider = t.GetComponent <TerrainCollider>();
                    if (mTerrainCollider != null)
                    {
                        //Debug.Log("Terrain Collider " + i + " : " + mTerrainCollider.bounds.size+" / "+t.name);
                        mBounds.Encapsulate(mTerrainCollider.bounds);
                    }
                    else
                    {
                        Debug.LogError("Could not get measure bounds of terrain.", this);
                        return;
                    }
                }
            }

            GameObject[] mGameObjects = UnityEngine.Object.FindObjectsOfType(typeof(GameObject)) as GameObject[];
            if (mGameObjects != null)
            {
#if UNITY_EDITOR
                //Debug.Log("NJGMap: Calculating bounds for multiple gameObjects (" + mGameObjects.Length + ")");
#endif
                for (i = 0, imax = mGameObjects.Length; i < imax; i++)
                {
                    GameObject go = mGameObjects[i];

                    // Dont consider this game object
                    if (go.layer == gameObject.layer)
                    {
                        continue;
                    }

                    // Only use objects from the layer mask
                    if (!IsInRenderLayers(go, boundLayers))
                    {
                        continue;
                    }

                    if (!flag)
                    {
                        mBounds = new Bounds(go.transform.position, new Vector3(1f, 1f, 1f));
                        flag    = true;
                    }
                    Renderer renderer = go.renderer;
                    if (renderer != null)
                    {
                        mBounds.Encapsulate(renderer.bounds);
                    }
                    else
                    {
                        Collider collider = go.collider;
                        if (collider != null)
                        {
                            mBounds.Encapsulate(collider.bounds);
                        }
                    }
                }
            }

            if (!flag)
            {
                Debug.Log("Could not find terrain nor any other bounds in scene", this);
                mBounds = new Bounds(gameObject.transform.position, new Vector3(1f, 1f, 1f));
            }

            mBounds.Expand(new Vector3(boundsOffset, 0, boundsOffset));

            if (mapResolution == Resolution.Double)
            {
                //mBounds.Expand(new Vector3(-mBounds.extents.x, 0f, -mBounds.extents.z));
            }

            // Set bounds
            bounds = mBounds;
        }
Exemplo n.º 10
0
        private void UpdateColliders()
        {
            for (int i = 0; i < colliders.Count; i++)
            {
                Collider source = colliders[i];
                if (source == null || !source.enabled || !source.gameObject.activeInHierarchy)
                {
                    continue;
                }

                Rigidbody   rb = source.GetComponentInParent <Rigidbody>();
                ObiCollider oc = source.GetComponent <ObiCollider>();

                // Get the adequate rigidBodyIndex. If several colliders share a rigidbody, they'll get the same rigidBodyIndex.
                int rigidBodyIndex = -1;
                if (rb != null)
                {
                    if (!rigidbodyIDs.TryGetValue(rb.GetInstanceID(), out rigidBodyIndex))
                    {
                        rigidBodyIndex = Oni.GetRigidbodyCount(oniColliderGroup);
                        Oni.SetRigidbodies(oniColliderGroup, new Oni.Rigidbody[] {
                            new Oni.Rigidbody(rb)
                        }, 1, rigidBodyIndex);
                        rigidbodyIDs[rb.GetInstanceID()] = rigidBodyIndex;
                    }
                }

                float thickness = (oc != null)?oc.thickness:0;

                if (source is SphereCollider)
                {
                    Oni.SetColliders(oniColliderGroup, new Oni.Collider[] {
                        new Oni.Collider(source, Oni.ShapeType.Sphere, thickness, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Sphere), rigidBodyIndex, (oc != null)?oc.materialIndex:0)
                    }, 1, Oni.GetColliderCount(oniColliderGroup));
                    Oni.SetSphereShapes(oniColliderGroup, new Oni.SphereShape[] {
                        new Oni.SphereShape(source as SphereCollider)
                    }, 1, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Sphere));
                }
                else if (source is BoxCollider)
                {
                    Oni.SetColliders(oniColliderGroup, new Oni.Collider[] {
                        new Oni.Collider(source, Oni.ShapeType.Box, thickness, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Box), rigidBodyIndex, (oc != null)?oc.materialIndex:0)
                    }, 1, Oni.GetColliderCount(oniColliderGroup));
                    Oni.SetBoxShapes(oniColliderGroup, new Oni.BoxShape[] {
                        new Oni.BoxShape(source as BoxCollider)
                    }, 1, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Box));
                }
                else if (source is CapsuleCollider)
                {
                    Oni.SetColliders(oniColliderGroup, new Oni.Collider[] {
                        new Oni.Collider(source, Oni.ShapeType.Capsule, thickness, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Capsule), rigidBodyIndex, (oc != null)?oc.materialIndex:0)
                    }, 1, Oni.GetColliderCount(oniColliderGroup));
                    Oni.SetCapsuleShapes(oniColliderGroup, new Oni.CapsuleShape[] {
                        new Oni.CapsuleShape(source as CapsuleCollider)
                    }, 1, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Capsule));
                }
                else if (source is CharacterController)
                {
                    Oni.SetColliders(oniColliderGroup, new Oni.Collider[] {
                        new Oni.Collider(source, Oni.ShapeType.Capsule, thickness, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Capsule), rigidBodyIndex, (oc != null)?oc.materialIndex:0)
                    }, 1, Oni.GetColliderCount(oniColliderGroup));
                    Oni.SetCapsuleShapes(oniColliderGroup, new Oni.CapsuleShape[] {
                        new Oni.CapsuleShape(source as CharacterController)
                    }, 1, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Capsule));
                }
                else if (source is TerrainCollider)
                {
                    TerrainCollider tc = source as TerrainCollider;

                    Oni.HeightData data;
                    if (!heightData.TryGetValue(tc, out data))
                    {
                        data = heightData[tc] = new Oni.HeightData(tc);
                    }

                    Oni.SetColliders(oniColliderGroup, new Oni.Collider[] {
                        new Oni.Collider(source, Oni.ShapeType.Heightmap, thickness, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Heightmap), rigidBodyIndex, (oc != null)?oc.materialIndex:0)
                    }, 1, Oni.GetColliderCount(oniColliderGroup));
                    Oni.SetHeightmapShapes(oniColliderGroup, new Oni.HeightmapShape[] {
                        new Oni.HeightmapShape(tc, data.AddrOfHeightData())
                    }, 1, Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.Heightmap));
                }
                else if (source is MeshCollider)
                {
                    MeshCollider             mc = source as MeshCollider;
                    MeshColliderShapeAndData shapeAndData;

                    if (mc.sharedMesh != null)
                    {
                        // We can share the same triangle data across several instances of the same MeshCollider:
                        if (!meshColliderData.TryGetValue(mc.sharedMesh, out shapeAndData))
                        {
                            // Get current amount of triangle mesh shapes:
                            int shapeIndex = Oni.GetShapeCount(oniColliderGroup, Oni.ShapeType.TriangleMesh);

                            // Generate mesh collider triangle data and shape:
                            Oni.TriangleMeshData  data  = new Oni.TriangleMeshData(mc);
                            Oni.TriangleMeshShape shape = new Oni.TriangleMeshShape(mc,
                                                                                    (oc != null)?oc.meshColliderType:Oni.TriangleMeshShape.MeshColliderType.ThinTwoSided,
                                                                                    thickness,
                                                                                    data.AddrOfVertexData(),
                                                                                    data.AddrOfTriangleData());

                            // Pack both in a small wrapper:
                            shapeAndData = new MeshColliderShapeAndData(data, shape, shapeIndex);

                            // Tell Oni we want to define a new triangle mesh:
                            Oni.SetTriangleMeshShapes(oniColliderGroup,
                                                      new Oni.TriangleMeshShape[] { shapeAndData.meshShape },
                                                      1, shapeIndex);

                            Oni.UpdateTriangleMeshShapes(oniColliderGroup, 1, shapeIndex);

                            // Store mesh collider data:
                            meshColliderData[mc.sharedMesh] = shapeAndData;
                        }

                        Oni.SetColliders(oniColliderGroup, new Oni.Collider[] {
                            new Oni.Collider(source, Oni.ShapeType.TriangleMesh, thickness, shapeAndData.shapeIndex, rigidBodyIndex, (oc != null)?oc.materialIndex:0)
                        }, 1, Oni.GetColliderCount(oniColliderGroup));
                    }
                }
                else
                {
                    Debug.LogWarning("Collider type " + source.GetType() + " not supported by Obi. Ignoring it.");
                }
            }
        }
Exemplo n.º 11
0
			public void SetSettings ()
			{
				MapMagic magic = MapMagic.instance;

				terrain.heightmapPixelError = magic.pixelError;
				if (magic.showBaseMap) terrain.basemapDistance = magic.baseMapDist;
				else terrain.basemapDistance = 999999;
				terrain.castShadows = magic.castShadows;
				#if UNITY_2017_4_OR_NEWER
				terrain.reflectionProbeUsage = magic.reflectionProbeUsage;
				#endif
				
				if (terrainCollider==null) terrainCollider = terrain.GetComponent<TerrainCollider>();
				if (terrainCollider!=null) terrainCollider.enabled = MapMagic.instance.applyColliders;

				#if UNITY_2018_3_OR_NEWER
				terrain.drawInstanced = magic.drawInstanced;
				terrain.allowAutoConnect = magic.autoConnect;
				#endif

				//material
				if (!Preview.enabled)
				{
					#if UNITY_2019_2_OR_NEWER
					if (MapMagic.instance.customTerrainMaterial != null)
					{
						//checking if customTerrainMaterial assigned as a terrain mat
						if (terrain.materialTemplate == MapMagic.instance.customTerrainMaterial)
						{
							Debug.LogError("Terrain material template == MM.customTerrainMaterial (" + terrain.materialTemplate + "," + terrain.materialTemplate.shader + ")");
							terrain.materialTemplate = null;
						}

						//remove previous material if the shader doesn't match
						if (terrain.materialTemplate != null  &&  terrain.materialTemplate.shader != MapMagic.instance.customTerrainMaterial.shader) 
						{
							GameObject.DestroyImmediate(terrain.materialTemplate); //removes custom shader textures as well. Unity does not remove them!
							Resources.UnloadUnusedAssets();
							terrain.materialTemplate = null; //need to reset material template to prevent unity crash
						}
						
						//duplicating material to terrain
						if (terrain.materialTemplate == null) 
						{
							terrain.materialTemplate = new Material(MapMagic.instance.customTerrainMaterial);
							terrain.materialTemplate.name += " (Copy)";
						}
					}
					#else
					terrain.materialType = MapMagic.instance.terrainMaterialType;

					if (MapMagic.instance.terrainMaterialType == Terrain.MaterialType.Custom && MapMagic.instance.assignCustomTerrainMaterial)
						terrain.materialTemplate = MapMagic.instance.customTerrainMaterial;
					#endif
				}

				terrain.drawTreesAndFoliage = magic.detailDraw;
				terrain.detailObjectDistance = magic.detailDistance;
				terrain.detailObjectDensity = magic.detailDensity;
				terrain.treeDistance = magic.treeDistance;
				terrain.treeBillboardDistance = magic.treeBillboardStart;
				terrain.treeCrossFadeLength = magic.treeFadeLength;
				terrain.treeMaximumFullLODCount = magic.treeFullLod;
				#if UNITY_EDITOR
				terrain.bakeLightProbesForTrees = magic.bakeLightProbesForTrees;
				#endif

				terrain.terrainData.wavingGrassSpeed = magic.windSpeed;
				terrain.terrainData.wavingGrassAmount = magic.windSize;
				terrain.terrainData.wavingGrassStrength = magic.windBending;
				terrain.terrainData.wavingGrassTint = magic.grassTint;

				//copy layer, tag, scripts from mm to terrains
				if (MapMagic.instance.copyLayersTags)
				{
					GameObject go = terrain.gameObject;
					go.layer = MapMagic.instance.gameObject.layer;
					go.isStatic = MapMagic.instance.gameObject.isStatic;
					try { go.tag = MapMagic.instance.gameObject.tag; } catch { Debug.LogError("MapMagic: could not copy object tag"); }
				}
				if (MapMagic.instance.copyComponents)
				{
					GameObject go = terrain.gameObject;
					MonoBehaviour[] components = MapMagic.instance.GetComponents<MonoBehaviour>();
					for (int i=0; i<components.Length; i++)
					{
						if (components[i] is MapMagic || components[i] == null) continue; //if MapMagic itself or script not assigned
						if (terrain.gameObject.GetComponent(components[i].GetType()) == null) Extensions.CopyComponent(components[i], go);
					}
				}
			}
Exemplo n.º 12
0
    void DoClick(object sender, ClickedEventArgs e)
    {
        if (teleportOnClick)
        {
            // First get the current Transform of the the reference space (i.e. the Play Area, e.g. CameraRig prefab)
            var t = reference;
            if (t == null)
            {
                return;
            }

            // Get the current Y position of the reference space
            float refY = t.position.y;

            // Create a plane at the Y position of the Play Area
            // Then create a Ray from the origin of the controller in the direction that the controller is pointing
            Plane plane = new Plane(Vector3.up, -refY);
            Ray   ray   = new Ray(this.transform.position, transform.forward);

            // Set defaults
            bool  hasGroundTarget = false;
            float dist            = 0f;
            if (teleportType == TeleportType.TeleportTypeUseTerrain)             // If we picked to use the terrain
            {
                RaycastHit      hitInfo;
                TerrainCollider tc = Terrain.activeTerrain.GetComponent <TerrainCollider>();
                hasGroundTarget = tc.Raycast(ray, out hitInfo, 1000f);
                dist            = hitInfo.distance;
            }
            else if (teleportType == TeleportType.TeleportTypeUseCollider)             // If we picked to use the collider
            {
                RaycastHit hitInfo;
                hasGroundTarget = Physics.Raycast(ray, out hitInfo);
                dist            = hitInfo.distance;
            }
            else             // If we're just staying flat on the current Y axis
            {
                // Intersect a ray with the plane that was created earlier
                // and output the distance along the ray that it intersects
                hasGroundTarget = plane.Raycast(ray, out dist);
            }

            if (hasGroundTarget)
            {
                // Get the current Camera (head) position on the ground relative to the world
                //Vector3 headPosOnGround = new Vector3(SteamVR_Render.Top().head.position.x, refY, SteamVR_Render.Top().head.position.z);

                // We need to translate the reference space along the same vector
                // that is between the head's position on the ground and the intersection point on the ground
                // i.e. intersectionPoint - headPosOnGround = translateVector
                // currentReferencePosition + translateVector = finalPosition

                /*
                 * Vector3 createPoint = new Vector3();
                 * createPoint = t.position + (ray.origin + (ray.direction * dist)) + new Vector3(0,0,0);
                 * Instantiate(createObj, createPoint, Quaternion.identity); //[createObjSelected]
                 */

                if (selectingStep == selectingStepEnum.units)
                {
                    slpoint1      = t.position + (ray.origin + (ray.direction * dist));
                    selectingStep = selectingStepEnum.target;
                    Debug.Log("SelectingStep set to target");
                }
                else
                if (selectingStep == selectingStepEnum.target)
                {
                    targetPoint   = t.position + (ray.origin + (ray.direction * dist));
                    selectingStep = selectingStepEnum.none;
                    Debug.Log("SelectingStep set to none");
                    GameObject[] list = GameObject.FindGameObjectsWithTag("Player's Unit");
                    for (int i = 0; i < list.Length; i++)
                    {
                        list[i].BroadcastMessage("Target", targetPoint);
                        Debug.Log("TARGETED");
                        slpoint1 = new Vector3(0, 0, 0);
                        slpoint2 = new Vector3(0, 0, 0);
                    }
                }
                //teleport
                //t.position = t.position + (ray.origin + (ray.direction * dist)) - headPosOnGround;
            }
        }
    }
Exemplo n.º 13
0
    private void Update()
    {
        var trackedController = GetComponent <SteamVR_TrackedController>();

        if (trackedController.triggerPressed)
        {
            // First get the current Transform of the the reference space (i.e. the Play Area, e.g. CameraRig prefab)
            var t = reference;
            if (t == null)
            {
                return;
            }

            // Get the current Y position of the reference space
            float refY = t.position.y;

            // Create a plane at the Y position of the Play Area
            // Then create a Ray from the origin of the controller in the direction that the controller is pointing
            Plane plane = new Plane(Vector3.up, -refY);
            Ray   ray   = new Ray(this.transform.position, transform.forward);

            // Set defaults
            bool  hasGroundTarget = false;
            float dist            = 0f;
            if (teleportType == TeleportType.TeleportTypeUseTerrain) // If we picked to use the terrain
            {
                RaycastHit      hitInfo;
                TerrainCollider tc = Terrain.activeTerrain.GetComponent <TerrainCollider>();
                hasGroundTarget = tc.Raycast(ray, out hitInfo, 1000f);
                dist            = hitInfo.distance;
            }
            else if (teleportType == TeleportType.TeleportTypeUseCollider) // If we picked to use the collider
            {
                RaycastHit hitInfo;
                hasGroundTarget = Physics.Raycast(ray, out hitInfo);
                dist            = hitInfo.distance;
            }
            else // If we're just staying flat on the current Y axis
            {
                // Intersect a ray with the plane that was created earlier
                // and output the distance along the ray that it intersects
                hasGroundTarget = plane.Raycast(ray, out dist);
            }

            if (hasGroundTarget && selectingStep == selectingStepEnum.target)
            {
                slpoint2 = t.position + (ray.origin + (ray.direction * dist));
            }
        }
        else
        {
            if (selectingStep == selectingStepEnum.none)
            {
                selectingStep = selectingStepEnum.units;

                Debug.Log("SelectingStep set to units");
            }
        }
        if (selectingStep == selectingStepEnum.target)
        {
            //x1 to x2 on z1
            DrawLine(new Vector3(slpoint1.x, slpoint1.y + .1f, slpoint1.z),
                     new Vector3(slpoint2.x, slpoint1.y + .1f, slpoint1.z), Color.blue);

            //x1 to x2 on z2
            DrawLine(new Vector3(slpoint1.x, slpoint1.y + .1f, slpoint2.z),
                     new Vector3(slpoint2.x, slpoint1.y + .1f, slpoint2.z), Color.blue);

            //z1 to z2 on x1
            DrawLine(new Vector3(slpoint1.x, slpoint1.y + .1f, slpoint1.z),
                     new Vector3(slpoint1.x, slpoint1.y + .1f, slpoint2.z), Color.blue);

            //z1 to z2 on x2
            DrawLine(new Vector3(slpoint2.x, slpoint1.y + .1f, slpoint1.z),
                     new Vector3(slpoint2.x, slpoint1.y + .1f, slpoint2.z), Color.blue);
        }
    }
Exemplo n.º 14
0
 public TerrainSurfaceRaycaster(GameObject surfaceObject, bool raycastReverse)
     : base(surfaceObject, raycastReverse)
 {
     _terrainCollider = surfaceObject.GetComponent <TerrainCollider>();
 }
Exemplo n.º 15
0
    void DoClick(object sender, ClickedEventArgs e)
    {
        if (teleportOnClick)
        {
            // First get the current Transform of the the reference space (i.e. the Play Area, e.g. CameraRig prefab)
            var t = reference;
            if (t == null)
            {
                return;
            }

            // Get the current Y position of the reference space
            float refY = t.position.y;
            Debug.Log(refY.ToString());

            // Create a plane at the Y position of the Play Area
            // Then create a Ray from the origin of the controller in the direction that the controller is pointing
            Plane plane = new Plane(Vector3.up, -refY);
            Ray   ray   = new Ray(this.transform.position, transform.forward);

            // Set defaults
            bool  hasGroundTarget = false;
            float dist            = 0f;
            if (teleportType == TeleportType.TeleportTypeUseTerrain)             // If we picked to use the terrain
            {
                RaycastHit      hitInfo;
                TerrainCollider tc = Terrain.activeTerrain.GetComponent <TerrainCollider>();
                hasGroundTarget = tc.Raycast(ray, out hitInfo, 1000f);
                dist            = hitInfo.distance;
            }
            else if (teleportType == TeleportType.TeleportTypeUseCollider)             // If we picked to use the collider
            {
                RaycastHit hitInfo;
                hasGroundTarget = Physics.Raycast(ray, out hitInfo);
                dist            = hitInfo.distance;
            }
            else             // If we're just staying flat on the current Y axis
            {
                // Intersect a ray with the plane that was created earlier
                // and output the distance along the ray that it intersects
                hasGroundTarget = plane.Raycast(ray, out dist);
            }

            if (hasGroundTarget)
            {
                // Get the current Camera (head) position on the ground relative to the world
                Vector3 headPosOnGround = new Vector3(SteamVR_Render.Top().head.position.x, refY, SteamVR_Render.Top().head.position.z);

                // We need to translate the reference space along the same vector
                // that is between the head's position on the ground and the intersection point on the ground
                // i.e. intersectionPoint - headPosOnGround = translateVector
                // currentReferencePosition + translateVector = finalPosition
                //Teleport a maxdistance
                t.position = t.position + (ray.origin + (ray.direction * maxDist)) - headPosOnGround;
                //Make sure the player doesn't fly
                t.position = new Vector3(t.position.x, 0, t.position.z);
                //Make sure the player can't teleport again
                teleportOnClick = false;
            }
        }
    }
Exemplo n.º 16
0
        public void UpdateBodiesInfo()
        {
            oniColliders.Clear();
            oniRigidbodies.Clear();
            oniSpheres.Clear();
            oniBoxes.Clear();
            oniCapsules.Clear();
            oniHeightmaps.Clear();

            rigidbodyIDs.Clear();

            for (int i = 0; i < colliders.Count; i++)
            {
                Collider source = colliders[i];
                if (source == null)
                {
                    continue;
                }

                Rigidbody   rb = colliders[i].GetComponentInParent <Rigidbody>();
                ObiCollider oc = colliders[i].GetComponent <ObiCollider>();

                // Get the adequate rigidBodyIndex. If several colliders share a rigidbody, they'll get the same rigidBodyIndex.
                int rigidBodyIndex = -1;
                if (rb != null)
                {
                    if (!rigidbodyIDs.TryGetValue(rb.GetInstanceID(), out rigidBodyIndex))
                    {
                        rigidBodyIndex = oniRigidbodies.Count;
                        oniRigidbodies.Add(new Oni.Rigidbody(rb));
                        rigidbodyIDs[rb.GetInstanceID()] = rigidBodyIndex;
                    }
                }

                if (source is SphereCollider)
                {
                    oniColliders.Add(new Oni.Collider(source, Oni.ShapeType.Sphere, oniSpheres.Count, rigidBodyIndex, (oc != null)?oc.materialIndex:0));
                    oniSpheres.Add(new Oni.SphereShape(source as SphereCollider));
                }
                else if (source is BoxCollider)
                {
                    oniColliders.Add(new Oni.Collider(source, Oni.ShapeType.Box, oniBoxes.Count, rigidBodyIndex, (oc != null)?oc.materialIndex:0));
                    oniBoxes.Add(new Oni.BoxShape(source as BoxCollider));
                }
                else if (source is CapsuleCollider)
                {
                    oniColliders.Add(new Oni.Collider(source, Oni.ShapeType.Capsule, oniCapsules.Count, rigidBodyIndex, (oc != null)?oc.materialIndex:0));
                    oniCapsules.Add(new Oni.CapsuleShape(source as CapsuleCollider));
                }
                else if (source is CharacterController)
                {
                    oniColliders.Add(new Oni.Collider(source, Oni.ShapeType.Capsule, oniCapsules.Count, rigidBodyIndex, (oc != null)?oc.materialIndex:0));
                    oniCapsules.Add(new Oni.CapsuleShape(source as CharacterController));
                }
                else if (source is TerrainCollider)
                {
                    TerrainCollider tc = source as TerrainCollider;
                    if (!heightData.ContainsKey(tc))
                    {
                        heightData[tc] = new Oni.HeightData(source as TerrainCollider);
                    }

                    oniColliders.Add(new Oni.Collider(source, Oni.ShapeType.Heightmap, oniHeightmaps.Count, rigidBodyIndex, (oc != null)?oc.materialIndex:0));
                    oniHeightmaps.Add(new Oni.HeightmapShape(source as TerrainCollider, heightData[tc].AddrOfHeightData()));
                }
                else
                {
                    Debug.LogWarning(source.GetType() + " not supported by Obi. Ignoring it.");
                }
            }

            UpdateColliders();
            UpdateRigidbodies();
            UpdateSpheres();
            UpdateBoxes();
            UpdateCapsules();
            UpdateHeightmaps();
        }
Exemplo n.º 17
0
        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.C))
            {
                // Remove all projectors.
                while (m_DecalProjectors.Count > 0)
                {
                    m_DecalsMesh.ClearAll();
                    m_DecalProjectors.Clear();

                    // Clearing of the decals mesh means we need to initialize it again.
                    m_DecalsMesh.Initialize(m_DecalsInstance);
                }
                m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh);
            }

            if (Input.GetButtonDown("Fire1"))
            {
                Ray        l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));
                RaycastHit l_RaycastHit;
                if (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity))
                {
                    // Collider hit.

                    // Make sure there are not too many projectors.
                    if (m_DecalProjectors.Count >= m_MaximumNumberOfProjectors)
                    {
                        // If there are more than the maximum number of projectors, we delete
                        // the oldest one.
                        DecalProjector l_DecalProjector = m_DecalProjectors [0];
                        m_DecalProjectors.RemoveAt(0);
                        m_DecalsMesh.RemoveProjector(l_DecalProjector);
                    }

                    // Calculate the position and rotation for the new decal projector.
                    Vector3    l_ProjectorPosition = l_RaycastHit.point - (m_DecalProjectorOffset * l_Ray.direction.normalized);
                    Quaternion l_ProjectorRotation = ProjectorRotationUtility.ProjectorRotation(Camera.main.transform.forward, Vector3.up);

                    // Randomize the rotation.
                    Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f);
                    l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation;

                    TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider;
                    if (l_TerrainCollider != null)
                    {
                        // Terrain collider hit.

                        Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> ();
                        if (l_Terrain != null)
                        {
                            // Create the decal projector with all the required information.
                            DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex, CurrentColor, 0.0f);

                            // Add the projector to our list and the decals mesh, such that both are
                            // synchronized. All the mesh data that is now added to the decals mesh
                            // will belong to this projector.
                            m_DecalProjectors.Add(l_DecalProjector);
                            m_DecalsMesh.AddProjector(l_DecalProjector);

                            // The terrain data has to be converted to the decals instance's space.
                            Matrix4x4 l_TerrainToDecalsMatrix = m_WorldToDecalsMatrix * Matrix4x4.TRS(l_Terrain.transform.position, Quaternion.identity, Vector3.one);

                            // Pass the terrain data with the corresponding conversion to the decals mesh.
                            m_DecalsMesh.Add(l_Terrain, l_TerrainToDecalsMatrix);

                            // Cut and offset the decals mesh.
                            m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                            m_DecalsMesh.OffsetActiveProjectorVertices();

                            // The changes are only present in the decals mesh at the moment. We have
                            // to pass them to the decals instance to visualize them.
                            m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh);

                            // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                            // based on the surface you have hit.
                            NextUVRectangleIndex();
                        }
                        else
                        {
                            Debug.LogError("Terrain is null!");
                        }
                    }
                    else
                    {
                        // We hit a collider. Next we have to find the mesh that belongs to the collider.
                        // That step depends on how you set up your mesh filters and collider relative to
                        // each other in the game objects. It is important to have a consistent way in order
                        // to have a simpler implementation.

                        MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> ();
                        MeshFilter   l_MeshFilter   = l_RaycastHit.collider.GetComponent <MeshFilter> ();

                        if (l_MeshCollider != null || l_MeshFilter != null)
                        {
                            Mesh l_Mesh = null;
                            if (l_MeshCollider != null)
                            {
                                // Mesh collider was hit. Just use the mesh data from that one.
                                l_Mesh = l_MeshCollider.sharedMesh;
                            }
                            else if (l_MeshFilter != null)
                            {
                                // Otherwise take the data from the shared mesh.
                                l_Mesh = l_MeshFilter.sharedMesh;
                            }

                            if (l_Mesh != null)
                            {
                                // Create the decal projector.
                                DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, m_DecalProjectorScale, m_CullingAngle, m_MeshOffset, m_UVRectangleIndex, m_UVRectangleIndex, CurrentColor, 0.0f);

                                // Add the projector to our list and the decals mesh, such that both are
                                // synchronized. All the mesh data that is now added to the decals mesh
                                // will belong to this projector.
                                m_DecalProjectors.Add(l_DecalProjector);
                                m_DecalsMesh.AddProjector(l_DecalProjector);

                                // Get the required matrices.
                                Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix;
                                Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix;

                                // Add the mesh data to the decals mesh, cut and offset it.
                                m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);
                                m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                                m_DecalsMesh.OffsetActiveProjectorVertices();

                                // The changes are only present in the decals mesh at the moment. We have
                                // to pass them to the decals instance to visualize them.
                                m_DecalsInstance.UpdateDecalsMeshes(m_DecalsMesh);

                                // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                                // based on the surface you have hit.
                                NextUVRectangleIndex();
                            }
                        }
                    }
                }
            }
        }
 public static ReadOnlyTerrainCollider AsReadOnly(this TerrainCollider self) => self.IsTrulyNull() ? null : new ReadOnlyTerrainCollider(self);
Exemplo n.º 19
0
        /// <summary>
        /// Create a terrain tile based on these settings
        /// </summary>
        /// <param name="tx">X location</param>
        /// <param name="tz">Z location</param>
        /// <param name="world">The array managing it</param>
        private void CreateTile(int tx, int tz, ref Terrain[,] world, GaiaResource resources)
        {
            if (tx < 0 || tx >= m_tilesX)
            {
                Debug.LogError("X value out of bounds");
                return;
            }

            if (tz < 0 || tz >= m_tilesZ)
            {
                Debug.LogError("Z value out of bounds");
                return;
            }

            //Look for issues in the terrain settings and fix them
            GetAndFixDefaults();

            //this will center terrain at origin
            Vector2 m_offset = new Vector2(-m_terrainSize * m_tilesX * 0.5f, -m_terrainSize * m_tilesZ * 0.5f);

            //create the terrains if they dont already exist
            if (world.Length < m_tilesX)
            {
                world = new Terrain[m_tilesX, m_tilesZ];
            }

            //Create the terrain
            Terrain     terrain;
            TerrainData terrainData = new TerrainData();

            terrainData.name = string.Format("Terrain_{0}_{1}-{2:yyyyMMdd-HHmmss}", tx, tz, DateTime.Now);
            terrainData.alphamapResolution = m_controlTextureResolution;
            terrainData.baseMapResolution  = m_baseMapSize;
            terrainData.SetDetailResolution(m_detailResolution, m_detailResolutionPerPatch);
            terrainData.heightmapResolution = m_heightmapResolution;
            //terrainData.physicsMaterial = m_physicsMaterial;
            terrainData.wavingGrassAmount   = m_bending;
            terrainData.wavingGrassSpeed    = m_size;
            terrainData.wavingGrassStrength = m_speed;
            terrainData.wavingGrassTint     = m_grassTint;
            terrainData.size = new Vector3(m_terrainSize, m_terrainHeight, m_terrainSize);

            #if UNITY_EDITOR
            AssetDatabase.CreateAsset(terrainData, string.Format("Assets/{0}.asset", terrainData.name));
            #endif

            terrain      = Terrain.CreateTerrainGameObject(terrainData).GetComponent <Terrain>();
            terrain.name = terrainData.name;
            terrain.transform.position      = new Vector3(m_terrainSize * tx + m_offset.x, 0, m_terrainSize * tz + m_offset.y);
            terrain.basemapDistance         = m_baseMapDist;
            terrain.castShadows             = m_castShadows;
            terrain.detailObjectDensity     = m_detailDensity;
            terrain.detailObjectDistance    = m_detailDistance;
            terrain.heightmapPixelError     = m_pixelError;
            terrain.treeBillboardDistance   = m_billboardStart;
            terrain.treeCrossFadeLength     = m_fadeLength;
            terrain.treeDistance            = m_treeDistance;
            terrain.treeMaximumFullLODCount = m_maxMeshTrees;
            #if UNITY_EDITOR
            terrain.bakeLightProbesForTrees = false;
            #endif
            if (m_material != null)
            {
                terrain.materialType     = Terrain.MaterialType.Custom;
                terrain.materialTemplate = m_material;
            }
            if (m_physicsMaterial != null)
            {
                TerrainCollider collider = terrain.GetComponent <TerrainCollider>();
                if (collider != null)
                {
                    collider.material = m_physicsMaterial;
                }
                else
                {
                    Debug.LogWarning("Unable to assign physics material to terrain!");
                }
            }

            //Assign prototypes
            if (resources != null)
            {
                resources.ApplyPrototypesToTerrain(terrain);
            }
            else
            {
                terrain.Flush();
            }

            //Save the new tile
            world[tx, tz] = terrain;

            //Parent it to the environment
            GameObject gaiaObj = GameObject.Find("Gaia Environment");
            if (gaiaObj == null)
            {
                gaiaObj = new GameObject("Gaia Environment");
            }
            terrain.transform.parent = gaiaObj.transform;
        }
Exemplo n.º 20
0
			public void SetSettings ()
			{
				MapMagic magic = MapMagic.instance;

				terrain.heightmapPixelError = magic.pixelError;
				if (magic.showBaseMap) terrain.basemapDistance = magic.baseMapDist;
				else terrain.basemapDistance = 999999;
				terrain.castShadows = magic.castShadows;
				
				if (terrainCollider==null) terrainCollider = terrain.GetComponent<TerrainCollider>();
				if (terrainCollider!=null) terrainCollider.enabled = MapMagic.instance.applyColliders;

				//material
				if (!Preview.enabled)
				{
					terrain.materialType = MapMagic.instance.terrainMaterialType;

					if (MapMagic.instance.terrainMaterialType == Terrain.MaterialType.Custom && MapMagic.instance.assignCustomTerrainMaterial)
						terrain.materialTemplate = MapMagic.instance.customTerrainMaterial;

					/*if (MapMagic.instance.terrainMaterialType == Terrain.MaterialType.Custom)
					{
						if (MapMagic.instance.materialTemplateMode)
						{
							//assigning new mat only it has different name or shader in template mode
							if (terrain.materialTemplate == null || terrain.materialTemplate.shader != MapMagic.instance.customTerrainMaterial.shader || terrain.materialTemplate.name != MapMagic.instance.customTerrainMaterial.name)
								terrain.materialTemplate = MapMagic.instance.customTerrainMaterial;
						}
						else
							terrain.materialTemplate = MapMagic.instance.customTerrainMaterial;

//						terrain.materialTemplate = MapMagic.instance.customTerrainMaterial;
					}*/
				}

				terrain.drawTreesAndFoliage = magic.detailDraw;
				terrain.detailObjectDistance = magic.detailDistance;
				terrain.detailObjectDensity = magic.detailDensity;
				terrain.treeDistance = magic.treeDistance;
				terrain.treeBillboardDistance = magic.treeBillboardStart;
				terrain.treeCrossFadeLength = magic.treeFadeLength;
				terrain.treeMaximumFullLODCount = magic.treeFullLod;
				#if UNITY_EDITOR
				terrain.bakeLightProbesForTrees = magic.bakeLightProbesForTrees;
				#endif

				terrain.terrainData.wavingGrassSpeed = magic.windSpeed;
				terrain.terrainData.wavingGrassAmount = magic.windSize;
				terrain.terrainData.wavingGrassStrength = magic.windBending;
				terrain.terrainData.wavingGrassTint = magic.grassTint;

				//copy layer, tag, scripts from mm to terrains
				if (MapMagic.instance.copyLayersTags)
				{
					GameObject go = terrain.gameObject;
					go.layer = MapMagic.instance.gameObject.layer;
					go.isStatic = MapMagic.instance.gameObject.isStatic;
					try { go.tag = MapMagic.instance.gameObject.tag; } catch { Debug.LogError("MapMagic: could not copy object tag"); }
				}
				if (MapMagic.instance.copyComponents)
				{
					GameObject go = terrain.gameObject;
					MonoBehaviour[] components = MapMagic.instance.GetComponents<MonoBehaviour>();
					for (int i=0; i<components.Length; i++)
					{
						if (components[i] is MapMagic || components[i] == null) continue; //if MapMagic itself or script not assigned
						if (terrain.gameObject.GetComponent(components[i].GetType()) == null) Extensions.CopyComponent(components[i], go);
					}
				}
			}
Exemplo n.º 21
0
        public void Initialize()
        {               //this just creates a basic chunk object
            if (mInitialized)
            {
                return;
            }

            mChunkName          = ChunkName(State);
            mChunkDataDirectory = ChunkDataDirectory(mChunkName);
            gameObject.name     = mChunkName;
            //initialize assumes that the chunk state has been loaded
            transform.position            = State.TileOffset;
            ChunkGroup                    = WIGroups.GetOrAdd(gameObject, mChunkName, WIGroups.Get.World, null);
            ChunkGroup.Props.IgnoreOnSave = true;

            Transforms.WorldItems.gameObject.SetActive(true);
            Transforms.AboveGroundWorldItems.gameObject.SetActive(true);
            Transforms.BelowGroundWorldItems.gameObject.SetActive(true);
            Transforms.AboveGroundStaticDistant.gameObject.SetActive(true);

            Mods.Get.Runtime.LoadMod <ChunkTriggerData> (ref TriggerData, mChunkDataDirectory, "Triggers");
            Mods.Get.Runtime.LoadMod <ChunkNodeData> (ref NodeData, mChunkDataDirectory, "Nodes");
            //Mods.Get.Runtime.LoadMod <ChunkSceneryData> (ref SceneryData, mChunkDataDirectory, "Scenery");
            Mods.Get.Runtime.LoadMod <ChunkTerrainData> (ref TerrainData, mChunkDataDirectory, "Terrain");

            /*for (int i = 0; i < SceneryData.AboveGround.RiverNames.Count; i++) {
             *      //Debug.Log("Loading river " + SceneryData.AboveGround.RiverNames[i]);
             *      River river = null;
             *      if (Mods.Get.Runtime.LoadMod <River> (ref river, "River", SceneryData.AboveGround.RiverNames [i])) {
             *              Rivers.Add (river);
             *      }
             * }*/

            CalculateBounds();

            mChunkScale.Set(State.SizeX, Globals.ChunkMaximumYBounds, State.SizeZ);

            //load tree data
            if (Mods.Get.Runtime.LoadMod <ChunkTreeData> (ref TreeData, mChunkDataDirectory, "Trees"))
            {
                //update our tree instances with our offset and create our quad tree
                //make sure not to use the TreeInstances convenience property
                for (int i = 0; i < TreeData.TreeInstances.Length; i++)
                {
                    TreeInstanceTemplate tit = TreeData.TreeInstances [i];
                    tit.ParentChunk = this;
                    tit.ChunkOffset = ChunkOffset;
                    tit.ChunkScale  = ChunkScale;
                }
                TreeInstanceQuad = new QuadTree <TreeInstanceTemplate> (
                    ChunkBounds,
                    Math.Max(TreeInstances.Length / QuadTreeMaxContentScaler, QuadTreeMaxContentMinimum),
                    TreeData.TreeInstances);
            }

            //load plant data
            //make sure not to use the PlantInstances convenience property
            //it will return an empty array
            if (Mods.Get.Runtime.LoadMod <ChunkPlantData> (ref PlantData, mChunkDataDirectory, "Plants"))
            {
                for (int i = 0; i < PlantData.PlantInstances.Length; i++)
                {
                    PlantInstanceTemplate pit = PlantData.PlantInstances [i];
                    pit.HasInstance = false;
                    pit.ChunkOffset = ChunkOffset;
                    pit.ChunkScale  = ChunkScale;
                    pit.ParentChunk = this;
                }
                PlantInstanceQuad = new QuadTree <PlantInstanceTemplate> (
                    ChunkBounds,
                    Math.Max(PlantData.PlantInstances.Length / QuadTreeMaxContentScaler, QuadTreeMaxContentMinimum),
                    PlantData.PlantInstances);
            }

            //Dictionary <string,Texture2D> matChunkMaps = new Dictionary <string, Texture2D> ();
            for (int groundIndex = 0; groundIndex < TerrainData.TextureTemplates.Count; groundIndex++)
            {
                TerrainTextureTemplate ttt = TerrainData.TextureTemplates [groundIndex];
                Texture2D Diffuse          = null;
                if (Mats.Get.GetTerrainGroundTexture(ttt.DiffuseName, out Diffuse))
                {
                    ChunkDataMaps.Add("Ground" + groundIndex.ToString(), Diffuse);
                }
            }

            ChunkDataMaps.Add("ColorOverlay", PrimaryTerrain.materialTemplate.GetTexture("_CustomColorMap") as Texture2D);
            ChunkDataMaps.Add("Splat1", PrimaryTerrain.materialTemplate.GetTexture("_Splat2") as Texture2D);
            ChunkDataMaps.Add("Splat2", PrimaryTerrain.materialTemplate.GetTexture("_Splat2") as Texture2D);

            Texture2D chunkMap = null;

            //Debug.Log ("Getting terrain color overlay in " + Name);

            /*if (Mods.Get.Runtime.ChunkMap (ref chunkMap, Name, "ColorOverlay")) {
             *                  ChunkDataMaps.Add ("ColorOverlay", chunkMap);
             *          }*/
            if (GameWorld.Get.ChunkMap(ref chunkMap, Name, "AboveGroundTerrainType"))
            {
                ChunkDataMaps.Add("AboveGroundTerrainType", chunkMap);
            }
            if (GameWorld.Get.ChunkMap(ref chunkMap, Name, "BelowGroundTerrainType"))
            {
                ChunkDataMaps.Add("BelowGroundTerrainType", chunkMap);
            }
            if (GameWorld.Get.ChunkMap(ref chunkMap, Name, "RegionData"))
            {
                ChunkDataMaps.Add("RegionData", chunkMap);
            }

            /*if (Mods.Get.Runtime.ChunkMap (ref chunkMap, Name, "Splat1")) {
             *                  ChunkDataMaps.Add ("Splat1", chunkMap);
             *          }
             *          if (Mods.Get.Runtime.ChunkMap (ref chunkMap, Name, "Splat2")) {
             *                  ChunkDataMaps.Add ("Splat2", chunkMap);
             *          }*/

            //now start coroutines that load the nodes
            CreateNodesAndTriggers();

            //activate the main terrain
            PrimaryTerrain.gameObject.layer = Globals.LayerNumSolidTerrain;
            PrimaryTerrain.enabled          = true;
            PrimaryCollider = PrimaryTerrain.GetComponent <TerrainCollider>();

            //set the static objects
            DetailPrototype[] details = PrimaryTerrain.terrainData.detailPrototypes;
            for (int i = 0; i < details.Length; i++)
            {
                if (details[i].usePrototypeMesh)
                {
                    if (details[i].renderMode == DetailRenderMode.VertexLit)
                    {
                        details[i].renderMode = DetailRenderMode.Grass;
                    }
                    if (details[i].prototype == null)
                    {
                        Debug.Log("DETAIL " + i + " WAS NULL IN CHUNK " + name);
                    }
                    else if (details[i].prototype.name.Contains("Static"))
                    {
                        details[i].dryColor     = Colors.Alpha(details[i].dryColor, 0f);
                        details[i].healthyColor = Colors.Alpha(details[i].healthyColor, 0f);
                    }
                }
            }
            PrimaryTerrain.terrainData.detailPrototypes = details;

            //remove plant instance prefab, replace it with an empty one
            TreePrototype[] treePrototypes = PrimaryTerrain.terrainData.treePrototypes;
            for (int i = 0; i < treePrototypes.Length; i++)
            {
                if (treePrototypes[i].prefab == Plants.Get.PlantInstancePrefab)
                {
                    treePrototypes[i].prefab = Plants.Get.RuntimePlantInstancePrefab;
                }
            }
            PrimaryTerrain.terrainData.treePrototypes = treePrototypes;

            if (ColliderTemplates != null)
            {
                Array.Clear(ColliderTemplates, 0, ColliderTemplates.Length);
                ColliderTemplates = null;
                Plants.Get.GetTerrainPlantPrototypes(treePrototypes, ref ColliderTemplates);
            }

            /*if (!GameManager.Get.NoTreesMode) {
             *  TreePrototype[] treePrototypes = null;
             *  if (ColliderTemplates != null) {
             *      Array.Clear(ColliderTemplates, 0, ColliderTemplates.Length);
             *      ColliderTemplates = null;
             *  }
             *  //Debug.Log("Getting tree prototypes for " + Name);
             *  Plants.Get.GetTerrainPlantPrototypes(TerrainData.TreeTemplates, TreeData.TreeInstances, ref treePrototypes, ref ColliderTemplates);
             *  //PrimaryTerrain.terrainData.treePrototypes = treePrototypes;
             * }*/

            //turn everything off initially
            Transforms.AboveGroundStaticImmediate.gameObject.SetActive(false);
            Transforms.AboveGroundStaticAdjascent.gameObject.SetActive(false);
            Transforms.AboveGroundStaticDistant.gameObject.SetActive(false);
            Transforms.BelowGroundStatic.gameObject.SetActive(false);

            mInitialized = true;
        }
Exemplo n.º 22
0
        private void ExportTerrain(XmlWriter writer, TerrainData terrainData, TerrainCollider terrainCollider, string subPrefix, bool enabled, PrefabContext prefabContext)
        {
            if (terrainData == null)
            {
                return;
            }

            var subSubPrefix = subPrefix + "\t";

            var terrainSize = terrainData.size;

            StartNode(writer, subPrefix);

            _engine.ScheduleAssetExport(terrainData, prefabContext);

            var(min, max, size) = GetTerrainSize(terrainData);

            var offset = new Vector3(terrainSize.x * 0.5f, terrainSize.y * min, terrainSize.z * 0.5f);

            WriteAttribute(writer, subPrefix, "Position", offset);
            StartComponent(writer, subPrefix, "Terrain", enabled);

            WriteAttribute(writer, subSubPrefix, "Height Map",
                           "Image;" + _engine.EvaluateTerrainHeightMap(terrainData));
            WriteAttribute(writer, subSubPrefix, "Material",
                           "Material;" + _engine.EvaluateTerrainMaterial(terrainData));
            //WriteTerrainMaterial(terrainData, materialFileName, "Textures/Terrains/" + folderAndName + ".Weights.tga");
            var vertexSpacing = new Vector3(terrainSize.x / size.x, terrainSize.y * (max - min) / 255.0f,
                                            terrainSize.z / size.y);

            WriteAttribute(writer, subSubPrefix, "Vertex Spacing",
                           vertexSpacing);
            EndElement(writer, subPrefix);
            if (terrainCollider != null)
            {
                StartComponent(writer, subPrefix, "CollisionShape", enabled);
                WriteCommonCollisionAttributes(writer, subSubPrefix, terrainCollider);
                WriteAttribute(writer, subSubPrefix, "Shape Type", "Terrain");
                EndElement(writer, subPrefix);
                StartComponent(writer, subPrefix, "RigidBody", enabled);
                var localToWorldMatrix = terrainCollider.transform.localToWorldMatrix;
                var pos = localToWorldMatrix.MultiplyPoint(offset);
                WriteAttribute(writer, subPrefix, "Physics Position", pos);
                EndElement(writer, subPrefix);
            }

            if (terrainData.detailPrototypes.Length > 0)
            {
                StartNode(writer, subPrefix);
                var detailOffset = subPrefix + "\t";
                StartComponent(writer, detailOffset, "StaticModel", enabled);
                EndElement(writer, detailOffset);
                EndElement(writer, subPrefix);
            }

            EndElement(writer, subPrefix);

            var numTrees = Math.Min(terrainData.treeInstances.Length, terrainData.treeInstanceCount);

            //numTrees = Math.Min(numTrees, 20);
            for (var index = 0; index < numTrees; index++)
            {
                var treeInstance = terrainData.treeInstances[index];
                ExportTree(writer, subPrefix, treeInstance, terrainData, enabled, prefabContext);
            }
        }
Exemplo n.º 23
0
		/// <summary>
		/// Creates terrain from given volumeInfo for the given gameObject.
		/// If gameObject has a valid Terrain component, then it is reused.
		/// Similarly, if the Terrain component has a valid TerrainData, or if the given terrainData is valid, then it is used.
		/// Otherwise a new TerrainData is created and set to the Terrain.
		/// Populates the volumePositionOffset with the heightfield offset position.
		/// Returns true if successfully created the terrain, otherwise false.
		/// </summary>
		/// <param name="session">Houdini Engine session to query heightfield data from</param>
		/// <param name="volumeInfo">Volume info pertaining to the heightfield to generate the Terrain from</param>
		/// <param name="geoID">The geometry ID</param>
		/// <param name="partID">The part ID (height layer)</param>
		/// <param name="gameObject">The target GameObject containing the Terrain component</param>
		/// <param name="terrainData">A valid TerrainData to use, or if empty, a new one is created and populated</param>
		/// <param name="volumePositionOffset">Heightfield offset</param>
		/// <returns>True if successfully popupated the terrain</returns>
		public static bool GenerateTerrainFromVolume(HEU_SessionBase session, ref HAPI_VolumeInfo volumeInfo, HAPI_NodeId geoID, HAPI_PartId partID,
			GameObject gameObject, ref TerrainData terrainData, out Vector3 volumePositionOffset, ref Terrain terrain)
		{
			volumePositionOffset = Vector3.zero;

			if (volumeInfo.zLength == 1 && volumeInfo.tupleSize == 1)
			{
				// Heightfields will be converted to terrain in Unity.
				// Unity requires terrainData.heightmapResolution to be square power of two plus 1 (eg. 513, 257, 129, 65).
				// Houdini gives volumeInfo.xLength and volumeInfo.yLength which are the number of height values per dimension.
				// Note that volumeInfo.xLength and volumeInfo.yLength is equal to Houdini heightfield size / grid spacing.
				// The heightfield grid spacing is given as volumeTransformMatrix.scale but divided by 2 (grid spacing / 2 = volumeTransformMatrix.scale).
				// It is recommended to use grid spacing of 2.

				// Use the volumeInfo.transform to get the actual heightfield position and size.
				Matrix4x4 volumeTransformMatrix = HEU_HAPIUtility.GetMatrixFromHAPITransform(ref volumeInfo.transform, false);
				Vector3 position = HEU_HAPIUtility.GetPosition(ref volumeTransformMatrix);
				Vector3 scale = HEU_HAPIUtility.GetScale(ref volumeTransformMatrix);

				// Calculate real terrain size in both Houdini and Unity.
				// The height values will be mapped over this terrain size.
				float gridSpacingX = scale.x * 2f;
				float gridSpacingY = scale.y * 2f;
				float terrainSizeX = Mathf.Round((volumeInfo.xLength - 1) * gridSpacingX);
				float terrainSizeY = Mathf.Round((volumeInfo.yLength - 1) * gridSpacingY);

				//Debug.LogFormat("GS = {0},{1},{2}. SX = {1}. SY = {2}", gridSpacingX, gridSpacingY, terrainSizeX, terrainSizeY);

				//Debug.LogFormat("HeightField Pos:{0}, Scale:{1}", position, scale.ToString("{0.00}"));
				//Debug.LogFormat("HeightField tileSize:{0}, xLength:{1}, yLength:{2}", volumeInfo.tileSize.ToString("{0.00}"), volumeInfo.xLength.ToString("{0.00}"), volumeInfo.yLength.ToString("{0.00}"));
				//Debug.LogFormat("HeightField Terrain Size x:{0}, y:{1}", terrainSizeX.ToString("{0.00}"), terrainSizeY.ToString("{0.00}"));
				//Debug.LogFormat("HeightField minX={0}, minY={1}, minZ={2}", volumeInfo.minX.ToString("{0.00}"), volumeInfo.minY.ToString("{0.00}"), volumeInfo.minZ.ToString("{0.00}"));

				const int UNITY_MINIMUM_HEIGHTMAP_RESOLUTION = 33;
				if (terrainSizeX < UNITY_MINIMUM_HEIGHTMAP_RESOLUTION || terrainSizeY < UNITY_MINIMUM_HEIGHTMAP_RESOLUTION)
				{
					Debug.LogWarningFormat("Unity Terrain has a minimum heightmap resolution of {0}. This HDA heightmap size is {1}x{2}."
						+ "\nPlease resize the terrain to a value higher than this.",
						UNITY_MINIMUM_HEIGHTMAP_RESOLUTION, terrainSizeX, terrainSizeY);
					return false;
				}

				bool bNewTerrain = false;
				bool bNewTerrainData = false;
				terrain = gameObject.GetComponent<Terrain>();
				if (terrain == null)
				{
					terrain = gameObject.AddComponent<Terrain>();
					bNewTerrain = true;
				}

				TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent<TerrainCollider>(gameObject);

				// This ensures to reuse existing terraindata, and only creates new if none exist or none provided
				if (terrain.terrainData == null)
				{
					if (terrainData == null)
					{
						terrainData = new TerrainData();
						bNewTerrainData = true;
					}

					terrain.terrainData = terrainData;
					SetTerrainMaterial(terrain);
				}

				terrainData = terrain.terrainData;
				collider.terrainData = terrainData;

				if (bNewTerrain)
				{
#if UNITY_2018_3_OR_NEWER
					terrain.allowAutoConnect = true;
					// This has to be set after setting material
					terrain.drawInstanced = true;
#endif
				}

				// Heightmap resolution must be square power-of-two plus 1. 
				// Unity will automatically resize terrainData.heightmapResolution so need to handle the changed size (if Unity changed it).
				int heightMapResolution = volumeInfo.xLength;
				terrainData.heightmapResolution = heightMapResolution;
				int terrainResizedDelta = terrainData.heightmapResolution - heightMapResolution;
				if (terrainResizedDelta < 0)
				{
					Debug.LogWarningFormat("Note that Unity automatically resized terrain resolution to {0} from {1}. Use terrain size of power of two plus 1, and grid spacing of 2.", heightMapResolution, terrainData.heightmapResolution);
					heightMapResolution = terrainData.heightmapResolution;
				}
				else if (terrainResizedDelta > 0)
				{
					Debug.LogErrorFormat("Unsupported terrain size. Use terrain size of power of two plus 1, and grid spacing of 2. Given size is {0} but Unity resized it to {1}.", heightMapResolution, terrainData.heightmapResolution);
					return false;
				}

				int mapWidth = volumeInfo.xLength;
				int mapHeight = volumeInfo.yLength;

				// Get the converted height values from Houdini and find the min and max height range.
				float minHeight = 0;
				float maxHeight = 0;
				float heightRange = 0;
				float[] normalizedHeights = GetNormalizedHeightmapFromPartWithMinMax(session, geoID, partID, 
					volumeInfo.xLength, volumeInfo.yLength, ref minHeight, ref maxHeight, ref heightRange);
				float[,] unityHeights = ConvertHeightMapHoudiniToUnity(heightMapResolution, heightMapResolution, normalizedHeights);

				// The terrainData.baseMapResolution is not set here, but rather left to whatever default Unity uses
				// The terrainData.alphamapResolution is set later when setting the alphamaps.

				if (bNewTerrainData)
				{
					// 32 is the default for resolutionPerPatch
					const int detailResolution = 1024;
					const int resolutionPerPatch = 32;
					terrainData.SetDetailResolution(detailResolution, resolutionPerPatch);
				}

				// Note SetHeights must be called before setting size in next line, as otherwise
				// the internal terrain size will not change after setting the size.
				terrainData.SetHeights(0, 0, unityHeights);

				// Note that Unity uses a default height range of 600 when a flat terrain is created.
				// Without a non-zero value for the height range, user isn't able to draw heights.
				// Therefore, set 600 as the value if height range is currently 0 (due to flat heightfield).
				if (heightRange == 0)
				{
					heightRange = terrainData.size.y > 1 ? terrainData.size.y : 600;
				}

				terrainData.size = new Vector3(terrainSizeX, heightRange, terrainSizeY);

				terrain.Flush();

				// Unity Terrain has origin at bottom left, whereas Houdini uses centre of terrain. 

				// Use volume bounds to set position offset when using split tiles
				float xmin, xmax, zmin, zmax, ymin, ymax, xcenter, ycenter, zcenter;
				session.GetVolumeBounds(geoID, partID, out xmin, out ymin, out zmin, out xmax, out ymax, out zmax, out xcenter,
					out ycenter, out zcenter);
				//Debug.LogFormat("xmin: {0}, xmax: {1}, ymin: {2}, ymax: {3}, zmin: {4}, zmax: {5}, xc: {6}, yc: {7}, zc: {8}",
				//	xmin, xmax, ymin, ymax, zmin, zmax, xcenter, ycenter, zcenter);

				// Offset position is based on size of heightfield
				float offsetX = (float)heightMapResolution / (float)mapWidth;
				float offsetZ = (float)heightMapResolution / (float)mapHeight;
				//Debug.LogFormat("offsetX: {0}, offsetZ: {1}", offsetX, offsetZ);

				volumePositionOffset = new Vector3((terrainSizeX + xmin) * offsetX, minHeight + position.y, zmin * offsetZ);

				return true;
			}
			else
			{
				Debug.LogWarning("Non-heightfield volume type not supported!");
			}

			return false;
		}
Exemplo n.º 24
0
 public override void Setup()
 {
     this.ignoredColliders = new ListDictionary <Collider, List <Collider> >(8);
     this.terrainCollider  = (TerrainCollider)((Component)this.terrain).GetComponent <TerrainCollider>();
 }
Exemplo n.º 25
0
        public static Vector3 ClosestPointOnSurface(TerrainCollider collider, Vector3 to, float radius)
        {
            var terrainData = collider.terrainData;

            var local = collider.transform.InverseTransformPoint(to);

            // Calculate the size of each tile on the terrain horizontally and vertically
            float pixelSizeX = terrainData.size.x / (terrainData.heightmapResolution - 1);
            float pixelSizeZ = terrainData.size.z / (terrainData.heightmapResolution - 1);

            var percentZ = Mathf.Clamp01(local.z / terrainData.size.z);
            var percentX = Mathf.Clamp01(local.x / terrainData.size.x);

            float positionX = percentX * (terrainData.heightmapResolution - 1);
            float positionZ = percentZ * (terrainData.heightmapResolution - 1);

            // Calculate our position, in tiles, on the terrain
            int pixelX = Mathf.FloorToInt(positionX);
            int pixelZ = Mathf.FloorToInt(positionZ);

            // Calculate the distance from our point to the edge of the tile we are in
            float distanceX = (positionX - pixelX) * pixelSizeX;
            float distanceZ = (positionZ - pixelZ) * pixelSizeZ;

            // Find out how many tiles we are overlapping on the X plane
            float radiusExtentsLeftX  = radius - distanceX;
            float radiusExtentsRightX = radius - (pixelSizeX - distanceX);

            int overlappedTilesXLeft  = radiusExtentsLeftX > 0 ? Mathf.FloorToInt(radiusExtentsLeftX / pixelSizeX) + 1 : 0;
            int overlappedTilesXRight = radiusExtentsRightX > 0 ? Mathf.FloorToInt(radiusExtentsRightX / pixelSizeX) + 1 : 0;

            // Find out how many tiles we are overlapping on the Z plane
            float radiusExtentsLeftZ  = radius - distanceZ;
            float radiusExtentsRightZ = radius - (pixelSizeZ - distanceZ);

            int overlappedTilesZLeft  = radiusExtentsLeftZ > 0 ? Mathf.FloorToInt(radiusExtentsLeftZ / pixelSizeZ) + 1 : 0;
            int overlappedTilesZRight = radiusExtentsRightZ > 0 ? Mathf.FloorToInt(radiusExtentsRightZ / pixelSizeZ) + 1 : 0;

            // Retrieve the heights of the pixels we are testing against
            int startPositionX = pixelX - overlappedTilesXLeft;
            int startPositionZ = pixelZ - overlappedTilesZLeft;

            int numberOfXPixels = overlappedTilesXRight + overlappedTilesXLeft + 1;
            int numberOfZPixels = overlappedTilesZRight + overlappedTilesZLeft + 1;

            // Account for if we are off the terrain
            if (startPositionX < 0)
            {
                numberOfXPixels -= Mathf.Abs(startPositionX);
                startPositionX   = 0;
            }

            if (startPositionZ < 0)
            {
                numberOfZPixels -= Mathf.Abs(startPositionZ);
                startPositionZ   = 0;
            }

            if (startPositionX + numberOfXPixels + 1 > terrainData.heightmapResolution)
            {
                numberOfXPixels = terrainData.heightmapResolution - startPositionX - 1;
            }

            if (startPositionZ + numberOfZPixels + 1 > terrainData.heightmapResolution)
            {
                numberOfZPixels = terrainData.heightmapResolution - startPositionZ - 1;
            }

            // Retrieve the heights of the tile we are in and all overlapped tiles
            var heights = terrainData.GetHeights(startPositionX, startPositionZ, numberOfXPixels + 1, numberOfZPixels + 1);

            // Pre-scale the heights data to be world-scale instead of 0...1
            for (int i = 0; i < numberOfXPixels + 1; i++)
            {
                for (int j = 0; j < numberOfZPixels + 1; j++)
                {
                    heights[j, i] *= terrainData.size.y;
                }
            }

            // Find the shortest distance to any triangle in the set gathered
            float shortestDistance = float.MaxValue;

            Vector3 shortestPoint = Vector3.zero;

            for (int x = 0; x < numberOfXPixels; x++)
            {
                for (int z = 0; z < numberOfZPixels; z++)
                {
                    // Build the set of points that creates the two triangles that form this tile
                    Vector3 a = new Vector3((startPositionX + x) * pixelSizeX, heights[z, x], (startPositionZ + z) * pixelSizeZ);
                    Vector3 b = new Vector3((startPositionX + x + 1) * pixelSizeX, heights[z, x + 1], (startPositionZ + z) * pixelSizeZ);
                    Vector3 c = new Vector3((startPositionX + x) * pixelSizeX, heights[z + 1, x], (startPositionZ + z + 1) * pixelSizeZ);
                    Vector3 d = new Vector3((startPositionX + x + 1) * pixelSizeX, heights[z + 1, x + 1], (startPositionZ + z + 1) * pixelSizeZ);

                    Vector3 nearest;

                    BSPTree.ClosestPointOnTriangleToPoint(ref a, ref d, ref c, ref local, out nearest);

                    float distance = (local - nearest).sqrMagnitude;

                    if (distance <= shortestDistance)
                    {
                        shortestDistance = distance;
                        shortestPoint    = nearest;
                    }

                    BSPTree.ClosestPointOnTriangleToPoint(ref a, ref b, ref d, ref local, out nearest);

                    distance = (local - nearest).sqrMagnitude;

                    if (distance <= shortestDistance)
                    {
                        shortestDistance = distance;
                        shortestPoint    = nearest;
                    }
                }
            }

            return(collider.transform.TransformPoint(shortestPoint));
        }
Exemplo n.º 26
0
		public static bool GenerateTerrainFromVolume(HEU_SessionBase session, ref HAPI_VolumeInfo volumeInfo, HAPI_NodeId geoID, HAPI_PartId partID, 
			GameObject gameObject, out TerrainData terrainData, out Vector3 volumePositionOffset)
		{
			terrainData = null;
			volumePositionOffset = Vector3.zero;

			if (volumeInfo.zLength == 1 && volumeInfo.tupleSize == 1)
			{
				// Heightfields will be converted to terrain in Unity.
				// Unity requires terrainData.heightmapResolution to be square power of two plus 1 (eg. 513, 257, 129, 65).
				// Houdini gives volumeInfo.xLength and volumeInfo.yLength which are the number of height values per dimension.
				// Note that volumeInfo.xLength and volumeInfo.yLength is equal to Houdini heightfield size / grid spacing.
				// The heightfield grid spacing is given as volumeTransformMatrix.scale but divided by 2 (grid spacing / 2 = volumeTransformMatrix.scale).
				// It is recommended to use grid spacing of 2.

				// Use the volumeInfo.transform to get the actual heightfield position and size.
				Matrix4x4 volumeTransformMatrix = HEU_HAPIUtility.GetMatrixFromHAPITransform(ref volumeInfo.transform, false);
				Vector3 position = HEU_HAPIUtility.GetPosition(ref volumeTransformMatrix);
				Vector3 scale = HEU_HAPIUtility.GetScale(ref volumeTransformMatrix);

				// Calculate real terrain size in both Houdini and Unity.
				// The height values will be mapped over this terrain size.
				float gridSpacingX = scale.x * 2f;
				float gridSpacingY = scale.y * 2f;
				//float gridSpacingZ = scale.z * 2f;
				float multiplierOffsetX = Mathf.Round(scale.x);
				float multiplierOffsetY = Mathf.Round(scale.y);
				//float multiplierOffsetZ = Mathf.Round(scale.z);
				float terrainSizeX = Mathf.Round(volumeInfo.xLength * gridSpacingX - multiplierOffsetX);
				float terrainSizeY = Mathf.Round(volumeInfo.yLength * gridSpacingY - multiplierOffsetY);

				//Debug.LogFormat("GS = {0},{1},{2}. SX = {1}. SY = {2}", gridSpacingX, gridSpacingY, gridSpacingZ, terrainSizeX, terrainSizeY);

				//Debug.LogFormat("HeightField Pos:{0}, Scale:{1}", position, scale.ToString("{0.00}"));
				//Debug.LogFormat("HeightField tileSize:{0}, xLength:{1}, yLength:{2}", volumeInfo.tileSize.ToString("{0.00}"), volumeInfo.xLength.ToString("{0.00}"), volumeInfo.yLength.ToString("{0.00}"));
				//Debug.LogFormat("HeightField Terrain Size x:{0}, y:{1}", terrainSizeX.ToString("{0.00}"), terrainSizeY.ToString("{0.00}"));
				//Debug.LogFormat("HeightField minX={0}, minY={1}, minZ={2}", volumeInfo.minX.ToString("{0.00}"), volumeInfo.minY.ToString("{0.00}"), volumeInfo.minZ.ToString("{0.00}"));

				const int UNITY_MINIMUM_HEIGHTMAP_RESOLUTION = 33;
				if (terrainSizeX < UNITY_MINIMUM_HEIGHTMAP_RESOLUTION || terrainSizeY < UNITY_MINIMUM_HEIGHTMAP_RESOLUTION)
				{
					Debug.LogWarningFormat("Unity Terrain has a minimum heightmap resolution of {0}. This HDA heightmap size is {1}x{2}."
						+ "\nPlease resize the terrain to a value higher than this.",
						UNITY_MINIMUM_HEIGHTMAP_RESOLUTION, terrainSizeX, terrainSizeY);
					return false;
				}

				Terrain terrain = HEU_GeneralUtility.GetOrCreateComponent<Terrain>(gameObject);
				TerrainCollider collider = HEU_GeneralUtility.GetOrCreateComponent<TerrainCollider>(gameObject);
				
				if (terrain.terrainData == null)
				{
					terrain.terrainData = new TerrainData();
				}

				terrainData = terrain.terrainData;
				collider.terrainData = terrainData;

				// Heightmap resolution must be square power-of-two plus 1. 
				// Unity will automatically resize terrainData.heightmapResolution so need to handle the changed size (if Unity changed it).
				int heightMapResolution = volumeInfo.xLength;
				terrainData.heightmapResolution = heightMapResolution;
				int terrainResizedDelta = terrainData.heightmapResolution - heightMapResolution;
				if (terrainResizedDelta < 0)
				{
					Debug.LogWarningFormat("Note that Unity automatically resized terrain resolution to {0} from {1}. Use terrain size of power of two plus 1, and grid spacing of 2.", heightMapResolution, terrainData.heightmapResolution);
					heightMapResolution = terrainData.heightmapResolution;
				}
				else if(terrainResizedDelta > 0)
				{
					Debug.LogErrorFormat("Unsupported terrain size. Use terrain size of power of two plus 1, and grid spacing of 2. (delta = {0})", terrainResizedDelta);
					return false;
				}

				// Get the height values from Houdini and find the min and max height range.
				int totalHeightValues = volumeInfo.xLength * volumeInfo.yLength;
				float[] heightValues = new float[totalHeightValues];

				bool bResult = HEU_GeneralUtility.GetArray2Arg(geoID, partID, session.GetHeightFieldData, heightValues, 0, totalHeightValues);
				if (!bResult)
				{
					return false;
				}

				float minHeight = heightValues[0];
				float maxHeight = minHeight;
				for (int i = 0; i < totalHeightValues; ++i)
				{
					float f = heightValues[i];
					if (f > maxHeight)
					{
						maxHeight = f;
					}
					else if (f < minHeight)
					{
						minHeight = f;
					}
				} 

				const int UNITY_MAX_HEIGHT_RANGE = 65536;
				float heightRange = (maxHeight - minHeight);
				if (Mathf.RoundToInt(heightRange) > UNITY_MAX_HEIGHT_RANGE)
				{
					Debug.LogWarningFormat("Unity Terrain has maximum height range of {0}. This HDA height range is {1}, so it will be maxed out at {0}.\nPlease resize to within valid range!",
						UNITY_MAX_HEIGHT_RANGE, Mathf.RoundToInt(heightRange));
					heightRange = UNITY_MAX_HEIGHT_RANGE;
				}

				int mapWidth = volumeInfo.xLength;
				int mapHeight = volumeInfo.yLength;

				int paddingWidth = heightMapResolution - mapWidth;
				int paddingLeft = Mathf.CeilToInt(paddingWidth * 0.5f);
				int paddingRight = heightMapResolution - paddingLeft;
				//Debug.LogFormat("Padding: Width={0}, Left={1}, Right={2}", paddingWidth, paddingLeft, paddingRight);

				int paddingHeight = heightMapResolution - mapHeight;
				int paddingTop = Mathf.CeilToInt(paddingHeight * 0.5f);
				int paddingBottom = heightMapResolution - paddingTop;
				//Debug.LogFormat("Padding: Height={0}, Top={1}, Bottom={2}", paddingHeight, paddingTop, paddingBottom);

				// Set height values at centre of the terrain, with padding on the sides if we resized
				float[,] unityHeights = new float[heightMapResolution, heightMapResolution];
				for (int y = 0; y < heightMapResolution; ++y)
				{
					for (int x = 0; x < heightMapResolution; ++x)
					{	
						if (y >= paddingTop && y < (paddingBottom) && x >= paddingLeft && x < (paddingRight))
						{
							int ay = x - paddingLeft;
							int ax = y - paddingTop;

							// Unity expects normalized height values
							float h = heightValues[ay + ax * mapWidth] - minHeight;
							float f = h / heightRange;

							// Flip for right-hand to left-handed coordinate system
							int ix = x;
							int iy = heightMapResolution - (y + 1);

							// Unity expects height array indexing to be [y, x].
							unityHeights[ix, iy] = f;
						}
					}
				}

				terrainData.baseMapResolution = heightMapResolution;
				terrainData.alphamapResolution = heightMapResolution;

				//int detailResolution = heightMapResolution;
				// 128 is the maximum for resolutionPerPatch
				const int resolutionPerPatch = 128;
				terrainData.SetDetailResolution(resolutionPerPatch, resolutionPerPatch);

				// Note SetHeights must be called before setting size in next line, as otherwise
				// the internal terrain size will not change after setting the size.
				terrainData.SetHeights(0, 0, unityHeights);

				terrainData.size = new Vector3(terrainSizeX, heightRange, terrainSizeY);

				terrain.Flush();

				// Unity Terrain has origin at bottom left, whereas Houdini uses centre of terrain. 

				// Use volume bounds to set position offset when using split tiles
				float xmin, xmax, zmin, zmax, ymin, ymax, xcenter, ycenter, zcenter;
				session.GetVolumeBounds(geoID, partID, out xmin, out ymin, out zmin, out xmax, out ymax, out zmax, out xcenter,
					out ycenter, out zcenter);
				//Debug.LogFormat("xmin: {0}, xmax: {1}, ymin: {2}, ymax: {3}, zmin: {4}, zmax: {5}, xc: {6}, yc: {7}, zc: {8}",
				//	xmin, xmax, ymin, ymax, zmin, zmax, xcenter, ycenter, zcenter);

				// Offset position is based on size of heightfield
				float offsetX = (float)heightMapResolution / (float)mapWidth;
				float offsetZ = (float)heightMapResolution / (float)mapHeight;
				//Debug.LogFormat("offsetX: {0}, offsetZ: {1}", offsetX, offsetZ);

				//Debug.LogFormat("position.x: {0}, position.z: {1}", position.x, position.z);

				//volumePositionOffset = new Vector3(-position.x * offsetX, minHeight + position.y, position.z * offsetZ);
				volumePositionOffset = new Vector3((terrainSizeX + xmin) * offsetX, minHeight + position.y, zmin * offsetZ);

				return true;
			}
			else
			{
				Debug.LogWarning("Non-heightfield volume type not supported!");
			}

			return false;
		}
 // Use this for initialization
 void Start()
 {
     terrainCollider = GetComponent <TerrainCollider>();
 }
    public static void SectorizeTerrain(Terrain terrain, int sectorsWidth, int sectorsLength, int sectorsHeight, bool splitTerrain, bool createPortalGeo, bool includeStatic, bool includeDynamic)
    {
        if (!terrain)
        {
            Debug.LogWarning("Cannot sectorize null terrain.");
            return;
        }

        if (terrain.transform.root.GetComponentsInChildren <SECTR_Sector>().Length > 0)
        {
            Debug.LogWarning("Cannot sectorize terrain that is already part of a Sector.");
        }

        string undoString = "Sectorized " + terrain.name;

        if (sectorsWidth == 1 && sectorsLength == 1)
        {
            SECTR_Sector newSector = terrain.gameObject.AddComponent <SECTR_Sector>();
            SECTR_Undo.Created(newSector, undoString);
            newSector.ForceUpdate(true);
            return;
        }

        if (splitTerrain && (!Mathf.IsPowerOfTwo(sectorsWidth) || !Mathf.IsPowerOfTwo(sectorsLength)))
        {
            Debug.LogWarning("Splitting terrain requires power of two sectors in width and length.");
            splitTerrain = false;
        }
        else if (splitTerrain && sectorsWidth != sectorsLength)
        {
            Debug.LogWarning("Splitting terrain requires same number of sectors in width and length.");
            splitTerrain = false;
        }

        int     terrainLayer = terrain.gameObject.layer;
        Vector3 terrainSize  = terrain.terrainData.size;
        float   sectorWidth  = terrainSize.x / sectorsWidth;
        float   sectorHeight = terrainSize.y / sectorsHeight;
        float   sectorLength = terrainSize.z / sectorsLength;

        int heightmapWidth  = (terrain.terrainData.heightmapWidth / sectorsWidth);
        int heightmapLength = (terrain.terrainData.heightmapHeight / sectorsLength);
        int alphaWidth      = terrain.terrainData.alphamapWidth / sectorsWidth;
        int alphaLength     = terrain.terrainData.alphamapHeight / sectorsLength;
        int detailWidth     = terrain.terrainData.detailWidth / sectorsWidth;
        int detailLength    = terrain.terrainData.detailHeight / sectorsLength;

        string sceneDir     = "";
        string sceneName    = "";
        string exportFolder = splitTerrain ? SECTR_Asset.MakeExportFolder("TerrainSplits", false, out sceneDir, out sceneName) : "";

        Transform baseTransform = null;

        if (splitTerrain)
        {
            GameObject baseObject = new GameObject(terrain.name);
            baseTransform = baseObject.transform;
            SECTR_Undo.Created(baseObject, undoString);
        }

        List <Transform> rootTransforms = new List <Transform>();
        List <Bounds>    rootBounds     = new List <Bounds>();

        _GetRoots(includeStatic, includeDynamic, rootTransforms, rootBounds);

        // Create Sectors
        string progressTitle   = "Sectorizing Terrain";
        int    progressCounter = 0;

        EditorUtility.DisplayProgressBar(progressTitle, "Preparing", 0);

        SECTR_Sector[,,] newSectors = new SECTR_Sector[sectorsWidth, sectorsLength, sectorsHeight];
        Terrain[,] newTerrains      = splitTerrain ? new Terrain[sectorsWidth, sectorsLength] : null;
        for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex)
        {
            for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex)
            {
                for (int heightIndex = 0; heightIndex < sectorsHeight; ++heightIndex)
                {
                    string newName = terrain.name + " " + widthIndex + "-" + lengthIndex + "-" + heightIndex;

                    EditorUtility.DisplayProgressBar(progressTitle, "Creating sector " + newName, progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight));

                    GameObject newSectorObject = new GameObject("SECTR " + newName + " Sector");
                    newSectorObject.transform.parent = baseTransform;
                    Vector3 sectorCorner = new Vector3(widthIndex * sectorWidth,
                                                       heightIndex * sectorHeight,
                                                       lengthIndex * sectorLength) + terrain.transform.position;
                    newSectorObject.transform.position = sectorCorner;
                    newSectorObject.isStatic           = true;
                    SECTR_Sector newSector = newSectorObject.AddComponent <SECTR_Sector>();
                    newSector.OverrideBounds = !splitTerrain && (sectorsWidth > 1 || sectorsLength > 1);
                    newSector.BoundsOverride = new Bounds(sectorCorner + new Vector3(sectorWidth * 0.5f, sectorHeight * 0.5f, sectorLength * 0.5f),
                                                          new Vector3(sectorWidth, sectorHeight, sectorLength));
                    newSectors[widthIndex, lengthIndex, heightIndex] = newSector;

                    if (splitTerrain && heightIndex == 0)
                    {
                        GameObject newTerrainObject = new GameObject(newName + " Terrain");
                        newTerrainObject.layer                   = terrainLayer;
                        newTerrainObject.transform.parent        = newSectorObject.transform;
                        newTerrainObject.transform.localPosition = Vector3.zero;
                        newTerrainObject.transform.localRotation = Quaternion.identity;
                        newTerrainObject.transform.localScale    = Vector3.one;
                        newTerrainObject.isStatic                = true;
                        Terrain newTerrain = newTerrainObject.AddComponent <Terrain>();
                        newTerrain.terrainData = SECTR_Asset.Create <TerrainData>(exportFolder, newName, new TerrainData());
                        EditorUtility.SetDirty(newTerrain.terrainData);
                        SECTR_VC.WaitForVC();

                        // Copy properties
                        // Basic terrain properties
                        newTerrain.editorRenderFlags   = terrain.editorRenderFlags;
                        newTerrain.castShadows         = terrain.castShadows;
                        newTerrain.heightmapMaximumLOD = terrain.heightmapMaximumLOD;
                        newTerrain.heightmapPixelError = terrain.heightmapPixelError;
                        newTerrain.lightmapIndex       = -1;                   // Can't set lightmap UVs on terrain.
                        newTerrain.materialTemplate    = terrain.materialTemplate;

                        // Copy geometric data
                        int heightmapBaseX  = widthIndex * heightmapWidth;
                        int heightmapBaseY  = lengthIndex * heightmapLength;
                        int heightmapWidthX = heightmapWidth + (sectorsWidth > 1 ? 1 : 0);
                        int heightmapWidthY = heightmapLength + (sectorsLength > 1 ? 1 : 0);
                        newTerrain.terrainData.heightmapResolution = terrain.terrainData.heightmapResolution / sectorsWidth;
                        newTerrain.terrainData.size = new Vector3(sectorWidth, terrainSize.y, sectorLength);
                        newTerrain.terrainData.SetHeights(0, 0, terrain.terrainData.GetHeights(heightmapBaseX, heightmapBaseY, heightmapWidthX, heightmapWidthY));

                        // Copy alpha maps
                        int alphaBaseX = alphaWidth * widthIndex;
                        int alphaBaseY = alphaLength * lengthIndex;
                        newTerrain.terrainData.splatPrototypes    = terrain.terrainData.splatPrototypes;
                        newTerrain.basemapDistance                = terrain.basemapDistance;
                        newTerrain.terrainData.baseMapResolution  = terrain.terrainData.baseMapResolution / sectorsWidth;
                        newTerrain.terrainData.alphamapResolution = terrain.terrainData.alphamapResolution / sectorsWidth;
                        newTerrain.terrainData.SetAlphamaps(0, 0, terrain.terrainData.GetAlphamaps(alphaBaseX, alphaBaseY, alphaWidth, alphaLength));

                        // Copy detail info
                        newTerrain.detailObjectDensity          = terrain.detailObjectDensity;
                        newTerrain.detailObjectDistance         = terrain.detailObjectDistance;
                        newTerrain.terrainData.detailPrototypes = terrain.terrainData.detailPrototypes;
                        newTerrain.terrainData.SetDetailResolution(terrain.terrainData.detailResolution / sectorsWidth, 8);                         // TODO: extract detailResolutionPerPatch

                        int detailBaseX = detailWidth * widthIndex;
                        int detailBaseY = detailLength * lengthIndex;
                        int numLayers   = terrain.terrainData.detailPrototypes.Length;
                        for (int layer = 0; layer < numLayers; ++layer)
                        {
                            newTerrain.terrainData.SetDetailLayer(0, 0, layer, terrain.terrainData.GetDetailLayer(detailBaseX, detailBaseY, detailWidth, detailLength, layer));
                        }

                        // Copy grass and trees
                        newTerrain.terrainData.wavingGrassAmount   = terrain.terrainData.wavingGrassAmount;
                        newTerrain.terrainData.wavingGrassSpeed    = terrain.terrainData.wavingGrassSpeed;
                        newTerrain.terrainData.wavingGrassStrength = terrain.terrainData.wavingGrassStrength;
                        newTerrain.terrainData.wavingGrassTint     = terrain.terrainData.wavingGrassTint;
                        newTerrain.treeBillboardDistance           = terrain.treeBillboardDistance;
                        newTerrain.treeCrossFadeLength             = terrain.treeCrossFadeLength;
                        newTerrain.treeDistance               = terrain.treeDistance;
                        newTerrain.treeMaximumFullLODCount    = terrain.treeMaximumFullLODCount;
                        newTerrain.terrainData.treePrototypes = terrain.terrainData.treePrototypes;
                        newTerrain.terrainData.RefreshPrototypes();

                        foreach (TreeInstance treeInstace in terrain.terrainData.treeInstances)
                        {
                            if (treeInstace.prototypeIndex >= 0 && treeInstace.prototypeIndex < newTerrain.terrainData.treePrototypes.Length &&
                                newTerrain.terrainData.treePrototypes[treeInstace.prototypeIndex].prefab)
                            {
                                Vector3 worldSpaceTreePos = Vector3.Scale(treeInstace.position, terrainSize) + terrain.transform.position;
                                if (newSector.BoundsOverride.Contains(worldSpaceTreePos))
                                {
                                    Vector3 localSpaceTreePos = new Vector3((worldSpaceTreePos.x - newTerrain.transform.position.x) / sectorWidth,
                                                                            treeInstace.position.y,
                                                                            (worldSpaceTreePos.z - newTerrain.transform.position.z) / sectorLength);
                                    TreeInstance newInstance = treeInstace;
                                    newInstance.position = localSpaceTreePos;
                                    newTerrain.AddTreeInstance(newInstance);
                                }
                            }
                        }

                        // Copy physics
                                                #if UNITY_4_LATE
                        newTerrain.terrainData.physicMaterial = terrain.terrainData.physicMaterial;
                                                #endif

                        // Force terrain to rebuild
                        newTerrain.Flush();

                        UnityEditor.EditorUtility.SetDirty(newTerrain.terrainData);
                        SECTR_VC.WaitForVC();
                        newTerrain.enabled = false;
                        newTerrain.enabled = true;

                        TerrainCollider terrainCollider = terrain.GetComponent <TerrainCollider>();
                        if (terrainCollider)
                        {
                            TerrainCollider newCollider = newTerrainObject.AddComponent <TerrainCollider>();
                                                        #if !UNITY_4_LATE
                            newCollider.sharedMaterial = terrainCollider.sharedMaterial;
                                                        #endif
                            newCollider.terrainData = newTerrain.terrainData;
                        }

                        newTerrains[widthIndex, lengthIndex] = newTerrain;
                        SECTR_Undo.Created(newTerrainObject, undoString);
                    }
                    newSector.ForceUpdate(true);
                    SECTR_Undo.Created(newSectorObject, undoString);

                    _Encapsulate(newSector, rootTransforms, rootBounds, undoString);
                }
            }
        }

        // Create portals and neighbors
        progressCounter = 0;
        for (int widthIndex = 0; widthIndex < sectorsWidth; ++widthIndex)
        {
            for (int lengthIndex = 0; lengthIndex < sectorsLength; ++lengthIndex)
            {
                for (int heightIndex = 0; heightIndex < sectorsHeight; ++heightIndex)
                {
                    EditorUtility.DisplayProgressBar(progressTitle, "Creating portals...", progressCounter++ / (float)(sectorsWidth * sectorsLength * sectorsHeight));

                    if (widthIndex < sectorsWidth - 1)
                    {
                        _CreatePortal(createPortalGeo, newSectors[widthIndex + 1, lengthIndex, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex], baseTransform, undoString);
                    }

                    if (lengthIndex < sectorsLength - 1)
                    {
                        _CreatePortal(createPortalGeo, newSectors[widthIndex, lengthIndex + 1, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex], baseTransform, undoString);
                    }

                    if (heightIndex > 0)
                    {
                        _CreatePortal(createPortalGeo, newSectors[widthIndex, lengthIndex, heightIndex], newSectors[widthIndex, lengthIndex, heightIndex - 1], baseTransform, undoString);
                    }
                    else if (splitTerrain)
                    {
                        SECTR_Sector terrainSector = newSectors[widthIndex, lengthIndex, 0];
                        terrainSector.LeftTerrain   = widthIndex > 0 ? newSectors[widthIndex - 1, lengthIndex, 0] : null;
                        terrainSector.RightTerrain  = widthIndex < sectorsWidth - 1 ? newSectors[widthIndex + 1, lengthIndex, 0] : null;
                        terrainSector.BottomTerrain = lengthIndex > 0 ? newSectors[widthIndex, lengthIndex - 1, 0] : null;
                        terrainSector.TopTerrain    = lengthIndex < sectorsLength - 1 ? newSectors[widthIndex, lengthIndex + 1, 0] : null;
                        terrainSector.ConnectTerrainNeighbors();

                        // Blend together the seams of the alpha maps, which requires
                        // going through all of the mip maps of all of the layer textures.
                        // We have to blend here rather than when we set the alpha data (above)
                        // because Unity computes mips and we need to blend all of the mips.
                        Terrain newTerrain = newTerrains[widthIndex, lengthIndex];

                        // Use reflection trickery to get at the raw texture values.
                        System.Reflection.PropertyInfo alphamapProperty = newTerrain.terrainData.GetType().GetProperty("alphamapTextures",
                                                                                                                       System.Reflection.BindingFlags.NonPublic |
                                                                                                                       System.Reflection.BindingFlags.Public |
                                                                                                                       System.Reflection.BindingFlags.Instance |
                                                                                                                       System.Reflection.BindingFlags.Static);
                        // Get the texture we'll write into
                        Texture2D[] alphaTextures = (Texture2D[])alphamapProperty.GetValue(newTerrain.terrainData, null);
                        int         numTextures   = alphaTextures.Length;

                        // Get the textures we'll read from
                        Texture2D[] leftNeighborTextures   = terrainSector.LeftTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex - 1, lengthIndex].terrainData, null) : null;
                        Texture2D[] rightNeighborTextures  = terrainSector.RightTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex + 1, lengthIndex].terrainData, null) : null;
                        Texture2D[] topNeighborTextures    = terrainSector.TopTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex, lengthIndex + 1].terrainData, null) : null;
                        Texture2D[] bottomNeighborTextures = terrainSector.BottomTerrain != null ? (Texture2D[])alphamapProperty.GetValue(newTerrains[widthIndex, lengthIndex - 1].terrainData, null) : null;

                        for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex)
                        {
                            Texture2D alphaTexture  = alphaTextures[textureIndex];
                            Texture2D leftTexture   = leftNeighborTextures != null ? leftNeighborTextures[textureIndex] : null;
                            Texture2D rightTexture  = rightNeighborTextures != null ? rightNeighborTextures[textureIndex] : null;
                            Texture2D topTexture    = topNeighborTextures != null ? topNeighborTextures[textureIndex] : null;
                            Texture2D bottomTexture = bottomNeighborTextures != null ? bottomNeighborTextures[textureIndex] : null;
                            int       numMips       = alphaTexture.mipmapCount;
                            for (int mipIndex = 0; mipIndex < numMips; ++mipIndex)
                            {
                                Color[] alphaTexels = alphaTexture.GetPixels(mipIndex);
                                int     width       = (int)Mathf.Sqrt(alphaTexels.Length);
                                int     height      = width;
                                for (int texelWidthIndex = 0; texelWidthIndex < width; ++texelWidthIndex)
                                {
                                    for (int texelHeightIndex = 0; texelHeightIndex < height; ++texelHeightIndex)
                                    {
                                        // We can take advantage of the build order to average on the leading edges (right and top)
                                        // and then copy form the trailing edges (left and bottom)
                                        if (texelWidthIndex == 0 && leftTexture)
                                        {
                                            Color[] neighborTexels = leftTexture.GetPixels(mipIndex);
                                            alphaTexels[texelWidthIndex + texelHeightIndex * width] = neighborTexels[(width - 1) + (texelHeightIndex * width)];
                                        }
                                        else if (texelWidthIndex == width - 1 && rightTexture)
                                        {
                                            Color[] neighborTexels = rightTexture.GetPixels(mipIndex);
                                            alphaTexels[texelWidthIndex + texelHeightIndex * width] += neighborTexels[0 + (texelHeightIndex * width)];
                                            alphaTexels[texelWidthIndex + texelHeightIndex * width] *= 0.5f;
                                        }
                                        else if (texelHeightIndex == 0 && bottomTexture)
                                        {
                                            Color[] neighborTexels = bottomTexture.GetPixels(mipIndex);
                                            alphaTexels[texelWidthIndex + texelHeightIndex * width] = neighborTexels[texelWidthIndex + ((height - 1) * width)];
                                        }
                                        else if (texelHeightIndex == height - 1 && topTexture)
                                        {
                                            Color[] neighborTexels = topTexture.GetPixels(mipIndex);
                                            alphaTexels[texelWidthIndex + texelHeightIndex * width] += neighborTexels[texelWidthIndex + (0 * width)];
                                            alphaTexels[texelWidthIndex + texelHeightIndex * width] *= 0.5f;
                                        }
                                    }
                                }
                                alphaTexture.SetPixels(alphaTexels, mipIndex);
                            }
                            alphaTexture.Apply(false);
                        }
                    }
                }
            }
        }

        EditorUtility.ClearProgressBar();

        // destroy original terrain
        if (splitTerrain)
        {
            SECTR_Undo.Destroy(terrain.gameObject, undoString);
        }
    }
Exemplo n.º 29
0
    private void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Ray        l_Ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));
            RaycastHit l_RaycastHit;
            if (Physics.Raycast(l_Ray, out l_RaycastHit, Mathf.Infinity))
            {
                // Collider hit.

                // Make sure there are not too many projectors.
                if (m_DecalProjectors.Count >= 50)
                {
                    // If there are more than 50 projectors, we remove the first one from
                    // our list and certainly from the decals mesh (the intermediate mesh
                    // format). All the mesh data that belongs to this projector will
                    // be removed.
                    DecalProjector l_DecalProjector = m_DecalProjectors [0];

                    // The vertex color list has to be updated as well.
                    m_VertexColors.RemoveRange(0, l_DecalProjector.DecalsMeshUpperVertexIndex + 1);

                    m_DecalProjectors.RemoveAt(0);
                    m_DecalsMesh.RemoveProjector(l_DecalProjector);
                }

                // Calculate the position and rotation for the new decal projector.
                Vector3    l_ProjectorPosition = l_RaycastHit.point - (decalProjectorOffset * l_Ray.direction.normalized);
                Vector3    l_ForwardDirection  = Camera.main.transform.up;
                Vector3    l_UpDirection       = -Camera.main.transform.forward;
                Quaternion l_ProjectorRotation = Quaternion.LookRotation(l_ForwardDirection, l_UpDirection);

                // Randomize the rotation.
                Quaternion l_RandomRotation = Quaternion.Euler(0.0f, Random.Range(0.0f, 360.0f), 0.0f);
                l_ProjectorRotation = l_ProjectorRotation * l_RandomRotation;

                TerrainCollider l_TerrainCollider = l_RaycastHit.collider as TerrainCollider;
                if (l_TerrainCollider != null)
                {
                    // Terrain collider hit.

                    Terrain l_Terrain = l_TerrainCollider.GetComponent <Terrain> ();
                    if (l_Terrain != null)
                    {
                        // Create the decal projector with all the required information.
                        DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);

                        // Add the projector to our list and the decals mesh, such that both are
                        // synchronized. All the mesh data that is now added to the decals mesh
                        // will belong to this projector.
                        m_DecalProjectors.Add(l_DecalProjector);
                        m_DecalsMesh.AddProjector(l_DecalProjector);

                        // The terrain data has to be converted to the decals instance's space.
                        Matrix4x4 l_TerrainToDecalsMatrix = Matrix4x4.TRS(l_Terrain.transform.position, Quaternion.identity, Vector3.one) * m_WorldToDecalsMatrix;

                        // Pass the terrain data with the corresponding conversion to the decals mesh.
                        m_DecalsMesh.Add(l_Terrain, l_TerrainToDecalsMatrix);

                        // Cut the data in the decals mesh accoring to the size and position of the decal projector. Offset the
                        // vertices afterwards and pass the newly computed mesh to the decals instance, such that it becomes
                        // visible.
                        m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                        m_DecalsMesh.OffsetActiveProjectorVertices();
                        m_Decals.UpdateDecalsMeshes(m_DecalsMesh);

                        // Update the vertex colors too.
                        Color l_VertexColor = CurrentColor;
                        int   l_VertexCount = l_DecalProjector.DecalsMeshUpperVertexIndex - l_DecalProjector.DecalsMeshLowerVertexIndex + 1;
                        for (int i = 0; i < l_VertexCount; i = i + 1)
                        {
                            m_VertexColors.Add(l_VertexColor);
                        }
                        m_Decals.DecalsMeshRenderers [0].MeshFilter.mesh.colors = m_VertexColors.ToArray();

                        // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                        // based on the surface you have hit.
                        NextUVRectangleIndex();
                        NextColorIndex();
                    }
                    else
                    {
                        Debug.Log("Terrain is null!");
                    }
                }
                else
                {
                    // We hit a collider. Next we have to find the mesh that belongs to the collider.
                    // That step depends on how you set up your mesh filters and collider relative to
                    // each other in the game objects. It is important to have a consistent way in order
                    // to have a simpler implementation.

                    MeshCollider l_MeshCollider = l_RaycastHit.collider.GetComponent <MeshCollider> ();
                    MeshFilter   l_MeshFilter   = l_RaycastHit.collider.GetComponent <MeshFilter> ();

                    if (l_MeshCollider != null || l_MeshFilter != null)
                    {
                        Mesh l_Mesh = null;
                        if (l_MeshCollider != null)
                        {
                            // Mesh collider was hit. Just use the mesh data from that one.
                            l_Mesh = l_MeshCollider.sharedMesh;
                        }
                        else if (l_MeshFilter != null)
                        {
                            // Otherwise take the data from the shared mesh.
                            l_Mesh = l_MeshFilter.sharedMesh;
                        }

                        if (l_Mesh != null)
                        {
                            // Create the decal projector.
                            DecalProjector l_DecalProjector = new DecalProjector(l_ProjectorPosition, l_ProjectorRotation, decalProjectorScale, cullingAngle, meshOffset, m_UVRectangleIndex, m_UVRectangleIndex);

                            // Add the projector to our list and the decals mesh, such that both are
                            // synchronized. All the mesh data that is now added to the decals mesh
                            // will belong to this projector.
                            m_DecalProjectors.Add(l_DecalProjector);
                            m_DecalsMesh.AddProjector(l_DecalProjector);

                            // Get the required matrices.
                            Matrix4x4 l_WorldToMeshMatrix = l_RaycastHit.collider.renderer.transform.worldToLocalMatrix;
                            Matrix4x4 l_MeshToWorldMatrix = l_RaycastHit.collider.renderer.transform.localToWorldMatrix;

                            // Add the mesh data to the decals mesh, cut and offset it before we pass it
                            // to the decals instance to be displayed.
                            m_DecalsMesh.Add(l_Mesh, l_WorldToMeshMatrix, l_MeshToWorldMatrix);
                            m_DecalsMeshCutter.CutDecalsPlanes(m_DecalsMesh);
                            m_DecalsMesh.OffsetActiveProjectorVertices();
                            m_Decals.UpdateDecalsMeshes(m_DecalsMesh);

                            // Update the vertex colors too.
                            Color l_VertexColor = CurrentColor;
                            int   l_VertexCount = l_DecalProjector.DecalsMeshUpperVertexIndex - l_DecalProjector.DecalsMeshLowerVertexIndex + 1;
                            for (int i = 0; i < l_VertexCount; i = i + 1)
                            {
                                m_VertexColors.Add(l_VertexColor);
                            }
                            m_Decals.DecalsMeshRenderers [0].MeshFilter.mesh.colors = m_VertexColors.ToArray();

                            // For the next hit, use a new uv rectangle. Usually, you would select the uv rectangle
                            // based on the surface you have hit.
                            NextUVRectangleIndex();
                            NextColorIndex();
                        }
                    }
                }
            }
        }
    }
Exemplo n.º 30
0
 public Octave3DTerrainCollider(TerrainCollider terrainCollider)
 {
     _terrainCollider = terrainCollider;
 }