float Terrain::getHeightAt(float *map, int res_x, int res_y, float x, float y) { // interpolate height int ix,iy; ix = (int) x; iy = (int) y; float tx = x-ix; float ty = y-iy; float h3 = (1-ty)*getHeightAt(map, res_x, res_y, ix,iy) + ty*getHeightAt(map, res_x, res_y, ix, iy+1); float h4 = (1-ty)*getHeightAt(map, res_x, res_y, ix+1,iy) + ty*getHeightAt(map, res_x, res_y, ix+1, iy+1); return (1-tx)*h3 + (tx)*h4; }
void Terrain::loadHeightMap(string filename, int res_x, int res_y) { PNG inputFile; inputFile.load(filename); dim_x = inputFile.width; dim_y = inputFile.height; unsigned char * data = inputFile.getData(); int size = dim_x*dim_y; float * originalHeightMap = new float[size]; int i,x,y; for (i=0; i<size; i++){ originalHeightMap[i] = 256*data[2*i]+data[2*i + 1]; } // recalculate to the given resolution (use linear interpolation...) size = res_x*res_y; heightMap = new float[size]; float step_x = float(dim_x)/float(res_x); float step_y = float(dim_y)/float(res_y); for(x=0; x<res_x; x++) { for(y=0; y<res_y; y++) { heightMap[x*res_y + y] = getHeightAt(originalHeightMap, dim_x, dim_y, float(x*step_x), float(y*step_y)); } } SAFE_DELETE_ARRAY_PTR(originalHeightMap); }
/** Addition from SongOfTheWeave */ Vector3 TerrainInfo::getTangentAt(float x, float z) const { Ogre::Vector3 v3Return; int flip = 1; Vector3 here (x, getHeightAt(x, z), z); Vector3 left (x - 1, getHeightAt(x - 1, z), z); if (left.x < 0.0) { flip *= -1; left = Vector3(x + 1, getHeightAt(x + 1, z), z); } left -= here; v3Return = flip * left; v3Return.normalise(); return v3Return; }
float Terrain::getHeightAt(float x, float y) { //x+=5.f; //y+=5.f; // recalc in raster position from space coords x *= red_x; y *= red_y; // interpolate height int ix,iy; ix = (int) x; iy = (int) y; //return getHeightAt(ix,iy); float tx = x-ix; float ty = y-iy; float h3 = (1-ty)*getHeightAt(ix,iy) + ty*getHeightAt(ix, iy+1); float h4 = (1-ty)*getHeightAt(ix+1,iy) + ty*getHeightAt(ix+1, iy+1); return (1-tx)*h3 + (tx)*h4; }
float Heightmap::getInterpolatedHeightAt(float x, float z) { if(0.0f <= x && x <= 1.0f && 0.0f <= z && z <= 1.0f) { int col1 = floor<int>(x * (float)(columns + 1)); int col2 = col1 + 1; float dx = x * (float)(columns + 1) - (float)col1; int row1 = floor<int>(z * (float)(rows + 1)); int row2 = row1 + 1; float dz = z * (float)(rows + 1) - (float)row1; float x1 = x - dx; float x2 = x1 + 1.0f; float z1 = z - dz; float z2 = z1 + 1.0f; float height = 0.0f; if(dx + dz < 1) { triangle_intersection(vec3(x1, getHeightAt(col1, row1), z1), vec3(x1, getHeightAt(col1, row2), z2), vec3(x2, getHeightAt(col2, row1), z1), vec3(x, 0, z), vec3(0, 1, 0), &height); } else { triangle_intersection(vec3(x2, getHeightAt(col2, row1), z1), vec3(x1, getHeightAt(col1, row2), z2), vec3(x2, getHeightAt(col2, row2), z2), vec3(x, 0, z), vec3(0, 1, 0), &height); } return height; } return 0.0f; }
Vector3 TerrainInfo::getNormalAt(float x, float z) const { int flip = 1; Vector3 here (x, getHeightAt(x, z), z); Vector3 left (x-1, getHeightAt(x-1, z), z); Vector3 down (x, getHeightAt(x, z+1), z+1); if (left.x < 0.0) { flip *= -1; left = Vector3(x+1, getHeightAt(x+1, z), z); } if (down.z >= mOffset.z + mScale.z*(mHeight-1)) { flip *= -1; down = Vector3(x, getHeightAt(x, z-1), z-1); } left -= here; down -= here; Vector3 norm = flip * left.crossProduct(down); norm.normalise(); return norm; }
std::pair<bool, Vector3> TerrainInfo::rayIntersects(const Ray& ray) const { AxisAlignedBox box = getExtents(); Vector3 point = ray.getOrigin(); Vector3 dir = ray.getDirection(); // first, does the ray start from inside the terrain extents? if (!box.contains(point)) { // not inside the box, so let's see if we are actually // colliding with it pair<bool, Real> res = ray.intersects(box); if (!res.first) return make_pair(false, Vector3::ZERO); // update point to the collision position point = ray.getPoint(res.second); } // now move along the ray until we intersect or leave the bounding box while (true) { // have we arived at or under the terrain height? // note that this approach means that ray queries from below won't work // correctly, but then again, that shouldn't be a usual case... float height = getHeightAt(point.x, point.z); if (point.y <= height) { point.y = height; return make_pair(true, point); } // move further... point += dir; // check if we are still inside the boundaries if (point.x < box.getMinimum().x || point.z < box.getMinimum().z || point.x > box.getMaximum().x || point.z > box.getMaximum().z) return make_pair(false, Vector3::ZERO); } }
void Terrain::init() { // material material = new Material(v4(0.2), v4(0.7), v4(0.0), 0.5); // load & create shaders int shaderID = shaderManager->loadShader("Terrain", TERRAIN_VS_FILENAME, TERRAIN_FS_FILENAME); shader = shaderManager->getShader(shaderID); border_values_location = shader->getLocation("border_values"); border_widths_location = shader->getLocation("border_widths"); heightInterval_location = shader->getLocation("visibleHeightInterval"); // load heightmap int resolution_x = TERRAIN_RESOLUTION_X; int resolution_y = TERRAIN_RESOLUTION_Y; float size_x = TERRAIN_SIZE_X; float size_y = TERRAIN_SIZE_Y; float step_x =size_x/float(resolution_x); float step_y =size_y/float(resolution_y); red_x = 1.f/step_x; red_y = 1.f/step_y; loadHeightMap(HEIGHTMAP_SOURCE, resolution_x, resolution_y); // load textures loadTextures(TERRAIN_TEX_NAME, TERRAIN_TEX_COUNT); // shadow map shader->linkTexture(textureManager->getTexture(textureManager->shadowMapID)); LCmatrixLoc = shader->getLocation("LightMVPCameraVInverseMatrix"); shadowMappingEnabledLoc = shader->getLocation("shadowMappingEnabled"); fastModeLoc = shader->getLocation("fastMode"); LMV_CVImatrixLoc = shader->getLocation("LightMViewCameraViewInverseMatrix"); LPmatrixLoc = shader->getLocation("LightProjectionMatrix"); dim_x = resolution_x; dim_y = resolution_y; drawingMethod = GL_TRIANGLE_STRIP; // create grid of triangles glGenBuffers(1, &eboId); glGenBuffers(1, &vboId); int ch = 3; vertices = new GLfloat[dim_x*dim_y*ch]; normals = new GLfloat[dim_x*dim_y*ch]; texCoords = new GLfloat[dim_x*dim_y*2]; elements = new GLuint[(dim_x-1)*2*dim_y]; channels [INDEX] = 1; channels [VERTEX] = 3; channels [NORMAL] = 3; channels [TEXCOORD0] = 2; typeSizes [INDEX] = sizeof(GLuint); typeSizes [VERTEX] = sizeof(GLfloat); typeSizes [NORMAL] = sizeof(GLfloat); typeSizes [TEXCOORD0] = sizeof(GLfloat); glTypes [INDEX] = GL_UNSIGNED_INT; glTypes [VERTEX] = GL_FLOAT; glTypes [NORMAL] = GL_FLOAT; glTypes [TEXCOORD0] = GL_FLOAT; for (int k = 0; k < VBO_ATR_COUNT; k++){ sizes[k]=0; } sizes [INDEX] = (dim_x-1)*2*dim_y * channels[INDEX] * typeSizes[INDEX]; sizes [VERTEX] = dim_x * dim_y * channels[VERTEX] * typeSizes[VERTEX]; sizes [NORMAL] = dim_x * dim_y * channels[NORMAL] * typeSizes[NORMAL]; sizes [TEXCOORD0] = dim_x * dim_y * channels[TEXCOORD0]* typeSizes[TEXCOORD0]; offsets [INDEX] = 0; offsets [VERTEX] = 0; offsets [NORMAL] = offsets [VERTEX] + sizes [VERTEX]; offsets [TEXCOORD0] = offsets [NORMAL] + sizes [NORMAL]; int x,y,n; vboCount = 0; float tex_cnt_x = 100.f; float tex_cnt_y = 100.f; sz_x = size_x; sz_y = size_y; float sx2 = sz_x/2.f; float sy2 = sz_y/2.f; int hx, hy; for (x=0; x<dim_x; x++){ for (y=0; y<dim_y; y++){ vertices[(x*dim_y + y)*ch + 0] = x*step_x - sx2;//x vertices[(x*dim_y + y)*ch + 1] = getHeightAt(x,y);//height vertices[(x*dim_y + y)*ch + 2] = y*step_y - sy2;//y // normals v3 normal; normal.x = getHeightAt(x-1,y) - getHeightAt(x+1,y); normal.y = step_x; normal.z = getHeightAt(x,y-1) - getHeightAt(x,y+1); normal.normalize(); if (normal.y<0){ normal = -normal; } normals[(x*dim_y + y)*ch + 0] = normal.x; normals[(x*dim_y + y)*ch + 1] = normal.y; normals[(x*dim_y + y)*ch + 2] = normal.z; // texCoords texCoords[(x*dim_y + y)*2 + 0] = x * tex_cnt_x / dim_x; texCoords[(x*dim_y + y)*2 + 1] = y * tex_cnt_y / dim_y; vboCount += 3; } } int eli = 0; bool reverse = false; for (x=0; x<dim_x-1; x++){ if (!reverse){ for (y=0; y<dim_y; y++){ elements[eli] = (x+1)*dim_y + y; eli++; elements[eli] = (x)*dim_y + y; eli++; } } else { for (y=dim_y-1; y>=0; y--){ elements[eli] = (x)*dim_y + y; eli++; elements[eli] = (x+1)*dim_y + y; eli++; } } reverse = !reverse; } eboCount = eli; // total vbo buffer size int vboSize=0; for (int b = 0; b < VBO_ATR_COUNT; b++){ if (b!=INDEX){ vboSize+=sizes[b]; } } glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizes[INDEX], elements, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, vboId); // alloc space glBufferData(GL_ARRAY_BUFFER, vboSize, 0, GL_STATIC_DRAW); // fill vertices glBufferSubData(GL_ARRAY_BUFFER, offsets[VERTEX], sizes[VERTEX], vertices); // fill normals glBufferSubData(GL_ARRAY_BUFFER, offsets[NORMAL], sizes[NORMAL], normals); // fill texcoords glBufferSubData(GL_ARRAY_BUFFER, offsets[TEXCOORD0], sizes[TEXCOORD0], texCoords); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); }