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;
	}

	//extra
	if (name[9]=='+') //todo 需要和相邻的voxel相关?
	{
		//rule = name+10;
	}
	//execpt
	else 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];
					//旋转到一号角判断有无piece
					if (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://90
								vDstV->x  =  posZ;
								vDstV->z  = -posX;
								vDstV->nx =  nz;
								vDstV->nz = -nx;
								break;
							case 2://180
								vDstV->x  = -posX;
								vDstV->z  = -posZ;
								vDstV->nx = -nx;
								vDstV->nz = -nz;
								break;
							case 3://270
								vDstV->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 test
			mesh->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
		//    e
		class 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 debug
		vec4  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 PieceNum
	MarchingPiece 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-1
	int    VoxelGridSizeXY;

	vec3   VoxelGridExtend;
	vec3   HalfVoxelGridExtend;

	EnergyCell* m_gridEnergys;    //EnergyGridSize
	VoxelBlock* m_voxels;         //VoxelGridSize

	int            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 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值