public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { AreaAttribute area = attribute as AreaAttribute; EditorGUI.BeginProperty(position, label, property); if (property.propertyType != SerializedPropertyType.Integer) { EditorGUI.LabelField(position, label.text, "Use this attribute with Integer"); } else { if (area.drawLabel & (label.text != string.Empty)) { position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label); } int value = property.intValue; //GUI.Label(new Rect(position.x, position.y, idWidth, position.height), value.ToString()); Area pathFinderArea = PathFinder.GetArea(value); if (pathFinderArea == null) { property.intValue = 0; pathFinderArea = PathFinder.GetArea(0); } TextAnchor curAnchor = GUI.skin.box.alignment; GUI.skin.box.alignment = TextAnchor.MiddleCenter; Color curColor = GUI.color; GUI.color = pathFinderArea.color; GUI.Box(new Rect(position.x, position.y, colorBoxWidth, position.height), value.ToString()); GUI.color = curColor; GUI.skin.box.alignment = curAnchor; EditorGUI.BeginChangeCheck(); value = EditorGUI.IntPopup( new Rect(position.x + colorBoxWidth, position.y, position.width - colorBoxWidth, position.height), value, PathFinder.settings.areaNames, PathFinder.settings.areaIDs); if (EditorGUI.EndChangeCheck()) { property.intValue = value; } } EditorGUI.EndProperty(); }
public Area GetArea() { return(PathFinder.GetArea(areaInt)); }
//not main thread public override void Collect(VolumeContainer container) { Area defaultArea = PathFinder.GetArea(0); foreach (var terrain in _terrainsInfo) { //terrain Volume terrainVolume; if (terrain.alphaMap != null) { terrainVolume = new Volume(template.lengthX_extra, template.lengthZ_extra, terrain.possibleArea); } else { terrainVolume = new Volume(template.lengthX_extra, template.lengthZ_extra, defaultArea); } terrainVolume.terrain = true; float[][] heightMap = terrain.heightMap; int[][] passabilityMap = terrain.passabilityMap; var areaLibrary = PathFinder.settings.areaLibrary; //apply terrain area info if it exist //SetTerrainArea(terrainVolume, terrain, defaultArea); if (terrain.alphaMap != null) { int[][] areaMap = ProcessAlphaMap(terrain); for (int x = 0; x < template.lengthX_extra; x++) { for (int z = 0; z < template.lengthZ_extra; z++) { terrainVolume.SetVoxel(x, z, heightMap[x][z], areaLibrary[areaMap[x][z]], passabilityMap[x][z]); if (areaMap[x][z] == 1) { terrainVolume.SetPassability(x, z, Passability.Unwalkable); } } } } else { for (int x = 0; x < template.lengthX_extra; x++) { for (int z = 0; z < template.lengthZ_extra; z++) { terrainVolume.SetVoxel(x, z, heightMap[x][z], defaultArea, passabilityMap[x][z]); } } } terrainVolume.SetVolumeMinimum(-1000f); //trees Volume treeVolume = base.CollectTrees(terrain); //connecting terrain and trees to single volume if (treeVolume != null) { terrainVolume.Subtract(treeVolume); terrainVolume.ConnectToItself(); terrainVolume.Override(treeVolume); } //sent terrain to container container.AddVolume(terrainVolume); //container.AddVolume(treeVolume); } }
private void AddColliderTerrain(Collider collider, TerrainCollectorType terrainCollectionType) { Terrain terrain = collider.GetComponent <Terrain>(); if (terrain == null | terrain.enabled == false) { return; } if (profiler != null) { profiler.AddLogFormat("collecting terrain {0}", terrain.gameObject.name); } TerrainColliderInfoMesh info = new TerrainColliderInfoMesh(terrain); info.trees = CollectTreeData(terrain); //general stuff float voxelSize = template.voxelSize; Bounds offsetedBounds = template.chunkOffsetedBounds; Vector3 boundsMin = offsetedBounds.min; Vector3 boundsMax = offsetedBounds.max; float minSize = PathFinder.settings.terrainFastMinimalSize; //terrain stuff TerrainData data = terrain.terrainData; Vector3 position = terrain.transform.position; Vector3 scale = data.size; //height map int resolution = 1; int heightMapSizeX = data.heightmapWidth; int heightMapSizeZ = data.heightmapHeight; float hScaleX = scale.x / (heightMapSizeX - 1); float hScaleZ = scale.z / (heightMapSizeZ - 1); for (int i = 0; i < 4; i++) { if (minSize > hScaleX * resolution) { resolution = (int)Mathf.Pow(2, i); } else { break; } } int hTargetMinX = Mathf.Clamp(((Mathf.RoundToInt((boundsMin.x - position.x) / hScaleX) / resolution) - 1) * resolution, 0, heightMapSizeX); int hTargetMinZ = Mathf.Clamp(((Mathf.RoundToInt((boundsMin.z - position.z) / hScaleZ) / resolution) - 1) * resolution, 0, heightMapSizeX); int hTargetMaxX = Mathf.Clamp(((Mathf.RoundToInt((boundsMax.x - position.x) / hScaleX) / resolution) + 1) * resolution + 1, 0, heightMapSizeX); int hTargetMaxZ = Mathf.Clamp(((Mathf.RoundToInt((boundsMax.z - position.z) / hScaleZ) / resolution) + 1) * resolution + 1, 0, heightMapSizeX); int hSizeX = hTargetMaxX - hTargetMinX; int hSizeZ = hTargetMaxZ - hTargetMinZ; int hTargetSizeX = hSizeX / resolution + 1; int hTargetSizeZ = hSizeZ / resolution + 1; if (resolution == 1) { hTargetSizeX = hSizeX; hTargetSizeZ = hSizeZ; } info.heightMap = data.GetHeights(hTargetMinX, hTargetMinZ, hSizeX, hSizeZ); info.heightMatrix = Matrix4x4.TRS( position + new Vector3(hScaleX * hTargetMinX, 0, hScaleZ * hTargetMinZ), Quaternion.identity, new Vector3(hScaleX * resolution, scale.y, hScaleZ * resolution)); info.hSizeX = hTargetSizeX; info.hSizeZ = hTargetSizeZ; info.resolution = resolution; //rest VectorInt.Vector3Int terrainStartInt = new VectorInt.Vector3Int((position / voxelSize) + template.halfVoxelOffset); VectorInt.Vector3Int terrainEndInt = new VectorInt.Vector3Int((position + data.size) / voxelSize + template.halfVoxelOffset); int startXClamp = Mathf.Clamp(terrainStartInt.x, template.startX_extra, template.endX_extra); int startZClamp = Mathf.Clamp(terrainStartInt.z, template.startZ_extra, template.endZ_extra); int endXClamp = Mathf.Clamp(terrainEndInt.x, template.startX_extra, template.endX_extra); int endZClamp = Mathf.Clamp(terrainEndInt.z, template.startZ_extra, template.endZ_extra); int terrainStartX = terrainStartInt.x; int terrainStartZ = terrainStartInt.z; float terrainSizeX = terrainEndInt.x - terrainStartX; float terrainSizeZ = terrainEndInt.z - terrainStartZ; var navmeshSettings = terrain.gameObject.GetComponent <TerrainNavmeshSettings>(); if (navmeshSettings != null && navmeshSettings.isActiveAndEnabled && navmeshSettings.data.Any(x => x != 0)) //0 is default so if there is settings full of deffault areas then dont need that { Vector3 size = data.size; info.settings = navmeshSettings; info.startXClamp = startXClamp; info.startZClamp = startZClamp; info.endXClamp = endXClamp; info.endZClamp = endZClamp; info.terrainStartX = terrainStartX; info.terrainStartZ = terrainStartZ; info.terrainSizeX = terrainSizeX; info.terrainSizeZ = terrainSizeZ; //all this values needed in 2 places. here to use data.GetAlphamaps in main thread and later in not main thread //so we just store it in terrain collider info info.alphaWidth = data.alphamapWidth; info.alphaHeight = data.alphamapHeight; //normalized start and end //dont needed later float terNormStartX = Mathf.Clamp01((template.chunkData.realX - template.properties.radius - position.x) / size.x); float terNormStartZ = Mathf.Clamp01((template.chunkData.realZ - template.properties.radius - position.z) / size.z); float terNormEndX = Mathf.Clamp01((template.chunkData.realX + PathFinder.gridSize + template.properties.radius - position.x) / size.x); float terNormEndZ = Mathf.Clamp01((template.chunkData.realZ + PathFinder.gridSize + template.properties.radius - position.z) / size.z); //alpha map position of chunk info.alphaStartX = Mathf.RoundToInt(terNormStartX * info.alphaWidth); info.alphaStartZ = Mathf.RoundToInt(terNormStartZ * info.alphaHeight); //alpha map size of chunk //size needed only now info.alphaSizeX = Mathf.Min(Mathf.RoundToInt((terNormEndX - terNormStartX) * info.alphaWidth) + 1, info.alphaWidth - info.alphaStartX); info.alphaSizeZ = Mathf.Min(Mathf.RoundToInt((terNormEndZ - terNormStartZ) * info.alphaHeight) + 1, info.alphaHeight - info.alphaStartZ); info.alphaMap = data.GetAlphamaps(info.alphaStartX, info.alphaStartZ, info.alphaSizeX, info.alphaSizeZ); info.possibleArea = (from areaID in navmeshSettings.data select PathFinder.GetArea(areaID)).ToArray(); //else if doCollectAreaInfo == false than later it became defaul area } switch (terrainCollectionType) { case TerrainCollectorType.CPU: terrainsInfoForCPU.Add(info); break; case TerrainCollectorType.ComputeShader: CollectTerrainOnGPU(info); break; } }
private void AddColliderGenericGPU(Collider collider) { Matrix4x4 matrix = Matrix4x4.identity; Transform colliderTransform = collider.transform; Vector3[] verts = null; int[] tris = null; Bounds bounds = collider.bounds; if (collider is BoxCollider) { verts = cubeVerts; tris = cubeTris; matrix = Matrix4x4.TRS(bounds.center, colliderTransform.rotation, Vector3.Scale(colliderTransform.lossyScale, (collider as BoxCollider).size)); } else if (collider is SphereCollider) { verts = sphereVerts; tris = sphereTris; float r = bounds.extents.x / 0.5f; matrix = Matrix4x4.TRS(bounds.center, Quaternion.identity, new Vector3(r, r, r)); } else if (collider is CapsuleCollider) { tris = capsuleTris; verts = new Vector3[capsuleVerts.Length]; CapsuleCollider capsuleCollider = collider as CapsuleCollider; Vector3 lossyScale = colliderTransform.lossyScale; float height = capsuleCollider.height * lossyScale.y; float radius = capsuleCollider.radius * Mathf.Max(lossyScale.x, lossyScale.z); float size = Mathf.Max(1f, height / (radius * 2f)) - 2f; Matrix4x4 capsuleShapeMatrix = Matrix4x4.Scale(new Vector3(radius * 2f, radius * 2f, radius * 2f)); for (int index = 0; index < verts.Length; ++index) { if (capsuleVerts[index].y > 0.0) { verts[index] = capsuleShapeMatrix.MultiplyPoint( new Vector3( capsuleVerts[index].x, Mathf.Max((float)(capsuleVerts[index].y + size * 0.5), 0.0f), capsuleVerts[index].z)); } else if (capsuleVerts[index].y < 0.0) { verts[index] = capsuleShapeMatrix.MultiplyPoint( new Vector3( capsuleVerts[index].x, Mathf.Min((float)(capsuleVerts[index].y - size * 0.5), 0.0f), capsuleVerts[index].z)); } } matrix = Matrix4x4.TRS( capsuleCollider.bounds.center, //actual world position colliderTransform.rotation * //world rotation Quaternion.Euler( //plus capsule orientation capsuleCollider.direction == 2 ? 90f : 0.0f, 0.0f, capsuleCollider.direction == 0 ? 90f : 0.0f), Vector3.one); } else if (collider is CharacterController) { tris = capsuleTris; verts = new Vector3[capsuleVerts.Length]; CharacterController charControler = collider as CharacterController; Vector3 lossyScale = colliderTransform.lossyScale; float height = charControler.height * lossyScale.y; float radius = charControler.radius * Mathf.Max(lossyScale.x, lossyScale.z); float size = Mathf.Max(1f, height / (radius * 2f)) - 2f; Matrix4x4 capsuleShapeMatrix = Matrix4x4.Scale(new Vector3(radius * 2f, radius * 2f, radius * 2f)); for (int index = 0; index < verts.Length; ++index) { if (capsuleVerts[index].y > 0.0) { verts[index] = capsuleShapeMatrix.MultiplyPoint(new Vector3(capsuleVerts[index].x, Mathf.Max((float)(capsuleVerts[index].y + size * 0.5), 0.0f), capsuleVerts[index].z)); } else if (capsuleVerts[index].y < 0.0) { verts[index] = capsuleShapeMatrix.MultiplyPoint(new Vector3(capsuleVerts[index].x, Mathf.Min((float)(capsuleVerts[index].y - size * 0.5), 0.0f), capsuleVerts[index].z)); } } matrix = Matrix4x4.TRS(charControler.bounds.center, colliderTransform.rotation, Vector3.one); } else if (collider is MeshCollider) { Mesh curMesh = (collider as MeshCollider).sharedMesh; verts = curMesh.vertices; tris = curMesh.triangles; matrix = colliderTransform.localToWorldMatrix; } else { Debug.LogFormat("hey i dont know wich collider type is on {0}. please tell developer to fix that.", collider.gameObject.name); return; } var gameObjectArea = collider.transform.GetComponent <AreaGameObject>(); Area area; if (gameObjectArea != null) { area = PathFinder.GetArea(gameObjectArea.areaInt); } else { if (PathFinder.settings.checkRootTag) { area = PathFinderSettings.tagAssociations[collider.transform.root.tag]; } else { area = PathFinderSettings.tagAssociations[collider.transform.tag]; } } if (verts != null & tris != null) { float maxSlopeCos = Mathf.Cos(template.maxSlope * Mathf.PI / 180f); Vector3 offsetedPos = template.realOffsetedPosition; CSRasterization3DResult result = PathFinder.sceneInstance.Rasterize3D( verts, tris, bounds, matrix, template.lengthX_extra, template.lengthZ_extra, offsetedPos.x, offsetedPos.z, template.voxelSize, maxSlopeCos, false, false); if (result != null) { collectedComputeShaderData.Add(new ComputeShaderResultHolder(result, ColliderInfoMode.Solid, area)); } } }
public void SetGoalFindNearestArea(int globalDictionaryID, float maxSearchCost, bool snapToNavMesh = true, bool applyRaycast = false) { SetGoalFindNearestArea(PathFinder.GetArea(globalDictionaryID), maxSearchCost, snapToNavMesh, applyRaycast); }
//not main thread public override void Collect(VolumeContainer container) { Area defaultArea = PathFinder.GetArea(0); float maxSlopeCos = Mathf.Cos((float)((double)template.maxSlope * Math.PI / 180.0)); float voxelSize = template.voxelSize; Vector3 realChunkPos = template.realOffsetedPosition; float chunkPosX = realChunkPos.x; float chunkPosZ = realChunkPos.z; int offsetX = Mathf.RoundToInt(chunkPosX / voxelSize); int offsetZ = Mathf.RoundToInt(chunkPosZ / voxelSize); int sizeX = template.lengthX_extra; int sizeZ = template.lengthZ_extra; foreach (var terrain in terrainsInfo) { Volume terrainVolume; if (terrain.alphaMap != null) { terrainVolume = new Volume(template.lengthX_extra, template.lengthZ_extra, terrain.possibleArea); } else { terrainVolume = new Volume(template.lengthX_extra, template.lengthZ_extra, defaultArea); } terrainVolume.terrain = true; Vector3[] vrts; int[] trs; GetTerrainMesh(terrain, out vrts, out trs); //actual rasterization for (int i = 0; i < trs.Length; i += 3) { Vector3 A = vrts[trs[i]]; Vector3 B = vrts[trs[i + 1]]; Vector3 C = vrts[trs[i + 2]]; int passability = CalculateWalk(A, B, C, maxSlopeCos) ? 3 : 1;//if true then walkable else slope; int minX = Mathf.Clamp(Mathf.FloorToInt(SomeMath.Min(A.x, B.x, C.x) / voxelSize) - offsetX, 0, sizeX); int maxX = Mathf.Clamp(Mathf.CeilToInt(SomeMath.Max(A.x, B.x, C.x) / voxelSize) - offsetX, 0, sizeX); int minZ = Mathf.Clamp(Mathf.FloorToInt(SomeMath.Min(A.z, B.z, C.z) / voxelSize) - offsetZ, 0, sizeZ); int maxZ = Mathf.Clamp(Mathf.CeilToInt(SomeMath.Max(A.z, B.z, C.z) / voxelSize) - offsetZ, 0, sizeZ); for (int x = minX; x < maxX; x++) { for (int z = minZ; z < maxZ; z++) { float pointX = (x * voxelSize) + chunkPosX; float pointZ = (z * voxelSize) + chunkPosZ; if (SomeMath.LineSide(A.x, A.z, B.x, B.z, pointX, pointZ) <= 0.001 & SomeMath.LineSide(B.x, B.z, C.x, C.z, pointX, pointZ) <= 0.001 & SomeMath.LineSide(C.x, C.z, A.x, A.z, pointX, pointZ) <= 0.001) { terrainVolume.SetVoxelLight(x, z, SomeMath.CalculateHeight(A, B, C, pointX, pointZ), passability); } } } } //var areaLibrary = PathFinder.settings.areaLibrary; SetTerrainArea(terrainVolume, terrain, defaultArea); //apply terrain area info if it exist terrainVolume.SetVolumeMinimum(-1000f); //trees Volume treeVolume = base.CollectTrees(terrain); //connecting terrain and trees to single volume if (treeVolume != null) { terrainVolume.Subtract(treeVolume); terrainVolume.ConnectToItself(); terrainVolume.Override(treeVolume); } //sent terrain to container container.AddVolume(terrainVolume); } }