1、SCNGeometry简介
SCNGeometry负责呈现三维模型的类,它管理者物体的形状、纹理等。它可以由SCNGeometrySource和SCNGeometryElement来构造, 一个SCNGeometry 可以包含多个SCNGeometrySource和SCNGeometryElement对象. 还可以通过SCNMaterial定义几何形状表面的颜色或者纹理, SCNLight 定义光照效果, SCNProgram 设计OpenGL或者Metal着色语言等等。
SCNGeometrySource 在SceneKit中就是顶点的集合. 这些点用来构成一个几何图形. 创建了一个SCNGeometrySource对象,包含有2个顶点, 可以用来绘制一条直线.
SCNGeometryElement 用来描述如何把SCNGeometrySource中的顶点构成基本的几何图形. SCNGeometryPrimitiveType定义了在SceneKit所支持的基本几何图形的种类,
2、相关API简介
- 初始化
//懒加载,ios初始化用init + (instancetype)geometry API_AVAILABLE(macos(10.9)); //通过SCNGeometrySource和SCNGeometryElement对象创建 + (instancetype)geometryWithSources:(NSArray<SCNGeometrySource *> *)sources elements:(nullable NSArray<SCNGeometryElement *> *)elements;
- 几何属性管理
//名字 @property(nonatomic, copy, nullable) NSString *name;
- 几何材料的管理
//确定几何图形的外观(也就是说用什么样的材料) @property(nonatomic, copy) NSArray<SCNMaterial *> *materials; //确定几何体的第一个材料,如果没有返回nil @property(nonatomic, retain, nullable) SCNMaterial *firstMaterial; //新建材料material在材料数组中插入指定位置index - (void)insertMaterial:(SCNMaterial *)material atIndex:(NSUInteger)index; //从材料数组中移除指定位置的材料 - (void)removeMaterialAtIndex:(NSUInteger)index; //新建材料material在材料数组中替换指定位置index的材料 - (void)replaceMaterialAtIndex:(NSUInteger)index withMaterial:(SCNMaterial *)material; //返回与指定名称连接的第一个材料。 - (nullable SCNMaterial *)materialWithName:(NSString *)name;
- 几何数据的管理
//为几何图形提供顶点数据 @property(nonatomic, readonly) NSArray<SCNGeometrySource *> *geometrySources API_AVAILABLE(macos(10.10)); //返回指定语句的顶点数据 - (NSArray<SCNGeometrySource *> *)geometrySourcesForSemantic:(SCNGeometrySourceSemantic)semantic; //描述几何形状的几何元素数组 @property(nonatomic, readonly) NSArray<SCNGeometryElement *> *geometryElements API_AVAILABLE(macos(10.10)); //几何图形元素的个数 @property(nonatomic, readonly) NSInteger geometryElementCount; //返回指定索引处的几何元素 - (SCNGeometryElement *)geometryElementAtIndex:(NSInteger)elementIndex;
- 优化的详细级别
//管理几何的外观当视图很远时。一种可以自动替换的几何图形的替代解决方案,以提高渲染性能。 //一个SCNLevelOfDetail数组,SCNLevelOfDetail代表模型的细节层次,比如获取SCNGeometry属性等。 @property(nonatomic, copy, nullable) NSArray<SCNLevelOfDetail *> *levelsOfDetail API_AVAILABLE(macos(10.9));
- 平滑和细分几何
//指定接收器的细分级别。默认值为0。 //分等级0表示没有细分。当接收器的“tessel”属性不是nil时,对GPU进行细化。 @property(nonatomic) NSUInteger subdivisionLevel API_AVAILABLE(macos(10.10)); //自适应细分,默认值是YES,要求接收方的“tessel”属性不是nil。 @property(nonatomic) BOOL wantsAdaptiveSubdivision API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); //指定控制子分区的边缘折痕 //在细分后,几何元素识别几何图形的边缘应该保持锋利。这种几何元素的原始类型必须是SCNGeometryPrimitiveTypeLine。 //请参见上面的subdivisionLevel来控制子分区的级别 @property(nonatomic, retain, nullable) SCNGeometryElement *edgeCreasesElement API_AVAILABLE(macos(10.10)); //指定表面细分后边缘的平滑度或锐度。 //这个几何源的语义必须是“SCNGeometrySourceSemanticEdgeCrease”。折痕值是介于0和10之间的浮动值,其中0表示平滑,10表示无限锐。 //请参见上面的subdivisionLevel来控制子分区的级别。请参阅上面的edgecreeselement来指定边缘折痕的边缘。 @property(nonatomic, retain, nullable) SCNGeometrySource *edgeCreasesSource API_AVAILABLE(macos(10.10));
- 管理镶嵌
//指定如何在GPU的呈现时间内对几何图形进行镶嵌。默认为零 #if SCN_ENABLE_METAL @property(nonatomic, retain, nullable) SCNGeometryTessellator *tessellator API_AVAILABLE(macos(10.13), ios(11.0)) API_UNAVAILABLE(tvos, watchos); #endif
3、SCNGeometrySource顶点集合相关API简介
- 官方示例
typedef struct { float x, y, z; // position float nx, ny, nz; // normal float s, t; // texture coordinates } MyVertex; MyVertex vertices[VERTEX_COUNT] = { /* ... vertex data ... */ }; NSData *data = [NSData dataWithBytes:vertices length:sizeof(vertices)]; SCNGeometrySource *vertexSource, *normalSource, *tcoordSource; vertexSource = [SCNGeometrySource geometrySourceWithData:data semantic:SCNGeometrySourceSemanticVertex vectorCount:VERTEX_COUNT floatComponents:YES componentsPerVector:3 // x, y, z bytesPerComponent:sizeof(float) dataOffset:offsetof(MyVertex, x) dataStride:sizeof(MyVertex)]; normalSource = [SCNGeometrySource geometrySourceWithData:data semantic:SCNGeometrySourceSemanticNormal vectorCount:VERTEX_COUNT floatComponents:YES componentsPerVector:3 // nx, ny, nz bytesPerComponent:sizeof(float) dataOffset:offsetof(MyVertex, nx) dataStride:sizeof(MyVertex)]; tcoordSource = [SCNGeometrySource geometrySourceWithData:data semantic:SCNGeometrySourceSemanticTexcoord vectorCount:VERTEX_COUNT floatComponents:YES componentsPerVector:2 // s, t bytesPerComponent:sizeof(float) dataOffset:offsetof(MyVertex, s) dataStride:sizeof(MyVertex)];
- 创建几何源
/** 从给定的数据和参数中创建并返回一个几何源。 @param data 几何数据。 @param semantic 枚举值SCNGeometrySourceSemantic @param vectorCount 几何源向量的个数。 @param floatComponents 指示向量组件是否为浮点值的标志。 @param componentsPerVector 向量中标量分量的数目。 @param bytesPerComponent 表示向量组件的字节数。 @param offset 从数据开始的偏移量 @param stride 数据中从一个向量到另一个向量的字节数。 @return SCNGeometrySource */ + (instancetype)geometrySourceWithData:(NSData *)data semantic:(SCNGeometrySourceSemantic)semantic vectorCount:(NSInteger)vectorCount floatComponents:(BOOL)floatComponents componentsPerVector:(NSInteger)componentsPerVector bytesPerComponent:(NSInteger)bytesPerComponent dataOffset:(NSInteger)offset dataStride:(NSInteger)stride; /** 从顶点位置的数组中创建一个几何源。 @param vertices 顶点 @param count 顶点数量 @return SCNGeometrySource */ + (instancetype)geometrySourceWithVertices:(const SCNVector3 *)vertices count:(NSInteger)count; /** 从法向量的数组中创建一个几何源 @param normals 法线的缓冲区。 @param count 法线的数量。 @return SCNGeometrySource */ + (instancetype)geometrySourceWithNormals:(const SCNVector3 *)normals count:(NSInteger)count; /** 从纹理坐标点的数组中创建一个几何源。 @param texcoord 纹理坐标的缓冲区。 @param count 纹理坐标点的数量。 @return SCNGeometrySource */ + (instancetype)geometrySourceWithTextureCoordinates:(const CGPoint *)texcoord count:(NSInteger)count;
- 检查几何来源
//几何图形的数据来源 @property(nonatomic, readonly) NSData *data; //每个顶点的语义值 枚举 @property(nonatomic, readonly) SCNGeometrySourceSemantic semantic; //向量的个数 @property(nonatomic, readonly) NSInteger vectorCount; //该值指示向量组件是否为浮点值。 @property(nonatomic, readonly) BOOL floatComponents; //标量的组件的数量 @property(nonatomic, readonly) NSInteger componentsPerVector; //每个向量组件的大小 @property(nonatomic, readonly) NSInteger bytesPerComponent; //以字节为单位的偏移量,从数据的开始到第一个在几何源中使用的向量组件。 @property(nonatomic, readonly) NSInteger dataOffset; //数据中从一个向量到另一个向量的字节数。 @property(nonatomic, readonly) NSInteger dataStride;
- 创建GPU-Mutable几何来源
/** 创建一个几何源,其顶点数据位于指定的金属缓冲区中,允许通过金属计算着色器进行修改。 @param mtlBuffer 一个金属缓冲器。 @param vertexFormat 顶点格式 @param semantic 枚举SCNGeometrySourceSemantic @param vertexCount 顶点的数目。 @param offset 数据开始时的偏移量 @param stride 从一个向量到数据中的下一个向量的字节数。 @return SCNGeometrySource 试图修改SCNSceneRenderer委托调用之外的金属缓冲区的讨论是没有定义的。 通常使用它在willRenderScene回调中修改MTLBuffer,在用户自己的命令缓冲区中使用计算内核或顶点函数。所以类似: - (void)renderer:(id <SCNSceneRenderer>)aRenderer willRenderScene:(SCNScene *)scene atTime:(NSTimeInterval)time { // 请求新的命令缓冲区。 id <MTLCommandBuffer> myCommandBuffer = [aRenderer.commandQueue commandBuffer]; // 获取一个计算命令编码器。 id <MTLComputeCommandEncoder> myComputeCommandEncoder = [myCommandBuffer computeCommandEncoder]; // 配置计算命令编码器的管道状态、缓冲区输入等… //... // 调度 [myComputeCommandEncoder dispatchThreadgroups:numberOfWorkingGroups threadsPerThreadgroup:numberOfThreads]; [myComputeCommandEncoder endEncoding]; [myCommandBuffer commit]; } */ + (instancetype)geometrySourceWithBuffer:(id <MTLBuffer>)mtlBuffer vertexFormat:(MTLVertexFormat)vertexFormat semantic:(SCNGeometrySourceSemantic)semantic vertexCount:(NSInteger)vertexCount dataOffset:(NSInteger)offset dataStride:(NSInteger)stride API_AVAILABLE(macos(10.11), ios(9.0));
- SCNGeometrySourceSemantic枚举值
#if defined(SWIFT_SDK_OVERLAY2_SCENEKIT_EPOCH) && SWIFT_SDK_OVERLAY2_SCENEKIT_EPOCH >= 3 typedef NSString * SCNGeometrySourceSemantic NS_EXTENSIBLE_STRING_ENUM; #else typedef NSString * SCNGeometrySourceSemantic; #endif FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticVertex;//顶点位置数据的语义 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticNormal;//表面正常数据的语义 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticColor;//每个顶点颜色数据的语义。 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticTexcoord;//纹理坐标数据的语义。 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticTangent API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0));//表面切矢量数据的语义 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticVertexCrease API_AVAILABLE(macos(10.10));//用于细分曲面的顶点折痕数据的语义 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticEdgeCrease API_AVAILABLE(macos(10.10));//用于细分曲面的边缘折痕数据的语义 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticBoneWeights API_AVAILABLE(macos(10.10));//骨重量数据的语义,用于皮肤表面的骨骼动画 FOUNDATION_EXTERN SCNGeometrySourceSemantic const SCNGeometrySourceSemanticBoneIndices API_AVAILABLE(macos(10.10));//骨指数数据的语义,用于皮肤表面的骨骼动画。
4、SCNGeometryElement几何元素相关API简介
- 初始化
/** 从指定的数据和选项创建一个几何元素 @param data 包含元素索引的数据。您可以通过nil来使用隐式顶点排序(0,1,2…)。 @param primitiveType SCNGeometryPrimitiveType枚举值 @param primitiveCount 数据中的基元数。 @param bytesPerIndex 表示数据中单个索引值的字节数。 @return SCNGeometryElement */ + (instancetype)geometryElementWithData:(nullable NSData *)data primitiveType:(SCNGeometryPrimitiveType)primitiveType primitiveCount:(NSInteger)primitiveCount bytesPerIndex:(NSInteger)bytesPerIndex;
- 使用索引
//描述几何元素的数据。 @property(nonatomic, readonly) NSData *data; //SCNGeometryPrimitiveType 枚举值 @property(nonatomic, readonly) SCNGeometryPrimitiveType primitiveType; //元素中的基元数。 @property(nonatomic, readonly) NSInteger primitiveCount; //范围渲染。默认为[NSNotFound,0] //当将范围的位置设置为NSNotFound时,将呈现整个几何元素。 @property(nonatomic) NSRange primitiveRange API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); //表示元素数据中的每个索引值的字节数。 @property(nonatomic, readonly) NSInteger bytesPerIndex;
- SCNGeometryPrimitiveType枚举值
typedef NS_ENUM(NSInteger, SCNGeometryPrimitiveType) { SCNGeometryPrimitiveTypeTriangles = 0,//几何元素的数据是一个三角形序列,每个三角形由三个新的顶点描述。 SCNGeometryPrimitiveTypeTriangleStrip = 1,//几何元素的数据是一个三角形序列,每个三角形由一个新顶点和前一个三角形的两个顶点描述。 SCNGeometryPrimitiveTypeLine = 2,//几何元素的数据是一个线段序列,每个线段由两个新的顶点描述。 SCNGeometryPrimitiveTypePoint = 3,//几何元素的数据是一个未连接点的序列。 #if defined(SWIFT_SDK_OVERLAY2_SCENEKIT_EPOCH) && SWIFT_SDK_OVERLAY2_SCENEKIT_EPOCH >= 2 SCNGeometryPrimitiveTypePolygon API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0)) = 4//多边形 #endif }; #if !(defined(SWIFT_SDK_OVERLAY2_SCENEKIT_EPOCH) && SWIFT_SDK_OVERLAY2_SCENEKIT_EPOCH >= 2) #define SCNGeometryPrimitiveTypePolygon (SCNGeometryPrimitiveType)4 #endif
- 呈现点云
//使用这些属性将一个几何图形显示为一个点集合,而不是一个固体表面或线框。 //几何元素中各点的宽度,如几何图形中的局部三维坐标空间。默认1 @property(nonatomic) CGFloat pointSize API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); //在屏幕点上测量的最小的半径,用来渲染几何元素中的任何一点。默认1 @property(nonatomic) CGFloat minimumPointScreenSpaceRadius API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0)); //最大的半径,测量在屏幕上的点,在其中渲染任何一点的几何元素。默认1 @property(nonatomic) CGFloat maximumPointScreenSpaceRadius API_AVAILABLE(macos(10.13), ios(11.0), tvos(11.0), watchos(4.0));
5、SCNGeometryTessellator几何镶嵌者相关API简介
- 实例属性
//指定用于每个贴片镶嵌因素的比例因子。默认为1。 @property(nonatomic) CGFloat tessellationFactorScale; //指定镶嵌划分模式。默认为MTLTessellationPartitionModeInteger。 @property(nonatomic) MTLTessellationPartitionMode tessellationPartitionMode; typedef NS_ENUM(NSUInteger, MTLTessellationPartitionMode) { MTLTessellationPartitionModePow2 = 0, MTLTessellationPartitionModeInteger = 1, MTLTessellationPartitionModeFractionalOdd = 2, MTLTessellationPartitionModeFractionalEven = 3, } NS_ENUM_AVAILABLE(10_12, 10_0); //指定镶嵌应该是统一的还是自适应的。默认为NO @property(nonatomic, getter=isAdaptive) BOOL adaptive; //指定在屏幕空间中是否应该调整镶嵌的水平。默认为NO @property(nonatomic, getter=isScreenSpace) BOOL screenSpace; //指定边缘镶嵌因子。默认为1。 @property(nonatomic) CGFloat edgeTessellationFactor; //指定内部镶嵌因素。默认为1 @property(nonatomic) CGFloat insideTessellationFactor; //指定最大边长。默认为1。 @property(nonatomic) CGFloat maximumEdgeLength;
- 选择一个平滑算法SCNTessellationSmoothingMode枚举
//默认是SCNTessellationSmoothingModeNone @property(nonatomic) SCNTessellationSmoothingMode smoothingMode;
typedef NS_ENUM(NSInteger, SCNTessellationSmoothingMode) { SCNTessellationSmoothingModeNone = 0, SCNTessellationSmoothingModePNTriangles,//PN-Triangles是控制曲面的算法法,P表现point,N表示法线,Triangles说明总有有3个点其对应的法线,这个算法很适用于实时渲染中的曲面生成,空间的最基本的面就是三角形面。 SCNTessellationSmoothingModePhong// phong 光照模型渲染效果。 } API_AVAILABLE(macos(10.13), ios(11.0)) API_UNAVAILABLE(tvos, watchos);