Using a MTLTexture as the environment map of a SCNScene
Lighting SCN Environment with an MTK texture
Using Xcode 13.3.1 on macOS 12.3.1 for iOS 15.4 app.
The trick is, the environment lighting requires a cube texture, not a flat image.
- Create 6 square images for MetalKit cube texture
- in Xcode
Assets
folder create Cube Texture Set
- place textures to their corresponding slots
- mirror images horizontally and vertically, if needed
Paste the code:
import ARKit
import MetalKit
class ViewController: UIViewController {
@IBOutlet var sceneView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let imageName = "CubeTextureSet"
let textureLoader = MTKTextureLoader(device: sceneView.device!)
let environmentMap = try! textureLoader.newTexture(name: imageName,
scaleFactor: 2,
bundle: .main,
options: nil)
let daeScene = SCNScene(named: "art.scnassets/testCube.dae")!
let model = daeScene.rootNode.childNode(withName: "polyCube",
recursively: true)!
scene.lightingEnvironment.contents = environmentMap
scene.lightingEnvironment.intensity = 2.5
scene.background.contents = environmentMap
sceneView.scene = scene
sceneView.allowsCameraControl = true
scene.rootNode.addChildNode(model)
}
}
Apply metallic materials to models. Now MTL environment lighting is On.
If you need a procedural skybox texture – use MDLSkyCubeTexture class.
Also, this post may be useful for you.
SceneKit – Loading HDR or EXR lightingEnvironment has no effect
I usually use a Cube Texture Set, where each of 6 images is square (height == width)
.
Also, the following cube map representations are supported:
- Vertical strip as single image
(height == 6 * width)
- Horizontal strip as single image
(6 * height == width)
- Spherical projection as single image
(2 * height == width)
Here's a SwiftUI code:
func makeUIView(context: Context) -> SCNView {
let sceneView = SCNView(frame: .zero)
sceneView.scene = SCNScene()
// if EXR or HDR is 2:1 spherical map, it really meets the requirements
sceneView.scene?.lightingEnvironment.contents = UIImage(named: "std.exr")
sceneView.backgroundColor = .black
sceneView.autoenablesDefaultLighting = true
sceneView.allowsCameraControl = true
let node = SCNNode()
node.geometry = SCNSphere(radius: 0.1)
node.geometry?.firstMaterial?.lightingModel = .physicallyBased
node.geometry?.firstMaterial?.metalness.contents = 1.0
sceneView.scene?.rootNode.addChildNode(node)
return sceneView
}
Pay particular attention – you need .physicallyBased
lighting model to get HDR or EXR reflections.
And let's set it for BG:
sceneView.scene?.background.contents = UIImage(named: "std.exr")
Why your .exr
doesn't work?
The solutions is simple: delete your .exr
from project, empty the Trash and after that drag-and-drop .exr
file, in Choose options for adding these files
window choose Add to targets
:
Now your .exr
must work.
SceneKit – How can I programmatically adjust 'Sun elevation' parameter?
You can simultaneously use MDL Sky Box for scene lighting and for BG:
sceneView.scene?.background.contents = MDLSkyCubeTexture(name: "procedural sky",
channelEncoding: .float32,
textureDimensions: vector_int2(512,512),
turbidity: 0.12,
sunElevation: 1.00,
upperAtmosphereScattering: 0.05,
groundAlbedo: 0.32)
sceneView.scene?.lightingEnvironment.contents = sceneView.scene?.background.contents
sceneView.scene?.lightingEnvironment.intensity = 2.0
access particular set of pixels MTLTexture in metal
Yes, as a look at the MTLTexture
documentation would have shown you. You can use one of the getBytes()
methods to copy a region of texture data out to a buffer, and one of the replace()
methods to replace a region of the texture's pixel with data from a buffer you supply.
Related Topics
Healthkit Error: Missing Com.Apple.Developer.Healthkit Entitlement
Swift Uisearchcontroller Wired Up in Core Data Project, App Runs, But Search Not Updating
Sprite-Kit: Moving an Element in Circular Path
Resetting Zone Allocator with Allocations Still Alive
Swift Draw Shadow to a Uibezier Path
Building User Database Model in Firebase
How to Save Cgimage to Data in Swift
Uiimage Created from Mtkview Results in Color/Opacity Differences
Enumerateobjectsusingblock in Swift
Swift Calling Static Methods: Type(Of: Self) VS Explicit Class Name
Swift Struct Doesn't Conform to Protocol Equatable
What Is Import Func, Struct, Class, and @_Exported in Swift
Collection View Cell Button Not Triggering Action
Is Code Coverage Already Working for Swift
Bitwise Operations with Cgbitmapinfo and Cgimagealphainfo
Xcode 8 Swift Update with Error "Use Legacy Swift Language Version"