我将此作为新答案发布,因为它与其他答案不同。
根据您的评论,我了解到您希望使用具有透明度的图像作为材质的漫反射内容,但在图像透明的地方使用背景颜色。换句话说,你不会使用a composite of the image over a color 作为漫反射内容。
使用 UIImage
您可以通过几种不同的方式来实现此合成图像。最简单且可能最熟悉的解决方案是创建一个新的 UIImage,它在颜色上绘制图像。此新图片的大小和比例与您的图片相同,但可以是不透明的,因为它具有纯色背景。
func imageByComposing(image: UIImage, over color: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(image.size, true, image.scale)
defer {
UIGraphicsEndImageContext()
}
let imageRect = CGRect(origin: .zero, size: image.size)
// fill with background color
color.set()
UIRectFill(imageRect)
// draw image on top
image.drawInRect(imageRect)
return UIGraphicsGetImageFromCurrentImageContext()
}
使用此图像作为漫反射材质属性的内容,将为您提供您所追求的效果。
使用着色器修改器
如果您发现自己必须非常频繁地更改颜色(可能为其设置动画),您还可以使用自定义着色器或着色器修改器在颜色上合成图像。
在这种情况下,您希望将图像 A 在颜色 B 上合成,以便输出颜色(C O) 是:
CO = CA + CB * (1 - ɑA)
通过将图像作为漫反射内容传递,并将输出分配给漫反射内容,表达式可以简化为:
Cdiffuse = Cdiffuse + Ccolor * (1 - ɑdiffuse)
C漫射 += Ccolor * (1 - ɑ漫射)
通常输出 alpha 取决于 A 和 B 的 alpha,但由于 B(颜色)是不透明的 (1),所以输出 alpha 也是 1。
这可以写成一个小的着色器修改器。由于这个解决方案的动机是能够改变颜色,所以颜色被创建为一个可以在代码中更新的统一变量。
// Define a color that can be set/changed from code
uniform vec3 backgroundColor;
#pragma body
// Composit A (the image) over B (the color):
// output = image + color * (1-alpha_image)
float alpha = _surface.diffuse.a;
_surface.diffuse.rgb += backgroundColor * (1.0 - alpha);
// make fully opaque (since the color is fully opaque)
_surface.diffuse.a = 1.0;
然后将从文件中读取此着色器修改器,并将其设置在材质着色器修改器字典中
enum ShaderLoadingError: ErrorType {
case FileNotFound, FailedToLoad
}
func shaderModifier(named shaderName: String, fileExtension: String = "glsl") throws -> String {
guard let url = NSBundle.mainBundle().URLForResource(shaderName, withExtension: fileExtension) else {
throw ShaderLoadingError.FileNotFound
}
do {
return try String(contentsOfURL: url)
} catch {
throw ShaderLoadingError.FailedToLoad
}
}
// later, in the code that configures the material ...
do {
let modifier = try shaderModifier(named: "Composit") // the name of the shader modifier file (assuming 'glsl' file extension)
theMaterial.shaderModifiers = [SCNShaderModifierEntryPointSurface: modifier]
} catch {
// Handle the error here
print(error)
}
然后,您可以通过为材质的“backgroundColor”设置新值来更改颜色。请注意,没有初始值,因此必须设置一个。
let backgroundColor = SCNVector3Make(1.0, 0.0, 0.7) // r, g, b
// Set the color components as an SCNVector3 wrapped in an NSValue
// for the same key as the name of the uniform variable in the sahder modifier
theMaterial.setValue(NSValue(SCNVector3: backgroundColor), forKey: "backgroundColor")
如您所见,第一个解决方案更简单,如果它适合您的需求,我会推荐它。第二种解决方案更复杂,但启用了背景颜色动画。