Section 4 - Add Textured Paints
Add controls to enable the textured paint feature of Remodel-AR.
Step 1
Start with the code from “Add Export Features”.
//
// ContentView.swift
// Painty
//sw
import RemodelAR
import SwiftUI
struct ContentView: View {
@ObservedObject var model = ARStateModel()
@State private var colorIndex = 0
@State private var showStroke = true
var body: some View {
ZStack {
ZStack(alignment: .bottom, content: {
arView
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
HStack {
savePhotoButton
save3DModelButton
resetSceneButton
}
colorPicker
}
})
}
.onAppear {
model.pickColor(paint: colorItems[0])
}
}
}
private extension ContentView {
var arView: ARView {
RemodelARLib.makeARView(model: model, arMethod: .Lidar)
}
var colorItems: [WallPaint] {
let numHues = 20
var colors = [WallPaint]()
for i in 0..<numHues {
let color_8_8 = Color(hue: Double(i)/Double(numHues),
saturation: 0.8,
brightness: 0.8)
let color_8_6 = Color(hue: Double(i)/Double(numHues),
saturation: 0.8,
brightness: 0.6)
let color_8_4 = Color(hue: Double(i)/Double(numHues),
saturation: 0.8,
brightness: 0.4)
let color_8_2 = Color(hue: Double(i)/Double(numHues),
saturation: 0.8,
brightness: 0.2)
colors.append(WallPaint(id: "\(i * 4 + 1)", color: color_8_8.uiColor()))
colors.append(WallPaint(id: "\(i * 4 + 2)", color: color_8_6.uiColor()))
colors.append(WallPaint(id: "\(i * 4 + 3)", color: color_8_4.uiColor()))
colors.append(WallPaint(id: "\(i * 4 + 4)", color: color_8_2.uiColor()))
}
return colors
}
var colorPicker: some View {
ScrollView(.horizontal) {
HStack {
ForEach(0..<colorItems.count) { i in
Button(action: {
showStroke = true
colorIndex = i
model.pickColor(paint: colorItems[i])
}) {
RoundedRectangle(cornerRadius: 17)
.strokeBorder(lineWidth: (showStroke && i == colorIndex) ? 5 : 0)
.foregroundColor(.white)
.background(Color(colorItems[i].color))
.clipShape(RoundedRectangle(cornerRadius: 17))
.frame(width: 74, height: 74)
.animation(Animation.interpolatingSpring(stiffness: 60, damping: 15))
}
.onTapGesture {
self.showStroke = true
}
}
}
.padding()
}
}
}
private extension ContentView {
var savePhotoButton: some View {
Button(action: {
model.sharePhoto()
}, label: {
Image(systemName: "camera.fill")
.foregroundColor(.white)
})
.padding()
.background(Color(.sRGB, white: 0, opacity: 0.15))
.cornerRadius(10)
}
var save3DModelButton: some View {
Button(action: {
model.save3DModel()
}, label: {
Image("saveMesh")
.foregroundColor(.white)
})
.padding()
.background(Color(.sRGB, white: 0, opacity: 0.15))
.cornerRadius(10)
}
var resetSceneButton: some View {
Button(action: {
model.resetScene()
}, label: {
Image("reset")
.foregroundColor(.white)
})
.padding()
.background(Color(.sRGB, white: 0, opacity: 0.15))
.cornerRadius(10)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Step 2
Create the required @State variables.
@State private var textureIndex = -1
@State private var showTextureStroke = false
Step 3
Create a new extension to the ContentView. Add a variable to return an array of texture images.
private extension ContentView {
var textureNames: [String] {
[
"chalk",
"concrete",
"concreteLines",
"corium",
"ebdaa",
"elora",
"glostex",
"graniteArenal",
"khayalBeauty010",
"linetex",
"marmo",
"marotex",
"mashasco",
"newtex",
"rawa",
"rawaKothban",
"said",
"texture",
"tourmaline",
"worood"
]
}
var textureImages: [UIImage] {
textureNames.compactMap({ UIImage(named: $0) })
}
}
Step 4
Add a variable to the extension that creates a texture picker view
var texturePicker: some View {
ScrollView(.horizontal) {
HStack {
ForEach(0..<textureImages.count) { i in
Button(action: {
if i == textureIndex {
showTextureStroke = false
textureIndex = -1
model.pickTexture(texture: nil)
} else {
showTextureStroke = true
textureIndex = i
model.pickTexture(texture: textureImages[i])
}
}) {
RoundedRectangle(cornerRadius: 17)
.strokeBorder(lineWidth: (showTextureStroke && i == textureIndex) ? 5 : 0)
.foregroundColor(.white)
.background(Image(uiImage: textureImages[i]))
.clipShape(RoundedRectangle(cornerRadius: 17))
.frame(width: 74, height: 74)
.animation(Animation.interpolatingSpring(stiffness: 60, damping: 15))
}
.onTapGesture {
self.showTextureStroke.toggle()
}
}
}
.padding()
}
}
Step 5
Modify the view body to add the newly created texturePicker view.
var body: some View {
ZStack {
ZStack(alignment: .bottom, content: {
arView
.edgesIgnoringSafeArea(.all)
VStack {
Spacer()
HStack {
savePhotoButton
save3DModelButton
resetSceneButton
}
VStack(spacing: -20) {
texturePicker
colorPicker
}
}
})
}
.onAppear {
model.pickColor(paint: colorItems[0])
}
}
Step 6
Build and run your project. You will see a texture picker has been added to the view. Scroll through the texture picker and select different textures before tapping on the walls. You should be able to paint walls with different textures now. To remove a texture from a wall, tap the selected texture to deselect it, then tap on the wall to paint without a texture.
If at any point you need help from the Passio team, please reach out to us at support@passiolife.com
Last updated