当前位置: 首页 > article >正文

townscaper随机生成城镇算法分析

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

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

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

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

//右手系
//顶点编号
//        +----------+
//       /|V4       /|v5              y+            
//      / |        / |                |           
//     +----------+  |                |            
//   V7|  |       |v6|                |           
//     |  |       |  |				  |
//     |  |       |  |				  +-------> x+
//     |  +-------|--+               /
//     | / V0     | / V1            /
//     |/         |/               z+ 
//     +----------+                
//    V3          V2 //顶点标记
//        +----------+
//       /|v16      /|v32
//      / |        / |
//     +----------+  |
// v128|  |      v|64|              
//     |  |       |  |             
//     |  |       |  |             
//     |  +-------|--+             
//     | /v1      | /v2            
//     |/         |/               
//     +----------+                
//   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号体素模型。

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

static const char* pieceName[PieceNum] =
{"TFAAAAAA",// 面1: 0true - 1false - other any - "FTAAAAAA",// 面2: 1true - 0false - other any - "TAAAFAAA",// 面3: 0true - 4false - other any - "FAAATAAA",// 面4: 4true - 0false - other any - "AAAATFAA",// 面5: 4true - 5false - other any - "AAAAFTAA",// 面6: 5true - 4false - other any - "TFAAFFAA",// 面7: 0true - 1,4,5false - other any - 	"FTAAFFAA",// 面8: 1true - 0,4,5false - other any - "TAAAFTAA",// 面9: 0,5true - 4false - other any - "ATAATFAA",// 面10: 1,4true - 5false - other any - 
};
bool HasPiece(int voxel,int piece)
{const char* name = pieceName[piece];const char* rule = name;//piece拼接规则://"mTFAAFFAA-TFFFFFFF",//第1个字母:  r表示只旋转不镜像(rot),m表示带旋转加镜像(mirror), //第2~9个字母:[e0==true & e1,4,5==false & eother==any]    //第10个字母: -表示除去if (name[0]=='r' || name[0]=='m'){rule = name+1;bool match = true;for (int i=0;i<8;++i,++rule){if ('T'==(*rule) && ((voxel&(1<<i))==0)){//match = false;return false;}if ('F'==(*rule) && ((voxel&(1<<i))!=0)){return false;}//if ('N'==(*name) )//{//	return false;//}}}else	{return false;}//extraif (name[9]=='+') //todo 需要和相邻的voxel相关?{//rule = name+10;}//execptelse if (name[9]=='-'){rule = name+10;for (int i=0;i<8;++i,++rule){if ('T'==(*rule) && ((voxel&(1<<i))==0)){//execpt = false;return true;}if ('F'==(*rule) && ((voxel&(1<<i))!=0)){return true;}if ('N'==(*rule) ){return true;}//if ('A'==(*name))//{//}}}else	{return false;}return false;
}

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

void  MarchingTownSys::GenMovieLib(int stage,const char* filename)
{MovieClip pieceLib;pieceLib.LoadFromFile(filename);Mesh* pieceMeshArr[PieceNum];for (int i=0;i<PieceNum;i++){MovieClip* movie = pieceLib.GetMovieClip(pieceName[i]);if (movie){pieceMeshArr[i] = movie->GetMesh();}else{pieceMeshArr[i] = NULL;}}for (int voxel=0;voxel<256;voxel++){MovieClip* movie = m_voxelMovies[stage][voxel];if (movie){Mesh* mesh = movie->GetMesh();int vVertexNum = 0;int trigonNum  = 0;int voxelTemp  = voxel;//四次旋转对称 计算容量for (int r=0;r<4;r++){for (int p=0;p<PieceNum;p++){Mesh* pieceMesh = pieceMeshArr[p];if (HasPiece(voxelTemp,p) && pieceMesh){vVertexNum += pieceMesh->m_vVertexNum;trigonNum  += pieceMesh->m_trigonNum;}}voxelTemp = MarchingTables::VoxelRotY90[voxelTemp];}mesh->Resize(vVertexNum,vVertexNum,trigonNum);//四次旋转对称 vVertexNum = 0;trigonNum  = 0;voxelTemp  = voxel;for (int r=0;r<4;r++){for (int p=0;p<PieceNum;p++){Mesh* pieceMesh = pieceMeshArr[p];//旋转到一号角判断有无pieceif (HasPiece(voxelTemp,p) && pieceMesh){//将piece逆向旋转添加到模型int meshRot = (4-r)%4;int mirror  = 0;Mesh::Vertex*  vDstV = mesh->m_vVertexs + vVertexNum;Mesh::TVertex* vDstT = mesh->m_tVertexs + vVertexNum;Mesh::Vertex*  vSrcV = pieceMesh->m_vVertexs;Mesh::TVertex* vSrcT = pieceMesh->m_tVertexs;float posX,posZ,nx,nz;for (int i=0;i<pieceMesh->m_vVertexNum;i++){posX = vSrcV->x;posZ = vSrcV->z;nx= vSrcV->nx;nz= vSrcV->nz;if (mirror){posX *= -1;nx   *= -1;}switch(meshRot){case 0:vDstV->x  = posX;vDstV->z  = posZ;vDstV->nx = nx;vDstV->nz = nz;break;case 1://90vDstV->x  =  posZ;vDstV->z  = -posX;vDstV->nx =  nz;vDstV->nz = -nx;break;case 2://180vDstV->x  = -posX;vDstV->z  = -posZ;vDstV->nx = -nx;vDstV->nz = -nz;break;case 3://270vDstV->x  = -posZ;vDstV->z  =  posX;vDstV->nx = -nz;vDstV->nz =  nx;break;}vDstV->y    = vSrcV->y;vDstV->ny   = vSrcV->ny;vDstT->u = vSrcT->u;vDstT->v = vSrcT->v;vDstT->w = vSrcT->w;vSrcV++;vSrcT++;vDstV++;vDstT++;}int offsetIndex = vVertexNum;vVertexNum += pieceMesh->m_vVertexNum;Mesh::Trigon*  srcTrigon = pieceMesh->m_trigons;Mesh::Trigon*  dstTrigon = mesh->m_trigons+trigonNum;for (int i=0;i<pieceMesh->m_trigonNum;i++){if (mirror){//时针序dstTrigon->vIndex[0] = srcTrigon->vIndex[2] + offsetIndex;dstTrigon->vIndex[1] = srcTrigon->vIndex[1] + offsetIndex;dstTrigon->vIndex[2] = srcTrigon->vIndex[0] + offsetIndex;}	else{	dstTrigon->vIndex[0] = srcTrigon->vIndex[0] + offsetIndex;dstTrigon->vIndex[1] = srcTrigon->vIndex[1] + offsetIndex;dstTrigon->vIndex[2] = srcTrigon->vIndex[2] + offsetIndex;}srcTrigon++;dstTrigon++;}trigonNum += pieceMesh->m_trigonNum;}}voxelTemp = MarchingTables::VoxelRotY90[voxelTemp];}//for testmesh->CreateBuff();}}
}

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

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

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

效果图:

 源码:

//========================================================
//  @Date:     2016.05
//  @File:     Include/Math/MarchingTowns.h
//  @Brief:     MarchingTowns
//  @Author:     LouLei
//  @Email:  twopointfive@163.com
//  @Copyright (Crapell) - All Rights Reserved
//========================================================#ifndef  __MarchingTowns__H__
#define  __MarchingTowns__H__#include "Math/MathLib.h"
#include "Texture.h"namespace RendSys
{class MovieClip;class Mesh;
};class VertexBuffer;
class IndexBuffer;class MarchingTownSys
{
public:typedef int IndexInt;
#define FVF_VERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)struct SVertex{float pos[3];float normal[3];float uvw[3];};class VoxelBlock;class EnergyCell{public:int   IntersectRay (const vec3 &start, const vec3 &end, vec3 &resPos);//3~6边形面围成5~8面体 将能量点围在中间,两个能量点连线穿过多面体的面。 边界位置的面可能不完整(只有两个点)不被记录//            e      e//            :     .//        +----------+//       /|v4 :   . /|v5                          //      / |   :  . / |                y+           //     +----------+  |                |            //   v7|  |   :.  |v6|                |           // e...|..|...e...|..|....e  	      |//     |  |  .:   |  |				  +-------> x+//     |  +-------|--+               ///     | / v0 :   | / v1            ///     |/ .   :   |/               z+ //     +----------+                //    v3.     :   v2       //     .      e//    eclass Face{public:bool  IntersectRay (const vec3 &start, const vec3 &end, vec3 &resPos);VoxelBlock* vox[6]; //多面体顶点为邻接体素的中心 int         vNum;EnergyCell* nei;  //穿过面连接到另一个能量点//多面体的边穿过两个相邻体素的公共面};		float energy;unsigned int seed;vec3I index;vec3  pos;Face  faces[8];int   faceNum;};class VoxelBlock{public:bool  IsPointIn(const vec3& point) const;//        +----------+//       /|e4       /|e5                         //      / |        / |                y+           //     +----------+  |                |            //   e7|  |       |e6|                |           //     |  |   v   |  |				  |//     |  |       |  |				  +-------> x+//     |  +-------|--+               ///     | / e0     | / e1            ///     |/         |/               z+ //     +----------+                //    e3          e2       vec3I index;vec3  cen;int   voxelCase;EnergyCell* energy8[8]; //平行六面体boundbox  ffd自由变形int   column;           //柱子//         +-----------------+//        /|                /|  //       / |               / |            y+           //      /  |              /  |            |            //     +-----------------+   |            |             //     |   |             |   |            |            //     |   |             |   |		  	  |//     |   |f0       f1  |   |f2		  +-------> x+	//     |   +--------+----|---+           / //     |  /              |  /		    ///     | +f3      +f4    | +f5         z+    //     |/                |/               //     +--------+--------+                //    f6        f7       f8  vec3  ffd3[9];//for debugvec4  planes[6];};enum Stage{Normal     = 0,  //普通墙体 平房顶Tileroof   = 1,  //瓦片屋顶Pierground = 2,  //桥墩地基Handrail   = 3,  //扶手栏杆StageNum,};class MarchingPiece{public:MarchingPiece();bool  HasMirror();RendSys::Mesh* GetMesh(unsigned int seed);bool  Partof(int voxel);char  name[32];//去掉rand后缀int   randNum;RendSys::Mesh* mesh[8]; //同类模型最多8个随机外观};public:MarchingTownSys();~MarchingTownSys();//!voxelGridSize:体素格子大小,8个格子是一个体素。 正四面体:8个势能格子全1,8格子周围全0。void  Init(const vec3I& voxelGridSize,const vec3& groundExtend);void  SetMovieLib(const char* movieFile);void  SetPieceLib(const char* movieFile);void  Free();void  DistortStandard(float cornerDistort,float cenDistort);void  Rand();void  Clear();void  Update();void  Render();void  RenderEdit();void  SetGroundPos(const vec3& pos);
//protected://!计算势能float GetGridEnergy(int cx,int cy,int cz);void  SetEnergy(float val,int seed,int cx,int cy,int cz);void  MakeBound();//last 即使为空也拣选EnergyCell* PickGrid(const vec3& rayPos,const vec3& rayDir,bool last=true);void  ClearEnergys();void  GenSurface();//方案一://!计算体素面片bool  GenVoxelFragment(int stage,VoxelBlock* block);void  GenMovieLibWithPiece(int stage,const char* filename);//从piece预生成lib,随机性不好void  SetTableMovie(int stage,RendSys::MovieClip* movie,const char* name);//方案二: 冗余顶点比方案一多 最好焊接一下顶点 接头处不好建模时可以使用装饰物遮挡//!计算体素面片bool  GenVoxelFragmentWithPiece(int stage,VoxelBlock* block);void  GenVoxelMeshWithPiece(int stage,int voxelCase,RendSys::Mesh* mesh, unsigned int seed[8]);void  SetTablePiece(int stage,RendSys::MovieClip* movie,const char* name);//bool  AddMeshFFD2(int meshRot,int mirror,RendSys::Mesh* mesh, VoxelBlock* block);bool  AddMeshFFD3(int meshRot,int mirror,RendSys::Mesh* mesh, VoxelBlock* block);//计算法线void  ComputeNormal();//计算环境光遮蔽void  ComputeLumen(SVertex *pVertex,int cx,int cy,int cz);//EnergyGrid 和VoxelGrid 偏离了半格  inline vec3  EnergyToWorld (const vec3 &energyGrid);inline vec3  WorldToEnergyI(const vec3 &World);inline vec3  WorldToEnergyF(const vec3 &World);public://方案一:RendSys::MovieClip* m_movieLib;RendSys::MovieClip* m_voxelMovies[StageNum][256];//方案二:RendSys::MovieClip* m_pieceLib;int PieceNum;#define PieceNum PieceNumMarchingPiece pieceArr[256];//柱子 柱子模型需要坐在原点RendSys::MovieClip* m_columnMovies[256];bool   m_visible;int    m_seed;int    FFDSTYLE;float  m_cornerDistort;float  m_cenDistort;vec3   m_halfGroundExtend;vec3   m_groundCen;vec3   m_groundMin;vec3   m_groundMax;float  m_threshould;//!一个体素voxel格子 占 8个1/4势能energy格子vec3I  EnergyGridSize;int    EnergyGridSizeXY;vec3I  VoxelGridSize;         //==EnergyGridSize-1int    VoxelGridSizeXY;vec3   VoxelGridExtend;vec3   HalfVoxelGridExtend;EnergyCell* m_gridEnergys;    //EnergyGridSizeVoxelBlock* m_voxels;         //VoxelGridSizeint            IndexsMax;SVertex*       m_vertexs;int            m_vertexNum;IndexInt*      m_indexs;int            m_indexNum;VertexBuffer*  m_vertexBuffer;IndexBuffer*   m_indexBuffer;int    m_brushType; //0 添加 删除 随机外观int    m_continueBrush;vec3         m_pickedPos;EnergyCell*  m_pickedEnergyCell;int          m_pickedEnergyFace;VoxelBlock*  m_pickedVoxelBlock;char debugStr[512];TexturePtr   debugTexture;};inline vec3 MarchingTownSys ::EnergyToWorld(const vec3 &energyGrid)
{//EnergyGrid 从 m_groundMin - HalfVoxelGridExtend开始//VoxelGrid  从 m_groundMin开始return energyGrid.Mult(VoxelGridExtend) + m_groundMin - HalfVoxelGridExtend;
}inline vec3 MarchingTownSys ::WorldToEnergyI(const vec3 &World)
{vec3 energyGrid = (World - m_groundMin + HalfVoxelGridExtend) / VoxelGridExtend;energyGrid.x = floor(energyGrid.x);energyGrid.y = floor(energyGrid.y);energyGrid.z = floor(energyGrid.z);return energyGrid;
}
inline vec3 MarchingTownSys ::WorldToEnergyF(const vec3 &World)
{vec3 energyGrid = (World - m_groundMin + HalfVoxelGridExtend) / VoxelGridExtend;energyGrid.x = (energyGrid.x);energyGrid.y = (energyGrid.y);energyGrid.z = (energyGrid.z);return energyGrid;
}
#endif 

http://www.lryc.cn/news/2414685.html

相关文章:

  • linux中cpio文件如何,linux cpio命令的使用
  • ElasticSearch学习篇10_Lucene数据存储之BKD动态磁盘树(论文Bkd-Tree: A Dynamic Scalable kd-Tree)
  • Unity ECS小知识1 - PhysicsTrigger Event
  • 利用Interceptor拦截NetKeeper账户:技术创新与实用性探析
  • 稳压二极管和雪崩二极管的工作原理及选型学习总结
  • Android UI 详解之ToggleButton按钮和Swith按钮
  • 怎么在桌面上嵌入窗口(使用FindWindow(),FindWindowEx(),EnumChildWindows())
  • ADODB用法详解
  • 去掉字符串首尾逗号_去除字符串首尾空格和特殊字符
  • C/C++数据结构课程设计(15题)[2023-10-29]
  • 致敬mentohust,路由器使用Socket认证华科校园网
  • Python 中如何使用 @property
  • 使用TerminateProcess结束进程时,错误码为5的解决方法
  • 常量指针与指针常量的区别
  • 信道估计(channel estimation)图解——从SISO到MIMO原理介绍
  • tbody标签的作用介绍
  • CreateEvent的理解
  • 短剧小程序源码|小程序短剧平台源码搭建
  • background属性介绍
  • [翻译] LaTeX 中的列表
  • 内存地址的计算方法
  • ROS2 学习笔记(一)新建项目的基础流程
  • 分享个好用的开源录屏工具 Captura
  • 高速收发器之发送器详解(Transmitter)
  • 计算机程序设计艺术 介绍
  • CreateMutex创建互斥内核对象
  • 目前最受欢迎的12个Python web框架,你用过几个?
  • SqlCommand.ExecuteNonQuery()方法的使用注意
  • Delicatessen音乐名词什么意思
  • Tribon二次开发-COM接口的使用(抽取数据)