当我添加半透明图像(sample)作为SCNNode的纹理时,如何为图像透明的节点指定颜色属性。由于我能够将颜色或图像指定为材质属性,因此无法为节点指定颜色值。有没有办法为材料属性指定颜色和图像,或者是否有解决此问题的方法。
答案 0 :(得分:3)
如果您要将图片分配到contents
材料属性的transparent
,则可以将材料transparencyMode
更改为.AOne
或.RGBZero
。
.AOne
表示透明度来自图片alpha通道。.RGBZero
表示透明度来自图像中的亮度(红色,绿色和蓝色)。如果没有自定义着色器,则无法将任意颜色配置为透明度。
但是,从样本图像的外观来看,我认为将样本图像分配到transparent
材质属性contents
并使用.AOne
透明模式会给您带来结果你在寻找。
答案 1 :(得分:1)
我将此作为新答案发布,因为它与其他答案不同。
根据您的评论,我了解您希望使用具有透明度的图像作为材质的漫反射内容,但在图像透明的任何地方使用背景颜色。换句话说,您不会将a composite of the image over a color用作漫反射内容。
有几种不同的方法可以实现这种合成图像。最简单且最常见的解决方案是创建一个新的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 )是:
C O = C A + C B *(1 - ɑ A )
通过将图像作为漫反射内容传递,并将输出分配给漫反射内容,表达式可以简化为:
C diffuse = C diffuse + C color *(1 - ɑ diffuse )
C diffuse + = C color *(1 - ɑ diffuse )
通常输出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")
正如您所看到的,第一个解决方案更简单,如果它符合您的需求,我会推荐它。第二种解决方案更复杂,但可以使背景颜色动画化。
答案 2 :(得分:0)
以防有人在将来遇到这个问题...对于某些任务,ricksters解决方案可能是最简单的。就我而言,我想在映射到球体的图像上显示一个网格。我最初将图像合成为一个并应用它们,但随着时间的推移,我变得更加花哨,这开始变得复杂。所以我做了两个球,一个在另一个里面。我将网格放在内部网格上,将图像放在外部网格上并预先安装...
DateTime.TryParseExact("20170131", "yyyyMMdd", nothing, DateTimeStyles.None, orderDateTime)
我很惊讶我没有设置sphereMaterial.transparency,它似乎自动得到了。