zoukankan      html  css  js  c++  java
  • 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;

     

                            }

      

  • 相关阅读:
    oracl遇到的问题
    Ubuntu安装pyucharm的专业版本
    android adb logcat详解(三)
    android monkey压力测试(二)
    android adb常用命令(一)
    python *args 与 **kwargs
    python中带有下划线的变量和函数
    如何区分Python package
    Python Importlib.import_module动态导入模块
    python os.path.dirname(__file__)
  • 原文地址:https://www.cnblogs.com/loserof/p/10115456.html
Copyright © 2011-2022 走看看