Merge pull request #276 from tangziwen/terrain

update Terrain, support skirt
This commit is contained in:
XiaoYang 2015-03-31 09:14:27 +08:00
commit 45987b6a60
5 changed files with 346 additions and 71 deletions

View File

@ -8,14 +8,16 @@ USING_NS_CC;
#include "renderer/CCRenderer.h"
#include "renderer/CCGLProgramStateCache.h"
#include "renderer/ccGLStateCache.h"
#include "base/CCDirector.h"
#include "2d/CCCamera.h"
#include <stdlib.h>
NS_CC_BEGIN
Terrain * Terrain::create(TerrainData &parameter)
Terrain * Terrain::create(TerrainData &parameter, CrackFixedType fixedType)
{
Terrain * terrain = new (std::nothrow)Terrain();
terrain->_terrainData = parameter;
terrain->_crackFixedType = fixedType;
terrain->_isCameraViewChanged = true;
terrain->_isTerrainModelMatrixChanged = true;
//chunksize
@ -28,7 +30,7 @@ Terrain * Terrain::create(TerrainData &parameter)
textImage->initWithImageFile(parameter.detailMaps[0].detailMapSrc);
auto texture = new (std::nothrow)Texture2D();
texture->initWithImage(textImage);
terrain->textures.push_back(texture);
terrain->_detailMapTextures[0] = texture;
}else
{
//alpha map
@ -42,8 +44,7 @@ Terrain * Terrain::create(TerrainData &parameter)
textImage->initWithImageFile(parameter.detailMaps[i].detailMapSrc);
auto texture = new (std::nothrow)Texture2D();
texture->initWithImage(textImage);
terrain->textures.push_back(texture);
terrain->detailSize[i] = parameter.detailMaps[i].detailMapSize;
terrain->_detailMapTextures[i] = texture;
}
}
terrain->init();
@ -94,7 +95,7 @@ void Terrain::onDraw(const Mat4 &transform, uint32_t flags)
if(!_alphaMap)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,textures[0]->getName());
glBindTexture(GL_TEXTURE_2D,_detailMapTextures[0]->getName());
auto texture_location = glGetUniformLocation(glProgram->getProgram(),"u_texture0");
glUniform1i(texture_location,0);
auto alpha_location = glGetUniformLocation(glProgram->getProgram(),"u_has_alpha");
@ -104,7 +105,7 @@ void Terrain::onDraw(const Mat4 &transform, uint32_t flags)
for(int i =0;i<_maxDetailMapValue;i++)
{
glActiveTexture(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D,textures[i]->getName());
glBindTexture(GL_TEXTURE_2D,_detailMapTextures[i]->getName());
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
@ -116,7 +117,7 @@ void Terrain::onDraw(const Mat4 &transform, uint32_t flags)
sprintf(str,"u_detailSize[%d]",i);
auto detailSizeLocation = glGetUniformLocation(glProgram->getProgram(),str);
glUniform1f(detailSizeLocation,detailSize[i]);
glUniform1f(detailSizeLocation,_terrainData.detailMaps[i].detailMapSize);
}
auto alpha_location = glGetUniformLocation(glProgram->getProgram(),"u_has_alpha");
@ -145,7 +146,7 @@ void Terrain::onDraw(const Mat4 &transform, uint32_t flags)
_oldTerrrainModelMatrix = terrainWorldTransform;
}
quad->updateAABB(_oldTerrrainModelMatrix);
_quadRoot->updateAABB(_oldTerrrainModelMatrix);
if(_isCameraViewChanged || _isTerrainModelMatrixChanged)
{
@ -157,11 +158,11 @@ void Terrain::onDraw(const Mat4 &transform, uint32_t flags)
if(_isCameraViewChanged || _isTerrainModelMatrixChanged)
{
quad->resetNeedDraw(true);//reset it
_quadRoot->resetNeedDraw(true);//reset it
//camera frustum culling
quad->cullByCamera(camera,_oldTerrrainModelMatrix);
_quadRoot->cullByCamera(camera,_oldTerrrainModelMatrix);
}
quad->draw();
_quadRoot->draw();
if(_isCameraViewChanged)
{
_isCameraViewChanged = false;
@ -219,7 +220,7 @@ void Terrain::initHeightMap(const char * heightMap)
if(m+1<chunk_amount_y) _chunkesArray[m][n]->front = _chunkesArray[m+1][n];
}
}
quad = new QuadTree(0,0,imageWidth,imageHeight,this);
_quadRoot = new QuadTree(0,0,imageWidth,imageHeight,this);
}
Terrain::Terrain()
@ -511,7 +512,7 @@ void Terrain::resetHeightMap(const char * heightMap)
}
}
}
delete quad;
delete _quadRoot;
initHeightMap(heightMap);
}
@ -527,7 +528,112 @@ float Terrain::getMaxHeight()
cocos2d::AABB Terrain::getAABB()
{
return quad->_worldSpaceAABB;
return _quadRoot->_worldSpaceAABB;
}
Terrain::QuadTree * Terrain::getQuadTree()
{
return _quadRoot;
}
void Terrain::setAlphaMap(cocos2d::Texture2D * newAlphaMapTexture)
{
_alphaMap->release();
_alphaMap = newAlphaMapTexture;
}
void Terrain::setDetailMap(unsigned int index, DetailMap detailMap)
{
if(index>4)
{
CCLOG("invalid DetailMap index %d\n",index);
}
_terrainData.detailMaps[index] = detailMap;
if(_detailMapTextures[index])
{
_detailMapTextures[index]->release();
}
_detailMapTextures[index] = new (std::nothrow)Texture2D();
auto textImage = new (std::nothrow)Image();
textImage->initWithImageFile(detailMap.detailMapSrc);
_detailMapTextures[index]->initWithImage(textImage);
}
Terrain::ChunkIndices Terrain::lookForIndicesLOD(int neighborLod[4], int selfLod, bool * result)
{
(* result) =false;
ChunkIndices tmp;
tmp.indices = 0;
tmp.size = 0;
if(_chunkLodIndicesSet.empty())
{
(* result) =false;
return tmp;
}else
{
int test[5];
memcpy(test,neighborLod,sizeof(int [4]));
test[4] = selfLod;
for(int i =0;i<_chunkLodIndicesSet.size();i++)
{
if(memcmp(test,_chunkLodIndicesSet[i].relativeLod,sizeof(test))==0)
{
(*result) = true;
return _chunkLodIndicesSet[i]._chunkIndices;
}
}
}
(* result) =false;
return tmp;
}
Terrain::ChunkIndices Terrain::insertIndicesLOD(int neighborLod[4], int selfLod, GLushort * indices,int size)
{
ChunkLODIndices lodIndices;
memcpy(lodIndices.relativeLod,neighborLod,sizeof(int [4]));
lodIndices.relativeLod[4] = selfLod;
lodIndices._chunkIndices.size = size;
glGenBuffers(1,&(lodIndices._chunkIndices.indices));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lodIndices._chunkIndices.indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*size,indices,GL_STATIC_DRAW);
this->_chunkLodIndicesSet.push_back(lodIndices);
return lodIndices._chunkIndices;
}
Terrain::ChunkIndices Terrain::lookForIndicesLODSkrit(int selfLod, bool * result)
{
ChunkIndices badResult;
badResult.indices = 0;
badResult.size = 0;
if(this->_chunkLodIndicesSkirtSet.empty())
{
(*result) = false;
return badResult;
}
for(int i =0;i<_chunkLodIndicesSkirtSet.size();i++)
{
if(_chunkLodIndicesSkirtSet[i].selfLod == selfLod)
{
(*result) = true;
return _chunkLodIndicesSkirtSet[i]._chunkIndices;
}
}
(*result) = false;
return badResult;
}
Terrain::ChunkIndices Terrain::insertIndicesLODSkirt(int selfLod, GLushort * indices, int size)
{
ChunkLODIndicesSkirt skirtIndices;
skirtIndices.selfLod = selfLod;
skirtIndices._chunkIndices.size = size;
glGenBuffers(1,&(skirtIndices._chunkIndices.indices));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skirtIndices._chunkIndices.indices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*size,indices,GL_STATIC_DRAW);
this->_chunkLodIndicesSkirtSet.push_back(skirtIndices);
return skirtIndices._chunkIndices;
}
void Terrain::Chunk::finish()
@ -568,10 +674,21 @@ void Terrain::Chunk::bindAndDraw()
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
if(_terrain->_isCameraViewChanged)
{
switch (_terrain->_crackFixedType)
{
case CrackFixedType::SKIRT:
updateIndicesLODSkirt();
break;
case CrackFixedType::INCREASE_LOWER:
updateVerticesForLOD();
updateIndices();
updateIndicesLOD();
break;
default:
break;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vbo[1]);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_chunkIndices.indices);
GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION | GL::VERTEX_ATTRIB_FLAG_TEX_COORD| GL::VERTEX_ATTRIB_FLAG_NORMAL);
unsigned long offset = 0;
//position
@ -583,8 +700,8 @@ void Terrain::Chunk::bindAndDraw()
glEnableVertexAttribArray(_terrain->_normalLocation);
//normal
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_NORMAL,3,GL_FLOAT,GL_FALSE,sizeof(TerrainVertexData),(GLvoid *)offset);
glDrawElements(GL_TRIANGLES, (GLsizei)_lod[_currentLod].indices.size(), GL_UNSIGNED_SHORT, 0);
glDrawElements(GL_TRIANGLES, (GLsizei)_chunkIndices.size, GL_UNSIGNED_SHORT, 0);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, _chunkIndices.size);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
#endif
@ -594,6 +711,10 @@ void Terrain::Chunk::generate(int imgWidth,int imageHei,int m,int n,const unsign
{
pos_y = m;
pos_x = n;
switch (_terrain->_crackFixedType)
{
case CrackFixedType::SKIRT:
{
for(int i=_size.height*m;i<=_size.height*(m+1);i++)
{
if(i>=imageHei) break;
@ -604,6 +725,40 @@ void Terrain::Chunk::generate(int imgWidth,int imageHei,int m,int n,const unsign
vertices.push_back (v);
}
}
// add two skirt
//#1
for(int i =_size.height*m;i<=_size.height*(m+1);i++)
{
auto v = _terrain->vertices[i*imgWidth +_size.width*(n+1)];
v.position.y = -5;
vertices.push_back (v);
}
//#2
for(int j =_size.width*n;j<=_size.width*(n+1);j++)
{
auto v = _terrain->vertices[_size.height*(m+1)*imgWidth + j];
v.position.y = -5;
vertices.push_back (v);
}
}
break;
case CrackFixedType::INCREASE_LOWER:
{
for(int i=_size.height*m;i<=_size.height*(m+1);i++)
{
if(i>=imageHei) break;
for(int j=_size.width*n;j<=_size.width*(n+1);j++)
{
if(j>=imgWidth)break;
auto v =_terrain->vertices[i*imgWidth + j];
vertices.push_back (v);
}
}
}
break;
}
calculateAABB();
finish();
}
@ -622,7 +777,7 @@ Terrain::Chunk::Chunk()
}
}
void Terrain::Chunk::updateIndices()
void Terrain::Chunk::updateIndicesLOD()
{
int currentNeighborLOD[4];
if(left)
@ -646,6 +801,12 @@ void Terrain::Chunk::updateIndices()
{
return;// no need to update
}
bool isOk;
_chunkIndices = _terrain->lookForIndicesLOD(currentNeighborLOD,_currentLod,&isOk);
if(isOk)
{
return;
}
memcpy(_neighborOldLOD,currentNeighborLOD,sizeof(currentNeighborLOD));
_oldLod = _currentLod;
int gridY = _size.height;
@ -796,8 +957,8 @@ void Terrain::Chunk::updateIndices()
_lod[_currentLod].indices.push_back(i+step);
}
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*_lod[_currentLod].indices.size(),&_lod[_currentLod].indices[0],GL_STATIC_DRAW);
_chunkIndices = _terrain->insertIndicesLOD(currentNeighborLOD,_currentLod,&_lod[_currentLod].indices[0],_lod[_currentLod].indices.size());
}else{
//No lod difference, use simple method
_lod[_currentLod].indices.clear();
@ -816,8 +977,7 @@ void Terrain::Chunk::updateIndices()
_lod[_currentLod].indices.push_back (nLocIndex + step * (gridX+1) + step);
}
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vbo[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLushort)*_lod[_currentLod].indices.size(),&_lod[_currentLod].indices[0],GL_STATIC_DRAW);
_chunkIndices = _terrain->insertIndicesLOD(currentNeighborLOD,_currentLod,&_lod[_currentLod].indices[0],_lod[_currentLod].indices.size());
}
}
@ -894,6 +1054,64 @@ Terrain::Chunk::~Chunk()
// glDeleteBuffers(2,vbo);
}
void Terrain::Chunk::updateIndicesLODSkirt()
{
if(_oldLod == _currentLod) return;
_oldLod = _currentLod;
bool isOk;
_chunkIndices = _terrain->lookForIndicesLODSkrit(_currentLod,&isOk);
if(isOk) return;
int gridY = _size.height;
int gridX = _size.width;
int step = int(powf(2.0f, float(_currentLod)));
for(int i =0;i<gridY;i+=step)
{
for(int j = 0;j<gridX;j+=step)
{
int nLocIndex = i * (gridX+1) + j;
_lod[_currentLod].indices.push_back (nLocIndex);
_lod[_currentLod].indices.push_back (nLocIndex + step * (gridX+1));
_lod[_currentLod].indices.push_back (nLocIndex + step);
_lod[_currentLod].indices.push_back (nLocIndex + step);
_lod[_currentLod].indices.push_back (nLocIndex + step * (gridX+1));
_lod[_currentLod].indices.push_back (nLocIndex + step * (gridX+1) + step);
}
}
//add skirt
//#1
for(int i =0;i<gridY;i+=step)
{
int nLocIndex = i * (gridX+1) + gridX-step+1;
_lod[_currentLod].indices.push_back (nLocIndex);
_lod[_currentLod].indices.push_back (nLocIndex + step * (gridX+1));
_lod[_currentLod].indices.push_back ((gridY+1) *(gridX+1)+i);
_lod[_currentLod].indices.push_back ((gridY+1) *(gridX+1)+i);
_lod[_currentLod].indices.push_back (nLocIndex + step * (gridX+1));
_lod[_currentLod].indices.push_back ((gridY+1) *(gridX+1)+i+step);
}
//#2
for(int j =0;j<gridX;j+=step)
{
int nLocIndex = (gridY-step+1)* (gridX+1) + j;
_lod[_currentLod].indices.push_back (nLocIndex);
_lod[_currentLod].indices.push_back ((gridX+1)*(gridY+1)+_size.height+1 +j);
_lod[_currentLod].indices.push_back (nLocIndex + step);
_lod[_currentLod].indices.push_back (nLocIndex + step);
_lod[_currentLod].indices.push_back ((gridX+1)*(gridY+1)+_size.height+1 +j);
_lod[_currentLod].indices.push_back ((gridX+1)*(gridY+1)+_size.height+1 +j+step);
}
_chunkIndices = _terrain->insertIndicesLODSkirt(_currentLod,&_lod[_currentLod].indices[0],_lod[_currentLod].indices.size());
}
Terrain::QuadTree::QuadTree(int x, int y, int w, int h, Terrain * terrain)
{
_terrain = terrain;

View File

@ -32,6 +32,12 @@ THE SOFTWARE.
#include "3d/CCRay.h"
#include <vector>
NS_CC_BEGIN
/**
* @addtogroup _3d
* @{
*/
/*
* the maximum amount of the chunkes
**/
@ -73,9 +79,15 @@ NS_CC_BEGIN
* We can use ray-terrain intersection to pick a point of the terrain;
* Also we can get an arbitrary point of the terrain's height and normal vector for convenience .
**/
class CC_DLL Terrain :public Node{
class CC_DLL Terrain :public Node
{
public:
enum class CrackFixedType{
SKIRT,
INCREASE_LOWER,
};
/*
*DetailMap
*this struct maintain a detail map data ,including source file ,detail size.
@ -120,6 +132,24 @@ public:
};
private:
struct ChunkIndices
{
GLuint indices;
unsigned short size;
};
struct ChunkLODIndices
{
int relativeLod[5];
ChunkIndices _chunkIndices;
};
struct ChunkLODIndicesSkirt
{
int selfLod;
ChunkIndices _chunkIndices;
};
/*
*terrain vertices internal data format
**/
@ -154,6 +184,7 @@ private:
std::vector<GLushort> indices;
};
GLuint vbo[2];
ChunkIndices _chunkIndices;
/*we now have four levels of detail*/
LOD _lod[4];
/*AABB in local space*/
@ -169,7 +200,9 @@ private:
/*use linear-sample vertices for LOD mesh*/
void updateVerticesForLOD();
/*updateIndices for every frame*/
void updateIndices();
void updateIndicesLOD();
void updateIndicesLODSkirt();
void calculateSlope();
/*current LOD of the chunk*/
@ -232,7 +265,7 @@ public:
bool init();
void initHeightMap(const char* heightMap);
/*create entry*/
static Terrain * create(TerrainData &parameter);
static Terrain * create(TerrainData &parameter, CrackFixedType fixedType = CrackFixedType::INCREASE_LOWER);
/*get specified position's height mapping to the terrain*/
float getHeight(float x, float z, Vec3 * normal= nullptr);
float getHeight(Vec2 pos, Vec3*Normal = nullptr);
@ -245,6 +278,12 @@ public:
void setLODDistance(float lod_1, float lod_2, float lod_3);
/*Switch frustumCulling Flag*/
void setIsEnableFrustumCull(bool bool_value);
/** set the alpha map*/
void setAlphaMap(cocos2d::Texture2D * newAlphaMapTexture);
/**set the Detail Map */
void setDetailMap(unsigned int index, DetailMap detailMap);
// Overrides, internal use only
virtual void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4 &transform, uint32_t flags) override;
//Ray-Terrain intersection.
@ -265,6 +304,17 @@ public:
//get terrain's AABB
AABB getAABB();
//get the terrain's quad tree which is also the root node
QuadTree * getQuadTree();
ChunkIndices lookForIndicesLODSkrit(int selfLod, bool * result);
ChunkIndices lookForIndicesLOD(int neighborLod[4], int selfLod, bool * result);
ChunkIndices insertIndicesLOD(int neighborLod[4], int selfLod, GLushort * indices, int size);
ChunkIndices insertIndicesLODSkirt(int selfLod, GLushort * indices, int size);
protected:
Terrain();
@ -277,18 +327,19 @@ protected:
//calculate Normal Line for each Vertex
void calculateNormal();
protected:
std::vector <ChunkLODIndices> _chunkLodIndicesSet;
std::vector<ChunkLODIndicesSkirt> _chunkLodIndicesSkirtSet;
Mat4 _CameraMatrix;
bool _isCameraViewChanged;
TerrainData _terrainData;
bool _isDrawWire;
unsigned char * _data;
float _lodDistance[3];
std::vector<Texture2D *>textures;
Texture2D * _detailMapTextures[4];
Texture2D * _alphaMap;
CustomCommand _customCommand;
GLuint vbo[2];
QuadTree * quad;
int detailSize[4];
QuadTree * _quadRoot;
Chunk * _chunkesArray[MAX_CHUNKES][MAX_CHUNKES];
std::vector<TerrainVertexData> vertices;
std::vector<GLushort> indices;
@ -304,6 +355,11 @@ protected:
GLuint _normalLocation;
float m_maxHeight;
float m_minHeight;
CrackFixedType _crackFixedType;
};
// end of actions group
/// @}
NS_CC_END
#endif

View File

@ -48,10 +48,12 @@ TerrainSimple::TerrainSimple()
_camera->setCameraFlag(CameraFlag::USER1);
addChild(_camera);
Terrain::DetailMap r("TerrainTest/dirt.dds"),g("TerrainTest/Grass2.dds"),b("TerrainTest/road.dds"),a("TerrainTest/Grass1.dds");
Terrain::DetailMap r("TerrainTest/dirt.dds"),g("TerrainTest/Grass2.dds"),b("TerrainTest/road.dds"),a("TerrainTest/GreenSkin.jpg");
Terrain::TerrainData data("TerrainTest/heightmap16.jpg","TerrainTest/alphamap.png",r,g,b,a);
_terrain = Terrain::create(data);
_terrain = Terrain::create(data,Terrain::CrackFixedType::SKIRT);
_terrain->setLODDistance(1000.2,6.4,9.6);
_terrain->setMaxDetailMapAmount(4);
addChild(_terrain);
_terrain->setCameraMask(2);
@ -63,7 +65,7 @@ TerrainSimple::TerrainSimple()
std::string TerrainSimple::title() const
{
return "Simple Terrain";
return "Terrain with skirt";
}
std::string TerrainSimple::subtitle() const
@ -178,16 +180,15 @@ TerrainWalkThru::TerrainWalkThru()
_camera->setCameraFlag(CameraFlag::USER1);
addChild(_camera);
Terrain::DetailMap r("TerrainTest/dirt.dds"),g("TerrainTest/Grass2.dds",10),b("TerrainTest/road.dds"),a("TerrainTest/Grass1.dds",20);
Terrain::DetailMap r("TerrainTest/dirt.dds"),g("TerrainTest/Grass2.dds",10),b("TerrainTest/road.dds"),a("TerrainTest/GreenSkin.jpg",20);
Terrain::TerrainData data("TerrainTest/heightmap16.jpg","TerrainTest/alphamap.png",r,g,b,a);
Terrain::TerrainData data("TerrainTest/heightmap16.jpg","TerrainTest/alphamap.png",r,g,b,a,Size(32,32),40.0f,2);
_terrain = Terrain::create(data);
_terrain->setScale(20);
_terrain->setMaxDetailMapAmount(4);
_terrain->setCameraMask(2);
_terrain->setDrawWire(false);
_terrain->setLODDistance(150,220,300);
_terrain->setLODDistance(64,128,192);
_player = Player::create("Sprite3DTest/girl.c3b",_camera,_terrain);
_player->setCameraMask(2);
_player->setScale(0.08);

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB