'RealityKit iOS Metal Shader rendering colors incorrectly

So I'm using Metal to write custom shaders for my entities in RealityKit so that I can create gradients, but the colors are rendering strangely once I apply the gradient. The color renders correctly at full RGB values, e.g. (1,0,0), (1,1,1), (1,1,0), etc. but when using decimal values the render is incorrect. Here's a screenshot showing the values. The squares in front have simple single color shaders applied and the ones in the back are colored with a UIColor on the Material in RealityKit. In all of these, I'm using UnlitMaterial and the base MeshResource.generatePlane() function.

enter image description here

These are the color values used as UIColors in the back, and as Metal half3s in the front.

let color1 = UIColor(red: 1, green: 0, blue: 0, alpha: 1)
let color2 = UIColor(red: 1, green: 0.25, blue: 0.25, alpha: 1)
let color3 = UIColor(red: 1, green: 0.5, blue: 0.5, alpha: 1)
let color4 = UIColor(red: 1, green: 0.75, blue: 0.75, alpha: 1)
let color5 = UIColor(red: 1, green: 0.875, blue: 0.875, alpha: 1)
let color6 = UIColor(red: 1, green: 1, blue: 1, alpha: 1)

Here's one of the Metal Shaders

[[visible]]
void colorShader2(realitykit::surface_parameters params) {
    // Gets surface parameters
    auto surface = params.surface();
    
    half value = 0.25;
    
    // set color to RGB Values
    half3 color = half3(1,value,value);
    
    // Set the base color to the color
    surface.set_emissive_color(color);
    surface.set_base_color(color);
    
    surface.set_opacity(half(1.0));
}

Here's the Swift code to apply the shader, largely pulled from Apple's documentation. These functions are in an extension of the Entity type.

func loadCustomSurfaceShader(mySurfaceShader: String) -> CustomMaterial.SurfaceShader {

        // Get the Metal Device.
        guard let device = MTLCreateSystemDefaultDevice() else {
            fatalError("Error creating default metal device.")
        }

        // Get a reference to the Metal library.
        guard let library = device.makeDefaultLibrary() else {
            fatalError("Error creating default Metal library")
        }
        
        // Load a surface shader function named mySurfaceShader.
        let surfaceShader = CustomMaterial.SurfaceShader(named: mySurfaceShader,
                                                         in: library)
        
        return surfaceShader
    }
    
    func replaceMaterialWithCustomMaterial(entity: Entity, surfaceShader: CustomMaterial.SurfaceShader) {

        // Make sure the entity has a ModelComponent.
        guard var modelComponent = entity.components[ModelComponent.self] as? ModelComponent else {
            return
        }

        // Loop through the entity's materials and replace the existing material with
        // one based on the original material.
        guard let customMaterials = try? modelComponent.materials.map({ material -> CustomMaterial in
            let customMaterial = try CustomMaterial(from: material, surfaceShader: surfaceShader)
            return customMaterial
        }) else { return}
        modelComponent.materials = customMaterials
        entity.components[ModelComponent.self] = modelComponent
    }
    
    func applyShader(_ shader: LookShaders) {
        let shader = self.loadCustomSurfaceShader(mySurfaceShader: shader.rawValue)
        self.replaceMaterialWithCustomMaterial(entity: self, surfaceShader: shader)
    }

I'm pretty stumped as to why this is happening, but I'm sure there might be something simple enough I'm missing.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source