private void OnEnable() { return; Debug.Assert(m_compute is null, "The grass compute shader is null", gameObject); Debug.Assert(material is null, "The material is null", gameObject); DebugHardware(); if (initialized) { OnDisable(); } initialized = true; var positions = sourceMesh.vertices; var tris = sourceMesh.triangles; var vertices = new SourceVertex[positions.Length]; for (var i = 0; i < vertices.Length; i++) { vertices[i] = new SourceVertex { position = positions[i] }; } var numSourceTriangles = tris.Length / 3; sourceVertBuffer = new ComputeBuffer(vertices.Length, SOURCE_VERT_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); sourceVertBuffer.SetData(vertices); sourceTriBuffer = new ComputeBuffer(tris.Length, SOURCE_TRI_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); sourceTriBuffer.SetData(tris); drawBuffer = new ComputeBuffer(numSourceTriangles * Mathf.CeilToInt(grassSettings.SettingsData.grassPerVertex * 0.25f), DRAW_STRIDE, ComputeBufferType.Append); drawBuffer.SetCounterValue(0); argsBuffer = new ComputeBuffer(1, INDIRECT_ARGS_STRIDE, ComputeBufferType.IndirectArguments); m_grassKernelId = m_compute.FindKernel("Main"); m_compute.SetBuffer(m_grassKernelId, m_sourceVerticesPropertyId, sourceVertBuffer); m_compute.SetBuffer(m_grassKernelId, m_sourceTrianglesPropertyId, sourceTriBuffer); m_compute.SetBuffer(m_grassKernelId, m_drawTrianglesPropertyId, drawBuffer); m_compute.SetBuffer(m_grassKernelId, m_indirectArgsBufferPropertyId, argsBuffer); m_compute.SetInt(m_numSourceTrianglesPropertyId, numSourceTriangles); material.SetBuffer(m_drawTrianglesPropertyId, drawBuffer); m_compute.GetKernelThreadGroupSizes(m_grassKernelId, out var threadGroupSize, out _, out _); dispatchSize = Mathf.CeilToInt((float)numSourceTriangles / threadGroupSize); localBounds = sourceMesh.bounds; localBounds.Expand(1); }
/// <summary> /// Indicates whether the current <see cref="DirectedWeightedEdge{TVertex}"/> /// is equal to another <see cref="DirectedWeightedEdge{TVertex}"/>. /// </summary> /// <param name="other"> /// The <see cref="DirectedWeightedEdge{TVertex}"/> to compare with this /// object. /// </param> /// <returns> /// <see langword="true"/> if the other /// <see cref="DirectedWeightedEdge{TVertex}"/> is equal to this /// <see cref="DirectedWeightedEdge{TVertex}"/>; otherwise, /// <see langword="false"/>. /// </returns> /// <seealso cref="IEquatable{T}.Equals(T)"/> public bool Equals(DirectedWeightedEdge <TVertex> other) { if (other == null) { return(false); } return((SourceVertex.Equals(other.SourceVertex) && DestinationVertex.Equals(other.DestinationVertex)) && Weight.Equals(other.Weight)); }
/// <inheritdoc /> public override int GetHashCode() { var hashCode = 0; unchecked { hashCode ^= SourceVertex.GetHashCode() * 31; hashCode ^= TargetVertex.GetHashCode() * 31; hashCode ^= Weight.GetHashCode() * 31; } return(hashCode); }
public void ModifyPointAt(int index, Color newColor, Vector2 newUV) { SourceVertex V = vertices[index]; vertices[index] = new SourceVertex() { position = V.position, normal = V.normal, uv = newUV, color = new Vector3(newColor.r, newColor.g, newColor.b) }; DEBUG_uvs[index] = newUV; DEBUG_colors[index] = newColor; dirty = true; //RebuildDebugMesh(); }
private void Initialize() { Debug.Assert(m_computeShader == null, "Compute Shader Is Missing Or Invalid!", gameObject); Debug.Assert(m_material == null, "Flower Material Is Missing Or Invalid!", gameObject); Debug.Assert(m_sourceMesh == null, "Source Mesh Is Missing Or Invalid!", gameObject); var meshVertPositions = m_sourceMesh.vertices; var meshTris = m_sourceMesh.triangles; var meshVertices = new SourceVertex[meshVertPositions.Length]; for (var i = 0; i < meshVertices.Length; i++) { meshVertices[i] = new SourceVertex { position = meshVertPositions[i] }; } var numSourceTriangles = meshTris.Length / 3; m_sourceVertBuffer = new ComputeBuffer(meshVertices.Length, SOURCE_VERT_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); m_sourceVertBuffer.SetData(meshVertices); m_sourceTriBuffer = new ComputeBuffer(meshTris.Length, SOURCE_TRI_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); m_sourceTriBuffer.SetData(meshTris); m_drawBuffer = new ComputeBuffer(numSourceTriangles, DRAW_STRIDE, ComputeBufferType.Append); m_argsBuffer = new ComputeBuffer(1, INDIRECT_ARGS_STRIDE, ComputeBufferType.IndirectArguments); m_kernelId = m_computeShader.FindKernel("Main"); m_computeShader.SetBuffer(m_kernelId, m_sourceVerticesPropertyId, m_sourceVertBuffer); m_computeShader.SetBuffer(m_kernelId, m_sourceTrianglesPropertyId, m_sourceTriBuffer); m_computeShader.SetBuffer(m_kernelId, m_drawTrianglesPropertyId, m_drawBuffer); m_computeShader.SetBuffer(m_kernelId, m_indirectArgsBufferPropertyId, m_argsBuffer); m_computeShader.SetInt(m_numSourceTrianglesPropertyId, numSourceTriangles); m_material.SetBuffer(m_drawTrianglesPropertyId, m_drawBuffer); m_computeShader.GetKernelThreadGroupSizes(m_kernelId, out var threadGroupSize, out _, out _); m_dispatchSize = Mathf.CeilToInt((float)numSourceTriangles / threadGroupSize); m_localBounds = m_sourceMesh.bounds; m_localBounds.Expand(1); }
public void AddVertex(Vector3 position) { SourceVertex newVertex = new SourceVertex(position, Vertices.Count); //add edges between vertices if connectable foreach (SourceVertex vertex in Vertices) { if (World.IsValidPath(vertex.Position, position)) { float distance = vertex.Position.Distance(position); vertex.Edges.AddLast(new Edge(newVertex, distance)); newVertex.Edges.AddLast(new Edge(vertex, distance)); } } Vertices.AddLast(newVertex); }
private static void DecomposeMesh(Mesh mesh, int subMeshIndex, out SourceVertex[] vertices, out int[] indices) { SubMeshDescriptor subMeshDescriptor = mesh.GetSubMesh(subMeshIndex); Vector3[] meshVertices = mesh.vertices; Vector2[] meshUVs = mesh.uv; int[] meshIndices = mesh.triangles; vertices = new SourceVertex[subMeshDescriptor.vertexCount]; indices = new int[subMeshDescriptor.indexCount]; for (int i = 0; i < mesh.vertexCount; ++i) { int wholeMeshIndex = i + subMeshDescriptor.firstVertex; vertices[i] = new SourceVertex { position = meshVertices[wholeMeshIndex], uv = meshUVs[wholeMeshIndex] }; } for (int i = 0; i < subMeshDescriptor.indexCount; ++i) { indices[i] = meshIndices[i + subMeshDescriptor.indexStart] + subMeshDescriptor.baseVertex - subMeshDescriptor.firstVertex; } }
public Path Search(Vector3 source, Vector3 destination) { //temporary add source and destination as vertices AddVertex(source); AddVertex(destination); int sourceIndex = Vertices.Count - 2; int destIndex = Vertices.Count - 1; float[] dist = new float[Vertices.Count]; SourceVertex[] previous = new SourceVertex[Vertices.Count]; SourceVertex[] verticesArray = Vertices.ToArray(); MinHeap heap = new MinHeap(verticesArray.Length); LinkedList<Vector3> result = new LinkedList<Vector3>(); //Dijkstra's algorithm //initialize everything to maximum distance for (int i = 0; i < dist.Length; i++) dist[i] = float.MaxValue; //set source distance to 0 dist[sourceIndex] = 0; //add all vertices to heap for (int i = 0; i < dist.Length; i++) heap.Add(dist[i], i); while (heap.Count > 0) { int u = heap.Poll().Value; if (u == destIndex) { //destination reached result.AddFirst(verticesArray[u].Position); while (previous[u] != null) { //backtrack to source result.AddFirst(previous[u].Position); u = previous[u].Index; } break; } //no valid paths if (dist[u] == float.MaxValue) break; //iterate through all edges foreach (Edge edge in verticesArray[u].Edges) { int v = edge.Destination.Index; //only check v if v is still in the heap if (!heap.ContainsValue(v)) continue; //calculate distance of current path float alt = dist[u] + edge.Distance; if (alt < dist[v]) { //current path is shorter dist[v] = alt; previous[v] = verticesArray[u]; heap.Update(alt, v); } } } //remove source and destination from vertices list RemoveLastVertex(); RemoveLastVertex(); if (result.Count == 0) return null; return new Path(result.ToArray()); }
public Edge(SourceVertex dest, float dist) { this.Destination = dest; this.Distance = dist; }
private void OnEnable() { // If initialized, call on disable to clean things up if (initialized) { OnDisable(); } initialized = true; // Grab data from the source mesh Vector3[] positions = sourceMesh.vertices; Vector2[] uvs = sourceMesh.uv; int[] tris = sourceMesh.triangles; // Create the data to upload to the source vert buffer SourceVertex[] vertices = new SourceVertex[positions.Length]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = new SourceVertex() { position = positions[i], uv = uvs[i], }; } int numTriangles = tris.Length / 3; // The number of triangles in the source mesh is the index array / 3 // Create compute buffers // The stride is the size, in bytes, each object in the buffer takes up sourceVertBuffer = new ComputeBuffer(vertices.Length, SOURCE_VERT_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); sourceVertBuffer.SetData(vertices); sourceTriBuffer = new ComputeBuffer(tris.Length, SOURCE_TRI_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); sourceTriBuffer.SetData(tris); // We split each triangle into three new ones drawBuffer = new ComputeBuffer(numTriangles * 3, DRAW_STRIDE, ComputeBufferType.Append); drawBuffer.SetCounterValue(0); // Set the count to zero argsBuffer = new ComputeBuffer(1, ARGS_STRIDE, ComputeBufferType.IndirectArguments); // The data in the args buffer corresponds to: // 0: vertex count per draw instance. We will only use one instance // 1: instance count. One // 2: start vertex location if using a Graphics Buffer // 3: and start instance location if using a Graphics Buffer argsBuffer.SetData(new int[] { 0, 1, 0, 0 }); // Cache the kernel IDs we will be dispatching idPyramidKernel = pyramidComputeShader.FindKernel("Main"); idTriToVertKernel = triToVertComputeShader.FindKernel("Main"); // Set data on the shaders pyramidComputeShader.SetBuffer(idPyramidKernel, "_SourceVertices", sourceVertBuffer); pyramidComputeShader.SetBuffer(idPyramidKernel, "_SourceTriangles", sourceTriBuffer); pyramidComputeShader.SetBuffer(idPyramidKernel, "_DrawTriangles", drawBuffer); pyramidComputeShader.SetInt("_NumSourceTriangles", numTriangles); triToVertComputeShader.SetBuffer(idTriToVertKernel, "_IndirectArgsBuffer", argsBuffer); material.SetBuffer("_DrawTriangles", drawBuffer); // Calculate the number of threads to use. Get the thread size from the kernel // Then, divide the number of triangles by that size pyramidComputeShader.GetKernelThreadGroupSizes(idPyramidKernel, out uint threadGroupSize, out _, out _); dispatchSize = Mathf.CeilToInt((float)numTriangles / threadGroupSize); // Get the bounds of the source mesh and then expand by the pyramid height localBounds = sourceMesh.bounds; localBounds.Expand(pyramidHeight); }
/// <summary> /// Gets a hash code for this <see cref="DirectedWeightedEdge{TVertex}"/>. /// </summary> /// <returns> /// A hash code for the current <see cref="DirectedWeightedEdge{TVertex}"/>. /// </returns> public override int GetHashCode() { return(SourceVertex.GetHashCode() ^ DestinationVertex.GetHashCode() ^ Weight.GetHashCode()); }
private void Start() { // 创建一个较大的 Mesh, 用于存放更多的草地. sourceMesh = gameObject.GetComponent <CreatePlaneMesh>().CreatePlane(); sourceMesh.name = "Plane Sub"; Vector3[] positions = sourceMesh.vertices; int[] tris = sourceMesh.triangles; SourceVertex[] vertices = new SourceVertex[positions.Length]; for (int i = 0; i < vertices.Length; i++) { vertices[i] = new SourceVertex() { position = positions[i], }; } int numSourceTriangles = tris.Length / 3; // 初始化 Buffer. sourceVertexBuffer = new ComputeBuffer(vertices.Length, SOURCE_VERT_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); sourceVertexBuffer.SetData(vertices); sourceTriangleBuffer = new ComputeBuffer(tris.Length, SOURCE_TRI_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); sourceTriangleBuffer.SetData(tris); drawTriangleBuffer = new ComputeBuffer(numSourceTriangles * (2 * grassSettings.maxBladeSegments - 1), DRAW_STRIDE, ComputeBufferType.Append); drawTriangleBuffer.SetCounterValue(0); argsBuffer = new ComputeBuffer(1, INDIRECT_ARGS_STRIDE, ComputeBufferType.IndirectArguments); // 设置数据. kernelIndex = grassComputeShader.FindKernel("CSMain"); // 设置 Buffer. grassComputeShader.SetBuffer(kernelIndex, "_SourceVertexBuffer", sourceVertexBuffer); grassComputeShader.SetBuffer(kernelIndex, "_SourceTriangleBuffer", sourceTriangleBuffer); grassComputeShader.SetBuffer(kernelIndex, "_DrawTriangles", drawTriangleBuffer); grassComputeShader.SetBuffer(kernelIndex, "_IndirectArgsBuffer", argsBuffer); // 设置数量. grassComputeShader.SetInt("_NumSourceTriangles", numSourceTriangles); // 设置草地数据. grassComputeShader.SetFloat("_BladeWidth", grassSettings.bladeWidth); grassComputeShader.SetFloat("_BladeWidthRandom", grassSettings.bladeWidthRandom); grassComputeShader.SetFloat("_BladeHeight", grassSettings.bladeHeight); grassComputeShader.SetFloat("_BladeHeightRandom", grassSettings.bladeHeightRandom); grassComputeShader.SetFloat("_BendRotationRandom", grassSettings.bendRotationRandom); grassComputeShader.SetFloat("_BladeForward", grassSettings.bladeForward); grassComputeShader.SetTexture(kernelIndex, "_WindTexture", grassSettings.windTexture); grassComputeShader.SetVector("_WindTextureST", grassSettings.windTextureST); grassComputeShader.SetFloat("_WindStrength", grassSettings.windStrength); grassComputeShader.SetVector("_WindFrequency", grassSettings.windFrequency); grassMaterial.SetBuffer("_DrawTriangles", drawTriangleBuffer); // 计算线程分配. grassComputeShader.GetKernelThreadGroupSizes(kernelIndex, out uint threadGroupSize, out _, out _); dispatchSize = Mathf.CeilToInt((float)numSourceTriangles / threadGroupSize); localBounds = sourceMesh.bounds; localBounds.Expand(1); }
/// <inheritdoc /> public override string ToString() { return(string.Format("{0}.{1}[Source={2}, Target={3}, Weight={4}]", GetType().Namespace, GetType().Name, SourceVertex?.ToString(), TargetVertex?.ToString(), Weight?.ToString())); }
private void OnEnable() { // If initialized, call on disable to clean things up if (m_Initialized) { OnDisable(); } // Setup compute shader and material manually // Don't do anything if resources are not found, // or no vertex is put on the mesh. if (grassPainter == null || sourceMesh == null || computeShader == null || material == null) { return; } sourceMesh = grassPainter.mesh; // update mesh if (sourceMesh.vertexCount == 0) { return; } m_Initialized = true; // Instantiate the shaders so they can point to their own buffers m_InstantiatedComputeShader = Instantiate(computeShader); m_InstantiatedMaterial = Instantiate(material); // Grab data from the source mesh Vector3[] positions = sourceMesh.vertices; Vector3[] normals = sourceMesh.normals; Vector2[] uvs = sourceMesh.uv; Color[] colors = sourceMesh.colors; // Create the data to upload to the source vert buffer SourceVertex[] vertices = new SourceVertex[positions.Length]; for (int i = 0; i < vertices.Length; i++) { Color color = colors[i]; vertices[i] = new SourceVertex() { position = positions[i], normal = normals[i], uv = uvs[i], color = new Vector3(color.r, color.g, color.b) // Color --> Vector3 }; } int numSourceVertices = vertices.Length; // Each segment has two points int maxBladesPerVertex = Mathf.Max(1, m_AllowedBladesPerVertex); int maxSegmentsPerBlade = Mathf.Max(1, m_AllowedSegmentsPerBlade); int maxBladeTriangles = maxBladesPerVertex * ((maxSegmentsPerBlade - 1) * 2 + 1); // Create compute buffers // The stride is the size, in bytes, each object in the buffer takes up m_SourceVertBuffer = new ComputeBuffer(vertices.Length, SOURCE_VERT_STRIDE, ComputeBufferType.Structured, ComputeBufferMode.Immutable); m_SourceVertBuffer.SetData(vertices); m_DrawBuffer = new ComputeBuffer(numSourceVertices * maxBladeTriangles, DRAW_STRIDE, ComputeBufferType.Append); m_DrawBuffer.SetCounterValue(0); m_ArgsBuffer = new ComputeBuffer(1, INDIRECT_ARGS_STRIDE, ComputeBufferType.IndirectArguments); // Cache the kernel IDs we will be dispatching m_IdGrassKernel = m_InstantiatedComputeShader.FindKernel("Main"); // Set buffer data m_InstantiatedComputeShader.SetBuffer(m_IdGrassKernel, "_SourceVertices", m_SourceVertBuffer); m_InstantiatedComputeShader.SetBuffer(m_IdGrassKernel, "_GrassTriangles", m_DrawBuffer); m_InstantiatedComputeShader.SetBuffer(m_IdGrassKernel, "_IndirectArgsBuffer", m_ArgsBuffer); // Set vertex data m_InstantiatedComputeShader.SetInt("_NumSourceVertices", numSourceVertices); m_InstantiatedComputeShader.SetInt("_MaxBladesPerVertex", maxBladesPerVertex); m_InstantiatedComputeShader.SetInt("_MaxSegmentsPerBlade", maxSegmentsPerBlade); m_InstantiatedMaterial.SetBuffer("_GrassTriangles", m_DrawBuffer); m_InstantiatedMaterial.SetShaderPassEnabled("ShadowCaster", castShadow); if (overrideMaterial) { m_InstantiatedMaterial.SetColor("_TopColor", topColor); m_InstantiatedMaterial.SetColor("_BottomColor", bottomColor); } // Calculate the number of threads to use. Get the thread size from the kernel // Then, divide the number of triangles by that size m_InstantiatedComputeShader.GetKernelThreadGroupSizes(m_IdGrassKernel, out uint threadGroupSize, out _, out _); m_DispatchSize = Mathf.CeilToInt((float)numSourceVertices / threadGroupSize); // Get the bounds of the source mesh and then expand by the maximum blade width and height m_LocalBounds = sourceMesh.bounds; m_LocalBounds.Expand(Mathf.Max(grassHeight + grassRandomHeight, grassWidth)); }