/// <summary> /// Helper function /// </summary> /// <param name="_terrain"></param> /// <param name="_texture"></param> /// <param name="iMoveDelta"></param> /// <returns></returns> public static bool CanMove(TerrainShape _terrain, DetailTextureResource _texture, int iMoveDelta) { if (_terrain == null || !_terrain.Modifiable || _terrain.EngineTerrain == null || _texture == null) { return(false); } int iOldIndex = _terrain.DetailTextures.IndexOf(_texture); int iNewIndex = iOldIndex + iMoveDelta; if (_texture._bIsBaseTexture) { return(false); } if (iOldIndex < 0 || iOldIndex >= _terrain.DetailTextures.Count) { return(false); } if (iNewIndex < 1 || iNewIndex >= _terrain.DetailTextures.Count) { return(false); } return(true); }
///<summary> /// Constructs a new Terrain. ///</summary> ///<param name="shape">Shape to use for the terrain.</param> ///<param name="worldTransform">Transform to use for the terrain.</param> public Terrain(TerrainShape shape, AffineTransform worldTransform) { WorldTransform = worldTransform; Shape = shape; Events = new ContactEventManager <Terrain>(); }
public override bool OnStart() { if (!base.OnStart()) { return(false); } TerrainShape terrain = OwnerTerrain; if (terrain == null || terrain.EngineTerrain == null || DecorationModel == null) { return(false); } if (!terrain.EngineTerrain.GetDecorationModelDensityResolution(this.DecorationModel)) { return(false); } _fMinAngleCos = (float)Math.Cos(_fMinAngle * Math.PI / 180.0f); _fMaxAngleCos = (float)Math.Cos(_fMaxAngle * Math.PI / 180.0f); fInvRange = _fMinAngleCos - _fMaxAngleCos; if (fInvRange > 0.0f) { fInvRange = 1.0f / fInvRange; } return(true); }
void Awake() { player = GameObject.FindGameObjectWithTag("Player").GetComponent <Player>(); network = GameObject.FindGameObjectWithTag("Planet").GetComponent <TetherNetwork>(); TerrainChunk.chunkPrefab = chunkPrefab; float foo = Time.time; shader = new RunShader(compute); shape = new TerrainShape(biomesJSON) { settings = settings, shader = densities }; chunks = new Dictionary <Vector3, TerrainChunk>(); needUpdate = new Queue <TerrainChunk>(); for (int x = -2; x <= 2; x++) { for (int y = -2; y <= 2; y++) { for (int z = -2; z <= 2; z++) { CreateChunk(new Vector3(x * 39, y * 39, z * 39) + new Vector3(0, 975, 0)); } } } Debug.Log(Time.realtimeSinceStartup - foo + " TIME"); }
public override Shape CreateShape() { var terrain = GetComponent <Terrain>(); var data = terrain.terrainData; int resolusion = data.heightmapResolution; var heights = data.GetHeights(0, 0, resolusion, resolusion); float verticalScale = data.size.y; for (int x = 0; x < resolusion; x++) { for (int z = 0; z < resolusion; z++) { heights[x, z] *= verticalScale; } } for (int x = 0; x < resolusion - 1; x++) { for (int z = x; z < resolusion; z++) { float h1 = heights[x, z]; float h2 = heights[z, x]; heights[x, z] = h2; heights[z, x] = h1; } } var result = new TerrainShape(heights, data.size.x / (resolusion - 1), data.size.z / (resolusion - 1)); return(result); }
protected NewDetailTextureCollectionAction(SerializationInfo info, StreamingContext context) : base(info, context) { _terrain = (TerrainShape)info.GetValue("_terrain", typeof(TerrainShape)); _oldList = (ArrayList)info.GetValue("_oldList", typeof(ArrayList)); _newList = (ArrayList)info.GetValue("_newList", typeof(ArrayList)); }
public MoveDetailTextureAction(TerrainShape terrain, DetailTextureResource texture, int iMoveDelta) { _texture = texture; _terrain = terrain; _iMoveDelta = iMoveDelta; iOldIndex = _terrain.DetailTextures.IndexOf(_texture); iNewIndex = iOldIndex + iMoveDelta; }
public TerrainVisibilityZoneShape(TerrainShape owner, int iSectorX, int iSectorY) : base(string.Format("TerrainZone_{0}_{1}", iSectorX, iSectorX)) { _iSectorX = iSectorX; _iSectorY = iSectorY; _ownerTerrain = owner; _createHotSpots = false; }
protected MoveDetailTextureAction(SerializationInfo info, StreamingContext context) : base(info, context) { _terrain = (TerrainShape)info.GetValue("_terrain", typeof(TerrainShape)); _texture = (DetailTextureResource)info.GetValue("_texture", typeof(DetailTextureResource)); iOldIndex = info.GetInt32("iOldIndex"); iNewIndex = info.GetInt32("iNewIndex"); }
private void button_Apply_Click(object sender, EventArgs e) { if (!_bHasApplyButton) { return; } progress.Percentage = 0.0f; progressBar.Visible = true; TerrainShape terrain = TerrainEditor.CurrentTerrain; // in case this is a heightmap filter... IHeightmapFilter hmFilter = _filter as IHeightmapFilter; if (hmFilter != null) { if (!hmFilter.OnStart(terrain.Heightmap, x1, y1, x2, y2)) { string err = _filter.LastError; string msg = "An error occurred while running this action."; if (!string.IsNullOrEmpty(err)) { msg += "\n\nDetailed message: " + err; } EditorManager.ShowMessageBox(msg, "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); hmFilter.OnFinish(); return; } terrain.EngineTerrain.ApplyHeightmapFilter(hmFilter, progress); hmFilter.OnFinish(); // trigger the action that has the backed-up height values EditorManager.Actions.Add(new TerrainChangedAction(terrain.EngineTerrain, "Import Heightmap : " + _filter.Name)); } // ...or decoration filter IDecorationFilter decoFilter = _filter as IDecorationFilter; if (decoFilter != null) { if (!decoFilter.OnStart()) { string err = decoFilter.LastError; string msg = "An error occurred while running this action."; if (!string.IsNullOrEmpty(err)) { msg += "\n\nDetailed message: " + err; } EditorManager.ShowMessageBox(msg, "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); decoFilter.OnFinish(); return; } terrain.EngineTerrain.ApplyDecorationFilter(decoFilter, progress); EditorManager.Actions.Add(new TerrainChangedAction(terrain.EngineTerrain, "Decoration : " + _filter.Name)); decoFilter.OnFinish(); } }
public Terrain(GraphicsDevice graphicsDevice, Camera camera, Texture2D heightMap, Game game, World world) : this(graphicsDevice, camera, heightMap, game) { TerrainShape terrainShape = new TerrainShape(heightData, 1, 1); body = new RigidBody(terrainShape); body.Position = new JVector(); body.IsStatic = true; body.Material.KineticFriction = 0.0f; world.AddBody(body); }
///<summary> /// Constructs a new Terrain. ///</summary> ///<param name="shape">Shape to use for the terrain.</param> ///<param name="worldTransform">Transform to use for the terrain.</param> public Terrain(TerrainShape shape, AffineTransform worldTransform) { this.worldTransform = worldTransform; Shape = shape; collisionRules.group = CollisionRules.DefaultKinematicCollisionGroup; material = new Material(); materialChangedDelegate = OnMaterialChanged; material.MaterialChanged += materialChangedDelegate; events = new ContactEventManager <Terrain>(this); }
public NewDetailTextureCollectionAction(TerrainShape terrain, ArrayList oldList, ArrayList newList) { _terrain = terrain; _oldList = oldList; _newList = newList; // re-enum new objects: foreach (DetailTextureResource tex in _newList) { if (tex.ID == 0) { tex._ownerTerrain = _terrain; tex.ID = _terrain.GetNewDetailTextureID(); } } }
public override bool OnStart() { if (!base.OnStart()) { return(false); } TerrainShape terrain = OwnerTerrain; if (terrain == null || terrain.EngineTerrain == null || _sourceTexture == null || DecorationModel == null) { return(false); } if (!terrain.EngineTerrain.GetDecorationModelDensityResolution(this.DecorationModel)) { return(false); } return(true); }
public override Scene2DViewFilterCategory GetScene2DRenderingFilter(Scene2DView view) { if (FilterCat == null) { FilterCat = view.CreateFilterCategory("Terrain"); int iIndex = TerrainShape.GetTerrainIconIndex(); if (iIndex >= 0) { FilterCat.Image = EditorManager.GUI.ShapeTreeImages.ImageList.Images[iIndex]; } } if (FilterCollisionCat == null) { FilterCollisionCat = view.CreateFilterCategory("Terrain Collision"); FilterCollisionCat.Image = FilterCat.Image; FilterCollisionCat.Enabled = false; // disabled by default } return(FilterCat); }
public override void Initialize() { base.Initialize(); primitive = new TerrainPrimitive(GraphicsDevice, (int a, int b) => { return((float)(Math.Sin(a * 0.1f) * Math.Cos(b * 0.1f)) * 3); }); JitterDemo demo = this.Game as JitterDemo; TerrainShape terrainShape = new TerrainShape(primitive.heights, 1.0f, 1.0f); terrainBody = new RigidBody(terrainShape); terrainBody.IsStatic = true; terrainBody.Tag = true; demo.World.AddBody(terrainBody); World = Matrix.CreateTranslation(-50, 0, -50); }
public override void Build() { terrain = new Primitives3D.TerrainPrimitive(Demo.GraphicsDevice, ((a, b) => { return((float)(Math.Cos(a * 0.2f) * Math.Sin(b * 0.2f) * 2.0f)); })); TerrainShape shape = new TerrainShape(terrain.heights, 1.0f, 1.0f); RigidBody body = new RigidBody(shape); body.Position -= new JVector(50, 0, 50); body.IsStatic = true; body.Tag = BodyTag.DontDrawMe; //body.EnableDebugDraw = true; Demo.World.AddBody(body); AddCar(new JVector(0, 4, 0)); }
public override void PreRenderTickFunction(float fTimeDelta) { base.PreRenderTickFunction(fTimeDelta); TerrainShape terrain = TerrainEditor.CurrentTerrain; if (terrain != null) { terrain.EngineTerrain.Update3DCursor(TerrainEditor.Cursor3DProperties, (float)MouseX, (float)MouseY); if (this._resizeBrushKeyDown) { Vector3F vDist = terrain.EngineTerrain.GetCurrentCursorCenter() - this._vBrushResizeCenter; vDist.Z = 0.0f; float fDist = vDist.GetLength(); if (fDist > 1.0f) { // calc angle vDist.Normalize(); float fAngle = (float)(Math.Acos((double)vDist.Y) * 180 / Math.PI); if (vDist.X > 0.0f) { fAngle = 360.0f - fAngle; } TerrainEditor.Cursor3DProperties.Radius = fDist; TerrainEditor.Cursor3DProperties.Rotation = fAngle; // restore position again terrain.EngineTerrain.Update3DCursor(TerrainEditor.Cursor3DProperties, (float)_iBrushResizeMouseX, (float)_iBrushResizeMouseY); float fWgt = 0.8f; float fMiddleX = (float)MouseX * fWgt + (float)_iBrushResizeMouseX * (1.0f - fWgt); float fMiddleY = (float)MouseY * fWgt + (float)_iBrushResizeMouseY * (1.0f - fWgt); char degreeChar = (char)0xB0; this.View.RenderLine2D((float)MouseX, (float)MouseY, (float)_iBrushResizeMouseX, (float)_iBrushResizeMouseY, VisionColors.Yellow, 1.0f); this.View.WriteText2D(fMiddleX, fMiddleY, fDist.ToString("N2"), VisionColors.Yellow); this.View.WriteText2D(_iBrushResizeMouseX, _iBrushResizeMouseY, fAngle.ToString("N1") + degreeChar, VisionColors.Yellow); } } } }
/** * @brief Creates a terrain shape based on a Terrain component attached. **/ public override Shape CreateShape() { var terrain = GetComponent <Terrain>(); var data = terrain.terrainData; int resolusion = data.heightmapResolution; var heightsFloat = data.GetHeights(0, 0, resolusion, resolusion); FP[,] heights = new FP[heightsFloat.GetLength(0), heightsFloat.GetLength(1)]; for (int indexI = 0; indexI < heightsFloat.GetLength(0); indexI++) { for (int indexJ = 0; indexJ < heightsFloat.GetLength(1); indexJ++) { heights[indexI, indexJ] = heightsFloat[indexI, indexJ]; } } FP verticalScale = data.size.y; for (int x = 0; x < resolusion; x++) { for (int z = 0; z < resolusion; z++) { heights[x, z] *= verticalScale; } } for (int x = 0; x < resolusion - 1; x++) { for (int z = x; z < resolusion; z++) { FP h1 = heights[x, z]; FP h2 = heights[z, x]; heights[x, z] = h2; heights[z, x] = h1; } } var result = new TerrainShape(heights, data.size.x / (resolusion - 1), data.size.z / (resolusion - 1)); return(result); }
public void Update() { if (WorkingRevision == Revision || WorkingShape != null) { return; } int currentRevision = WorkingRevision; lock (PublicShape) { WorkingShape = new TerrainShape { TerrainBitmap = PublicShape.TerrainBitmap.Clone() as TerrainType[, ], }; } // Enqueue update-task var Task = new Task(() => { ExtractTrianglesAndOutline(); BuildTerrainTypeTexture(); lock (PublicShape) { // Copy new triangles/outline to TerrainShape PublicShape = WorkingShape; WorkingShape = null; Revision = currentRevision; } }); Task.Start(); if (currentRevision == 1) { Task.Wait(); } }
public override bool OnStart() { if (!base.OnStart()) { return(false); } TerrainShape terrain = OwnerTerrain; if (terrain == null || terrain.EngineTerrain == null || DecorationModel == null) { return(false); } if (!terrain.EngineTerrain.GetDecorationModelDensityResolution(DecorationModel)) { return(false); } iSampleCountX = DecorationModel.iDensityResX * terrain.Config.SectorCountX; iSampleCountY = DecorationModel.iDensityResY * terrain.Config.SectorCountY; string info; _bitmap = ImageLoader.LoadImage(_luminanceFilename, out info) as Bitmap; _bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); return(_bitmap != null); }
public PaintDetailTextureAction(TerrainShape terrain, DetailTextureResource texture) : base(terrain.EngineTerrain, "Edit detail texture") { _texture = texture; }
public ImportWeightmapFilter(TerrainShape owner) { _owner = owner; }
public TerrainMeshExport(TerrainShape owner) { Owner = owner; }
public SlopeDetailTexturesFilter(TerrainShape owner) { _owner = owner; }
public PaintDecorationAction(TerrainShape terrain, DecorationModelResource model) : base(terrain.EngineTerrain, "Edit decoration") { _model = model; }
public bool Build(ShapeCollection staticGeometries, ref int numGeometryVertices, ref int numGeometryTriangles) { if (!HasEngineInstance()) { return(false); } EngineNavMesh.ClearNavMesh(); EngineNavMesh.ClearGeometry(); EngineNavMesh.ClearCarvers(); EngineNavMesh.ClearSeedPoints(); EngineNavMesh.ClearLocalSettings(); EngineNavMesh.ClearDecorationCapsules(); SetEngineInstanceBaseProperties(); HavokNavMeshGlobalSettings globalSettings = GetGlobalSettings(); if (globalSettings == null) { return(false); } BoundingBox parentZoneBbox = new BoundingBox(); if (globalSettings.RestrictToInputGeometryFromSameZone && ParentZone != null) { parentZoneBbox = ParentZone.CalculateBoundingBox(); } // check if there's a parent zone foreach (ShapeBase shape in staticGeometries) { // treat as cutter if flag is set and if in different zone bool potentiallyTreatAsCutter = globalSettings.RestrictToInputGeometryFromSameZone && (shape.ParentZone != ParentZone); if (shape is EntityShape) { EntityShape entity = shape as EntityShape; eNavMeshUsage usage = entity.GetNavMeshUsage(); // exclude entities that have a vHavokRigidBody component with "Motion Type" != "Fixed" ShapeComponentType compType = (ShapeComponentType)EditorManager.EngineManager.ComponentClassManager.GetCollectionType("vHavokRigidBody"); if (compType != null && entity.Components != null) { ShapeComponent comp = entity.Components.GetComponentByType(compType); if (comp != null) { string propValue = comp.GetPropertyValue("Motion Type") as string; if (string.Compare(propValue, "Fixed") != 0) { usage = eNavMeshUsage.ExcludeFromNavMesh; } } } // potentially override usage if (potentiallyTreatAsCutter && (usage == eNavMeshUsage.IncludeInNavMesh)) { usage = eNavMeshUsage.CutterOnly; } if (usage != eNavMeshUsage.ExcludeFromNavMesh) { EngineNavMesh.AddEntityGeometry(entity.EngineEntity.GetNativeObject(), (int)usage, parentZoneBbox); } } else if (shape is StaticMeshShape) { StaticMeshShape staticMesh = shape as StaticMeshShape; eNavMeshUsage usage = staticMesh.GetNavMeshUsage(); // potentially override usage if (potentiallyTreatAsCutter && (usage == eNavMeshUsage.IncludeInNavMesh)) { usage = eNavMeshUsage.CutterOnly; } if (usage != eNavMeshUsage.ExcludeFromNavMesh) { EngineNavMesh.AddStaticMeshGeometry(staticMesh.EngineMesh.GetNativeObject(), (int)usage, parentZoneBbox); } } else if (shape is TerrainShape) { TerrainShape terrain = shape as TerrainShape; eNavMeshUsage usage = terrain.GetNavMeshUsage(); // potentially override usage if (potentiallyTreatAsCutter && (usage == eNavMeshUsage.IncludeInNavMesh)) { usage = eNavMeshUsage.CutterOnly; } if (usage != eNavMeshUsage.ExcludeFromNavMesh) { EngineNavMesh.AddTerrainGeometry(terrain.EngineTerrain.GetNativeObject(), (int)usage, parentZoneBbox); } } #if !HK_ANARCHY else if (shape is DecorationGroupShape) { DecorationGroupShape decorationGroup = shape as DecorationGroupShape; // Please note that currently the native HavokAiEnginePlugin only supports decoration capsules as cutters. if (decorationGroup.GetNavMeshLimitedUsage() == DecorationGroupShape.eNavMeshLimitedUsage.CutterOnly) { EngineNavMesh.AddDecorationGroupCapsules(decorationGroup.EngineGroup.GetGroupsObject()); } } #endif #if USE_SPEEDTREE else if (shape is Speedtree6GroupShape) { Speedtree6GroupShape trees = shape as Speedtree6GroupShape; if (trees.EnableCollisions) { EngineNavMesh.AddSpeedTree6Capsules(trees.EngineGroup.GetGroupsObject()); } } #endif } numGeometryVertices = EngineNavMesh.GetNumGeometryVertices(); numGeometryTriangles = EngineNavMesh.GetNumGeometryTriangles(); // Add carvers ShapeCollection carvers = EditorManager.Scene.AllShapesOfType(typeof(HavokNavMeshCarverShape)); foreach (ShapeBase shape in carvers) { HavokNavMeshCarverShape carver = shape as HavokNavMeshCarverShape; BoundingBox localBbox = null; carver.GetLocalBoundingBox(ref localBbox); localBbox.vMin.X *= carver.ScaleX; localBbox.vMin.Y *= carver.ScaleY; localBbox.vMin.Z *= carver.ScaleZ; localBbox.vMax.X *= carver.ScaleX; localBbox.vMax.Y *= carver.ScaleY; localBbox.vMax.Z *= carver.ScaleZ; EngineNavMesh.AddBoxCarver(localBbox.vMin, localBbox.vMax, carver.Position, carver.RotationMatrix, carver.IsInverted()); } // Add seed points ShapeCollection seedPoints = EditorManager.Scene.AllShapesOfType(typeof(HavokNavMeshSeedPointShape)); foreach (ShapeBase shape in seedPoints) { HavokNavMeshSeedPointShape seedPoint = shape as HavokNavMeshSeedPointShape; EngineNavMesh.AddSeedPoint(seedPoint.Position); } // Add local settings ShapeCollection localSettings = EditorManager.Scene.AllShapesOfType(typeof(HavokNavMeshLocalSettingsShape)); foreach (ShapeBase shape in localSettings) { HavokNavMeshLocalSettingsShape ls = shape as HavokNavMeshLocalSettingsShape; BoundingBox bbox = null; ls.GetLocalBoundingBox(ref bbox); bbox.vMin.X *= ls.ScaleX; bbox.vMin.Y *= ls.ScaleY; bbox.vMin.Z *= ls.ScaleZ; bbox.vMax.X *= ls.ScaleX; bbox.vMax.Y *= ls.ScaleY; bbox.vMax.Z *= ls.ScaleZ; // Nav Mesh Generation Settings EngineNavMesh.m_maxWalkableSlope = ls.MaxWalkableSlope / 180.0f * 3.14159f; // Nav Mesh Edge Matching Settings EngineNavMesh.m_maxStepHeight = ls.MaxStepHeight; EngineNavMesh.m_maxSeparation = ls.MaxSeparation; EngineNavMesh.m_maxOverhang = ls.MaxOverhang; EngineNavMesh.m_cosPlanarAlignmentAngle = (float)Math.Cos(ls.PlanarAlignmentAngle / 180.0f * 3.14159f); EngineNavMesh.m_cosVerticalAlignmentAngle = (float)Math.Cos(ls.VerticalAlignmentAngle / 180.0f * 3.14159f); EngineNavMesh.m_minEdgeOverlap = ls.MinEdgeOverlap; // Nav Mesh Simplification Settings EngineNavMesh.m_maxBorderSimplifyArea = ls.MaxBorderSimplifyArea; EngineNavMesh.m_maxConcaveBorderSimplifyArea = ls.MaxConcaveBorderSimplifyArea; EngineNavMesh.m_useHeightPartitioning = ls.UseHeightPartitioning; EngineNavMesh.m_maxPartitionHeightError = ls.MaxPartitionHeightError; // Nav Mesh Simplification Settings (Advanced) EngineNavMesh.m_minCorridorWidth = ls.MinCorridorWidth; EngineNavMesh.m_maxCorridorWidth = ls.MaxCorridorWidth; EngineNavMesh.m_holeReplacementArea = ls.HoleReplacementArea; EngineNavMesh.m_maxLoopShrinkFraction = ls.MaxLoopShrinkFraction; EngineNavMesh.m_maxBorderHeightError = ls.MaxBorderHeightError; EngineNavMesh.m_maxBorderDistanceError = ls.MaxBorderDistanceError; EngineNavMesh.m_maxPartitionSize = ls.MaxPartitionSize; EngineNavMesh.m_useConservativeHeightPartitioning = ls.UseConservativeHeightPartitioning; EngineNavMesh.m_hertelMehlhornHeightError = ls.HertelMehlhornHeightError; EngineNavMesh.m_cosPlanarityThreshold = (float)Math.Cos(ls.PlanarityThreshold / 180 * 3.14159f); EngineNavMesh.m_nonconvexityThreshold = ls.NonconvexityThreshold; EngineNavMesh.m_boundaryEdgeFilterThreshold = ls.BoundaryEdgeFilterThreshold; EngineNavMesh.m_maxSharedVertexHorizontalError = ls.MaxSharedVertexHorizontalError; EngineNavMesh.m_maxSharedVertexVerticalError = ls.MaxSharedVertexVerticalError; EngineNavMesh.m_maxBoundaryVertexHorizontalError = ls.MaxBoundaryVertexHorizontalError; EngineNavMesh.m_maxBoundaryVertexVerticalError = ls.MaxBoundaryVertexVerticalError; EngineNavMesh.m_mergeLongestEdgesFirst = ls.MergeLongestEdgesFirst; EngineNavMesh.AddLocalSettings(bbox.vMin, bbox.vMax, ls.Position, ls.RotationMatrix); } // todo: figure out how to pass class instances between here and EngineNavMesh. // basically the settings members of EngineNavMesh are reused for transferring the local settings to // EngineNavMesh. this should be harmless due to the following call which will revert any changes. SetEngineInstanceBaseProperties(); string fullSnapshotPath = Path.Combine(CSharpFramework.EditorManager.Scene.Project.ProjectDir, m_snapshotFilename); bool ret = EngineNavMesh.BuildNavMeshFromGeometry(m_saveInputSnapshot, fullSnapshotPath); EngineNavMesh.ClearGeometry(); EngineNavMesh.ClearCarvers(); EngineNavMesh.ClearSeedPoints(); EngineNavMesh.ClearLocalSettings(); EngineNavMesh.ClearDecorationCapsules(); return(ret); }
public override void GetMeshData(List <VertexPositionNormalTexture> vertices, List <ushort> indices) { int numColumns = DisplayedObject.Shape.Heights.GetLength(0); int numRows = DisplayedObject.Shape.Heights.GetLength(1); TerrainShape shape = DisplayedObject.Shape; //The terrain can be transformed arbitrarily. However, the collision against the triangles is always oriented such that the transformed local //up vector points in the same direction as the collidable surfaces. //To make sure the graphics match the terrain collision, try transforming the local space up direction into world space. Treat it as a normal- it requires an adjugate transpose, not a regular transformation. var normalTransform = Matrix3x3.AdjugateTranspose(DisplayedObject.WorldTransform.LinearTransform); var reverseWinding = BEPUutilities.Vector3.Dot(normalTransform.Up, DisplayedObject.WorldTransform.LinearTransform.Up) < 0; for (int j = 0; j < numRows; j++) { for (int i = 0; i < numColumns; i++) { VertexPositionNormalTexture v; BEPUutilities.Vector3 position, n; DisplayedObject.GetPosition(i, j, out position); shape.GetLocalNormal(i, j, out n); Matrix3x3.Transform(ref n, ref normalTransform, out n); n.Normalize(); MathConverter.Convert(ref position, out v.Position); MathConverter.Convert(ref n, out v.Normal); if (reverseWinding) { Vector3.Negate(ref v.Normal, out v.Normal); } v.TextureCoordinate = new Vector2(i, j); vertices.Add(v); if (i < numColumns - 1 && j < numRows - 1) { if (shape.QuadTriangleOrganization == QuadTriangleOrganization.BottomLeftUpperRight) { //v3 v4 //v1 v2 //v1 v2 v3 indices.Add((ushort)(numColumns * j + i)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i)); indices.Add((ushort)(numColumns * j + i + 1)); } else { indices.Add((ushort)(numColumns * j + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i)); } //v2 v4 v3 indices.Add((ushort)(numColumns * j + i + 1)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i)); indices.Add((ushort)(numColumns * (j + 1) + i + 1)); } else { indices.Add((ushort)(numColumns * (j + 1) + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i)); } } else if (shape.QuadTriangleOrganization == QuadTriangleOrganization.BottomRightUpperLeft) { //v1 v2 v4 indices.Add((ushort)(numColumns * j + i)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i + 1)); indices.Add((ushort)(numColumns * j + i + 1)); } else { indices.Add((ushort)(numColumns * j + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i + 1)); } //v1 v4 v3 indices.Add((ushort)(numColumns * j + i)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i)); indices.Add((ushort)(numColumns * (j + 1) + i + 1)); } else { indices.Add((ushort)(numColumns * (j + 1) + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i)); } } } } } }
public PaintHeightmapAction(TerrainShape terrain) : base(terrain.EngineTerrain, "Edit heightmap") { }
public override void GetMeshData(List <VertexPositionNormalTexture> vertices, List <ushort> indices) { int numColumns = DisplayedObject.Shape.Heights.GetLength(0); int numRows = DisplayedObject.Shape.Heights.GetLength(1); TerrainShape shape = DisplayedObject.Shape; //The terrain can be transformed arbitrarily. However, the collision against the triangles is always oriented such that the transformed local //up vector points in the same direction as the collidable surfaces. //To make sure the graphics match the terrain collision, see if a triangle normal faces in the same direction as the local up vector. //If not, construct the graphics with reversed winding. Vector3 a, b, c; DisplayedObject.GetPosition(0, 0, out a); DisplayedObject.GetPosition(1, 0, out b); DisplayedObject.GetPosition(0, 1, out c); Vector3 normal = Vector3.Cross(c - a, b - a); Vector3 terrainUp = new Vector3(DisplayedObject.WorldTransform.LinearTransform.M21, DisplayedObject.WorldTransform.LinearTransform.M22, DisplayedObject.WorldTransform.LinearTransform.M23); float dot; Vector3.Dot(ref normal, ref terrainUp, out dot); bool reverseWinding = dot < 0; for (int j = 0; j < numRows; j++) { for (int i = 0; i < numColumns; i++) { VertexPositionNormalTexture v; DisplayedObject.GetPosition(i, j, out v.Position); DisplayedObject.GetNormal(i, j, out v.Normal); if (reverseWinding) { Vector3.Negate(ref v.Normal, out v.Normal); } v.TextureCoordinate = new Vector2(i, j); vertices.Add(v); if (i < numColumns - 1 && j < numRows - 1) { if (shape.QuadTriangleOrganization == QuadTriangleOrganization.BottomLeftUpperRight) { //v3 v4 //v1 v2 //v1 v2 v3 indices.Add((ushort)(numColumns * j + i)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i)); indices.Add((ushort)(numColumns * j + i + 1)); } else { indices.Add((ushort)(numColumns * j + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i)); } //v2 v4 v3 indices.Add((ushort)(numColumns * j + i + 1)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i)); indices.Add((ushort)(numColumns * (j + 1) + i + 1)); } else { indices.Add((ushort)(numColumns * (j + 1) + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i)); } } else if (shape.QuadTriangleOrganization == QuadTriangleOrganization.BottomRightUpperLeft) { //v1 v2 v4 indices.Add((ushort)(numColumns * j + i)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i + 1)); indices.Add((ushort)(numColumns * j + i + 1)); } else { indices.Add((ushort)(numColumns * j + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i + 1)); } //v1 v4 v3 indices.Add((ushort)(numColumns * j + i)); if (reverseWinding) { indices.Add((ushort)(numColumns * (j + 1) + i)); indices.Add((ushort)(numColumns * (j + 1) + i + 1)); } else { indices.Add((ushort)(numColumns * (j + 1) + i + 1)); indices.Add((ushort)(numColumns * (j + 1) + i)); } } } } } }
public void update() { if (WorkingRevision == Revision || WorkingShape != null) return; int currentRevision = WorkingRevision; lock (PublicShape) { WorkingShape = new TerrainShape { TerrainBitmap = PublicShape.TerrainBitmap.Clone() as bool[,] }; } // Enqueue update-task var Task = new Task(()=>{ extractTrianglesAndOutline(); lock(PublicShape) { // Copy new triangles/outline to TerrainShape PublicShape = WorkingShape; WorkingShape = null; Revision = currentRevision; } }); Task.Start(); if (currentRevision == 1) Task.Wait(); }