• townscaper随机生成城镇算法分析


    的几年前曾经写过一个随机生成城镇的算法,生成的城镇房间从门可以进入内部行走,房间之间的走廊也可以走通,每个房间都包含一个寻路节点。但是有个缺点,模型面数很简陋,主要靠贴图来表现效果。随机生成后手动编辑改变也比较困难。

    最近看到一个 叫城镇叠叠乐的游戏比较有创意,英文名townscaper,用它生成的模型比较精致,打算研究一下其使用到的算法。

    townsaper主要使用的是Marchingcube算法,根据一个体素8个顶点是否为空对应256种情形(模型)来拼接最终的模型。普通的Marchingcube算法考虑到对称性共有15种基本构型( 考虑二义性是23种)。在townscaper中由于上下不具有对称性,一共有51种基本构型。

    首先对体素的顶点进行编号,根据编号产生标记值(2的编号次方),8个顶点的标记值相加为体素的编号。

    1. //右手系
    2. //顶点编号
    3. // +----------+
    4. // /|V4 /|v5 y+
    5. // / | / | |
    6. // +----------+ | |
    7. // V7| | |v6| |
    8. // | | | | |
    9. // | | | | +-------> x+
    10. // | +-------|--+ /
    11. // | / V0 | / V1 /
    12. // |/ |/ z+
    13. // +----------+
    14. // V3 V2
    15. //顶点标记
    16. // +----------+
    17. // /|v16 /|v32
    18. // / | / |
    19. // +----------+ |
    20. // v128| | v|64|
    21. // | | | |
    22. // | | | |
    23. // | +-------|--+
    24. // | /v1 | /v2
    25. // |/ |/
    26. // +----------+
    27. // v8 v4

    下面列举了必须用到的模型,mesh:  18  rot[129,  72,  36] mirror[ 33,  24, 132,  66];  表示18号体素模型经过旋转90/180/270度可以产生129,72,36号体素模型,经过旋转后再x轴镜像又可以产生33,  24, 132,  66号体素模型。

    1. //mesh: 1 rot[ 8, 4, 2] mirror[ , , , ]; ( 1 = 0) ( 1 = 1)
    2. //mesh: 3 rot[ 9, 12, 6] mirror[ , , , ]; ( 3 = 0 + 1) ( 3 = 1 + 2)
    3. //mesh: 5 rot[ 10, , ] mirror[ , , , ]; ( 5 = 0 + 2) ( 5 = 1 + 4)
    4. //mesh: 7 rot[ 11, 13, 14] mirror[ , , , ]; ( 7 = 0 + 1 + 2) ( 7 = 1 + 2 + 4)
    5. //mesh: 15 rot[ , , ] mirror[ , , , ]; ( 15 = 0 + 1 + 2 + 3) ( 15 = 1 + 2 + 4 + 8)
    6. //mesh: 16 rot[128, 64, 32] mirror[ , , , ]; ( 16 = 4) ( 16 = 16)
    7. //mesh: 17 rot[136, 68, 34] mirror[ , , , ]; ( 17 = 0 + 4) ( 17 = 1 + 16)
    8. //mesh: 18 rot[129, 72, 36] mirror[ 33, 24, 132, 66]; ( 18 = 1 + 4) ( 18 = 2 + 16)
    9. //mesh: 19 rot[137, 76, 38] mirror[ 35, 25, 140, 70]; ( 19 = 0 + 1 + 4) ( 19 = 1 + 2 + 16)
    10. //mesh: 20 rot[130, 65, 40] mirror[ , , , ]; ( 20 = 2 + 4) ( 20 = 4 + 16)
    11. //mesh: 21 rot[138, 69, 42] mirror[ , , , ]; ( 21 = 0 + 2 + 4) ( 21 = 1 + 4 + 16)
    12. //mesh: 22 rot[131, 73, 44] mirror[ 41, 28, 134, 67]; ( 22 = 1 + 2 + 4) ( 22 = 2 + 4 + 16)
    13. //mesh: 23 rot[139, 77, 46] mirror[ 43, 29, 142, 71]; ( 23 = 0 + 1 + 2 + 4) ( 23 = 1 + 2 + 4 + 16)
    14. //mesh: 26 rot[133, 74, 37] mirror[ , , , ]; ( 26 = 1 + 3 + 4) ( 26 = 2 + 8 + 16)
    15. //mesh: 27 rot[141, 78, 39] mirror[ , , , ]; ( 27 = 0 + 1 + 3 + 4) ( 27 = 1 + 2 + 8 + 16)
    16. //mesh: 30 rot[135, 75, 45] mirror[ , , , ]; ( 30 = 1 + 2 + 3 + 4) ( 30 = 2 + 4 + 8 + 16)
    17. //mesh: 31 rot[143, 79, 47] mirror[ , , , ]; ( 31 = 0 + 1 + 2 + 3 + 4) ( 31 = 1 + 2 + 4 + 8 + 16)
    18. //mesh: 48 rot[144, 192, 96] mirror[ , , , ]; ( 48 = 4 + 5) ( 48 = 16 + 32)
    19. //mesh: 49 rot[152, 196, 98] mirror[ 50, 145, 200, 100]; ( 49 = 0 + 4 + 5) ( 49 = 1 + 16 + 32)
    20. //mesh: 51 rot[153, 204, 102] mirror[ , , , ]; ( 51 = 0 + 1 + 4 + 5) ( 51 = 1 + 2 + 16 + 32)
    21. //mesh: 52 rot[146, 193, 104] mirror[ 56, 148, 194, 97]; ( 52 = 2 + 4 + 5) ( 52 = 4 + 16 + 32)
    22. //mesh: 53 rot[154, 197, 106] mirror[ 58, 149, 202, 101]; ( 53 = 0 + 2 + 4 + 5) ( 53 = 1 + 4 + 16 + 32)
    23. //mesh: 54 rot[147, 201, 108] mirror[ 57, 156, 198, 99]; ( 54 = 1 + 2 + 4 + 5) ( 54 = 2 + 4 + 16 + 32)
    24. //mesh: 55 rot[155, 205, 110] mirror[ 59, 157, 206, 103]; ( 55 = 0 + 1 + 2 + 4 + 5) ( 55 = 1 + 2 + 4 + 16 + 32)
    25. //mesh: 60 rot[150, 195, 105] mirror[ , , , ]; ( 60 = 2 + 3 + 4 + 5) ( 60 = 4 + 8 + 16 + 32)
    26. //mesh: 61 rot[158, 199, 107] mirror[ 62, 151, 203, 109]; ( 61 = 0 + 2 + 3 + 4 + 5) ( 61 = 1 + 4 + 8 + 16 + 32)
    27. //mesh: 63 rot[159, 207, 111] mirror[ , , , ]; ( 63 = 0 + 1 + 2 + 3 + 4 + 5) ( 63 = 1 + 2 + 4 + 8 + 16 + 32)
    28. //mesh: 80 rot[160, , ] mirror[ , , , ]; ( 80 = 4 + 6) ( 80 = 16 + 64)
    29. //mesh: 81 rot[168, 84, 162] mirror[ , , , ]; ( 81 = 0 + 4 + 6) ( 81 = 1 + 16 + 64)
    30. //mesh: 82 rot[161, 88, 164] mirror[ , , , ]; ( 82 = 1 + 4 + 6) ( 82 = 2 + 16 + 64)
    31. //mesh: 83 rot[169, 92, 166] mirror[163, 89, 172, 86]; ( 83 = 0 + 1 + 4 + 6) ( 83 = 1 + 2 + 16 + 64)
    32. //mesh: 85 rot[170, , ] mirror[ , , , ]; ( 85 = 0 + 2 + 4 + 6) ( 85 = 1 + 4 + 16 + 64)
    33. //mesh: 87 rot[171, 93, 174] mirror[ , , , ]; ( 87 = 0 + 1 + 2 + 4 + 6) ( 87 = 1 + 2 + 4 + 16 + 64)
    34. //mesh: 90 rot[165, , ] mirror[ , , , ]; ( 90 = 1 + 3 + 4 + 6) ( 90 = 2 + 8 + 16 + 64)
    35. //mesh: 91 rot[173, 94, 167] mirror[ , , , ]; ( 91 = 0 + 1 + 3 + 4 + 6) ( 91 = 1 + 2 + 8 + 16 + 64)
    36. //mesh: 95 rot[175, , ] mirror[ , , , ]; ( 95 = 0 + 1 + 2 + 3 + 4 + 6) ( 95 = 1 + 2 + 4 + 8 + 16 + 64)
    37. //mesh: 112 rot[176, 208, 224] mirror[ , , , ]; (112 = 4 + 5 + 6) (112 = 16 + 32 + 64)
    38. //mesh: 113 rot[184, 212, 226] mirror[178, 209, 232, 116]; (113 = 0 + 4 + 5 + 6) (113 = 1 + 16 + 32 + 64)
    39. //mesh: 114 rot[177, 216, 228] mirror[ , , , ]; (114 = 1 + 4 + 5 + 6) (114 = 2 + 16 + 32 + 64)
    40. //mesh: 115 rot[185, 220, 230] mirror[179, 217, 236, 118]; (115 = 0 + 1 + 4 + 5 + 6) (115 = 1 + 2 + 16 + 32 + 64)
    41. //mesh: 117 rot[186, 213, 234] mirror[ , , , ]; (117 = 0 + 2 + 4 + 5 + 6) (117 = 1 + 4 + 16 + 32 + 64)
    42. //mesh: 119 rot[187, 221, 238] mirror[ , , , ]; (119 = 0 + 1 + 2 + 4 + 5 + 6) (119 = 1 + 2 + 4 + 16 + 32 + 64)
    43. //mesh: 120 rot[180, 210, 225] mirror[ , , , ]; (120 = 3 + 4 + 5 + 6) (120 = 8 + 16 + 32 + 64)
    44. //mesh: 121 rot[188, 214, 227] mirror[182, 211, 233, 124]; (121 = 0 + 3 + 4 + 5 + 6) (121 = 1 + 8 + 16 + 32 + 64)
    45. //mesh: 122 rot[181, 218, 229] mirror[ , , , ]; (122 = 1 + 3 + 4 + 5 + 6) (122 = 2 + 8 + 16 + 32 + 64)
    46. //mesh: 123 rot[189, 222, 231] mirror[183, 219, 237, 126]; (123 = 0 + 1 + 3 + 4 + 5 + 6) (123 = 1 + 2 + 8 + 16 + 32 + 64)
    47. //mesh: 125 rot[190, 215, 235] mirror[ , , , ]; (125 = 0 + 2 + 3 + 4 + 5 + 6) (125 = 1 + 4 + 8 + 16 + 32 + 64)
    48. //mesh: 127 rot[191, 223, 239] mirror[ , , , ]; (127 = 0 + 1 + 2 + 3 + 4 + 5 + 6) (127 = 1 + 2 + 4 + 8 + 16 + 32 + 64)
    49. //mesh: 240 rot[ , , ] mirror[ , , , ]; (240 = 4 + 5 + 6 + 7) (240 = 16 + 32 + 64 + 128)
    50. //mesh: 241 rot[248, 244, 242] mirror[ , , , ]; (241 = 0 + 4 + 5 + 6 + 7) (241 = 1 + 16 + 32 + 64 + 128)
    51. //mesh: 243 rot[249, 252, 246] mirror[ , , , ]; (243 = 0 + 1 + 4 + 5 + 6 + 7) (243 = 1 + 2 + 16 + 32 + 64 + 128)
    52. //mesh: 245 rot[250, , ] mirror[ , , , ]; (245 = 0 + 2 + 4 + 5 + 6 + 7) (245 = 1 + 4 + 16 + 32 + 64 + 128)
    53. //mesh: 247 rot[251, 253, 254] mirror[ , , , ]; (247 = 0 + 1 + 2 + 4 + 5 + 6 + 7) (247 = 1 + 2 + 4 + 16 + 32 + 64 + 128)

     经过以上处理后,美术的工作量大大减少,townscaper使用的应该就是上述模型。

     其实53个模型的制作依然是不小的工作量。 还有更进一步的算法继续减少建模工作量,可以利用反向思维将碎片自动添加到基本构型中。利用镜像和旋转对称性,我们只需要制作一个角落处的接缝碎片即可。

        //碎片piece拼接规则:
        //碎片名字  :"mTFAAFFAA-TFFFFFFF",
        //第1个字母:  r表示只旋转不镜像(rot),m表示带旋转加镜像(mirror), 
        //第2~9个字母:[e0==true & e1,4,5==false & eother==any]    ,其中T表示true、F表示false、A表示any。
        //第10个字母: -表示除去

    1号碎片"TFAAAAAA-NNNNNNNN",// 面1: e0true 、e1false 、 other any -    except  none

    表示只要体素满足:顶点0为TRUE 并且 顶点1为FALSE 并且 排除无,那么体素的构型中就会包含该面片。

    1. static const char* pieceName[PieceNum] =
    2. {
    3. "TFAAAAAA",//1: 0true - 1false - other any -
    4. "FTAAAAAA",//2: 1true - 0false - other any -
    5. "TAAAFAAA",//3: 0true - 4false - other any -
    6. "FAAATAAA",//4: 4true - 0false - other any -
    7. "AAAATFAA",//5: 4true - 5false - other any -
    8. "AAAAFTAA",//6: 5true - 4false - other any -
    9. "TFAAFFAA",//7: 0true - 1,4,5false - other any -
    10. "FTAAFFAA",//8: 1true - 0,4,5false - other any -
    11. "TAAAFTAA",//9: 0,5true - 4false - other any -
    12. "ATAATFAA",//10: 1,4true - 5false - other any -
    13. };
    14. bool HasPiece(int voxel,int piece)
    15. {
    16. const char* name = pieceName[piece];
    17. const char* rule = name;
    18. //piece拼接规则:
    19. //"mTFAAFFAA-TFFFFFFF",
    20. //1个字母: r表示只旋转不镜像(rot),m表示带旋转加镜像(mirror),
    21. //2~9个字母:[e0==true & e1,4,5==false & eother==any]
    22. //10个字母: -表示除去
    23. if (name[0]=='r' || name[0]=='m')
    24. {
    25. rule = name+1;
    26. bool match = true;
    27. for (int i=0;i<8;++i,++rule)
    28. {
    29. if ('T'==(*rule) && ((voxel&(1<<i))==0))
    30. {
    31. //match = false;
    32. return false;
    33. }
    34. if ('F'==(*rule) && ((voxel&(1<<i))!=0))
    35. {
    36. return false;
    37. }
    38. //if ('N'==(*name) )
    39. //{
    40. // return false;
    41. //}
    42. }
    43. }
    44. else
    45. {
    46. return false;
    47. }
    48. //extra
    49. if (name[9]=='+') //todo 需要和相邻的voxel相关?
    50. {
    51. //rule = name+10;
    52. }
    53. //execpt
    54. else if (name[9]=='-')
    55. {
    56. rule = name+10;
    57. for (int i=0;i<8;++i,++rule)
    58. {
    59. if ('T'==(*rule) && ((voxel&(1<<i))==0))
    60. {
    61. //execpt = false;
    62. return true;
    63. }
    64. if ('F'==(*rule) && ((voxel&(1<<i))!=0))
    65. {
    66. return true;
    67. }
    68. if ('N'==(*rule) )
    69. {
    70. return true;
    71. }
    72. //if ('A'==(*name))
    73. //{
    74. //}
    75. }
    76. }
    77. else
    78. {
    79. return false;
    80. }
    81. return false;
    82. }

    遍历所有的面片判断是否添加到某体素基本构型中,即 产生了构型第一象限中的组成部分。构型 其它三个象限可以通过镜像或旋转变换到第一象限,逐个添加好面片后再将模型逆向变换回原来象限即可。

    1. void MarchingTownSys::GenMovieLib(int stage,const char* filename)
    2. {
    3. MovieClip pieceLib;
    4. pieceLib.LoadFromFile(filename);
    5. Mesh* pieceMeshArr[PieceNum];
    6. for (int i=0;i<PieceNum;i++)
    7. {
    8. MovieClip* movie = pieceLib.GetMovieClip(pieceName[i]);
    9. if (movie)
    10. {
    11. pieceMeshArr[i] = movie->GetMesh();
    12. }
    13. else
    14. {
    15. pieceMeshArr[i] = NULL;
    16. }
    17. }
    18. for (int voxel=0;voxel<256;voxel++)
    19. {
    20. MovieClip* movie = m_voxelMovies[stage][voxel];
    21. if (movie)
    22. {
    23. Mesh* mesh = movie->GetMesh();
    24. int vVertexNum = 0;
    25. int trigonNum = 0;
    26. int voxelTemp = voxel;
    27. //四次旋转对称 计算容量
    28. for (int r=0;r<4;r++)
    29. {
    30. for (int p=0;p<PieceNum;p++)
    31. {
    32. Mesh* pieceMesh = pieceMeshArr[p];
    33. if (HasPiece(voxelTemp,p) && pieceMesh)
    34. {
    35. vVertexNum += pieceMesh->m_vVertexNum;
    36. trigonNum += pieceMesh->m_trigonNum;
    37. }
    38. }
    39. voxelTemp = MarchingTables::VoxelRotY90[voxelTemp];
    40. }
    41. mesh->Resize(vVertexNum,vVertexNum,trigonNum);
    42. //四次旋转对称
    43. vVertexNum = 0;
    44. trigonNum = 0;
    45. voxelTemp = voxel;
    46. for (int r=0;r<4;r++)
    47. {
    48. for (int p=0;p<PieceNum;p++)
    49. {
    50. Mesh* pieceMesh = pieceMeshArr[p];
    51. //旋转到一号角判断有无piece
    52. if (HasPiece(voxelTemp,p) && pieceMesh)
    53. {
    54. //将piece逆向旋转添加到模型
    55. int meshRot = (4-r)%4;
    56. int mirror = 0;
    57. Mesh::Vertex* vDstV = mesh->m_vVertexs + vVertexNum;
    58. Mesh::TVertex* vDstT = mesh->m_tVertexs + vVertexNum;
    59. Mesh::Vertex* vSrcV = pieceMesh->m_vVertexs;
    60. Mesh::TVertex* vSrcT = pieceMesh->m_tVertexs;
    61. float posX,posZ,nx,nz;
    62. for (int i=0;i<pieceMesh->m_vVertexNum;i++)
    63. {
    64. posX = vSrcV->x;
    65. posZ = vSrcV->z;
    66. nx= vSrcV->nx;
    67. nz= vSrcV->nz;
    68. if (mirror)
    69. {
    70. posX *= -1;
    71. nx *= -1;
    72. }
    73. switch(meshRot)
    74. {
    75. case 0:
    76. vDstV->x = posX;
    77. vDstV->z = posZ;
    78. vDstV->nx = nx;
    79. vDstV->nz = nz;
    80. break;
    81. case 1://90
    82. vDstV->x = posZ;
    83. vDstV->z = -posX;
    84. vDstV->nx = nz;
    85. vDstV->nz = -nx;
    86. break;
    87. case 2://180
    88. vDstV->x = -posX;
    89. vDstV->z = -posZ;
    90. vDstV->nx = -nx;
    91. vDstV->nz = -nz;
    92. break;
    93. case 3://270
    94. vDstV->x = -posZ;
    95. vDstV->z = posX;
    96. vDstV->nx = -nz;
    97. vDstV->nz = nx;
    98. break;
    99. }
    100. vDstV->y = vSrcV->y;
    101. vDstV->ny = vSrcV->ny;
    102. vDstT->u = vSrcT->u;
    103. vDstT->v = vSrcT->v;
    104. vDstT->w = vSrcT->w;
    105. vSrcV++;
    106. vSrcT++;
    107. vDstV++;
    108. vDstT++;
    109. }
    110. int offsetIndex = vVertexNum;
    111. vVertexNum += pieceMesh->m_vVertexNum;
    112. Mesh::Trigon* srcTrigon = pieceMesh->m_trigons;
    113. Mesh::Trigon* dstTrigon = mesh->m_trigons+trigonNum;
    114. for (int i=0;i<pieceMesh->m_trigonNum;i++)
    115. {
    116. if (mirror)
    117. {
    118. //时针序
    119. dstTrigon->vIndex[0] = srcTrigon->vIndex[2] + offsetIndex;
    120. dstTrigon->vIndex[1] = srcTrigon->vIndex[1] + offsetIndex;
    121. dstTrigon->vIndex[2] = srcTrigon->vIndex[0] + offsetIndex;
    122. }
    123. else
    124. {
    125. dstTrigon->vIndex[0] = srcTrigon->vIndex[0] + offsetIndex;
    126. dstTrigon->vIndex[1] = srcTrigon->vIndex[1] + offsetIndex;
    127. dstTrigon->vIndex[2] = srcTrigon->vIndex[2] + offsetIndex;
    128. }
    129. srcTrigon++;
    130. dstTrigon++;
    131. }
    132. trigonNum += pieceMesh->m_trigonNum;
    133. }
    134. }
    135. voxelTemp = MarchingTables::VoxelRotY90[voxelTemp];
    136. }
    137. //for test
    138. mesh->CreateBuff();
    139. }
    140. }
    141. }

    本算法用到的一套模型碎片:

    也可以不预先将碎片拼接成基本体素,而是在最终拼接模型时直接使用碎片拼接这样更方便处理随机效果(在多套模型中随机取一个即可,给相邻的碎片使用相同的随机种子,这样就不会出现裂缝)。 

    通过四边形变形技术将正方形的Marchingcube变为不规则的形状,可以使建筑物不总是看起来像方块。这一步使用的是FFD2*2*2算法,或者简单的双线性差值也可以做到。(也可以使用FD3*3*3,中心控制点是可以随机偏移的,不会导致裂缝出现)

    效果图:

     源码:

    1. //========================================================
    2. // @Date: 2016.05
    3. // @File: Include/Math/MarchingTowns.h
    4. // @Brief: MarchingTowns
    5. // @Author: LouLei
    6. // @Email: twopointfive@163.com
    7. // @Copyright (Crapell) - All Rights Reserved
    8. //========================================================
    9. #ifndef __MarchingTowns__H__
    10. #define __MarchingTowns__H__
    11. #include "Math/MathLib.h"
    12. #include "Texture.h"
    13. namespace RendSys
    14. {
    15. class MovieClip;
    16. class Mesh;
    17. };
    18. class VertexBuffer;
    19. class IndexBuffer;
    20. class MarchingTownSys
    21. {
    22. public:
    23. typedef int IndexInt;
    24. #define FVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
    25. struct SVertex
    26. {
    27. float pos[3];
    28. float normal[3];
    29. float uvw[3];
    30. };
    31. class VoxelBlock;
    32. class EnergyCell
    33. {
    34. public:
    35. int IntersectRay (const vec3 &start, const vec3 &end, vec3 &resPos);
    36. //3~6边形面围成5~8面体 将能量点围在中间,两个能量点连线穿过多面体的面。 边界位置的面可能不完整(只有两个点)不被记录
    37. // e e
    38. // : .
    39. // +----------+
    40. // /|v4 : . /|v5
    41. // / | : . / | y+
    42. // +----------+ | |
    43. // v7| | :. |v6| |
    44. // e...|..|...e...|..|....e |
    45. // | | .: | | +-------> x+
    46. // | +-------|--+ /
    47. // | / v0 : | / v1 /
    48. // |/ . : |/ z+
    49. // +----------+
    50. // v3. : v2
    51. // . e
    52. // e
    53. class Face
    54. {
    55. public:
    56. bool IntersectRay (const vec3 &start, const vec3 &end, vec3 &resPos);
    57. VoxelBlock* vox[6]; //多面体顶点为邻接体素的中心
    58. int vNum;
    59. EnergyCell* nei; //穿过面连接到另一个能量点
    60. //多面体的边穿过两个相邻体素的公共面
    61. };
    62. float energy;
    63. unsigned int seed;
    64. vec3I index;
    65. vec3 pos;
    66. Face faces[8];
    67. int faceNum;
    68. };
    69. class VoxelBlock
    70. {
    71. public:
    72. bool IsPointIn(const vec3& point) const;
    73. // +----------+
    74. // /|e4 /|e5
    75. // / | / | y+
    76. // +----------+ | |
    77. // e7| | |e6| |
    78. // | | v | | |
    79. // | | | | +-------> x+
    80. // | +-------|--+ /
    81. // | / e0 | / e1 /
    82. // |/ |/ z+
    83. // +----------+
    84. // e3 e2
    85. vec3I index;
    86. vec3 cen;
    87. int voxelCase;
    88. EnergyCell* energy8[8]; //平行六面体boundbox ffd自由变形
    89. int column; //柱子
    90. // +-----------------+
    91. // /| /|
    92. // / | / | y+
    93. // / | / | |
    94. // +-----------------+ | |
    95. // | | | | |
    96. // | | | | |
    97. // | |f0 f1 | |f2 +-------> x+
    98. // | +--------+----|---+ /
    99. // | / | / /
    100. // | +f3 +f4 | +f5 z+
    101. // |/ |/
    102. // +--------+--------+
    103. // f6 f7 f8
    104. vec3 ffd3[9];
    105. //for debug
    106. vec4 planes[6];
    107. };
    108. enum Stage
    109. {
    110. Normal = 0, //普通墙体 平房顶
    111. Tileroof = 1, //瓦片屋顶
    112. Pierground = 2, //桥墩地基
    113. Handrail = 3, //扶手栏杆
    114. StageNum,
    115. };
    116. class MarchingPiece
    117. {
    118. public:
    119. MarchingPiece();
    120. bool HasMirror();
    121. RendSys::Mesh* GetMesh(unsigned int seed);
    122. bool Partof(int voxel);
    123. char name[32];//去掉rand后缀
    124. int randNum;
    125. RendSys::Mesh* mesh[8]; //同类模型最多8个随机外观
    126. };
    127. public:
    128. MarchingTownSys();
    129. ~MarchingTownSys();
    130. //!voxelGridSize:体素格子大小,8个格子是一个体素。 正四面体:8个势能格子全18格子周围全0
    131. void Init(const vec3I& voxelGridSize,const vec3& groundExtend);
    132. void SetMovieLib(const char* movieFile);
    133. void SetPieceLib(const char* movieFile);
    134. void Free();
    135. void DistortStandard(float cornerDistort,float cenDistort);
    136. void Rand();
    137. void Clear();
    138. void Update();
    139. void Render();
    140. void RenderEdit();
    141. void SetGroundPos(const vec3& pos);
    142. //protected:
    143. //!计算势能
    144. float GetGridEnergy(int cx,int cy,int cz);
    145. void SetEnergy(float val,int seed,int cx,int cy,int cz);
    146. void MakeBound();
    147. //last 即使为空也拣选
    148. EnergyCell* PickGrid(const vec3& rayPos,const vec3& rayDir,bool last=true);
    149. void ClearEnergys();
    150. void GenSurface();
    151. //方案一:
    152. //!计算体素面片
    153. bool GenVoxelFragment(int stage,VoxelBlock* block);
    154. void GenMovieLibWithPiece(int stage,const char* filename);//从piece预生成lib,随机性不好
    155. void SetTableMovie(int stage,RendSys::MovieClip* movie,const char* name);
    156. //方案二: 冗余顶点比方案一多 最好焊接一下顶点 接头处不好建模时可以使用装饰物遮挡
    157. //!计算体素面片
    158. bool GenVoxelFragmentWithPiece(int stage,VoxelBlock* block);
    159. void GenVoxelMeshWithPiece(int stage,int voxelCase,RendSys::Mesh* mesh, unsigned int seed[8]);
    160. void SetTablePiece(int stage,RendSys::MovieClip* movie,const char* name);
    161. //
    162. bool AddMeshFFD2(int meshRot,int mirror,RendSys::Mesh* mesh, VoxelBlock* block);
    163. bool AddMeshFFD3(int meshRot,int mirror,RendSys::Mesh* mesh, VoxelBlock* block);
    164. //计算法线
    165. void ComputeNormal();
    166. //计算环境光遮蔽
    167. void ComputeLumen(SVertex *pVertex,int cx,int cy,int cz);
    168. //EnergyGrid 和VoxelGrid 偏离了半格
    169. inline vec3 EnergyToWorld (const vec3 &energyGrid);
    170. inline vec3 WorldToEnergyI(const vec3 &World);
    171. inline vec3 WorldToEnergyF(const vec3 &World);
    172. public:
    173. //方案一:
    174. RendSys::MovieClip* m_movieLib;
    175. RendSys::MovieClip* m_voxelMovies[StageNum][256];
    176. //方案二:
    177. RendSys::MovieClip* m_pieceLib;
    178. int PieceNum;
    179. #define PieceNum PieceNum
    180. MarchingPiece pieceArr[256];
    181. //柱子 柱子模型需要坐在原点
    182. RendSys::MovieClip* m_columnMovies[256];
    183. bool m_visible;
    184. int m_seed;
    185. int FFDSTYLE;
    186. float m_cornerDistort;
    187. float m_cenDistort;
    188. vec3 m_halfGroundExtend;
    189. vec3 m_groundCen;
    190. vec3 m_groundMin;
    191. vec3 m_groundMax;
    192. float m_threshould;
    193. //!一个体素voxel格子 占 81/4势能energy格子
    194. vec3I EnergyGridSize;
    195. int EnergyGridSizeXY;
    196. vec3I VoxelGridSize; //==EnergyGridSize-1
    197. int VoxelGridSizeXY;
    198. vec3 VoxelGridExtend;
    199. vec3 HalfVoxelGridExtend;
    200. EnergyCell* m_gridEnergys; //EnergyGridSize
    201. VoxelBlock* m_voxels; //VoxelGridSize
    202. int IndexsMax;
    203. SVertex* m_vertexs;
    204. int m_vertexNum;
    205. IndexInt* m_indexs;
    206. int m_indexNum;
    207. VertexBuffer* m_vertexBuffer;
    208. IndexBuffer* m_indexBuffer;
    209. int m_brushType; //0 添加 删除 随机外观
    210. int m_continueBrush;
    211. vec3 m_pickedPos;
    212. EnergyCell* m_pickedEnergyCell;
    213. int m_pickedEnergyFace;
    214. VoxelBlock* m_pickedVoxelBlock;
    215. char debugStr[512];
    216. TexturePtr debugTexture;
    217. };
    218. inline vec3 MarchingTownSys ::EnergyToWorld(const vec3 &energyGrid)
    219. {
    220. //EnergyGrid 从 m_groundMin - HalfVoxelGridExtend开始
    221. //VoxelGrid 从 m_groundMin开始
    222. return energyGrid.Mult(VoxelGridExtend) + m_groundMin - HalfVoxelGridExtend;
    223. }
    224. inline vec3 MarchingTownSys ::WorldToEnergyI(const vec3 &World)
    225. {
    226. vec3 energyGrid = (World - m_groundMin + HalfVoxelGridExtend) / VoxelGridExtend;
    227. energyGrid.x = floor(energyGrid.x);
    228. energyGrid.y = floor(energyGrid.y);
    229. energyGrid.z = floor(energyGrid.z);
    230. return energyGrid;
    231. }
    232. inline vec3 MarchingTownSys ::WorldToEnergyF(const vec3 &World)
    233. {
    234. vec3 energyGrid = (World - m_groundMin + HalfVoxelGridExtend) / VoxelGridExtend;
    235. energyGrid.x = (energyGrid.x);
    236. energyGrid.y = (energyGrid.y);
    237. energyGrid.z = (energyGrid.z);
    238. return energyGrid;
    239. }
    240. #endif

  • 相关阅读:
    【SpringBoot】一文了解SpringBoot配置高级
    资深程序员-5年大厂经验代码究竟写的如何-H5-WEBgl-typeScript的笔记代码之一
    ThreadLocal全面解析
    归并排序和计数排序
    简易版人脸识别qt opencv
    vue+python把woff字体文件中的字体全部读取出来
    day49:QT day2,信号与槽、对话框
    下一代实时数据库:Apache Doris 【五】数据表的创建
    多元共进|科技促进艺术发展,助力文化传承
    Python常用的数据处理库有哪些?
  • 原文地址:https://blog.csdn.net/twopointfive/article/details/123593711