//#region Peek ////region where bunch of functions to peek next point ///// <summary> ///// Peek next node without removing it. Return only node type ///// return true if next node exist at all and false if not ///// </summary> //public bool PeekNextNode(out PathNodeType nodeType) { // if (_currentIndex >= nodes.Count) { // nodeType = PathNodeType.MoveWalk; // return false; // } // else { // nodeType = nodes[_currentIndex].nodeType; // return true; // } //} ///// <summary> ///// Peek next node without removing it. Return primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector3. ///// return true if next node exist at all and false if not ///// </summary> //public bool PeekNextNode(out Vector3 primaryNodePosition) { // if (_currentIndex >= nodes.Count) { // primaryNodePosition = new Vector3(); // return false; // } // else { // primaryNodePosition = vectors[nodes[_currentIndex].indexFirst]; // return true; // } //} ///// <summary> ///// Peek next node without removing it. Return primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector2 in top view. it is XZ of Vector3 result ///// return true if next node exist at all and false if not ///// </summary> //public bool PeekNextNode(out Vector2 primaryNodePosition) { // if (_currentIndex >= nodes.Count) { // primaryNodePosition = new Vector3(); // return false; // } // else { // primaryNodePosition = ToVector2(vectors[nodes[_currentIndex].indexFirst]); // return true; // } //} ///// <summary> ///// Peek next node without removing it. Return node type and primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector3. ///// return true if next node exist at all and false if not ///// </summary> //public bool PeekNextNode(out PathNodeType nodeType, out Vector3 primaryNodePosition) { // if (_currentIndex >= nodes.Count) { // nodeType = PathNodeType.MoveWalk; // primaryNodePosition = new Vector3(); // return false; // } // else { // PathNode node = nodes[_currentIndex]; // primaryNodePosition = vectors[node.indexFirst]; // nodeType = node.nodeType; // return true; // } //} ///// <summary> ///// Peek next node without removing it. Return node type and primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector2 in top view. it is XZ of Vector3 result ///// return true if next node exist at all and false if not ///// </summary> //public bool PeekNextNode(out PathNodeType nodeType, out Vector2 primaryNodePosition) { // if (_currentIndex >= nodes.Count) { // nodeType = PathNodeType.MoveWalk; // primaryNodePosition = new Vector3(); // return false; // } // else { // PathNode node = nodes[_currentIndex]; // primaryNodePosition = ToVector2(vectors[node.indexFirst]); // nodeType = node.nodeType; // return true; // } //} ///// <summary> ///// Peek next node without removing it. Return node type, primary and secondary node position ///// For moving primary position is where point is. And secondary is just (0,0,0). ///// For jumps primary node is where jump start and secondary is where jump end ///// Position is Vector3. ///// return true if next node exist at all and false if not ///// </summary> //public bool PeekNextNode(out PathNodeType nodeType, out Vector2 primaryNodePosition, out Vector3 secondaryNodePosition) { // if (_currentIndex >= nodes.Count) { // nodeType = PathNodeType.MoveWalk; // primaryNodePosition = new Vector3(); // secondaryNodePosition = new Vector3(); // return false; // } // else { // PathNode node = nodes[_currentIndex]; // primaryNodePosition = vectors[node.indexFirst]; // secondaryNodePosition = vectors[node.indexSecond]; // nodeType = node.nodeType; // return true; // } //} //#endregion //#region Dequeue ////region where bunch of functions to dequeue next point ///// <summary> ///// Remove next node. ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode() { // if (_currentIndex >= nodes.Count) { // return false; // } // else { // _currentIndex++; // return true; // } //} ///// <summary> ///// Remove next node and return it information. Return only node type. (not very userful but whatever. it might be) ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode(out PathNodeType nodeType) { // bool result = PeekNextNode(out nodeType); // if (result) _currentIndex++; // return result; //} ///// <summary> ///// Remove next node and return it information. Return primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector3. ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode(out Vector3 primaryNodePosition) { // bool result = PeekNextNode(out primaryNodePosition); // if (result) _currentIndex++; // return result; //} ///// <summary> ///// Remove next node and return it information. Return primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector2 in top view. it is XZ of Vector3 result ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode(out Vector2 primaryNodePosition) { // bool result = PeekNextNode(out primaryNodePosition); // if (result) _currentIndex++; // return result; //} ///// <summary> ///// Remove next node and return it information. Return node type and primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector3. ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode(out PathNodeType nodeType, out Vector3 primaryNodePosition) { // bool result = PeekNextNode(out nodeType, out primaryNodePosition); // if (result) _currentIndex++; // return result; //} ///// <summary> ///// Remove next node and return it information. Return node type and primary node position. ///// For moving it is actual move point. For jumps it is where jump start. ///// Position is Vector2 in top view. it is XZ of Vector3 result ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode(out PathNodeType nodeType, out Vector2 primaryNodePosition) { // bool result = PeekNextNode(out nodeType, out primaryNodePosition); // if (result) _currentIndex++; // return result; //} ///// <summary> ///// Remove next node and return it information. Return node type, primary and secondary node position ///// For moving primary position is where point is. And secondary is just (0,0,0). ///// For jumps primary node is where jump start and secondary is where jump end ///// Position is Vector3. ///// return true if next node exist at all and false if not ///// </summary> //public bool DequeueNextNode(out PathNodeType nodeType, out Vector2 primaryNodePosition, out Vector3 secondaryNodePosition) { // bool result = PeekNextNode(out nodeType, out primaryNodePosition, out secondaryNodePosition); // if (result) _currentIndex++; // return result; //} //#endregion //#region distance ////region where bunch of functions to return distance to next point ///// <summary> ///// Return distance from specific point to next node ///// return true if next node exist at all ///// </summary> //public bool ReturnNextNodeDistance3D(Vector3 point, out float distance) { // if (nodes.Count == 0) { // distance = 0f; // return false; // } // else { // distance = Vector3.Distance(point, vectors[nodes[_currentIndex].indexFirst]); // return true; // } //} ///// <summary> ///// Return 2D distance from specific point to next node ///// return true if next node exist at all ///// XZ axis from node taken to measure distance so it return top view distance ///// </summary> //public bool ReturnNextNodeDistance2D(Vector2 point, out float distance) { // if (nodes.Count == 0) { // distance = 0f; // return false; // } // else { // distance = Vector2.Distance(point, ToVector2(vectors[nodes[_currentIndex].indexFirst])); // return true; // } //} ///// <summary> ///// Return squared distance from specific point to next node ///// return true if next node exist at all ///// squared distance is distance * distance. so if you want actual distance you should call Math.Sqrt on result ///// it is slightly faster than returning normal distance so if you want to compare some distances this is way to go ///// </summary> //public bool ReturnNextNodeSqrDistance3D(Vector3 point, out float distance) { // if (nodes.Count == 0) { // distance = 0f; // return false; // } // else { // distance = SomeMath.SqrDistance(point, vectors[nodes[_currentIndex].indexFirst]); // return true; // } //} ///// <summary> ///// Return squared 2D distance from specific point to next node ///// return true if next node exist at all ///// XZ axis from node taken to measure distance so it return top view distance ///// it is slightly faster than returning normal distance so if you want to compare some distances this is way to go ///// </summary> //public bool ReturnNextNodeSqrDistance2D(Vector2 point, out float distance) { // if (nodes.Count == 0) { // distance = 0f; // return false; // } // else { // distance = SomeMath.SqrDistance(point, ToVector2(vectors[nodes[_currentIndex].indexFirst])); // return true; // } //} ///// <summary> ///// Return distance from owner position ///// return true if next node exist at all ///// </summary> //public bool ReturnNextNodeDistance3D(out float distance) { // return ReturnNextNodeDistance3D(owner.positionVector3, out distance); //} ///// <summary> ///// Return 2D distance from owner position ///// return true if next node exist at all ///// XZ axis from node taken to measure distance so it return top view distance ///// </summary> //public bool ReturnNextNodeDistance2D(out float distance) { // return ReturnNextNodeDistance2D(ToVector2(owner.positionVector3), out distance); //} ///// <summary> ///// Return squared distance from specific point to next node ///// return true if next node exist at all ///// squared distance is distance * distance. so if you want actual distance you should call Math.Sqrt on result ///// it is slightly faster than returning normal distance so if you want to compare some distances this is way to go ///// </summary> //public bool ReturnNextNodeSqrDistance3D(out float distance) { // return ReturnNextNodeSqrDistance3D(owner.positionVector3, out distance); //} ///// <summary> ///// Return squared 2D distance from specific point to next node ///// return true if next node exist at all ///// XZ axis from node taken to measure distance so it return top view distance ///// it is slightly faster than returning normal distance so if you want to compare some distances this is way to go ///// </summary> //public bool ReturnNextNodeSqrDistance2D(out float distance) { // return ReturnNextNodeSqrDistance2D(ToVector2(owner.positionVector3), out distance); //} //#endregion #endregion /// <summary> /// iterate through nodes and return if there is node other than move node. movable mean it's only when you move. not jump. so you can tell if agent about to jump /// </summary> public bool MovableDistanceLesserThan(float targetDistance, out float distance, out PathNode node, out bool reachLastPoint) { if (valid == false) { Debug.LogWarning("path are invalid"); node = new PathNode(0, 0, 0, PathNodeType.Invalid); distance = 0; reachLastPoint = true; return(false); } if (pathNodes.Count == _currentIndex) { node = new PathNode(0, 0, 0, PathNodeType.Invalid); distance = 0; reachLastPoint = true; return(true); } int remainNodes = count; Vector3 ownerPos = owner.positionVector3; node = pathNodes[currentIndex]; distance = SomeMath.Distance(ownerPos, node.Vector3); if ((int)node.type >= 4) //4, 5, 6, 7 are jumps right now { reachLastPoint = remainNodes == 1; return(distance < targetDistance); } if (remainNodes == 1) { reachLastPoint = true; return(distance < targetDistance); } for (int i = currentIndex + 1; i < pathNodes.Count; i++) { node = pathNodes[i]; distance += SomeMath.Distance(node.Vector3, pathNodes[i - 1].Vector3); node = pathNodes[i]; if (distance > targetDistance) { reachLastPoint = i == pathNodes.Count - 1; return(false); } if ((int)node.type >= 4) { reachLastPoint = i == pathNodes.Count - 1; return(distance < targetDistance); } } node = pathNodes[pathNodes.Count - 1]; reachLastPoint = true; return(true); }
/// <summary> /// return true if node were removed /// sqrDistance is normal distance * distance to simplify math /// distance measured by Vector2 /// </summary> public bool RemoveNextNodeIfCloserSqrVector2(float sqrDistance) { lock (this) { //if (path != null) // path.DebugByDebuger(); if (path == null || path.count == 0) { return(false); } Vector3 agentPos = positionVector3; PathNode node = path.currentNode; //Debug.Log(SomeMath.SqrDistance(node.x, node.z, agentPos.x, agentPos.z)); if (SomeMath.SqrDistance(node.x, node.z, agentPos.x, agentPos.z) < sqrDistance) { path.MoveToNextNode(); return(true); } else { return(false); } } }
/// <summary> /// return true if node were removed /// sqrDistance is normal distance * distance to simplify math /// distance measured by Vector3 /// </summary> public bool RemoveNextNodeIfCloserSqr(float sqrDistance) { lock (this) { if (path != null) { Debug.Log(path.pathNodes.Count); } if (path == null || path.count == 0) { return(false); } Vector3 agentPos = positionVector3; PathNode node = path.currentNode; if (SomeMath.SqrDistance(node.x, node.y, node.z, agentPos.x, agentPos.y, agentPos.z) < sqrDistance) { Debug.Log("Path index moved"); Debug.DrawRay(node.Vector3, Vector3.up, Color.red, 1f); path.MoveToNextNode(); return(true); } else { return(false); } } }
public void RecalculateBounds() { foreach (var mod in allMods) { recalculateBoundsHelper.Add(mod.bounds); } recalculateBoundsHelper.AddRange(childsAndBounds.Values); if (recalculateBoundsHelper.Count == 0) { return; } if (recalculateBoundsHelper.Count == 1) { bounds = recalculateBoundsHelper[0]; return; } else //if count > 1 { float boundsMinX, boundsMinY, boundsMinZ, boundsMaxX, boundsMaxY, boundsMaxZ; Bounds modBounds = recalculateBoundsHelper[0]; Vector3 center = modBounds.center; Vector3 extends = modBounds.extents; boundsMinX = center.x - extends.x; boundsMinY = center.y - extends.y; boundsMinZ = center.z - extends.z; boundsMaxX = center.x + extends.x; boundsMaxY = center.y + extends.y; boundsMaxZ = center.z + extends.z; for (int i = 1; i < recalculateBoundsHelper.Count; i++) { Bounds bounds = recalculateBoundsHelper[i]; Vector3 bCenter = bounds.center; Vector3 bExtents = bounds.extents; boundsMinX = SomeMath.Min(bCenter.x - bExtents.x, boundsMinX); boundsMinY = SomeMath.Min(bCenter.y - bExtents.y, boundsMinY); boundsMinZ = SomeMath.Min(bCenter.z - bExtents.z, boundsMinZ); boundsMaxX = SomeMath.Max(bCenter.x + bExtents.x, boundsMaxX); boundsMaxY = SomeMath.Max(bCenter.y + bExtents.y, boundsMaxY); boundsMaxZ = SomeMath.Max(bCenter.z + bExtents.z, boundsMaxZ); } bounds = new Bounds( new Vector3((boundsMinX + boundsMaxX) * 0.5f, (boundsMinY + boundsMaxY) * 0.5f, (boundsMinZ + boundsMaxZ) * 0.5f), new Vector3(boundsMaxX - boundsMinX, boundsMaxY - boundsMinY, boundsMaxZ - boundsMinZ)); recalculateBoundsHelper.Clear(); //Debuger_K.AddBounds(bounds, Color.red); } }
protected void RasterizeTriangle(Volume volume, Vector3 A, Vector3 B, Vector3 C, float fragmentSize, int startX, int endX, int startZ, int endZ, Area area, Passability passability, params VoxelState[] trueStates) { int minX = Mathf.Clamp(Mathf.RoundToInt(SomeMath.Min(A.x, B.x, C.x) / fragmentSize) - 1, startX, endX); int minZ = Mathf.Clamp(Mathf.RoundToInt(SomeMath.Min(A.z, B.z, C.z) / fragmentSize) - 1, startZ, endZ); int maxX = Mathf.Clamp(Mathf.RoundToInt(SomeMath.Max(A.x, B.x, C.x) / fragmentSize) + 1, startX, endX); int maxZ = Mathf.Clamp(Mathf.RoundToInt(SomeMath.Max(A.z, B.z, C.z) / fragmentSize) + 1, startZ, endZ); if (minX == maxX || minZ == maxZ) { return; //if too small return } Vector3[] vectorsStart = new Vector3[3] { A, B, C }; for (int x = minX; x < maxX; ++x) { int vertsInLength1 = ClipPolyToPlane(1f, 0.0f, -x * fragmentSize, vectorsStart, 3, ref _polyListXTemp); if (vertsInLength1 >= 3) { int vertsInLength2 = ClipPolyToPlane(-1f, 0.0f, (x + 1) * fragmentSize, _polyListXTemp, vertsInLength1, ref _polyListXFinal); if (vertsInLength2 >= 3) { for (int z = minZ; z < maxZ; ++z) { int vertsInLength3 = ClipPolyToPlane(0.0f, 1f, -z * fragmentSize, _polyListXFinal, vertsInLength2, ref _polyListZTemp); if (vertsInLength3 >= 3) { int vertsInLength4 = ClipPolyToPlane(0.0f, -1f, (z + 1) * fragmentSize, _polyListZTemp, vertsInLength3, ref _polyListZFinal); if (vertsInLength4 >= 3) { float min = _polyListZFinal[0].y; float max = _polyListZFinal[0].y; for (int index = 1; index < vertsInLength4; ++index) { min = Math.Min(min, _polyListZFinal[index].y); max = Math.Max(max, _polyListZFinal[index].y); } int indexX = Math.Abs(x - startX); int indexZ = Math.Abs(z - startZ); volume.SetVoxel(indexX, indexZ, max, min, area, (int)passability); } } } } } } }
public BattleGridPoint GetClosestPoint(Vector3 pos) { float minDist = float.MaxValue; BattleGridPoint result = null; foreach (var p in _points) { float curDist = SomeMath.SqrDistance(pos, p.positionV3); if (curDist < minDist) { minDist = curDist; result = p; } } return(result); }
public void RecalculateBounds() { Matrix4x4 G2L = container.localToWorldMatrix; Matrix4x4 L2W = localToWorldMatrix; float boundsMinX, boundsMinY, boundsMinZ, boundsMaxX, boundsMaxY, boundsMaxZ; switch (myType) { case AreaWorldModMagicValueType.Cuboid: Vector3 size = cubeSize; Vector3 point; point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(-size.x, -size.y, -size.z)));//back boundsMinX = boundsMaxX = point.x; boundsMinY = boundsMaxY = point.y; boundsMinZ = boundsMaxZ = point.z; point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(-size.x, size.y, -size.z))); //back if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(-size.x, -size.y, size.z))); //back if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(-size.x, size.y, size.z))); //back if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(size.x, -size.y, -size.z))); //forward if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(size.x, size.y, -size.z))); //forward if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(size.x, -size.y, size.z))); //forward if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } point = G2L.MultiplyPoint3x4(L2W.MultiplyPoint3x4(new Vector3(size.x, size.y, size.z))); //forward if (point.x < boundsMinX) { boundsMinX = point.x; } if (point.x > boundsMaxX) { boundsMaxX = point.x; } if (point.y < boundsMinY) { boundsMinY = point.y; } if (point.y > boundsMaxY) { boundsMaxY = point.y; } if (point.z < boundsMinZ) { boundsMinZ = point.z; } if (point.z > boundsMaxZ) { boundsMaxZ = point.z; } //haha //much optimisation bounds = new Bounds( new Vector3((boundsMinX + boundsMaxX) * 0.5f, (boundsMinY + boundsMaxY) * 0.5f, (boundsMinZ + boundsMaxZ) * 0.5f), new Vector3(boundsMaxX - boundsMinX, boundsMaxY - boundsMinY, boundsMaxZ - boundsMinZ)); break; case AreaWorldModMagicValueType.Sphere: bounds = new Bounds(container.position + (container.rotation * position), new Vector3(radius * 2, radius * 2, radius * 2)); break; case AreaWorldModMagicValueType.Capsule: Vector3 capsulePos = G2L.MultiplyPoint(position); Vector3 posLow = capsulePos + (G2L.rotation * L2W.rotation * new Vector3(0, (-height * 0.5f) + radius, 0)); Vector3 posHigh = capsulePos + (G2L.rotation * L2W.rotation * new Vector3(0, (height * 0.5f) - radius, 0)); boundsMinX = posLow.x - radius; boundsMinY = posLow.y - radius; boundsMinZ = posLow.z - radius; boundsMaxX = posLow.x + radius; boundsMaxY = posLow.y + radius; boundsMaxZ = posLow.z + radius; boundsMinX = SomeMath.Min(boundsMinX, posHigh.x - radius); boundsMinY = SomeMath.Min(boundsMinY, posHigh.y - radius); boundsMinZ = SomeMath.Min(boundsMinZ, posHigh.z - radius); boundsMaxX = SomeMath.Max(boundsMaxX, posHigh.x + radius); boundsMaxY = SomeMath.Max(boundsMaxY, posHigh.y + radius); boundsMaxZ = SomeMath.Max(boundsMaxZ, posHigh.z + radius); bounds = new Bounds( new Vector3((boundsMinX + boundsMaxX) * 0.5f, (boundsMinY + boundsMaxY) * 0.5f, (boundsMinZ + boundsMaxZ) * 0.5f), new Vector3(boundsMaxX - boundsMinX, boundsMaxY - boundsMinY, boundsMaxZ - boundsMinZ)); break; } }
public static void Raycast2Body2(float posX, float posY, float posZ, float rayDirX, float rayDirY, Cell cell, float maxLength, bool checkArea, bool checkPass, Area expArea, Passability expPass, RaycastAllocatedData rad, out RaycastHitNavMesh2 hit) { if (SomeMath.SqrMagnitude(rayDirX, rayDirY) == 0f) { hit = new RaycastHitNavMesh2(posX, posY, posZ, NavmeshRaycastResultType2.ReachMaxDistance, cell); return; } rad.chunkPixelSize = PathFinder.gridSize / PathFinder.CELL_GRID_SIZE; //trick to fix case when raycast start on "near" edge //currently can't be on chunk edge so we dont care if chunk changed rad.currentChunkData = cell.graph.chunk; int curGridX = (int)((posX - rad.currentChunkData.realX) / rad.chunkPixelSize); int curGridY = (int)((posZ - rad.currentChunkData.realZ) / rad.chunkPixelSize); //if (curGridX < 0) curGridX = 0; else if (curGridX > 9) curGridX = 9; //if (curGridY < 0) curGridY = 0; else if (curGridY > 9) curGridY = 9; rad.startIntX = (rad.currentChunkData.x * 10) + curGridX; rad.startIntY = (rad.currentChunkData.z * 10) + curGridY; var tempVal = maxLength / rad.chunkPixelSize; if (tempVal > 10000) //too big number anyway { rad.gridDistanceTreshold = SomeMath.Sqr(10000); } else { rad.gridDistanceTreshold = (int)SomeMath.Sqr(maxLength / rad.chunkPixelSize) + 1; } rad.dataArray = cell.graph.dataMap[curGridX][curGridY]; if (rad.dataArray != null) { for (int i = 0; i < rad.dataArray.Length; i++) { CellDataMapValue mapData = rad.dataArray[i]; if (mapData.from != cell) { continue; } if (mapData.data.RotateRightAndReturnDot(rayDirX, rayDirY) < 0) { continue; } float sqrDist = SomeMath.SqrDistance(mapData.data.NearestPointXZ(posX, posZ), new Vector2(posX, posZ)); if (sqrDist < 0.0001f) { Vector2 dirToCellCenter = (cell.centerVector2 - new Vector2(posX, posZ)).normalized * 0.001f; posX += dirToCellCenter.x; posZ += dirToCellCenter.y; //if (dot < 0.001f) {//oh wow. start point exactly on edge and ray alond side //} break; } } } //if (DEBUG) { // Debuger_K.AddRay(new Vector3(posX, posY + 0.1f, posZ), new Vector3(rayDirX, 0, rayDirY), Color.gray); //} rad.posX = posX; rad.posY = posY; rad.posZ = posZ; rad.rayDirX = rayDirX; rad.rayDirY = rayDirY; rad.checkPass = checkPass; rad.checkArea = checkArea; rad.expPass = expPass; rad.expArea = expArea; rad.raycastType = NavmeshRaycastResultType2.Nothing; rad.maxSqrLength = SomeMath.Sqr(maxLength); rad.curCell = cell; rad.prevCell = null; rad.raycastDone = false; float chunkX, chunkZ, curHullX, curHullZ, lastHullX = posX, lastHullZ = posZ; for (int i = 0; i < 4; i++) { rad.raycastSamples[i] = raycastSamplesTemplate[i].RotateRightAndReturnDot(rayDirX, rayDirY) < 0; } int chunkIteration = 0; while (rad.raycastDone == false) { chunkIteration++; if (chunkIteration > 50) { string s = string.Format("chunkIteration too large. x {0}, y {1}, z {2}, dx {3}, dy {4}, max {5}", posX, posY, posZ, rayDirX, rayDirY, maxLength); //HandleTextFile.WriteString(s); //Debuger_K.AddRay(new Vector3(posX, posY, posZ), Vector3.down, Color.cyan); //Debuger_K.AddRay(new Vector3(posX, posY, posZ), new Vector3(rayDirX, 0, rayDirY), Color.yellow, 50); //Debuger_K.UserfulPublicFlag = true; Debug.LogError(s); break; } rad.currentChunkData = rad.curCell.graph.chunk; rad.curChunkIntX = rad.currentChunkData.x * 10; rad.curChunkIntY = rad.currentChunkData.z * 10; rad.dataMap = rad.curCell.graph.dataMap; chunkX = rad.currentChunkData.realX; chunkZ = rad.currentChunkData.realZ; #region border points curHullX = posX; curHullZ = posZ; for (int i = 0; i < 4; i++) { if (rad.raycastSamples[i]) { CellContentData curSide = raycastSamplesTemplate[i]; float rX, rZ; if (SomeMath.RayIntersectSegment(posX, posZ, rayDirX, rayDirY, curSide.xLeft + chunkX, curSide.zLeft + chunkZ, curSide.xRight + chunkX, curSide.zRight + chunkZ, out rX, out rZ)) { curHullX = rX; curHullZ = rZ; } //if (DEBUG) // Debuger_K.AddLine(curSide.a, curSide.b, Color.red, chunkIteration); } } #region debug //if (DEBUG) { // Debuger_K.AddLine(new Vector3(curHullX, 0, curHullZ), new Vector3(lastHullX, 0, lastHullZ), Color.yellow, chunkIteration); // for (int x = 0; x < PathFinder.CELL_GRID_SIZE + 1; x++) { // Debuger_K.AddLine( // currentChunkData.realPositionV3 + new Vector3(x * chunkPixelSize, 0, 0), // currentChunkData.realPositionV3 + new Vector3(x * chunkPixelSize, 0, PathFinder.gridSize), // Color.red); // } // for (int z = 0; z < PathFinder.CELL_GRID_SIZE + 1; z++) { // Debuger_K.AddLine( // currentChunkData.realPositionV3 + new Vector3(0, 0, z * chunkPixelSize), // currentChunkData.realPositionV3 + new Vector3(PathFinder.gridSize, 0, z * chunkPixelSize), // Color.red); // } //} #endregion #endregion DDARasterization.DrawLine( lastHullX - chunkX, lastHullZ - chunkZ, curHullX - chunkX, curHullZ - chunkZ, rad.chunkPixelSize, rad, RaycastDelegate); lastHullX = curHullX; lastHullZ = curHullZ; } hit = new RaycastHitNavMesh2(rad.raycastResultX, rad.raycastResultY, rad.raycastResultZ, rad.raycastType, rad.curCell); }
private static bool RaycastDelegate(int x, int y, RaycastAllocatedData rad) { if (rad.raycastDone) { return(true); } if (x < 0) { x = 0; } else if (x > 9) { x = 9; //x = SomeMath.Clamp(0, CELL_GRID_SIZE - 1, x); } if (y < 0) { y = 0; } else if (y > 9) { y = 9; //y = SomeMath.Clamp(0, CELL_GRID_SIZE - 1, y); } if (SomeMath.SqrDistance(rad.startIntX, rad.startIntY, rad.curChunkIntX + x, rad.curChunkIntY + y) > rad.gridDistanceTreshold) { rad.raycastType = NavmeshRaycastResultType2.ReachMaxDistance; rad.raycastDone = true; } //IMPORTANT: edges in this list are sorted. "connection != null" at the begining and "connection == null" at the end. //some logic here based on this order rad.dataArray = rad.dataMap[x][y]; if (rad.dataArray == null) { return(false); } int dataArrayLength = rad.dataArray.Length; #region debug //if (DEBUG) { // Vector3 p = currentChunkData.realPositionV3 + new Vector3((x * chunkPixelSize) + (chunkPixelSize * 0.5f), 0, (y * chunkPixelSize) + (chunkPixelSize * 0.5f)); // Debuger_K.AddDot(curCell.centerV3, Color.cyan); // Debuger_K.AddDot(p, Color.red, 0.05f); // //list.ForEach(item => Debuger_K.AddLine(item.data.NearestPoint(p), p, Color.blue)); //} #endregion int cellLoop = 0; bool doCellLoop = true; while (doCellLoop) { cellLoop++; if (cellLoop > 50) { Debug.LogErrorFormat("cellLoop too large. x {0}, y {1}, z {2}, dx {3}, dy {4}, max {5}", rad.posX, rad.posY, rad.posZ, rad.rayDirX, rad.rayDirY, Mathf.Sqrt(rad.maxSqrLength)); break; } doCellLoop = false; for (int i = 0; i < dataArrayLength; i++) { CellDataMapValue mapData = rad.dataArray[i]; if (mapData.from != rad.curCell) { continue; } CellContentData ccd = mapData.data; if ((-(ccd.zRight - ccd.zLeft) * rad.rayDirX) + ((ccd.xRight - ccd.xLeft) * rad.rayDirY) < 0) { continue; } float ix, iy, iz; if (SomeMath.RayIntersectXZ(rad.posX, rad.posZ, rad.rayDirX, rad.rayDirY, ccd.xLeft, ccd.yLeft, ccd.zLeft, ccd.xRight, ccd.yRight, ccd.zRight, out ix, out iy, out iz) == false) { continue; } rad.raycastResultX = ix; rad.raycastResultY = iy; rad.raycastResultZ = iz; rad.prevCell = rad.curCell; if (SomeMath.SqrDistance(rad.posX, rad.posY, rad.posZ, ix, iy, iz) >= rad.maxSqrLength) { rad.raycastType = NavmeshRaycastResultType2.ReachMaxDistance; rad.raycastDone = true; return(true); } if (mapData.connection != null) { #region debug //if (DEBUG) { // Vector3 p = currentChunkData.realPositionV3 + new Vector3((x * chunkPixelSize) + (chunkPixelSize * 0.5f), 0, (y * chunkPixelSize) + (chunkPixelSize * 0.5f)); // //Debuger_K.AddLine(ToV3(curHullIntersection), resultVector); // if (prevCell != null) { // Vector3 p1p = SomeMath.MidPoint(curCell.centerV3, prevCell.centerV3); // //Vector3 p2p = SomeMath.MidPoint(p1p, p); // Debuger_K.AddLine(curCell.centerV3, prevCell.centerV3, Color.green); // Debuger_K.AddLine(p1p, p, Color.cyan); // } //} #endregion doCellLoop = true; rad.curCell = mapData.connection; if (rad.checkPass && rad.curCell.passability != rad.expPass) { rad.raycastType = NavmeshRaycastResultType2.PassabilityChange; rad.raycastDone = true; return(true); } else if (rad.checkArea && rad.curCell.area != rad.expArea) { rad.raycastType = NavmeshRaycastResultType2.AreaChange; rad.raycastDone = true; return(true); } } else { rad.curCell = null; rad.raycastType = NavmeshRaycastResultType2.NavmeshBorderHit; rad.raycastDone = true; return(true); } break; } } return(rad.raycastDone); }
public override void OnInspectorGUI() { AgentProperties myTarget = (AgentProperties)target; if (myTarget == null) { return; } float currentLabelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 130; UITools.Line(); generalTab = EditorGUILayout.Foldout(generalTab, generalTabContent); if (generalTab) { Rect rect = EditorGUILayout.GetControlRect(false, 100); //GUI.Box(rect, string.Empty); #region nice drawing float rectHeight = rect.height * 0.7f; float rectheightHalf = rectHeight * 0.5f; float rectheightQuarter = rectheightHalf * 0.5f; Vector2 rectCenter = rect.center; float agentWidth = (radius.floatValue / height.floatValue) * rectHeight * 0.8f; Vector2 leftBottom = new Vector2(rectCenter.x + agentWidth + rectheightQuarter, rectCenter.y + rectheightHalf); Vector2 rightBotton = new Vector2(rectCenter.x - agentWidth - rectheightQuarter, rectCenter.y + rectheightHalf); Handles.color = Color.black; float slope = maxSlope.floatValue; Vector2 slopeVector = new Vector2( (float)Math.Cos(slope * Math.PI / 180) * (rectHeight * 0.9f), (float)Math.Sin(slope * Math.PI / 180) * (rectHeight * 0.9f)); slopeVector = new Vector2(-slopeVector.x, slopeVector.y); GUI.Label(new Rect((leftBottom - (slopeVector * 0.15f)) - (new Vector2(0, 15)), new Vector2(100, 20)), string.Format("Slope {0}", maxSlope.floatValue)); float stepHeight = (maxStepHeight.floatValue / height.floatValue) * rectHeight; Handles.DrawAAPolyLine( 3, leftBottom - slopeVector, leftBottom, rightBotton, rightBotton - new Vector2(0, stepHeight), rightBotton - new Vector2(50, stepHeight)); GUI.Label(new Rect(rightBotton - new Vector2(50, stepHeight + 20), new Vector2(100, 20)), string.Format("Step {0}", maxStepHeight.floatValue)); //Vector2 leftStart = rectCenter - new Vector2(rectheightQuarter, rectheightQuarter); //Vector2 leftUp = leftStart + new Vector2(0, rectheightHalf); Color hColor = Handles.color; Handles.color = Color.black; Color niceColor = new Color(135f / 255f, 206f / 255f, 250f / 255f, 1f); Handles.color = niceColor; Handles.DrawSolidDisc(new Vector2(rectCenter.x, rectCenter.y - rectheightHalf), new Vector3(0f, -1f, 0.5f), agentWidth); Handles.DrawSolidDisc(new Vector2(rectCenter.x, rectCenter.y + rectheightHalf), new Vector3(0f, 1f, 0.5f), agentWidth); EditorGUI.DrawRect(new Rect( rectCenter.x - agentWidth, rectCenter.y - rectheightHalf, agentWidth + agentWidth, rectheightHalf * 2), niceColor); Vector2 rectCenterSlightlyOffseted = new Vector2(rectCenter.x - 0.5f, rectCenter.y); textFieldStyles.normal.textColor = Color.red; GUI.Label(new Rect(rectCenter.x + agentWidth, rectCenter.y, 100, 20), string.Format("Radius {0}", radius.floatValue), textFieldStyles); textFieldStyles.normal.textColor = Color.blue; GUI.Label(new Rect(rectCenter.x + agentWidth, rectCenter.y - rectheightHalf, 100, 20), string.Format("Height {0}", height.floatValue), textFieldStyles); //outlines Handles.color = Color.black; Handles.DrawWireDisc(new Vector2(rectCenterSlightlyOffseted.x, rectCenterSlightlyOffseted.y - rectheightHalf), new Vector3(0f, 1f, 0.5f), agentWidth); Handles.DrawWireDisc(new Vector2(rectCenterSlightlyOffseted.x, rectCenterSlightlyOffseted.y - rectheightHalf), new Vector3(0f, -1f, 0.5f), agentWidth); Handles.DrawWireDisc(new Vector2(rectCenterSlightlyOffseted.x, rectCenterSlightlyOffseted.y + rectheightHalf), new Vector3(0f, 1f, 0.5f), agentWidth); Handles.DrawLine( new Vector2(rectCenterSlightlyOffseted.x - agentWidth, rectCenterSlightlyOffseted.y - rectheightHalf), new Vector2(rectCenterSlightlyOffseted.x - agentWidth, rectCenterSlightlyOffseted.y + rectheightHalf)); Handles.DrawLine( new Vector2(rectCenterSlightlyOffseted.x + agentWidth, rectCenterSlightlyOffseted.y - rectheightHalf), new Vector2(rectCenterSlightlyOffseted.x + agentWidth, rectCenterSlightlyOffseted.y + rectheightHalf)); Handles.color = Color.red; Handles.DrawWireDisc(rectCenterSlightlyOffseted, new Vector3(0f, 1f, 0.5f), agentWidth); Handles.DrawWireDisc(rectCenterSlightlyOffseted + Vector2.up, new Vector3(0f, 1f, 0.5f), agentWidth); Handles.DrawWireDisc(rectCenterSlightlyOffseted + Vector2.down, new Vector3(0f, 1f, 0.5f), agentWidth); Handles.color = hColor; #endregion EditorGUILayout.PropertyField(radius, radiusContent); EditorGUILayout.PropertyField(height, heightContent); EditorGUILayout.PropertyField(maxSlope, maxSlopeContent); EditorGUILayout.PropertyField(maxStepHeight, maxStepHeightContent); EditorGUILayout.PropertyField(includedLayers, includedLayersContent); EditorGUILayout.PropertyField(ignoredTags, ignoredTagsContent, true); if (ignoredTags.arraySize > 0) { EditorGUILayout.PropertyField(checkHierarchyTag, checkHierarchyTagContent); } if (maxStepHeight.floatValue > height.floatValue) { maxStepHeight.floatValue = height.floatValue; } if (canCrouch.boolValue && maxStepHeight.floatValue > crouchHeight.floatValue) { maxStepHeight.floatValue = crouchHeight.floatValue; } if (radius.floatValue < 0.001f) { radius.floatValue = 0.001f; } if (height.floatValue < 0.001f) { height.floatValue = 0.001f; } if (maxStepHeight.floatValue < 0.001f) { maxStepHeight.floatValue = 0.001f; } if (includedLayers.intValue == 0) //big warning in case no layers sellected { rect = EditorGUILayout.GetControlRect(false, 30); Color gColor = GUI.color; GUI.color = Color.red; GUI.Box(rect, new GUIContent("No layers sellected", "Sellect at least something in included Layers")); GUI.color = gColor; } if (maxStepHeight.floatValue < (PathFinder.gridSize / myTarget.voxelsPerChunk)) //big warning in case no layers sellected { rect = EditorGUILayout.GetControlRect(false, 30); Color gColor = GUI.color; GUI.color = Color.yellow; GUI.Box(rect, new GUIContent("Step height is very low", "Agent probably will have incorrect navmesh generation if it that low. Recomend at least greater than voxel size")); GUI.color = gColor; } } UITools.Line(); voxelTab = EditorGUILayout.Foldout(voxelTab, voxelTabContent); if (voxelTab) { EditorGUILayout.PropertyField(voxelsPerChunk, voxelsPerChunkContent); float foxelSize = PathFinder.gridSize / myTarget.voxelsPerChunk; EditorGUILayout.LabelField("Voxel Size", foxelSize.ToString()); EditorGUILayout.LabelField("Voxel Per Radius", ((int)(myTarget.radius / foxelSize)).ToString()); GUILayout.BeginHorizontal(); setThisMuch = EditorGUILayout.IntField(setThisMuch, GUILayout.MaxWidth(100)); if (GUILayout.Button("Set this much")) { voxelsPerChunk.intValue = Mathf.CeilToInt(PathFinder.gridSize / (myTarget.radius / setThisMuch)); } if (voxelsPerChunk.intValue < setThisMuch) { voxelsPerChunk.intValue = voxelsPerChunk.intValue + 1; } GUILayout.EndHorizontal(); if (voxelsPerChunk.intValue < 10) { voxelsPerChunk.intValue = 10; } if ((int)(myTarget.radius / foxelSize) <= 0) //big warning in case no layers sellected { Rect rect = EditorGUILayout.GetControlRect(false, 30); Color gColor = GUI.color; GUI.color = Color.red; GUI.Box(rect, new GUIContent("Voxel per radius is 0", "Increase amount of voxels per radius. Recomend at least 2")); GUI.color = gColor; } } UITools.Line(); movementTab = EditorGUILayout.Foldout(movementTab, movementTabContent); if (movementTab) { EditorGUILayout.PropertyField(doNavMesh, doNavMeshContent); if (doNavMesh.boolValue) { EditorGUILayout.PropertyField(walkMod, walkModContent); EditorGUILayout.PropertyField(canCrouch, canCrouchContent); if (canCrouch.boolValue) { EditorGUILayout.PropertyField(crouchHeight, crouchHeightContent); EditorGUILayout.PropertyField(crouchMod, crouchModContent); if (crouchHeight.floatValue < 0) { crouchHeight.floatValue = 0; } if (crouchHeight.floatValue > height.floatValue) { crouchHeight.floatValue = height.floatValue; } } EditorGUILayout.PropertyField(canJump, canJumpContent); if (canJump.boolValue) { EditorGUILayout.PropertyField(JumpDown, JumpDownContent); EditorGUILayout.PropertyField(jumpDownMod, jumpDownModContent); EditorGUILayout.PropertyField(JumpUp, JumpUpContent); EditorGUILayout.PropertyField(jumpUpMod, jumpUpModContent); } } } UITools.Line(); coverTab = EditorGUILayout.Foldout(coverTab, coverTabContent); if (coverTab) { EditorGUILayout.PropertyField(canCover, canCoverContent); if (canCover.boolValue) { EditorGUILayout.PropertyField(fullCover, fullCoverContent); if (fullCover.floatValue < 0) { fullCover.floatValue = 0; } EditorGUILayout.PropertyField(canHalfCover, canHalfCoverContent); if (canHalfCover.boolValue) { EditorGUILayout.PropertyField(halfCover, halfCoverContent); halfCover.floatValue = SomeMath.Clamp(0, fullCover.floatValue, halfCover.floatValue); if (fullCover.floatValue < halfCover.floatValue) { fullCover.floatValue = halfCover.floatValue; } } EditorGUILayout.PropertyField(coverExtraSamples, coverExtraSamplesContent); if (coverExtraSamples.intValue < 0) { coverExtraSamples.intValue = 0; } } } UITools.Line(); battleGridTab = EditorGUILayout.Foldout(battleGridTab, battleGridTabContent); if (battleGridTab) { EditorGUILayout.PropertyField(battleGrid, battleGridContent); if (battleGrid.boolValue) { EditorGUILayout.PropertyField(battleGridDensity, battleGridDensityContent); } } UITools.Line(); otherTab = EditorGUILayout.Foldout(otherTab, otherTabContent); if (otherTab) { EditorGUILayout.PropertyField(offsetMultiplier, offsetMultiplierContent); } EditorGUIUtility.labelWidth = currentLabelWidth; serializedObject.ApplyModifiedProperties(); }
//private raycasting to take input by things upside private static void Raycast(Vector3 origin, Vector3 direction, AgentProperties properties, out RaycastHitNavMesh hit, float length, bool triggeredByPassabilityChange, bool triggeredByAreaChange, int maxIterations, Passability expectedPassability, Area expectedArea, Cell cell) { raycastExclude.Clear();//excluded list of edges float maxLengthSqr = length * length; for (int iteration = 0; iteration < maxIterations; iteration++) { raycastTempData.Clear();//iteration data cleared foreach (var pair in cell.dataContentPairs) { CellContentData curData = pair.Key; if (!raycastExclude.Add(curData))//mean it's already contain this { continue; } Vector3 intersect; if (SomeMath.RayIntersectXZ(origin, direction, curData.leftV3, curData.rightV3, out intersect)) { if (pair.Value != null) { Cell otherCell = pair.Value.connection; if (otherCell == cell | !otherCell.canBeUsed) { continue; } if ((triggeredByPassabilityChange && cell.passability != otherCell.passability) || (triggeredByAreaChange && cell.area != otherCell.area)) { hit = new RaycastHitNavMesh(intersect, SomeMath.SqrDistance(origin, intersect) < maxLengthSqr); return; } raycastTempData.Add(new RaycastSomeData(intersect, otherCell)); } else { raycastTempData.Add(new RaycastSomeData(intersect, null)); } } } //check if there possible connection for (int i = 0; i < raycastTempData.Count; i++) { if (raycastTempData[i].cell != null) { cell = raycastTempData[i].cell; goto CONTINUE; } } //now we definetly hit something and now find furthest float furthestSqrDist = 0f; Vector3 furthest = origin; for (int i = 0; i < raycastTempData.Count; i++) { float curSqrDist = SomeMath.SqrDistance(raycastTempData[i].point, origin); if (curSqrDist > furthestSqrDist) { furthestSqrDist = curSqrDist; furthest = raycastTempData[i].point; } } hit = new RaycastHitNavMesh(furthest, SomeMath.SqrDistance(origin, furthest) < maxLengthSqr); return; CONTINUE : { continue; } } hit = new RaycastHitNavMesh(origin, true, true); return; }
//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); } }