Skip to content

Instantly share code, notes, and snippets.

@ThomasGorisse
Created September 12, 2022 17:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThomasGorisse/7e07681e6aae794982ced3bc61af7f8d to your computer and use it in GitHub Desktop.
Save ThomasGorisse/7e07681e6aae794982ced3bc61af7f8d to your computer and use it in GitHub Desktop.
package io.github.sceneview.geometries
import com.google.android.filament.Engine
import dev.romainguy.kotlin.math.TWO_PI
import dev.romainguy.kotlin.math.normalize
import io.github.sceneview.math.Direction
import io.github.sceneview.math.Position
import io.github.sceneview.math.Size
import kotlin.math.cos
import kotlin.math.sin
/**
* Creates a [Geometry] in the shape of a cylinder with the give specifications.
*
* @param radius the radius of the constructed cylinder
* @param height the height of the constructed cylinder
* @param center the center of the constructed cylinder
*/
class Cylinder(
engine: Engine,
radius: Float,
height: Float,
center: Position,
sideCount: Int = 24
) : Geometry(
engine = engine,
vertices = mutableListOf<Vertex>().apply {
val halfHeight = height / 2
val thetaIncrement = TWO_PI / sideCount
var theta = 0f
val uStep = 1.0f / sideCount
val lowerCapVertices = mutableListOf<Vertex>()
val upperCapVertices = mutableListOf<Vertex>()
val upperEdgeVertices = mutableListOf<Vertex>()
// Generate vertices along the sides of the cylinder
for (side in 0..sideCount) {
// Calculate edge vertices along bottom of cylinder
var lowerPosition = Position(
x = radius * cos(theta), y = -halfHeight, z = radius * sin(theta)
)
lowerPosition += center
add(
Vertex(
position = lowerPosition,
normal = normalize(
Direction(x = lowerPosition.x, y = 0.0f, z = lowerPosition.z)
),
uvCoordinate = UvCoordinate(x = uStep * side, y = 0.0f)
)
)
// Create a copy of lower vertex with bottom-facing normals for cap
lowerCapVertices.add(
Vertex(
position = lowerPosition,
normal = Direction(y = -1.0f),
uvCoordinate = UvCoordinate(x = uStep * side, y = 0.0f)
)
)
// Calculate edge vertices along top of cylinder
var upperPosition = Position(
x = radius * cos(theta), y = halfHeight, z = radius * sin(theta)
)
upperPosition += center
upperEdgeVertices.add(
Vertex(
position = upperPosition,
normal = normalize(
Direction(
x = upperPosition.x,
y = 0.0f,
z = upperPosition.z
)
),
uvCoordinate = UvCoordinate(x = uStep * side, y = 1.0f)
)
)
// Create a copy of upper vertex with up-facing normals for cap
upperCapVertices.add(
Vertex(
position = upperPosition,
normal = Direction(y = 1.0f),
uvCoordinate = UvCoordinate(
x = (cos(theta) + 1.0f) / 2.0f, y = (sin(theta) + 1.0f) / 2.0f
)
)
)
theta += thetaIncrement
}
addAll(upperEdgeVertices)
// Generate vertices for the centers of the caps of the cylinder
val lowerCenterIndex = size
add(
Vertex(
position = center + Size(y = -halfHeight),
normal = Direction(y = -1.0f),
uvCoordinate = UvCoordinate(x = 0.5f, y = 0.5f)
)
)
addAll(lowerCapVertices)
val upperCenterIndex = size
add(
Vertex(
position = center + Size(y = halfHeight),
normal = Direction(y = 1.0f),
uvCoordinate = UvCoordinate(x = 0.5f, y = 0.5f)
)
)
addAll(upperCapVertices)
},
submeshes = mutableListOf<Submesh>().apply {
// Create triangles for each side
for (side in 0 until sideCount) {
val bottomRight = side + 1
val topLeft = side + sideCount + 1
val topRight = side + sideCount + 2
val lowerCenterIndex = 2 * sideCount
val upperCenterIndex = lowerCenterIndex + 1 + sideCount
add(
Submesh(
// First triangle of side
side, topRight, bottomRight,
// Second triangle of side
side, topLeft, topRight,
// Add bottom cap triangle
lowerCenterIndex, lowerCenterIndex + side + 1, lowerCenterIndex + side + 2,
// Add top cap triangle
upperCenterIndex, upperCenterIndex + side + 2, lowerCenterIndex + side + 1
)
)
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment