Unity利用深度图建模

深度图建模

总结

深度图精度获取
地形生成算法

主要进展

  1. 获取深度图
    1. 获取深度图:主要是用这篇文章提供的工程生成
      https://www.immersivelimit.com/tutorials/unity-depth-camera-simulation?rq=depth
test_depth.png
  1. 通过深度图获取点集
    关键就是一个图坐标转换为世界坐标。
    设图的像素中心为原点中心,从中心到像素坐标向量为一个轴,深度图的灰度值为一个轴,两轴经过一定比例放缩得到世界坐标。
for (int i = 0; i < width; i += 10)
{
    for (int j = 0; j < height; j += 10)
    {
        //根据像素点与中心点偏移和深度值,得到实际点离摄像头的位移
        Vector2 pixelOffsetV2 = new Vector2(i, j) - new Vector2(i / 2, j / 2);
        float depthOffset = depthMap.GetPixel(i, j).r * 255;//深度图,r,g,b值都相同

        print(i + " " + j + " " + depthOffset);
        if (depthOffset < 250)
        {
            //转换三维向量
            Vector3 pixelOffsetV3 = new Vector3(pixelOffsetV2.x, pixelOffsetV2.y, 0) * pixelK;
            Vector3 depthOffsetV3 = new Vector3(0, 0, depthOffset * depthK);

            //得到最终位移
            Vector3 realOffset = pixelOffsetV3 + depthOffsetV3;
            GameObject point = Instantiate(sphere, camera.transform.position + realOffset, Quaternion.identity, parent);
            points[i, j] = point;
        }
    }
}
  1. 渲染点云

    1. 通过gameobject实现点云
      最简单的方法,在每个点实例化一个小球,性能消耗较大,间隔取像素和剔除深度无穷远的像素,可较快并实时预览点云生成效果,实时调整轴放缩系数


      test_SphereModel.png
    2. 通过mesh的点模式实现点云
      主要参考下面资料
      mesh结构的基本用法
      https://docs.unity.cn/cn/current/Manual/Example-CreatingaBillboardPlane.html
      mesh的点线渲染
      https://blog.csdn.net/zhudaokuan/article/details/119609315

      CubeAndCylinder_depth.png

      CubeAndCylinder_MeshModel.png

      CubeAndCylinder_LineStrip.png

  2. 构建三角面mesh
    关键在于三角索引的顺序,最近的像素点画三角形,距离信息由二维数组的索引号表示,通过遍历每个点和距离找到合适的三个点画三角形。
    想象每个点作为四边形的左下角的那个点,每个四边形可以画两个三角形,所以每个点可以画两个三角形,先画右下角,再画左上角。直到把所有点遍历完。

/// <summary>
/// 根据深度图生成三角面
/// </summary>
void InitTriMesh2()
{
    int width = depthMap.width;
    int height = depthMap.height;

    //将得到的点转化为二维数组,几何位置近的画四边形
    int[,] pointsIndex = new int[width, height];

    //算一下生成的点数
    int num = 0;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            float depthOffset = depthMap.GetPixel(i, j).r * 255;//深度图,r,g,b值都相同
            if (depthOffset < 250)//有效点
            {
                if (isOpsite)
                    depthOffset = 255 - depthOffset;//取反~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                num++;
            }
        }
    }

    positions = new Vector3[num];
    indices = new int[num * 6];//三个点组成三角形的三个顶点,按最大复用率算
    colors = new Color[num];
    int index = 0;

    //for (int i = 0; i < width; i += 10)
    //{
    //    for (int j = 0; j < height; j += 10)
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            //根据像素点与中心点偏移和深度值,得到实际点离摄像头的位移
            Vector2 pixelOffsetV2 = new Vector2(i, j) - new Vector2(i / 2, j / 2);
            float depthOffset = depthMap.GetPixel(i, j).r * 255;//深度图,r,g,b值都相同
            if (isOpsite)
                depthOffset = 255 - depthOffset;//取反~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            print(i + " " + j + " " + depthOffset);
            if (depthOffset < 250)
            {
                //转换三维向量
                Vector3 pixelOffsetV3 = new Vector3(pixelOffsetV2.x, pixelOffsetV2.y, 0) * pixelK;
                Vector3 depthOffsetV3 = new Vector3(0, 0, depthOffset * depthK);

                //得到最终位移
                Vector3 realOffset = pixelOffsetV3 + depthOffsetV3;

                positions[index] = realOffset;

                pointsIndex[i, j] = index;//存储索引
                //indices[index] = index;
                colors[index] = Color.gray;
                index++;
            }
        }
    }

    //设置三角形索引
    int triIndex = 0;
    for (int i = 0; i < pointsIndex.GetLength(0); i++)
    {
        for (int j = 0; j < pointsIndex.GetLength(1); j++)
        {
            if (pointsIndex[i, j] != 0)//可能会抛弃掉第一个点 。分别找最近的点画两个三角形
            {
                //第一个三角形
                indices[triIndex] = pointsIndex[i, j];
                triIndex++;

                //找到右上角最近的
                int temI = i;
                int temJ = j;
                do
                {
                    temI++;
                    temI %= pointsIndex.GetLength(0);
                    temJ++;
                    temJ %= pointsIndex.GetLength(1);
                } while (pointsIndex[temI, temJ] == 0);//非有效索引就继续找

                indices[triIndex] = pointsIndex[temI, temJ];
                triIndex++;

                //找到右边最近的
                temI = i;
                temJ = j;
                do
                {
                    temI++;
                    temI %= pointsIndex.GetLength(0);
                } while (pointsIndex[temI, temJ] == 0);//非有效索引就继续找

                indices[triIndex] = pointsIndex[temI, temJ];
                triIndex++;


                //第二个三角形
                indices[triIndex] = pointsIndex[i, j];
                triIndex++;

                //找到上面最近的
                temI = i;
                temJ = j;
                do
                {
                    temJ++;
                    temJ %= pointsIndex.GetLength(1);
                } while (pointsIndex[temI, temJ] == 0);//非有效索引就继续找

                indices[triIndex] = pointsIndex[temI, temJ];
                triIndex++;


                //找到右上角最近的
                temI = i;
                temJ = j;
                do
                {
                    temI++;
                    temI %= pointsIndex.GetLength(0);
                    temJ++;
                    temJ %= pointsIndex.GetLength(1);
                } while (pointsIndex[temI, temJ] == 0);//非有效索引就继续找

                indices[triIndex] = pointsIndex[temI, temJ];
                triIndex++;
            }
        }
    }

    mesh = pointMeshObj.GetComponent<MeshFilter>().mesh;
    mesh.vertices = positions;
    mesh.colors = colors;
    mesh.SetIndices(indices, MeshTopology.Triangles, 0);

    //MeshUtility.Optimize(mesh);

}

初步建模.png
初步建模2.png

发现精度比较低,后来发现是unity会将导入的图像压缩导致的,将图片设为不压缩,效果会好一些。但还是没有光滑的效果。


压缩对比.png
  1. unity地形系统
    unity 地形系统可以通过高度图去生成地形。但是由于图片格式和我的深度图与Unity高度图色差相反,以及一些未知的图片尺寸问题,我的深度图导入到地形中生成不了正常地形。

相反的,用适用于地形的高度图,放到我的方法里去跑,可以生成点云,但是生成不了正常的模型,更别提光滑,可见实现方法还有很大差距。


Canyon02_Heightmap.jpg
高度点云.png
高度mesh.png

很多参考资料都涉及到shader相关知识,不仅为了渲染,还有大量的计算,感觉无论从基础实现还是优化,应该都绕不开shader。

参考资料

获取深度图
https://www.immersivelimit.com/tutorials/unity-depth-camera-simulation?rq=depth

点云实现
https://docs.unity.cn/cn/current/Manual/Example-CreatingaBillboardPlane.html

https://blog.csdn.net/zhudaokuan/article/details/119609315

https://blog.csdn.net/zhudaokuan/article/details/120135224?spm=1001.2014.3001.5501

高度图地形建模
https://zhuanlan.zhihu.com/p/592083710

基于深度相机的三维物体与人体扫描重建
https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CDFD&dbname=CDFD1214&filename=1013178503.nh&uniplatform=NZKPT&v=5-FXszT_zVskmmsaWloNbXPQP3jK8b3p0_gQsE9cT4lccPv2cgo4_l6cQMtA0soq

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容