/// <summary> /// Builds a ring of leafy parts (petals, sepals, etc.). /// </summary> /// <param name="meshBuilder">The mesh builder currently being added to.</param> /// <param name="offset">The position offset to apply (position at the top of the stem).</param> /// <param name="rotation">The rotation offset to apply(rotation at the top of the stem).</param> /// <param name="radius">The radius at the top of the stem.</param> /// <param name="partData">The parameters describing the part to be built.</param> private void BuildLeafRing(MeshBuilder meshBuilder, Vector3 offset, Quaternion rotation, float radius, LeafPartData partData) { //bail if this part has been disabled: if (!partData.m_Build) return; for (int i = 0; i < partData.m_Count; i++) { //calculate the rotation of this part: float yAngle = 360.0f * i / partData.m_Count; Quaternion radialRotation = rotation * Quaternion.Euler(0.0f, yAngle, 0.0f); //set the postion at the top of the stem, away from the middle: Vector3 position = offset + radialRotation * Vector3.forward * radius; //calculate a bend angle with random variation: float bendAngleRandom = Random.Range(-partData.m_BendAngleVariation, partData.m_BendAngleVariation); float bendAngle = partData.m_BendAngle + bendAngleRandom; //calculate a starting angle with random variation: float startAngleRandom = Random.Range(-partData.m_StartAngleVariation, partData.m_StartAngleVariation); float startAngle = partData.m_StartAngle + startAngleRandom; //build the leaf part: BuildLeafPart(meshBuilder, position, radialRotation, partData, false, bendAngle, startAngle); } }
/// <summary> /// Build a single leaf part (petals, sepals, etc.). /// </summary> /// <param name="meshBuilder">The mesh builder currently being added to.</param> /// <param name="offset">The position offset to apply (position at the base of the leaf part).</param> /// <param name="rotation">The rotation offset to apply.</param> /// <param name="partData">The parameters describing the part to be built.</param> /// <param name="isBackFace">Is this the back side of the part?</param> /// <param name="bendAngle">The bend angle</param> /// <param name="startAngle">The starting angle.</param> private void BuildLeafPart(MeshBuilder meshBuilder, Vector3 offset, Quaternion rotation, LeafPartData partData, bool isBackFace, float bendAngle, float startAngle) { //get the angle in radians: float bendAngleRadians = bendAngle * Mathf.Deg2Rad; //the radius of our bend (vertical) circle: float bendRadius = partData.m_Length / bendAngleRadians; //the angle increment per height segment (based on arc length): float angleInc = bendAngleRadians / partData.m_LengthSegmentCount; //get the starting angle in radians: float startAngleRadians = startAngle * Mathf.Deg2Rad; //calculate a startOffset based on the starting angle: Vector3 startOffset = Vector3.zero; startOffset.y = Mathf.Cos(startAngleRadians) * bendRadius; startOffset.z = Mathf.Sin(startAngleRadians) * bendRadius; //a multiplier to reverse some values for the back of the leaf part: float backFaceMultiplier = isBackFace ? -1.0f : 1.0f; //build the rows: for (int i = 0; i <= partData.m_LengthSegmentCount; i++) { //V coordinate: float v = (1.0f / partData.m_LengthSegmentCount) * i; //width of the current row, scaled to shape the leaf part: float localWidth = partData.m_Width * Mathf.Sin(v * Mathf.PI) * backFaceMultiplier; ////use this instead for rectangular leaves: //float localWidth = partData.m_Width * backFaceMultiplier; //offset the x value to put the origin of the leaf part at bottom-centre: float xOffset = -localWidth * 0.5f; //unit position along the edge of the vertical circle: Vector3 centrePos = Vector3.zero; centrePos.y = Mathf.Cos(angleInc * i + startAngleRadians); centrePos.z = Mathf.Sin(angleInc * i + startAngleRadians); //rotation at that position on the circle: float bendAngleDegrees = (angleInc * i + startAngleRadians) * Mathf.Rad2Deg; Quaternion bendRotation = Quaternion.Euler(bendAngleDegrees, 0.0f, 0.0f); //multiply the unit postion by the radius: centrePos *= bendRadius; //offset the position so that the base row (at the starting angle) sits on zero: centrePos -= startOffset; //calculate the normal for this row: Vector3 normal = rotation * (bendRotation * Vector3.up) * backFaceMultiplier; //build the row: for (int j = 0; j <= partData.m_WidthSegmentCount; j++) { //X position: float x = (localWidth / partData.m_WidthSegmentCount) * j; //U coordinate: float u = (1.0f / partData.m_WidthSegmentCount) * j; //calculate the final position of this quad: Vector3 position = offset + rotation * new Vector3(x + xOffset, centrePos.y, centrePos.z); Vector2 uv = new Vector2(u, v); bool buildTriangles = i > 0 && j > 0; //build the quad: BuildQuadForGrid(meshBuilder, position, uv, buildTriangles, partData.m_WidthSegmentCount + 1, normal); } } //if not building the back side of the leaf parts, and the part data does not have backfaces disabled, //rebuild this part, facing in the other direction: if (!isBackFace && partData.m_BuildBackfaces) { BuildLeafPart(meshBuilder, offset, rotation, partData, true, bendAngle, startAngle); } }
/// <summary> /// Build a single leaf part (petals, sepals, etc.). /// </summary> /// <param name="meshBuilder">The mesh builder currently being added to.</param> /// <param name="offset">The position offset to apply (position at the base of the leaf part).</param> /// <param name="rotation">The rotation offset to apply.</param> /// <param name="partData">The parameters describing the part to be built.</param> /// <param name="isBackFace">Is this the back side of the part?</param> /// <param name="bendAngle">The bend angle</param> /// <param name="startAngle">The starting angle.</param> private void BuildLeafPart(MeshBuilder meshBuilder, Vector3 offset, Quaternion rotation, LeafPartData partData, bool isBackFace, float bendAngle, float startAngle) { //get the angle in radians: float bendAngleRadians = bendAngle * Mathf.Deg2Rad; //the radius of our bend (vertical) circle: float bendRadius = partData.m_Length / bendAngleRadians; //the angle increment per height segment (based on arc length): float angleInc = bendAngleRadians / partData.m_LengthSegmentCount; //get the starting angle in radians: float startAngleRadians = startAngle * Mathf.Deg2Rad; //calculate a startOffset based on the starting angle: Vector3 startOffset = Vector3.zero; startOffset.y = Mathf.Cos(startAngleRadians) * bendRadius; startOffset.z = Mathf.Sin(startAngleRadians) * bendRadius; //a multiplier to reverse some values for the back of the leaf part: float backFaceMultiplier = isBackFace ? -1.0f : 1.0f; //build the rows: for (int i = 0; i <= partData.m_LengthSegmentCount; i++) { //V coordinate: float v = (1.0f / partData.m_LengthSegmentCount) * i; //width of the current row, scaled to shape the leaf part: float localWidth = partData.m_Width * Mathf.Sin(v * Mathf.PI) * backFaceMultiplier; ////use this instead for rectangular leaves: //float localWidth = partData.m_Width * backFaceMultiplier; //offset the x value to put the origin of the leaf part at bottom-centre: float xOffset = -localWidth * 0.5f; //unit position along the edge of the vertical circle: Vector3 centrePos = Vector3.zero; centrePos.y = Mathf.Cos(angleInc * i + startAngleRadians); centrePos.z = Mathf.Sin(angleInc * i + startAngleRadians); //rotation at that position on the circle: float bendAngleDegrees = (angleInc * i + startAngleRadians) * Mathf.Rad2Deg; Quaternion bendRotation = Quaternion.Euler(bendAngleDegrees, 0.0f, 0.0f); //multiply the unit postion by the radius: centrePos *= bendRadius; //offset the position so that the base row (at the starting angle) sits on zero: centrePos -= startOffset; //calculate the normal for this row: Vector3 normal = rotation * (bendRotation * Vector3.up) * backFaceMultiplier; //build the row: for (int j = 0; j <= partData.m_WidthSegmentCount; j++) { //X position: float x = (localWidth / partData.m_WidthSegmentCount) * j; //U coordinate: float u = (1.0f / partData.m_WidthSegmentCount) * j; //calculate the final position of this quad: Vector3 position = offset + rotation * new Vector3(x + xOffset, centrePos.y, centrePos.z); Vector2 uv = new Vector2(u, v); bool buildTriangles = i > 0 && j > 0; //build the quad: BuildQuadForGrid(meshBuilder, position, uv, buildTriangles, partData.m_WidthSegmentCount + 1, normal); } } //if not building the back side of the leaf parts, and the part data does not have backfaces disabled, //rebuild this part, facing in the other direction: if (!isBackFace && partData.m_BuildBackfaces) BuildLeafPart(meshBuilder, offset, rotation, partData, true, bendAngle, startAngle); }
/// <summary> /// Builds a ring of leafy parts (petals, sepals, etc.). /// </summary> /// <param name="meshBuilder">The mesh builder currently being added to.</param> /// <param name="offset">The position offset to apply (position at the top of the stem).</param> /// <param name="rotation">The rotation offset to apply(rotation at the top of the stem).</param> /// <param name="radius">The radius at the top of the stem.</param> /// <param name="partData">The parameters describing the part to be built.</param> private void BuildLeafRing(MeshBuilder meshBuilder, Vector3 offset, Quaternion rotation, float radius, LeafPartData partData) { //bail if this part has been disabled: if (!partData.m_Build) { return; } for (int i = 0; i < partData.m_Count; i++) { //calculate the rotation of this part: float yAngle = 360.0f * i / partData.m_Count; Quaternion radialRotation = rotation * Quaternion.Euler(0.0f, yAngle, 0.0f); //set the postion at the top of the stem, away from the middle: Vector3 position = offset + radialRotation * Vector3.forward * radius; //calculate a bend angle with random variation: float bendAngleRandom = Random.Range(-partData.m_BendAngleVariation, partData.m_BendAngleVariation); float bendAngle = partData.m_BendAngle + bendAngleRandom; //calculate a starting angle with random variation: float startAngleRandom = Random.Range(-partData.m_StartAngleVariation, partData.m_StartAngleVariation); float startAngle = partData.m_StartAngle + startAngleRandom; //build the leaf part: BuildLeafPart(meshBuilder, position, radialRotation, partData, false, bendAngle, startAngle); } }