• ARKit学习之SCNGeometrySource加顶点、法线、纹理及索引时贴图不正确


    1、背景

      需求:通过ARKit,让用户拍摄房间时显示挑选的家具或其它模型。

      要求:需要感知房间的空间大小,让家具物体贴近现实。

    2、功能实现

      由于公司不是用通用的3D模型obj、dae或者苹果官方的scn文件。

      之前对于3D建模知识完全不懂,所以只能摸索有没有更底层的方法。

      后面看例子,发现可以用SCNGeometrySource和SCNGeometryElement实现。

    代码如下:

      

    typedef struct {

        float x, y, z;    // position

        float nx, ny, nz; // normal

        float s, t;       // texture coordinates

    } SourceVertex;

     

    - (SCNGeometry *)geometryWithSourceVertex:(SourceVertex *)vertexcs faces:(int *)faces vertexNum:(int)vertexNum faceNum:(int)faceNum {

        

        NSData *data = [NSData dataWithBytes:vertexcs length:sizeof(SourceVertex)*vertexNum];

        SCNGeometrySource *vertexSource, *normalSource, *tcoordSource;

        vertexSource = [SCNGeometrySource geometrySourceWithData:data

                                                        semantic:SCNGeometrySourceSemanticVertex

                                                     vectorCount:vertexNum

                                                 floatComponents:YES

                                             componentsPerVector:3 // x, y, z

                                               bytesPerComponent:sizeof(float)

                                                      dataOffset:offsetof(SourceVertex, x)

                                                      dataStride:sizeof(SourceVertex)];

        

        normalSource = [SCNGeometrySource geometrySourceWithData:data

                                                        semantic:SCNGeometrySourceSemanticNormal

                                                     vectorCount:vertexNum

                                                 floatComponents:YES

                                             componentsPerVector:3 // nx, ny, nz

                                               bytesPerComponent:sizeof(float)

                                                      dataOffset:offsetof(SourceVertex, nx)

                                                      dataStride:sizeof(SourceVertex)];

        

        tcoordSource = [SCNGeometrySource geometrySourceWithData:data

                                                        semantic:SCNGeometrySourceSemanticTexcoord

                                                     vectorCount:vertexNum

                                                 floatComponents:YES

                                             componentsPerVector:2 // s, t

                                               bytesPerComponent:sizeof(float)

                                                      dataOffset:offsetof(SourceVertex, s)

                                                      dataStride:sizeof(SourceVertex)];

        

        

        NSData *eleData = [NSData dataWithBytes:faces length:faceNum*3*sizeof(int)];

        SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:eleData primitiveType:SCNGeometryPrimitiveTypeTriangles primitiveCount:faceNum bytesPerIndex:sizeof(int)];

        

        SCNGeometry * geometry = [SCNGeometry geometryWithSources:@[vertexSource,normalSource,tcoordSource]

                                                         elements:@[element]];

        return geometry;

    }

    3. 问题

      加载完成后,纹理图片显示不正确,会有扭曲的情况。

      由于例子比较少,网上的相关问题也少,搞到我花了很多时间去研究。开始以为是API方法问题,或者数据取值导致,但对照网上的加载显示六方形的方法,检查不出有问题。

      后来只能尝试把模型转成obj文件格式,通过ModelIO去加载obj,测试后完全没问题,那只能从数据方面入手了。

      不过尝试过,直接读obj的顶点、纹理、法向量和索引,加载出来的图形也是有问题。但通过ModelIO加载出来的数据,再用SCNGeometrySource加载也没问题。

      这样比较清晰了,数据要加工处理过才行。

      网上搜索到一个从obj加载数据,然后进行合面操作,网址是:https://blog.csdn.net/qinyuanpei/article/details/49991607 。加载出来显示没问题,但有性能问题,因为算法要对面索引

      进行n*n的循环,当面索引数据大的时候,加载一个面要1分钟以上。

    4. 解决方法

      通过搜索加载obj文件数据的方案发现,纹理显示不正确,是因为顶点、纹理数据和面索引对应不上,后面想到直接根据面索引,重排顶点和纹理数据就可以解决这个问题了。

    代码如下:

    for (int i = 0; i < facesNum; i++) {

                                // 第一个顶点

                                int index = faces[i*9] - 1;

                                vertexcs[i*3].x = point[index*3];

                                vertexcs[i*3].y = point[index*3+1];

                                vertexcs[i*3].z = point[index*3+2];

                                // 纹理

                                index = faces[i*9+1] - 1;

                                vertexcs[i*3].s = tex[index*2];

                                vertexcs[i*3].t = tex[index*2+1];

                                // 法向量

                                index = faces[i*9+2] - 1;

                                vertexcs[i*3].nx = normal[index*3];

                                vertexcs[i*3].ny = normal[index*3+1];

                                vertexcs[i*3].nz = normal[index*3+2];

                                

                                // 第二个顶点

                                index = faces[i*9+3] - 1;

                                vertexcs[i*3+1].x = point[index*3];

                                vertexcs[i*3+1].y = point[index*3+1];

                                vertexcs[i*3+1].z = point[index*3+2];

                                // 纹理

                                index = faces[i*9+4] - 1;

                                vertexcs[i*3+1].s = tex[index*2];

                                vertexcs[i*3+1].t = tex[index*2+1];

                                // 法向量

                                index = faces[i*9+5] - 1;

                                vertexcs[i*3+1].nx = normal[index*3];

                                vertexcs[i*3+1].ny = normal[index*3+1];

                                vertexcs[i*3+1].nz = normal[index*3+2];

                                

                                // 第三个顶点

                                index = faces[i*9+6] - 1;

                                vertexcs[i*3+2].x = point[index*3];

                                vertexcs[i*3+2].y = point[index*3+1];

                                vertexcs[i*3+2].z = point[index*3+2];

                                // 纹理

                                index = faces[i*9+7] - 1;

                                vertexcs[i*3+2].s = tex[index*2];

                                vertexcs[i*3+2].t = tex[index*2+1];

                                // 法向量

                                index = faces[i*9+8] - 1;

                                vertexcs[i*3+2].nx = normal[index*3];

                                vertexcs[i*3+2].ny = normal[index*3+1];

                                vertexcs[i*3+2].nz = normal[index*3+2];

     

                                triangleFace[i*3] = i*3;

                                triangleFace[i*3+1] = i*3+1;

                                triangleFace[i*3+2] = i*3+2;

     

                            }

      

  • 相关阅读:
    Educational Codeforces Round 88 (Rated for Div. 2) D. Yet Another Yet Another Task(枚举/最大连续子序列)
    Educational Codeforces Round 88 (Rated for Div. 2) A. Berland Poker(数学)
    Educational Codeforces Round 88 (Rated for Div. 2) E. Modular Stability(数论)
    Educational Codeforces Round 88 (Rated for Div. 2) C. Mixing Water(数学/二分)
    Codeforces Round #644 (Div. 3)
    Educational Codeforces Round 76 (Rated for Div. 2)
    Educational Codeforces Round 77 (Rated for Div. 2)
    Educational Codeforces Round 87 (Rated for Div. 2)
    AtCoder Beginner Contest 168
    Codeforces Round #643 (Div. 2)
  • 原文地址:https://www.cnblogs.com/loserof/p/10115456.html
Copyright © 2020-2023  润新知