材质对几何模型的影响
我们先建立一个工程,然后在聊。
第一步,创建游戏专用视图
SCNView *scnView = [[SCNView alloc]initWithFrame:self.view.bounds];
scnView.backgroundColor = [UIColor blackColor];
scnView.scene = [SCNScene scene];
[self.view addSubview:scnView];
第二步,创建摄像头
// 创建摄像头
SCNCamera *camera = [SCNCamera camera];
SCNNode *cameraNode = [SCNNode node];
cameraNode.camera = camera;
cameraNode.position = SCNVector3Make(0, 0, 5);
[scnView.scene.rootNode addChildNode:cameraNode];
第三步:添加一个球体模型到视图中
SCNSphere *sphere = [SCNSphere sphereWithRadius:1];
SCNNode *sphereNode = [SCNNode nodeWithGeometry:sphere];
[scnView.scene.rootNode addChildNode:sphereNode];
运行一下:
[图片上传中...(image-4ca708-1510628124400-23)]
准备工作已经做好,接下来,正式进入我们今天的内容
材质详解
我们需要了解两个类SCNMaterialProperty 和 SCNMaterial * SCNMatrialProperty
有什么用?
1.包含颜色,纹理和其他可视元素等材质属性
2.控制纹理的包装、过滤和纹理坐标变换
3.纹理的可视属性决定了物体在灯光和阴影下的样子
设置纹理属性的方法有哪些?(contents)
1.使用UIImage (可以直接设置图片的名称)
2.六个图片的数组
3.Core Animation 的layer 对象
4.Sprite Kit 纹理提供的静态图片
在什么地方可以使用SCNMatrialProperty
1.材质属性
2.SCNScene 的background
3.SCNLight的gobo属性
4.绑定纹理采样器自定义GLSL着色器源代码片段 在类中实现 SCNShadable 属性
a.如何创建纹理属性
+ (instancetype)materialPropertyWithContents:(id)contents
提示:
也可以使用GLSL 创建,由于内容过于多,暂时不讲,中级篇也不讲,高级会详细讲解。
b.纹理的属性的内容
var contents: AnyObject?
可以为一下几个对象
颜色(NSColor/UIColor / CGColorRef)
图片(NSImage/UIImage/CGImageRef)
图片名称(NSString)或者路径(NSURL)
图片数组(NSArray)
核心动画层(CALayer)
纹理(SKText,MDLTexture,MTLTexture,GLKTextureInfo)
2D 场景(SKScene)
注意
1.如果设置图片数组时,这个图片必须为六张,并且大小要一致
2.Core Animation layer 使用 AVPlayerLayer
或者AVCaptureVideoPreviewLayer 呈现 捕捉到的视频画面 3.可以动态的改变contents
c.设置材质性能因子(取值范围0-1,默认值为1)
var intensity: CGFloat
会产生什么影响呢?
1.normal 属性,强度变化的正常映射的表面的表观粗糙度。降低强度使表面显得更光滑
2.multiply 使用白色降低强度混物的材料性的颜色,有效降低颜色乘法效应强度
3.对于其他属性,会让内容变暗淡
怎么动态的改变属性内容呢?
千万别着急,现在还不是时候.中级篇会讲
d.转换应用材料属性的内容
@property(nonatomic) SCNMatrix4 contentsTransform
先给两张图理解一下,它干的事情吧,之后练习中我们再详细介绍它都可以进行哪些变化. 它变换的到底是什么:
纹理坐标对应显示的图片区域的大小
[图片上传中...(image-ba24de-1510628124399-22)]
[图片上传中...(image-f47556-1510628124399-21)]
e.包装模式(纹理坐标的的包装行为)
帮你理解一下
比如正方体的表面是100 我们提供的图片是50 这是我们可以,一种是原图显示,或者放大显示,或者重复显示,这个包装模式就是控制这些显示方式的.
var wrapS: SCNWrapMode // 控制水平
var wrapT: SCNWrapMode // 控制垂直
默认的值为:SCNWrapModeClamp.
我们看一下都有哪些可选项:
typedef enum {
//纹理坐标超高系统产生颜色的范围,将使用纹理边缘的颜色填充
SCNWrapModeClamp = 1,
// 当纹理坐标超高系统产生颜色的范围,将重复使用纹理图片
SCNWrapModeRepeat = 2,
//当纹理坐标超高系统产生颜色的范围 使用指定的颜色填充
SCNWrapModeClampToBorder = 3,
// 当纹理左边超过系统差生颜色的范围,将翻转纹理图片
SCNWrapModeMirror = 4,
} SCNWrapMode;
注意:
使用SCNWrapModeClampToBorder 时,使用borderColor 属性的颜色,代替超过图片之外的颜色。
f.纹理滤波
这个属性有什么用?
当材料表面的部分出现较大或小于原来的纹理图像时,纹理过滤决定了材料属性的内容的外观
@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;
给张图理解一下
[图片上传中...(image-cdc24-1510628124399-20)]
非均质性(各向异性)纹理滤波
var maxAnisotropy: CGFloat
你应该了解的?
1.用来过滤、处理当视角变化导致3D物体表面倾斜时造成的纹理错误
2.各向异性滤波,可以提供纹理渲染质量,当纹理的表面出现在一个相对于相机的极端角度,这时往往是通过采样多个mipmap层渲染每个像素,提高渲染质量,但是消耗的渲染的成本。
3.SceneKit自动增加或降低需要最大限度地提高渲染质量渲染每个像素的各向异性,由该属性指定的限制,渲染时所使用的最大各向异性水平依赖于使用中的图形硬件,如果设置值为MAXFloat 约束使用最高的GPU 支持的 各向异性的值.
4.maxAnisotropy的值小于等于1 则禁止使用各向异性
注意:
如果使用各向异性滤波,必须使用mipmap ,也就是说mipFilter 的值不能为SCNFilterModeNone.
给张图理解一下各向异性
[图片上传中...(image-d6800c-1510628124399-19)]
纹理通道
@property(nonatomic) NSInteger mappingChannel
先解释一下这属性
几何对象可能有多个纹理坐标源,每个都对应一个独一无二的通道数字,你可以使用这些通道数字,去绘制材质的内容通过不同的方式
举个例子帮你理解一下:
[图片上传中...(image-4587cd-1510628124399-18)]
很简单:
表示一个相框的一个几何体可能会使用一组纹理坐标来映射相框架本身的材质,另一组纹理坐标用于将图片放置到框架中
到目前为止,我们把SCNMatrialProperty的属性内容,已经全部讲解完毕,你理解了没?接下来,我们还要学习一个特别重要的类(SCNMaterial)
SCNMaterial
上面的工程建好的你,可以跟着下面的步骤做。
讲解这个类,我们换一种方式,我喜欢图文并茂,我相信你也喜欢。
这几点你要记牢了
1.材质可以在多个几何体重复使用
2.它是管理光线和阴影属性以及决定几何表面呈现出来的样子
3.一个几何体可以设置多个材质
a.漫发射属性(diffuse) 我们有一样图片是这样的:
[图片上传中...(image-4fc0b6-1510628124399-17)]
上代码:
sphere.firstMaterial.diffuse.contents = @"earth-diffuse.jpg";
运行结果:
[图片上传中...(image-5e1304-1510628124399-16)]
总结一下:
1.这个属性设置的几何体的基本的颜色,好比是你穿的衣服。
2.如果你不设置这个属性,它默认的contents内容是颜色white
其实它的过程像穿衣服一样
[图片上传中...(image-a603b4-1510628124399-15)]
影响环境光的相应属性(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];
给张图理解一下
[图片上传中...(image-475029-1510628124399-14)]
镜面材质属性(高光)
有什么效果?
当光照射到物体表面是,物体反射出来颜色
添加一张高光照片
[图片上传中...(image-c62f29-1510628124399-13)]
上代码:
sphere.firstMaterial.specular.contents = @"earth-specular.jpg";
运行结果:
[图片上传中...(image-5534ed-1510628124399-12)]
小提示:
如果你想要所有部分全部显示高光,你可以给他设置白色
再给张图理解一下
[图片上传中...(image-e8abb0-1510628124399-11)]
设置法线取向
理解:
1.按理来说,我们的法线都是垂直我们的表面的,通过这个属性,可以模拟光在每个顶点的取向。
2.可以通过纹理图片作为法线地图,使用RGB 表示 XYZ
下图就是一样模拟法线坐标的图像
[图片上传中...(image-34ccfc-1510628124399-10)]
映射(reflectiv)
你可以这样理解:
给材质外边加一个罩子,光能透过这个罩子照射到物体上,比如映射属性为白色反射所有光,所以你看不见任何颜色,黑色吸收任何光,光能照射到物体上,物体能反射光,所以你能看见。 下面是一张反射属性纹理图:
[图片上传中...(image-9a5b56-1510628124399-9)]
代码:
sphere.firstMaterial.reflective.contents = @"earth-reflective.jpg";
// 映射因子没有上限值
sphere.firstMaterial.fresnelExponent = 10;
执行结果:
[图片上传中...(image-8e2d3b-1510628124399-8)]
设置自身发光
特点:
自己能发光,不能照亮别的物体
首先我们添加一个黑色的聚光灯
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];
运行结果:
[图片上传中...(image-77c75e-1510628124399-7)]
我们添加一个自身发光的纹理图片
[图片上传中...(image-7d79db-1510628124399-6)]
代码:
sphere.firstMaterial.emission.contents = @"earth-emissive.jpg";
设置材质的透明度
什么意思?
也就是说,让这个几何物体的部分或者全部能变成透明的,不好理解看图
上代码:
sphere.firstMaterial.transparent.contents = @"cloudsTransparency.png";
sphere.firstMaterial.transparencyMode = SCNTransparencyModeRGBZero;
// 设置透明比例 0为不透 没有上限
sphere.firstMaterial.transparency = 2;
运行结果:
[图片上传中...(image-49229c-1510628124399-5)]
[图片上传中...(image-6afaca-1510628124399-4)]
设置一个颜色值和物体着色完成够的值相乘
我们先给物体添加一个自身材质属性和发光材质属性
sphere.firstMaterial.diffuse.contents = @"earth-diffuse.jpg" ;
sphere.firstMaterial.emission.contents = @"earth-emissive.jpg";
运行结果:
[图片上传中...(image-b0bd0c-1510628124399-3)]
接下来,我们让这个结果和绿色相乘
sphere.firstMaterial.multiply.contents = [UIColor greenColor];
运行结果:
[图片上传中...(image-3094bc-1510628124399-2)]
设置自照明
注意:
如果selfIllumination属性不为nil, emission 属性则不起作用 代码: // 把所用的光照全部去掉 sphere.firstMaterial.selfIllumination.contents = [UIColor blueColor];
运行结果:
[图片上传中...(image-eabdcc-1510628124398-1)]
材质可以有名字的
@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
[图片上传中...(image-81e518-1510628124398-0)]
每个都有对应的计算公式,举个例子,比如SCNLightingModelBlinn
color = ambient* al + diffuse* max(0, dot(N, L)) + specular*pow(max(0, dot(H, N)), shininess)
可能暂时用不到,用到了再去官方资料查找就好了。
本节的内容有点多,理解不了没有关系,在使用过程中慢慢体会就行,后面我们大量使用今天的内容,既然开始了,就坚持下去。