update terrain test add new method to get normal

This commit is contained in:
tangziwen 2015-01-27 15:18:59 +08:00
parent d6c3320d49
commit 9ec366a130
4 changed files with 74 additions and 61 deletions

View File

@ -99,9 +99,9 @@ NS_CC_BEGIN
bool Terrain::init()
{
_lodDistance[0]=96;
_lodDistance[1]=288;
_lodDistance[2]=480;
_lodDistance[0]=288;
_lodDistance[1]=512;
_lodDistance[2]=1000;
auto shader = GLProgram::createWithByteArrays(vertex_shader,fragment_shader_RGB_4_DETAIL);
auto state = GLProgramState::create(shader);
setGLProgramState(state);
@ -241,12 +241,12 @@ void Terrain::setChunksLOD(Vec3 cameraPos)
}
}
float Terrain::getHeight(float x, float y ,float z)
float Terrain::getHeight(float x, float y ,float z,Vec3 * normal)
{
Vec2 pos = Vec2(x,z);
//top-left
Vec2 tl = Vec2(-1*_terrainData.mapScale*imageWidth/2,-1*_terrainData.mapScale*imageWidth/2);
Vec2 tl = Vec2(-1*_terrainData.mapScale*imageWidth/2,-1*_terrainData.mapScale*imageHeight/2);
auto result = getNodeToWorldTransform()*Vec4(tl.x,0.0f,tl.y,1.0f);
tl = Vec2(result.x,result.z);
@ -266,19 +266,33 @@ float Terrain::getHeight(float x, float y ,float z)
float v =image_y - (int)image_y;
float i = (int)image_x;
float j = (int)image_y;
if(image_x>=imageWidth-1 || image_y >=imageHeight-1 || image_x<0 || image_y<0)
{
return y;
}else
{
float a = getImageHeight(i,j)*getScaleY();
float b = getImageHeight(i,j+1)*getScaleY();
float c = getImageHeight(i+1,j)*getScaleY();
float d = getImageHeight(i+1,j+1)*getScaleY();
if(normal)
{
normal->x = c - b;
normal->y = 2;
normal->z = d - a;
normal->normalize();
//(*normal) = (1-u)*(1-v)*getNormal(i,j)+ (1-u)*v*getNormal(i,j+1) + u*(1-v)*getNormal(i+1,j)+ u*v*getNormal(i+1,j+1);
}
float reuslt = (1-u)*(1-v)*getImageHeight(i,j)*getScaleY() + (1-u)*v*getImageHeight(i,j+1)*getScaleY() + u*(1-v)*getImageHeight(i+1,j)*getScaleY() + u*v*getImageHeight(i+1,j+1)*getScaleY();
return reuslt;
}
}
float Terrain::getHeight(Vec3 pos)
float Terrain::getHeight(Vec3 pos,Vec3*Normal)
{
return getHeight(pos.x,pos.y,pos.z);
return getHeight(pos.x,pos.y,pos.z,Normal);
}
float Terrain::getImageHeight(int pixel_x,int pixel_y)
@ -387,6 +401,20 @@ Terrain::~Terrain()
free(_chunkesArray);
}
cocos2d::Vec3 Terrain::getNormal(int pixel_x,int pixel_y)
{
float a = getImageHeight(pixel_x,pixel_y)*getScaleY();
float b = getImageHeight(pixel_x,pixel_y+1)*getScaleY();
float c = getImageHeight(pixel_x+1,pixel_y)*getScaleY();
float d = getImageHeight(pixel_x+1,pixel_y+1)*getScaleY();
Vec3 normal;
normal.x = c - b;
normal.y = 2;
normal.z = d - a;
normal.normalize();
return normal;
}
void Terrain::Chunk::finish()
{
//genearate two VBO ,the first for vertices, we just setup datas once ,won't changed at all

View File

@ -193,9 +193,9 @@ public:
/*create entry*/
static Terrain * create(TerrainData &parameter);
/*get specified position's height mapping to the terrain*/
float getHeight(float x, float y, float z);
float getHeight(Vec3 pos);
float getHeight(float x, float y, float z,Vec3 * normal = NULL);
float getHeight(Vec3 pos,Vec3 * nromal = NULL);
Vec3 getNormal(int pixel_x,int pixel_y);
/*get height from the raw height map*/
float getImageHeight(int pixel_x,int pixel_y);
/*Debug Use only, show the wireline instead of the surface. only support desktop platform*/

View File

@ -2,8 +2,8 @@
Vec3 camera_offset(0,30,90);
Vec3 camera_offset(0,45,60);
#define PLAYER_HEIGHT 0
static std::function<Layer*()> createFunctions[] =
{
CL(TerrainSimple),
@ -44,7 +44,7 @@ TerrainSimple::TerrainSimple()
Size visibleSize = Director::getInstance()->getVisibleSize();
//use custom camera
auto camera = Camera::createPerspective(60,visibleSize.width/visibleSize.height,0.1,200);
auto camera = Camera::createPerspective(60,visibleSize.width/visibleSize.height,0.1,500);
camera->setCameraFlag(CameraFlag::USER1);
addChild(camera);
@ -150,7 +150,7 @@ TerrainWalkThru::TerrainWalkThru()
_camera->setCameraFlag(CameraFlag::USER1);
addChild(_camera);
Terrain::TerrainData a("TerrainTest/heightmap16.jpg","TerrainTest/sand.jpg");
Terrain::TerrainData a("TerrainTest/heightmap16.jpg","TerrainTest/sand.jpg",Size(32,32),3);
_terrain = Terrain::create(a);
_terrain->setScale(20);
@ -159,14 +159,21 @@ TerrainWalkThru::TerrainWalkThru()
_action = new PlayerAction(_camera,_terrain);
_action->retain();
_player =Sprite3D::create("Sprite3DTest/orc.c3b");
_player =Sprite3D::create("Sprite3DTest/girl.c3b");
_player->runAction(_action);
_player->setCameraMask(2);
//_player->setScale(0.1);
_player->setPositionY(_terrain->getHeight(_player->getPosition3D()));
_player->setScale(0.08);
_player->setPositionY(_terrain->getHeight(_player->getPosition3D())+PLAYER_HEIGHT);
auto animation = Animation3D::create("Sprite3DTest/girl.c3b","Take 001");
if (animation)
{
auto animate = Animate3D::create(animation);
_player->runAction(RepeatForever::create(animate));
}
_camera->setPosition3D(_player->getPosition3D()+camera_offset);
_camera->setRotation3D(Vec3(-15,0,0));
_camera->setRotation3D(Vec3(-45,0,0));
forward = Label::create("forward","arial",22);
forward->setPosition(0,200);
@ -184,10 +191,6 @@ TerrainWalkThru::TerrainWalkThru()
right = Label::create("turn right","arial",22);
right->setPosition(0,150);
right->setAnchorPoint(Vec2(0,0));
addChild(forward);
addChild(backward);
addChild(left);
addChild(right);
addChild(_player);
addChild(_terrain);
}
@ -216,40 +219,6 @@ void TerrainWalkThru::onTouchesMoved(const std::vector<cocos2d::Touch*>& touches
void TerrainWalkThru::onTouchesBegan(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
{
auto touch = touches[0];
Size s = left->getContentSize();
Rect rect = Rect(left->getPositionX(), left->getPositionY(), s.width, s.height);
auto location = touch->getLocation();
if(rect.containsPoint(location))
{
//turn left
_action->turnLeft();
}
s = right->getContentSize();
rect = Rect(right->getPositionX(), right->getPositionY(), s.width, s.height);
if(rect.containsPoint(location))
{
//turn right
_action->turnRight();
}
s = forward->getContentSize();
rect = Rect(forward->getPositionX(), forward->getPositionY(), s.width, s.height);
if(rect.containsPoint(location))
{
//forward
_action->forward();
}
s = backward->getContentSize();
rect = Rect(backward->getPositionX(), backward->getPositionY(), s.width, s.height);
if(rect.containsPoint(location))
{
//backward
_action->backward();
}
}
void TerrainWalkThru::onTouchesEnd(const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event)
@ -296,7 +265,11 @@ void TerrainWalkThru::onTouchesEnd(const std::vector<cocos2d::Touch*>& touches,
startPosition = middlePoint;
}
Vec3 collisionPoint = (startPosition + endPosition) * 0.5f;
dir = collisionPoint - _player->getPosition3D();
dir.y = 0;
dir.normalize();
_action->_headingAngle = -1*acos(dir.dot(Vec3(0,0,-1)));
dir.cross(dir,Vec3(0,0,-1),&_action->_headingAxis);
_action->_targetPos=collisionPoint;
_action->forward();
}
@ -326,7 +299,6 @@ void PlayerAction::step(float dt)
Vec3 offset = newFaceDir * 25.0f * dt;
curPos+=offset;
player->setPosition3D(curPos);
player->setPositionY(_terrain->getHeight(player->getPosition3D()));
}
break;
case PLAYER_STATE_BACKWARD:
@ -335,7 +307,6 @@ void PlayerAction::step(float dt)
player->getNodeToWorldTransform().getForwardVector(&forward_vec);
forward_vec.normalize();
player->setPosition3D(player->getPosition3D()-forward_vec*15*dt);
player->setPositionY(_terrain->getHeight(player->getPosition3D()));
}
break;
case PLAYER_STATE_LEFT:
@ -351,10 +322,21 @@ void PlayerAction::step(float dt)
default:
break;
}
Vec3 Normal;
float player_h = _terrain->getHeight(player->getPosition3D(),&Normal);
float dot_product = Normal.dot(Vec3(0,1,0));
player->setPositionY(player_h+PLAYER_HEIGHT);
Quaternion q2;
q2.createFromAxisAngle(Vec3(0,1,0),-M_PI,&q2);
Quaternion headingQ;
headingQ.createFromAxisAngle(_headingAxis,_headingAngle,&headingQ);
player->setRotationQuat(headingQ*q2);
auto vec_offset =Vec4(camera_offset.x,camera_offset.y,camera_offset.z,1);
vec_offset = player->getNodeToWorldTransform()*vec_offset;
_cam->setRotation3D(player->getRotation3D());
_cam->setPosition3D(Vec3(vec_offset.x,vec_offset.y,vec_offset.z));
// _cam->setRotation3D(player->getRotation3D());
_cam->setPosition3D(player->getPosition3D() + camera_offset);
updateState();
}
@ -375,6 +357,7 @@ void PlayerAction::idle()
PlayerAction::PlayerAction(Camera * cam,Terrain * terrain)
{
_headingAngle = 0;
_playerState = PLAYER_STATE_IDLE;
_cam = cam;
_terrain = terrain;

View File

@ -59,6 +59,8 @@ public:
void idle();
cocos2d::Vec3 _targetPos;
void updateState();
float _headingAngle;
Vec3 _headingAxis;
private:
Terrain * _terrain;
Camera * _cam;