材质和几何体
我们需要了解两个类SCNMaterialProperty 和 SCNMaterial
SCNMatrialProperty
- 包含颜色,纹理和其他可视元素等材质属性
- 控制纹理的包装、过滤和纹理坐标变换
- 纹理的可视属性决定了物体在灯光和阴影下的样子
设置纹理属性的方法有哪些?(contents)
- 使用UIImage (可以直接设置图片的名称)
- 六个图片的数组
- Core Animation 的layer 对象
- Sprite Kit 纹理提供的静态图片
SCNMatrialProperty
- 材质属性
- SCNScene 的background
- SCNLight的gobo属性
- 绑定纹理采样器自定义GLSL着色器源代码片段 在类中实现 SCNShadable 属性
如何创建纹理属性
+ (instancetype)materialPropertyWithContents:(id)contents
纹理的属性的内容
var contents: AnyObject?
可以为以下几个对象
- 颜色(NSColor/UIColor / CGColorRef)
- 图片(NSImage/UIImage/CGImageRef)
- 图片名称(NSString)或者路径(NSURL)
- 图片数组(NSArray)
- 核心动画层(CALayer)
- 纹理(SKText,MDLTexture,MTLTexture,GLKTextureInfo)
- 2D 场景(SKScene)
注意
- 如果设置图片数组时,这个图片必须为六张,并且大小要一致
- Core Animation layer 使用 AVPlayerLayer 或者AVCaptureVideoPreviewLayer 呈现 捕捉到的视频画面
- 可以动态的改变contents
设置材质性能因子(取值范围0-1,默认值为1)
var intensity: CGFloat
会产生什么影响呢?
- normal 属性,强度变化的正常映射的表面的表观粗糙度。降低强度使表面显得更光滑
- multiply 使用白色降低强度混物的材料性的颜色,有效降低颜色乘法效应强度
- 对于其他属性,会让内容变暗淡
转换应用材料属性的内容
@property(nonatomic) SCNMatrix4 contentsTransform
先给两张图理解一下,它干的事情吧, 它变换的到底是什么:
纹理坐标对应显示的图片区域的大小
包装模式(纹理坐标的的包装行为)
比如正方体的表面是100 我们提供的图片是50 这是我们可以,一种是原图显示,或者放大显示,或者重复显示,这个包装模式就是控制这些显示方式的.
var wrapS: SCNWrapMode // 控制水平
var wrapT: SCNWrapMode // 控制垂直
默认的值为:SCNWrapModeClamp
typedef enum {
//纹理坐标超高系统产生颜色的范围,将使用纹理边缘的颜色填充
SCNWrapModeClamp = 1,
// 当纹理坐标超高系统产生颜色的范围,将重复使用纹理图片
SCNWrapModeRepeat = 2,
//当纹理坐标超高系统产生颜色的范围 使用指定的颜色填充
SCNWrapModeClampToBorder = 3,
// 当纹理左边超过系统差生颜色的范围,将翻转纹理图片
SCNWrapModeMirror = 4,
} SCNWrapMode;
注意:
使用SCNWrapModeClampToBorder 时,使用borderColor 属性的颜色,代替超过图片之外的颜色。
纹理滤波
这个属性有什么用?
当材料表面的部分出现较大或小于原来的纹理图像时,纹理过滤决定了材料属性的内容的外观
@property(nonatomic) SCNFilterMode minificationFilter
typedef enum : NSInteger {
//
SCNFilterModeNone = 0,
//当这个位置没有纹理颜色时,会采样离他最近的颜色值
SCNFilterModeNearest = 1,
//当这个位置没有纹理颜色时,线性插值颜色作为自己的颜色
SCNFilterModeLinear = 2,
} SCNFilterMode;
默认值为 SCNFilterModeLinear
mipmap滤波
var mipFilter: SCNFilterMode
有什么用?
当材料表面的部分出现较大或小于原来的纹理图像时,纹理过滤决定了材料属性的内容的外观 , 主要针对(mipmap) Mipmap(有时候拼写成mipmap)是一种电脑图形图像技术,用于在三维图像的二维代替物中达到立体感效应
mipmap 有多厉害
可以增加渲染的性能:当渲染的图片比较小时,SceneKit 会自动创建若干个mipmap层,给材质属性的图片内容,渲染的时候,SceneKit 会自动采样mipmap层
typedef enum : NSInteger {
SCNFilterModeNone = 0, // 默认值 不用mipmap
SCNFilterModeNearest = 1,
SCNFilterModeLinear = 2, // 线性
} SCNFilterMode;
给张图理解一下
纹理通道
@property(nonatomic) NSInteger mappingChannel
先解释一下这属性
几何对象可能有多个纹理坐标源,每个都对应一个独一无二的通道数字,你可以使用这些通道数字,去绘制材质的内容通过不同的方式
举个例子帮你理解一下:
很简单:
表示一个相框的一个几何体可能会使用一组纹理坐标来映射相框架本身的材质,另一组纹理坐标用于将图片放置到框架中
SCNMaterial
讲解这个类,我们换一种方式,我喜欢图文并茂,我相信你也喜欢。
这几点你要记牢了
- 材质可以在多个几何体重复使用
- 它是管理光线和阴影属性以及决定几何表面呈现出来的样子
- 一个几何体可以设置多个材质
漫发射属性(diffuse)
我们有一样图片是这样的:
上代码:
sphere.firstMaterial.diffuse.contents = @"earth-diffuse.jpg";
运行结果:
总结一下:
- 这个属性设置的几何体的基本的颜色,好比是你穿的衣服。
- 如果你不设置这个属性,它默认的contents内容是颜色white
其实它的过程像穿衣服一样
影响环境光的相应属性(ambient)
先上代码:
sphere.firstMaterial.locksAmbientWithDiffuse = YES;
sphere.firstMaterial.ambient.contents = [UIColor blueColor];
// 添加环境光
SCNNode *ambientlightNode = [SCNNode node];
ambientlightNode.light =[SCNLight light];
ambientlightNode.light.type = SCNLightTypeAmbient;
[scnView.scene.rootNode addChildNode:ambientlightNode];
给张图理解一下
镜面材质属性(高光)
有什么效果? 当光照射到物体表面是,物体反射出来颜色 添加一张高光照片
上代码:
sphere.firstMaterial.specular.contents = @"earth-specular.jpg";
运行结果:
小提示:
如果你想要所有部分全部显示高光,你可以给他设置白色
再给张图理解一下
设置法线取向
理解:
- 按理来说,我们的法线都是垂直我们的表面的,通过这个属性,可以模拟光在每个顶点的取向。
- 可以通过纹理图片作为法线地图,使用RGB 表示 XYZ
下图就是一样模拟法线坐标的图像
映射(reflectiv)
你可以这样理解: 给材质外边加一个罩子,光能透过这个罩子照射到物体上,比如映射属性为白色反射所有光,所以你看不见任何颜色,黑色吸收任何光,光能照射到物体上,物体能反射光,所以你能看见。 下面是一张反射属性纹理图:
代码:
sphere.firstMaterial.reflective.contents = @"earth-reflective.jpg";
// 映射因子没有上限值
sphere.firstMaterial.fresnelExponent = 10;
执行结果:
设置自身发光
特点:
自己能发光,不能照亮别的物体
首先我们添加一个黑色的聚光灯
SCNNode *spotLightNode = [SCNNode node];
spotLightNode.position = SCNVector3Make(0, 50, 0);
spotLightNode.rotation = SCNVector4Make(1, 0, 0, -M_PI/2.0);
spotLightNode.light = [SCNLight light];
spotLightNode.light.color = [UIColor blackColor];
spotLightNode.light.type = SCNLightTypeSpot;
[scnView.scene.rootNode addChildNode:spotLightNode];
运行结果:
我们添加一个自身发光的纹理图片
代码:
sphere.firstMaterial.emission.contents = @"earth-emissive.jpg";
设置材质的透明度
什么意思?
也就是说,让这个几何物体的部分或者全部能变成透明的,不好理解看图
上代码:
sphere.firstMaterial.transparent.contents = @"cloudsTransparency.png";
sphere.firstMaterial.transparencyMode = SCNTransparencyModeRGBZero;
// 设置透明比例 0为不透 没有上限
sphere.firstMaterial.transparency = 2;
运行结果:
设置一个颜色值和物体着色完成够的值相乘
我们先给物体添加一个自身材质属性和发光材质属性
sphere.firstMaterial.diffuse.contents = @"earth-diffuse.jpg" ;
sphere.firstMaterial.emission.contents = @"earth-emissive.jpg";
运行结果:
接下来,我们让这个结果和绿色相乘
sphere.firstMaterial.multiply.contents = [UIColor greenColor];
运行结果:
设置自照明
注意:
如果selfIllumination属性不为nil, emission 属性则不起作用
代码:
// 把所用的光照全部去掉
sphere.firstMaterial.selfIllumination.contents = [UIColor blueColor];
运行结果:
材质可以有名字的
@property(nonatomic, copy) NSString *name
如何渲染球体内部
// 默认渲染一边
sphere.firstMaterial.doubleSided = true;
// 剔除正面
sphere.firstMaterial.cullMode = SCNCullFront;
// 剔除反面
sphere.firstMaterial.cullMode = SCNCullBack;
混合渲染模式 确定如何使用这种材料的像素颜色与渲染目标中的其他像素颜色混合的模式
enum SCNBlendMode : Int {
case Alpha // 默认值
case Add
case Subtract
case Multiply
case Screen
case Replace
}
渲染材质是否产生深度信息
// 默认YES
var writesToDepthBuffer: Bool
@property(nonatomic) BOOL writesToDepthBuffer
// 渲染是否优先读取深度信息 默认为YES
var readsFromDepthBuffer: Bool
光照模式
NSString *const SCNLightingModelPhong
NSString *const SCNLightingModelBlinn
NSString *const SCNLightingModelLambert
NSString *const SCNLightingModelConstant
每个都有对应的计算公式,举个例子,比如
SCNLightingModelBlinn color = ambient* al + diffuse* max(0, dot(N, L)) + specular*pow(max(0, dot(H, N)), shininess)
可能暂时用不到,用到了再去官方资料查找就好了。