public void AddShard(int x, int z, TETerrainShardData data) { Debug.Assert(!m_shardMapping.ContainsKey(MakeKey(x, z))); m_shardMapping[MakeKey(x, z)] = shards.Count; shards.Add(data); data.owner = this; data.shardX = x; data.shardZ = z; RecalculateMinMax(); }
static MeshInfo CreateMeshInfo(TETerrainShardData shardData, int edgeLength, int edgeQuadCount, bool quadMesh, Vector4 uvScaleOffset, string label) { var mi = new MeshInfo(); mi.mesh = CreateMesh(shardData, edgeLength, edgeQuadCount, quadMesh, uvScaleOffset, label); mi.edgeLen = edgeLength; mi.edgeQuads = edgeQuadCount; mi.uvScaleOffset = uvScaleOffset; return(mi); }
static void UpdateMesh(Mesh mesh, TETerrainShardData shard, int edgeLength, int edgeQuadCount, bool quadMesh, Vector4 uvScaleOffset, bool updateHeight, bool updateNormal) { var quadEdgeLength = edgeLength / edgeQuadCount; var vertexCount = edgeQuadCount + 1; var rcpUVScale = 1f / (float)edgeQuadCount; uvScaleOffset.x *= rcpUVScale; uvScaleOffset.y *= rcpUVScale; var heightMap = shard.heightData; var heightScaleOffset = new Vector2(1f, 0f); Vector3[] pos = updateHeight ? mesh.vertices : null; Vector3[] nrm = updateNormal ? mesh.normals : null; for (int z = 0; z < vertexCount; ++z) { for (int x = 0; x < vertexCount; ++x) { var uv = new Vector2(x * uvScaleOffset.x + uvScaleOffset.z, z * uvScaleOffset.y + uvScaleOffset.w); var h = heightMap.GetPixelBilinear(uv.x, uv.y).r *heightScaleOffset.x + heightScaleOffset.y; if (updateNormal) { // TODO: Optimize normal extraction var hp1p0 = heightMap.GetPixelBilinear(uv.x + uvScaleOffset.x, uv.y).r *heightScaleOffset.x + heightScaleOffset.y; var hm1p0 = heightMap.GetPixelBilinear(uv.x - uvScaleOffset.x, uv.y).r *heightScaleOffset.x + heightScaleOffset.y; var hp0p1 = heightMap.GetPixelBilinear(uv.x, uv.y + uvScaleOffset.y).r *heightScaleOffset.x + heightScaleOffset.y; var hp0m1 = heightMap.GetPixelBilinear(uv.x, uv.y - uvScaleOffset.y).r *heightScaleOffset.x + heightScaleOffset.y; var normal = Vector3.Cross( new Vector3(quadEdgeLength * 2f, hp1p0 - hm1p0, 0f), new Vector3(0f, hp0p1 - hp0m1, -quadEdgeLength * 2f) ).normalized; nrm[z * vertexCount + x] = normal; } if (updateHeight) { pos[z * vertexCount + x].y = h; } } } if (updateNormal) { mesh.normals = nrm; } if (updateHeight) { mesh.vertices = pos; mesh.RecalculateBounds(); } }
void GenerateInstances(Vector3 focusPos, Vector3 detailCornerPos, Vector3 shardCornerPos, TETerrainShardData shardData, RenderTexture matId, ComputeBuffer meshBuffer, ComputeBuffer argBuffer) { meshBuffer.SetCounterValue(0); detailSpawnShader.SetBuffer(0, "meshOutput", meshBuffer); detailSpawnShader.SetTexture(0, "materialID", matId); detailSpawnShader.SetTexture(0, "noiseRG", detailNoiseRG); detailSpawnShader.SetVector("focusPos", focusPos); detailSpawnShader.SetVector("detailCornerPos", detailCornerPos); detailSpawnShader.SetVector("detailCellSize", Vector4.one * detailCellSize); detailSpawnShader.SetVector("shardCornerPos", shardCornerPos); detailSpawnShader.SetVector("shardSize", Vector4.one * farMeshEdgeLength); detailSpawnShader.SetTexture(0, "heightmap", shardData.HeightTexture); detailSpawnShader.SetTexture(0, "controlmap", shardData.ControlTexture); detailSpawnShader.SetTexture(0, "colormap", shardData.ColorTexture); detailSpawnShader.SetBuffer(0, "spriteTemplates", m_detailSpriteTemplatesBuffer); detailSpawnShader.SetBuffer(0, "detailLayers", m_detailDetailLayersBuffer); detailSpawnShader.SetBuffer(0, "materialOffsetCount", m_detailMaterialStartOffsetBuffer); detailSpawnShader.SetInt("weakTemplatesOffset", 0); detailSpawnShader.SetFloat("vegetationDensityScale", vegetationDensityScale); detailSpawnShader.Dispatch(0, detailCellSize, detailCellSize, 1); //argBuffer.SetData(m_args0100); ComputeBuffer.CopyCount(meshBuffer, argBuffer, 0); // Separate dispatch just to setup indirect factors :( detailSpawnShader.SetBuffer(1, "argBuffer", argBuffer); detailSpawnShader.Dispatch(1, 1, 1, 1); }
public Mesh GetMesh(TETerrainShardData.ElementType meshType, TETerrainShardRenderElement renderElement, TETerrainShardData shardData, int edgeLength, int edgeQuadCount, Vector4 uvScaleOffset, bool forceUpdateHeight, bool forceUpdateNormal, string label, bool isTemp) { if (isTemp) { return(CreateMesh(shardData, edgeLength, edgeQuadCount, false, uvScaleOffset, label)); } MeshSet meshSet = null; if (!m_renderElementMeshMap.TryGetValue(renderElement.elementHash, out meshSet)) { meshSet = m_renderElementMeshMap[renderElement.elementHash] = new MeshSet(); meshSet.meshes = new MeshInfo[3]; } MeshInfo meshInfo = meshSet.meshes[(int)meshType]; if (meshInfo != null && meshInfo.mesh) { if (meshInfo.edgeLen == edgeLength && meshInfo.edgeQuads == edgeQuadCount && meshInfo.uvScaleOffset == uvScaleOffset) { if (forceUpdateHeight || forceUpdateNormal) { UpdateMesh(meshInfo.mesh, shardData, edgeLength, edgeQuadCount, false, uvScaleOffset, forceUpdateHeight, forceUpdateNormal); #if UNITY_EDITOR UnityEditor.EditorUtility.SetDirty(this); #endif } return(meshInfo.mesh); } Object.DestroyImmediate(meshInfo.mesh, true); } meshInfo = meshSet.meshes[(int)meshType] = CreateMeshInfo(shardData, edgeLength, edgeQuadCount, false /*meshType != TETerrainShardData.ElementType.Far*/, uvScaleOffset, label); #if UNITY_EDITOR UnityEditor.AssetDatabase.AddObjectToAsset(meshInfo.mesh, this); UnityEditor.EditorUtility.SetDirty(this); #endif return(meshInfo.mesh); }
static Mesh CreateMesh(TETerrainShardData shard, int edgeLength, int edgeQuadCount, bool quadMesh, Vector4 uvScaleOffset, string label) { var quadEdgeLength = edgeLength / (float)edgeQuadCount; var vertexCount = edgeQuadCount + 1; var rcpUVScale = 1f / (float)edgeQuadCount; uvScaleOffset.x *= rcpUVScale; uvScaleOffset.y *= rcpUVScale; var heightMap = shard.heightData; var heightScaleOffset = new Vector2(1f, 0f); var pos = new Vector3[vertexCount * vertexCount]; var nrm = new Vector3[vertexCount * vertexCount]; var uv0 = new Vector2[vertexCount * vertexCount]; for (int z = 0; z < vertexCount; ++z) { for (int x = 0; x < vertexCount; ++x) { var uv = new Vector2(x * uvScaleOffset.x + uvScaleOffset.z, z * uvScaleOffset.y + uvScaleOffset.w); // TODO: Optimize normal extraction var h = heightMap.GetPixelBilinear(uv.x, uv.y).r *heightScaleOffset.x + heightScaleOffset.y; var hp1p0 = heightMap.GetPixelBilinear(uv.x + uvScaleOffset.x, uv.y).r *heightScaleOffset.x + heightScaleOffset.y; var hm1p0 = heightMap.GetPixelBilinear(uv.x - uvScaleOffset.x, uv.y).r *heightScaleOffset.x + heightScaleOffset.y; var hp0p1 = heightMap.GetPixelBilinear(uv.x, uv.y + uvScaleOffset.y).r *heightScaleOffset.x + heightScaleOffset.y; var hp0m1 = heightMap.GetPixelBilinear(uv.x, uv.y - uvScaleOffset.y).r *heightScaleOffset.x + heightScaleOffset.y; var normal = Vector3.Cross( new Vector3(quadEdgeLength * 2f, hp1p0 - hm1p0, 0f), new Vector3(0f, hp0p1 - hp0m1, -quadEdgeLength * 2f) ).normalized; pos[z * vertexCount + x] = new Vector3(x * quadEdgeLength, h, z * quadEdgeLength); nrm[z * vertexCount + x] = normal; uv0[z * vertexCount + x] = uv; } } var idx = new int[edgeQuadCount * edgeQuadCount * (quadMesh ? 4 : 6)]; for (int z = 0, i = 0; z < edgeQuadCount; ++z) { for (int x = 0; x < edgeQuadCount; ++x) { idx[i++] = (z + 0) * vertexCount + (x + 1); idx[i++] = (z + 0) * vertexCount + (x + 0); if (quadMesh) { idx[i++] = (z + 1) * vertexCount + (x + 0); idx[i++] = (z + 1) * vertexCount + (x + 1); } else { idx[i++] = (z + 1) * vertexCount + (x + 1); idx[i++] = (z + 0) * vertexCount + (x + 0); idx[i++] = (z + 1) * vertexCount + (x + 0); idx[i++] = (z + 1) * vertexCount + (x + 1); } } } var m = new Mesh(); m.name = label; m.vertices = pos; m.normals = nrm; m.uv = uv0; m.SetIndices(idx, quadMesh ? MeshTopology.Quads : MeshTopology.Triangles, 0); return(m); }