Skip to content

Commit

Permalink
Merge pull request #2 from maxxfrazer/smooth-objects
Browse files Browse the repository at this point in the history
Smoothing options (Cone and Cylinder)
  • Loading branch information
maxxfrazer authored Dec 3, 2021
2 parents fb8ad3d + 08b371a commit e3b7990
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 35 deletions.
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ identifier_name:
warning: 1
excluded:
- RealityGeometries+Example
- Playgrounds/*
42 changes: 30 additions & 12 deletions Sources/RealityGeometries/MeshResource+Cone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ import RealityKit

extension MeshResource {
fileprivate static func coneIndices(
_ sides: Int, _ lowerCenterIndex: UInt32, _ splitFaces: Bool
_ sides: Int, _ lowerCenterIndex: UInt32, _ splitFaces: Bool,
_ smoothNormals: Bool
) -> ([UInt32], [UInt32]) {
var indices: [UInt32] = []
var materialIndices: [UInt32] = []
for side in 0..<sides {
let bottomLeft = UInt32(side)
let bottomRight = UInt32(side + 1)
let topVertex = UInt32(side + sides + 1)
let uiSides = UInt32(sides) * (smoothNormals ? 1 : 2)
for side in 0..<UInt32(sides) {
let uiSideSmooth = side * (smoothNormals ? 1 : 2)
let bottomLeft = uiSideSmooth
let bottomRight = uiSideSmooth + 1
let topVertex = side + uiSides + 1

// First triangle of side
indices.append(contentsOf: [bottomLeft, topVertex, bottomRight])

// Add bottom cap triangle
indices.append(contentsOf: [0, UInt32(side) + 1, UInt32(side) + 2].map { $0 + lowerCenterIndex })
indices.append(contentsOf: [0, side + 1, side + 2].map { $0 + lowerCenterIndex })

if splitFaces {
materialIndices.append(0)
Expand All @@ -39,12 +42,14 @@ extension MeshResource {
var combinedVerts: [CompleteVertex]?
var indices: [UInt32]?
var materialIndices: [UInt32]?
var smoothNormals: Bool

mutating func calculateDetails(
height: Float, sides: Int, splitFaces: Bool
) -> Bool {
let halfHeight = height / 2
var vertices = lowerEdge
print(lowerEdge.count)
vertices.append(contentsOf: upperEdge)

let lowerCenterIndex = UInt32(vertices.count)
Expand All @@ -55,14 +60,14 @@ extension MeshResource {
vertices.append(contentsOf: lowerCap)
self.combinedVerts = vertices
(self.indices, self.materialIndices) = coneIndices(
sides, lowerCenterIndex, splitFaces
sides, lowerCenterIndex, splitFaces, self.smoothNormals
)
return true
}
}

fileprivate static func coneVertices(
_ sides: Int, _ radius: Float, _ height: Float
_ sides: Int, _ radius: Float, _ height: Float, _ smoothNormals: Bool = false
) -> ConeVertices {
var theta: Float = 0
let thetaInc = 2 * .pi / Float(sides)
Expand All @@ -85,9 +90,19 @@ extension MeshResource {
let lowerPosition: SIMD3<Float> = [radius * cosTheta, -height / 2, radius * sinTheta]
let coneBottomNormal: SIMD3<Float> = [coneNormY * cosTheta, coneNormX, coneNormY * sinTheta]

if side != 0, !smoothNormals {
vertices.append(CompleteVertex(
position: lowerPosition,
normal: [coneNormY * cos(theta - thetaInc / 2), coneNormX, coneNormY * sin(theta - thetaInc / 2)],
uv: [uStep * Float(side), 0]
))
}

let bottomVertex = CompleteVertex(
position: lowerPosition,
normal: coneBottomNormal,
normal: smoothNormals ? coneBottomNormal : [
coneNormY * cos(theta + thetaInc / 2), coneNormX, coneNormY * sin(theta + thetaInc / 2)
],
uv: [uStep * Float(side), 0]
)

Expand Down Expand Up @@ -115,7 +130,7 @@ extension MeshResource {
theta += thetaInc
}
return .init(
lowerEdge: vertices, upperEdge: upperEdgeVertices, lowerCap: lowerCapVertices
lowerEdge: vertices, upperEdge: upperEdgeVertices, lowerCap: lowerCapVertices, smoothNormals: smoothNormals
)
}

Expand All @@ -125,15 +140,18 @@ extension MeshResource {
/// - height: Height of the code from base to tip
/// - sides: How many sides the cone should have, default is 24, minimum is 3
/// - splitFaces: A Boolean you set to true to indicate that vertices shouldn’t be merged.
/// - smoothNormals: Whether to smooth the normals. Good for high numbers of sides to give a rounder shape.
/// Smoothed normal setting also reduces the total number of vertices
/// - Returns: A cone mesh
public static func generateCone(
radius: Float, height: Float, sides: Int = 24, splitFaces: Bool = false
radius: Float, height: Float, sides: Int = 24, splitFaces: Bool = false,
smoothNormals: Bool
) throws -> MeshResource {
assert(sides > 2, "Sides must be an integer above 2")
// first vertices added to vertices will be bottom edges
// upperEdgeVertices are all top edge vertices of the cylinder
// lowerCapVertices are the bottom edge vertices
var coneVerties = coneVertices(sides, radius, height)
var coneVerties = coneVertices(sides, radius, height, smoothNormals)
if !coneVerties.calculateDetails(
height: height, sides: sides, splitFaces: splitFaces
) {
Expand Down
64 changes: 41 additions & 23 deletions Sources/RealityGeometries/MeshResource+Cylinder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import RealityKit
extension MeshResource {
fileprivate static func cylinderIndices(
_ sides: Int, _ lowerCenterIndex: UInt32,
_ upperCenterIndex: UInt32, _ splitFaces: Bool
_ upperCenterIndex: UInt32, _ splitFaces: Bool, _ smoothNormals: Bool
) -> ([UInt32], [UInt32]) {
var indices: [UInt32] = []
var materialIndices: [UInt32] = []
let uiSides = UInt32(sides) * (smoothNormals ? 1 : 2)
for side in 0..<sides {
let bottomLeft = UInt32(side)
let bottomRight = UInt32(side + 1)
let topLeft = UInt32(side + sides + 1)
let topRight = UInt32(side + sides + 2)
let uiSide = UInt32(side) * (smoothNormals ? 1 : 2)
let bottomLeft = uiSide
let bottomRight = uiSide + 1
let topLeft = uiSide + uiSides + 1
let topRight = uiSide + uiSides + 2

// First triangle of side
indices.append(contentsOf: [bottomLeft, topRight, bottomRight])
Expand Down Expand Up @@ -49,6 +51,7 @@ extension MeshResource {
var combinedVerts: [CompleteVertex]?
var indices: [UInt32]?
var materialIndices: [UInt32]?
var smoothNormals: Bool
mutating func calculateCylinderDetails(height: Float, sides: Int, splitFaces: Bool) -> Bool {
let halfHeight = height / 2
var combinedVerts: [CompleteVertex] = lowerEdge
Expand All @@ -67,17 +70,16 @@ extension MeshResource {
combinedVerts.append(contentsOf: upperCap)
self.combinedVerts = combinedVerts
(self.indices, self.materialIndices) = cylinderIndices(
sides, lowerCenterIndex, upperCenterIndex, splitFaces
sides, lowerCenterIndex, upperCenterIndex, splitFaces, self.smoothNormals
)
return true
}
}

fileprivate static func cylinderVertices(
_ sides: Int, _ radius: Float, _ height: Float
_ sides: Int, _ radius: Float, _ height: Float, _ smoothNormals: Bool = false
) -> CylinderVertices {
var theta: Float = 0
let normalizeMult = 1 / sqrt(radius)
let thetaInc = 2 * .pi / Float(sides)
let uStep: Float = 1 / Float(sides)
// first vertices added will be bottom edges
Expand All @@ -91,17 +93,23 @@ extension MeshResource {

// create vertices for all sides of the cylinder
for side in 0...sides {
let cosTheta = cos(theta)
let sinTheta = sin(theta)

let lowerPosition: SIMD3<Float> = [
radius * cosTheta, -height / 2, radius * sinTheta
]
let cosTheta = cos(theta); let sinTheta = sin(theta)

let lowerPosition: SIMD3<Float> = [radius * cosTheta, -height / 2, radius * sinTheta]
if side != 0, !smoothNormals {
vertices.append(CompleteVertex(
position: lowerPosition,
normal: [cos(theta - thetaInc / 2), 0, sin(theta - thetaInc / 2)],
uv: [uStep * Float(side), 0]
))
}

let bottomVertex = CompleteVertex(
position: lowerPosition,
normal: [lowerPosition.x, 0, lowerPosition.z] * normalizeMult,
uv: [uStep * Float(side), 0]
normal: [
cos(theta + (smoothNormals ? 0 : thetaInc / 2)), 0,
sin(theta + (smoothNormals ? 0 : thetaInc / 2))
], uv: [uStep * Float(side), 0]
)

// add vertex for bottom side of cylinder, facing out
Expand All @@ -113,23 +121,30 @@ extension MeshResource {
normal: [0, -1, 0], uv: [cosTheta + 1, sinTheta + 1] / 2)
)

if side != 0, !smoothNormals {
upperEdgeVertices.append(CompleteVertex(
position: lowerPosition + [0, height, 0],
normal: [cos(theta - thetaInc / 2), 0, sin(theta - thetaInc / 2)],
uv: [uStep * Float(side), 1]
))
}

// add vertex for top side facing out
let topVertex = CompleteVertex(
position: bottomVertex.position + [0, height, 0],
position: lowerPosition + [0, height, 0],
normal: bottomVertex.normal, uv: [uStep * Float(side), 1]
)
upperEdgeVertices.append(topVertex)

upperCapVertices.append(CompleteVertex(
position: topVertex.position,
normal: [0, 1, 0], uv: [cosTheta + 1, sinTheta + 1] / 2)
position: topVertex.position, normal: [0, 1, 0], uv: [cosTheta + 1, sinTheta + 1] / 2)
)

theta += thetaInc
}
return CylinderVertices(
lowerEdge: vertices, upperEdge: upperEdgeVertices,
lowerCap: lowerCapVertices, upperCap: upperCapVertices
lowerEdge: vertices, upperEdge: upperEdgeVertices, lowerCap: lowerCapVertices,
upperCap: upperCapVertices, smoothNormals: smoothNormals
)
}

Expand All @@ -139,17 +154,20 @@ extension MeshResource {
/// - height: Height of the cylinder
/// - sides: How many sides the cone should have, default is 24, minimum is 3
/// - splitFaces: A Boolean you set to true to indicate that vertices shouldn’t be merged.
/// - smoothNormals: Whether to smooth the normals. Good for high numbers of sides to give a rounder shape.
/// Smoothed normal setting also reduces the total number of vertices
/// - Returns: A cylinder mesh.
public static func generateCylinder(
radius: Float, height: Float, sides: Int = 24, splitFaces: Bool = false
radius: Float, height: Float, sides: Int = 24,
splitFaces: Bool = false, smoothNormals: Bool = false
) throws -> MeshResource {
assert(sides > 2, "Sides must be an integer above 2")

// first vertices added to vertices will be bottom edges
// upperEdgeVertices are all top edge vertices of the cylinder
// lowerCapVertices are the bottom edge vertices
// upperCapVertices are the top edge vertices
var cylinderVerts = cylinderVertices(sides, radius, height)
var cylinderVerts = cylinderVertices(sides, radius, height, smoothNormals)
if !cylinderVerts.calculateCylinderDetails(
height: height, sides: sides, splitFaces: splitFaces
) {
Expand Down

0 comments on commit e3b7990

Please sign in to comment.