void init(const HeightMap &hm, f32 scale, colour_func cf, IVideoDriver *driver) { Scale = scale; const u32 mp = driver -> getMaximalPrimitiveCount(); Width = hm.width(); Height = hm.height(); const u32 sw = mp / (6 * Height); // the width of each piece u32 i=0; for(u32 y0 = 0; y0 < Height; y0 += sw) { u16 y1 = y0 + sw; if (y1 >= Height) y1 = Height - 1; // the last one might be narrower addstrip(hm, cf, y0, y1, i); ++i; } if (i<Mesh->getMeshBufferCount()) { // clear the rest for (u32 j=i; j<Mesh->getMeshBufferCount(); ++j) { Mesh->getMeshBuffer(j)->drop(); } Mesh->MeshBuffers.erase(i,Mesh->getMeshBufferCount()-i); } Mesh->recalculateBoundingBox(); }
void init(const HeightMap &hm, f32 scale, colour_func cf, IVideoDriver *driver) { Scale = scale; const u32 mp = driver -> getMaximalPrimitiveCount(); Width = hm.width(); Height = hm.height(); const u32 sw = mp / (6 * Height); // the width of each piece u32 i=0; for(u32 y0 = 0; y0 < Height; y0 += sw) { u16 y1 = y0 + sw; if (y1 >= Height) y1 = Height - 1; // the last one might be narrower addstrip(hm, cf, y0, y1, i); ++i; } if (i<Mesh->getMeshBufferCount()) { // clear the rest for (u32 j=i; j<Mesh->getMeshBufferCount(); ++j) { Mesh->getMeshBuffer(j)->drop(); } Mesh->MeshBuffers.erase(i,Mesh->getMeshBufferCount()-i); } // set dirty flag to make sure that hardware copies of this // buffer are also updated, see IMesh::setHardwareMappingHint Mesh->setDirty(); Mesh->recalculateBoundingBox(); }
/** Start at given point, move in given direction, find and Smooth coast in that direction */ static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int dir_y) { const int max_coast_dist_from_edge = 35; const int max_coast_Smooth_depth = 35; int x, y; int ed; // coast distance from edge int depth; height_t h_prev = 16; height_t h; assert(IsValidXY(org_x, org_y)); /* Search for the coast (first non-water tile) */ for (x = org_x, y = org_y, ed = 0; IsValidXY(x, y) && ed < max_coast_dist_from_edge; x += dir_x, y += dir_y, ed++) { /* Coast found? */ if (_height_map.height(x, y) > 15) break; /* Coast found in the neighborhood? */ if (IsValidXY(x + dir_y, y + dir_x) && _height_map.height(x + dir_y, y + dir_x) > 0) break; /* Coast found in the neighborhood on the other side */ if (IsValidXY(x - dir_y, y - dir_x) && _height_map.height(x - dir_y, y - dir_x) > 0) break; } /* Coast found or max_coast_dist_from_edge has been reached. * Soften the coast slope */ for (depth = 0; IsValidXY(x, y) && depth <= max_coast_Smooth_depth; depth++, x += dir_x, y += dir_y) { h = _height_map.height(x, y); h = min(h, h_prev + (4 + depth)); // coast softening formula _height_map.height(x, y) = h; h_prev = h; } }
TEST_F(Test_WorldTerrainNormalMap, slope45Degree) { const int hmSize = 2; HeightMap hm; hm.reserve(hmSize); hm.set(0, 0, 1.0f); hm.set(1, 0, 1.0f); hm.set(0, 1, 0); hm.set(1, 1, 0); NormalMap nm; nm.generate(hm); //only two normals EXPECT_EQ(nm.size(), 2); //both normals should be pointing at an angle more downish Vec3f n1 = nm.get(0); Vec3f n2 = nm.get(0); Vec3f outDown(0.0f, -.707107f, -.707107); expectVec3fAreEqual(n1, outDown); expectVec3fAreEqual(n2, outDown); { Vec3f p1(0, 1, 0); Vec3f p2(1, 1, 0); Vec3f p3(0, 0, 1); } }
void initHeightMap () { num_hm_elements = hm.sizeOfTriangleVertices()*2; vec4 hm_elements [num_hm_elements]; hm.flattenTriangles (hm_elements); // num_hm_elements = hm.getSize () * 2; // vec4 hm_elements [num_hm_elements]; // hm.flatten (hm_elements); // indices = new unsigned [ hm.sizeOfTriStripIndices () ]; // hm.flattenTriStripIndices (indices); glGenVertexArrays(1, &hm_vao); glBindVertexArray(hm_vao); GLuint buffer; glGenBuffers (1, &buffer); glBindBuffer (GL_ARRAY_BUFFER, buffer); glBufferData (GL_ARRAY_BUFFER, num_hm_elements*sizeof(vec4), hm_elements, GL_STATIC_DRAW); glEnableVertexAttribArray ( vPosition ); glVertexAttribPointer ( vPosition, 4, GL_FLOAT, GL_FALSE, sizeof(vec4)*2, BUFFER_OFFSET(0) ); glEnableVertexAttribArray( vColor ); glVertexAttribPointer ( vColor, 4, GL_FLOAT, GL_FALSE, sizeof(vec4)*2, BUFFER_OFFSET(sizeof (vec4))); }
TEST_F(Test_WorldTerrainNormalMap, flatTerrain) { const int hmSize = 2; HeightMap hm; hm.reserve(hmSize); for (int y=0; y<hmSize; y++) { for (int x=0; x<hmSize; x++) hm.set(x, y, 0.0f); } NormalMap nm; nm.generate(hm); //there should be only two normals (since there are two triangles) EXPECT_EQ(nm.size(), 2); //both normals should point straight up Vec3f n1 = nm.get(0); Vec3f n2 = nm.get(1); Vec3f up(0.0f, -1.0f, 0.0f); expectVec3fAreEqual(n1, up, "The normal is not straight up"); expectVec3fAreEqual(n2, up, "The normal is not straight up"); }
// From ReferenceTarget RefTargetHandle HeightMap::Clone(RemapDir& remap) { HeightMap* newob = new HeightMap(); //TODO: Make a copy all the data and also clone all the references newob->ReplaceReference(0,pblock2->Clone(remap)); newob->ivalid.SetEmpty(); BaseClone(this, newob, remap); return(newob); }
BOOST_FIXTURE_TEST_CASE(HeightMapTest1, Test4x4HeightMap) { HeightMap hm; hm.Swap(sample4x4); BOOST_CHECK_EQUAL(hm.At(Point2d(1, 1)), 0.0f); BOOST_CHECK_EQUAL(hm.At(Point2d(1, 2)), 1.0f); BOOST_CHECK_EQUAL(hm.At(Point2d(1, 3)), 1.0f); BOOST_CHECK_EQUAL(hm.GetSize(), 4u); }
BOOST_FIXTURE_TEST_CASE(HeightMapTest5, Test4x4HeightMap) { HeightMap hm; hm.Swap(sample4x4); Triangle3dPair tp = utils::GetTriangles(hm); BOOST_CHECK_EQUAL(tp.first, Triangle3d(Point3d(0, 0, 0), Point3d(0, 3, 0), Point3d(3, 3, 0))); BOOST_CHECK_EQUAL(tp.second, Triangle3d(Point3d(3, 3, 0), Point3d(3, 0, 0), Point3d(0, 0, 0))); }
/** * This routine sculpts in from the edge a random amount, again a Perlin * sequence, to avoid the rigid flat-edge slopes that were present before. The * Perlin noise map doesnt know where we are going to slice across, and so we * often cut straight through high terrain. the smoothing routine makes it * legal, gradually increasing up from the edge to the original terrain height. * By cutting parts of this away, it gives a far more irregular edge to the * map-edge. Sometimes it works beautifully with the existing sea & lakes, and * creates a very realistic coastline. Other times the variation is less, and * the map-edge shows its cliff-like roots. * * This routine may be extended to randomly sculpt the height of the terrain * near the edge. This will have the coast edge at low level (1-3), rising in * smoothed steps inland to about 15 tiles in. This should make it look as * though the map has been built for the map size, rather than a slice through * a larger map. * * Please note that all the small numbers; 53, 101, 167, etc. are small primes * to help give the perlin noise a bit more of a random feel. */ static void HeightMapCoastLines(uint8 water_borders) { int smallest_size = min(_settings_game.game_creation.map_x, _settings_game.game_creation.map_y); const int margin = 4; uint y, x; double max_x; double max_y; /* Lower to sea level */ for (y = 0; y <= _height_map.size_y; y++) { if (HasBit(water_borders, BORDER_NE)) { /* Top right */ max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.9, 53) + 0.25) * 5 + (perlin_coast_noise_2D(y, y, 0.35, 179) + 1) * 12); max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x); if (smallest_size < 8 && max_x > 5) max_x /= 1.5; for (x = 0; x < max_x; x++) { _height_map.height(x, y) = 0; } } if (HasBit(water_borders, BORDER_SW)) { /* Bottom left */ max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.85, 101) + 0.3) * 6 + (perlin_coast_noise_2D(y, y, 0.45, 67) + 0.75) * 8); max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x); if (smallest_size < 8 && max_x > 5) max_x /= 1.5; for (x = _height_map.size_x; x > (_height_map.size_x - 1 - max_x); x--) { _height_map.height(x, y) = 0; } } } /* Lower to sea level */ for (x = 0; x <= _height_map.size_x; x++) { if (HasBit(water_borders, BORDER_NW)) { /* Top left */ max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 2, 0.9, 167) + 0.4) * 5 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.4, 211) + 0.7) * 9); max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y); if (smallest_size < 8 && max_y > 5) max_y /= 1.5; for (y = 0; y < max_y; y++) { _height_map.height(x, y) = 0; } } if (HasBit(water_borders, BORDER_SE)) { /* Bottom right */ max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.85, 71) + 0.25) * 6 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.35, 193) + 0.75) * 12); max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y); if (smallest_size < 8 && max_y > 5) max_y /= 1.5; for (y = _height_map.size_y; y > (_height_map.size_y - 1 - max_y); y--) { _height_map.height(x, y) = 0; } } } }
Liquid_StaticNoiseOverlay_Impl::Liquid_StaticNoiseOverlay_Impl(GLImage & noise, GLImage & mask, float refactionIndex, float noiseIntensity) { const int BORDER = 1; //without this border the bluring below would ruin the seamless nature of the image HeightMap * noiseMap = imageToHeightMap_tilable(noise, BORDER); //images have only 255 steps - make the steps smoother noiseMap->blur(2); //reduce intensity of water effect noiseMap->scaleAll(noiseIntensity); renderer = new StaticNoiseLiquidRefactionRenderer(refactionIndex, *noiseMap, BORDER); //done with noiseMap delete noiseMap; //Split the mask into independent rectangles ImageMask im(mask); im.isolateMaskRegions(rects); Rect4i imgRect(0, 0, im.width(), im.height()); int largestRectArea = 1; for (int i = 0; i < rects.size(); i++) { Rect4i & rect = *rects.items()[i]; printf("Found rect "); rect.debugPrint(); //UPDATE: this bugfix is now done in Java code //bug workaround: For some reason certain widths of rectangles // causes strange gray looking textures after uploading with glTexSubImage2D(). // I can avoid the issue by making sure width is an even multiple of 8. I picked // 8 out of the blue and it seems to work even though I don't fully understand the problem. //roundMaskRect(rect, imgRect, 8); //printf("Rounded to "); //rect.debugPrint(); masks.add(im.copySubrect(rect)); int area = rect.area(); if (area > largestRectArea) largestRectArea = area; } fflush(stdout); //Allocate a temporary pixel buffer to use in the update() call. //It needs to be big enough to hold the largest MaskRect tempBuf.allocateBlank(1, largestRectArea, 0); }
void addstrip(const HeightMap &hm, colour_func cf, u16 y0, u16 y1, u32 bufNum) { SMeshBuffer *buf = 0; if (bufNum<Mesh->getMeshBufferCount()) { buf = (SMeshBuffer*)Mesh->getMeshBuffer(bufNum); } else { // create new buffer buf = new SMeshBuffer(); Mesh->addMeshBuffer(buf); // to simplify things we drop here but continue using buf buf->drop(); } buf->Vertices.set_used((1 + y1 - y0) * Width); u32 i=0; for (u16 y = y0; y <= y1; ++y) { for (u16 x = 0; x < Width; ++x) { const f32 z = hm.get(x, y); const f32 xx = (f32)x/(f32)Width; const f32 yy = (f32)y/(f32)Height; S3DVertex& v = buf->Vertices[i++]; v.Pos.set(x, Scale * z, y); v.Normal.set(hm.getnormal(x, y, Scale)); v.Color=cf(xx, yy, z); v.TCoords.set(xx, yy); } } buf->Indices.set_used(6 * (Width - 1) * (y1 - y0)); i=0; for(u16 y = y0; y < y1; ++y) { for(u16 x = 0; x < Width - 1; ++x) { const u16 n = (y-y0) * Width + x; buf->Indices[i]=n; buf->Indices[++i]=n + Width; buf->Indices[++i]=n + Width + 1; buf->Indices[++i]=n + Width + 1; buf->Indices[++i]=n + 1; buf->Indices[++i]=n; ++i; } } buf->recalculateBoundingBox(); }
BOOST_FIXTURE_TEST_CASE(VarianceTest1, Test5x5HeightMap) { HeightMap hm; hm.Swap(sample5x5); Variance v; v.Generate(Level5x5, hm, utils::GetTriangles(hm).first); BOOST_CHECK_EQUAL(2.0f, v.At(0)); BOOST_CHECK_EQUAL(2.0f, v.At(1)); BOOST_CHECK_EQUAL(0.5f, v.At(2)); BOOST_CHECK_EQUAL(v.GetSize(), 15u); }
void HeightMapLoaderCache::Get(const Point2d & pos, const size_t sz, HeightMap & hm) const { Size2d point = Size2d::Cast(pos); // special case of patch corner request if (sz == 1) { if (point.x() == (partSize_ - 1)) --point.x(); if (point.y() == (partSize_ - 1)) --point.y(); Size2d cornerPos = point / (partSize_ - 1); cornerPos *= (partSize_ - 1); const auto patchFound = heightMapCache_.find(cornerPos); if (patchFound == heightMapCache_.end()) { basePtr_->Get(pos, sz, hm); } else { HeightMap::Container vec; HeightMap::Value val = HeightMap::GetValueAt(pos - Point2d::Cast(cornerPos), patchFound->second, partSize_); vec.push_back(val); hm.Swap(vec); } } else { if (sz != partSize_) { throw std::runtime_error("Sizes other than part size aren't supported by height map cache (Get)"); } HeightMapCache::iterator found = heightMapCache_.find(point); if (found == heightMapCache_.end()) { basePtr_->Get(pos, sz, hm); } else { HeightMap::Container hmc = found->second; hm.Swap(hmc); } } }
// In this method, breadth first traverse method is employed to construct // a height map, and in order to increase searching rate, the upper and // right direction are preferred in the process of traverse. // This function requires the caller to ensure that maxtrix_[c.x][c.y] > 100. HeightMap HeightMatrix::BreadthFirstSearch(Coordinate c) { HeightMap hm; Direction four_directions[] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; for (int i = 0; i < row_; ++i) { memset(visited_[i], 0, column_ * sizeof(bool)); } std::queue<Coordinate> q; if (!visited_[c.x][c.y]) { q.push(c); //visited_[c.x][c.y] = true; Point p(c, IsCoordinateOnEdge(c), matrix_[c.x][c.y]); hm.AddNewPoints(p); } while (!q.empty()) { Coordinate tmp = q.front(); if (!visited_[tmp.x][tmp.y]) { visited_[tmp.x][tmp.y] = true; Point p(tmp, IsCoordinateOnEdge(tmp), matrix_[tmp.x][tmp.y]); hm.AddNewPoints(p); for (int i = 0; i < 4; ++i) { Coordinate next; next.x = tmp.x + four_directions[i].x; next.y = tmp.y + four_directions[i].y; if (IsCoordinateInMatrix(next) && matrix_[next.x][next.y] >= 100) { q.push(next); } } } q.pop(); } return hm; }
int main() { Serial::open(); Camera* camera = new Camera(HD720, 15.0); ERRCODE code = camera->init(MODE::QUALITY, 0); if (code != SUCCESS) { cout << errcode2str(code) << endl; delete camera; return 1; } int width = camera->getImageSize().width; int height = camera->getImageSize().height; PointCloud *cloud = new PointCloud(width, height); HeightMap *heightMap = new HeightMap(128, 128); CloudViewer *viewer = new CloudViewer(); PathPlanner *planner = new PathPlanner(heightMap); int key = ' '; Mat depth, imLeft; printf("LET'S GO!\n"); Serial::gas(0.25); // application quits when user stikes 'q' while (key != 'q') { camera->setConfidenceThreshold(98); // parameter is reliability index ~[1,100] with 100 as no filtering camera->grab(SENSING_MODE::RAW); depth = camera->retrieveMeasure(MEASURE::DEPTH); imLeft = camera->retrieveImage(SIDE::LEFT); cloud->fill(imLeft.data, (float*) depth.data, camera->getParameters()); cloud->fillHeightMap(heightMap); heightMap->calcSobel(0.6); planner->calcEdges(); steerToward(planner->getTarget()); viewer->AddData(heightMap); viewer->AddPlanner(planner); viewer->AddData(cloud); // Update the value of key so that we can quit when the user strikes 'q' key = viewer->getKey(); } printf("quitting\n"); delete camera; delete cloud; delete viewer; return 0; }
void Renderer::HeightMapOpenCallback(string param) { std::ifstream input(param, std::ios::binary); std::replace(param.begin(), param.end(), '\\', '/'); string imageName = param.substr(param.find_last_of("/")); saveFile("./data" + imageName, input); input.close(); ofImage * newImage = new ofImage(imageName.substr(1)); HeightMap * hm = new HeightMap(); hm->Setup(newImage); addVisibleShape(hm); }
void FieldCharacter::SetExtraHeightFromHeightMaps(vector<HeightMap *> *pHeightMapList) { extraHeight = 0; Vector2 characterPosition = GetVectorAnchorPosition(); for (unsigned int i = 0; i < pHeightMapList->size(); i++) { HeightMap *pHeightMap = (*pHeightMapList)[i]; if (pHeightMap->IsPointInBoundingPolygon(characterPosition)) { extraHeight += pHeightMap->GetHeightAtPoint(characterPosition); } } }
/** * The main new land generator using Perlin noise. Desert landscape is handled * different to all others to give a desert valley between two high mountains. * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic * areas won't be high enough, and there will be very little tropic on the map. * Thus Tropic works best on Hilly or Mountainous. */ void GenerateTerrainPerlin() { if (!AllocHeightMap()) return; GenerateWorldSetAbortCallback(FreeHeightMap); HeightMapGenerate(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); HeightMapNormalize(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); /* First make sure the tiles at the north border are void tiles if needed. */ if (_settings_game.construction.freeform_edges) { for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0)); for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y)); } int max_height = H2I(TGPGetMaxHeight()); /* Transfer height map into OTTD map */ for (int y = 0; y < _height_map.size_y; y++) { for (int x = 0; x < _height_map.size_x; x++) { TgenSetTileHeight(TileXY(x, y), Clamp(H2I(_height_map.height(x, y)), 0, max_height)); } } IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); FreeHeightMap(); GenerateWorldSetAbortCallback(NULL); }
int HeightMapCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) { //TODO: Implement the mouse creation code here if (msg==MOUSE_POINT){// || msg==MOUSE_MOVE switch(point) { case 0: // only happens with MOUSE_POINT msg if(!BuildHeightMapMesh()) return CREATE_ABORT; ob->InvalidateUI(); return CREATE_STOP; break; //case 1: // only happens with MOUSE_POINT msg // return CREATE_STOP; // break; } } else { if(msg == MOUSE_ABORT) return CREATE_ABORT; } return TRUE; }
//--------------------------------------------------------------------------- void OGLGeo::heightmap3(HeightMap &map_in) { //高さ地図の描画.上面のみ double x0,x1,y0,y1,z0,z1; for(int j=0;j<map_in.mesh_j;j++) { for(int i=0;i<map_in.mesh_i;i++) { x0=map_in.x0+i*map_in.dx; x1=map_in.x0+(i+1)*map_in.dx; y0=map_in.y0+j*map_in.dy; y1=map_in.y0+(j+1)*map_in.dy; // z0=map_in.z0; if(map_in.read(&z1,i,j)) { //上面 glBegin(GL_POLYGON); glNormal3d(0,0,1); glVertex3d(x0,y0,z1); glVertex3d(x1,y0,z1); glVertex3d(x1,y1,z1); glVertex3d(x0,y1,z1); glEnd(); } } } }
//--------------------------------------------------------------------------- void OGLGeo::heightmap2(HeightMap &map_in) { //高さ地図の描画その2.ポリゴンを使う PFacet facet1,facet2; Vertex p00,p01,p10,p11; double x0,y0,x1,y1; for(int j=0;j<map_in.mesh_j-1;j++) { for(int i=0;i<map_in.mesh_i-1;i++) { x0=map_in.itox(i); x1=map_in.itox(i+1); y0=map_in.jtoy(j); y1=map_in.jtoy(j+1); p00.x=x0; p00.y=y0; p01.x=x0; p01.y=y1; p10.x=x1; p10.y=y0; p11.x=x1; p11.y=y1; if( (map_in.read(&p00.z,i,j))&& (map_in.read(&p10.z,i+1,j))&& (map_in.read(&p01.z,i,j+1)) ) { facet1.a=p00; facet1.b=p10; facet1.c=p01; facet1.abgd(); pfacet(facet1); } if( (map_in.read(&p10.z,i+1,j))&& (map_in.read(&p11.z,i+1,j+1))&& (map_in.read(&p01.z,i,j+1)) ) { facet2.a=p10; facet2.b=p11; facet2.c=p01; facet2.abgd(); pfacet(facet2); } } } }
void HeightMapLoaderCache::Set(const Point2d & pos, const HeightMap & hm) { if (hm.GetSize() != partSize_) { throw std::runtime_error("Sizes other than part size aren't supported by height map cache (Set)"); } const Size2d p = Size2d::Cast(pos); if (!IsCornerPoint(p, partSize_)) { throw std::runtime_error("Non corner points aren't supported by height map cache (Set)"); } heightMapCache_[p] = hm.GetData(); //basePtr_->Set(pos, hm); }
Scene::Scene( const float level, const HeightMap &hmap ) { m_level = level; m_step = hmap.getCellSize(); m_ground = hmap.getGround(); std::set<Vector3D> vertexes; std::set< std::shared_ptr<Poly> > triangles; std::set<Vector3D> normals; //! Генерация вершин, полигонов и нормалей createMesh( hmap, vertexes, triangles, normals ); map< Vector3D*, shared_ptr<set<shared_ptr<Poly>>>> vecToPoly; createLinkPolyes( triangles, vecToPoly ); //! Создание MeshObject и разделение мешей while( !vecToPoly.empty() ) { shared_ptr<MeshObject> curObj( new MeshObject( vecToPoly) ); objects.insert( curObj ); } //! Создание MeshObject препятствий vecToPoly.clear(); createLinkPolyes( triangles, vecToPoly ); while( !vecToPoly.empty() ) { bool isObstacle = false; shared_ptr<MeshObstacle> curObj( new MeshObstacle( vecToPoly, level, isObstacle ) ); if( isObstacle ) obstacles.insert( curObj ); } vecToPoly.clear(); triangles.clear(); //! Создание поверхности воды Vector3D *vec[4]; Vector2D tex[4] = { Vector2D( 0, 0 ), Vector2D( 0, 1 ), Vector2D( 1, 0 ), Vector2D( 1, 1 ) }; // Текстурные координаты одинаковы для всех полигонов ( пополигонный тайлинг) auto v1 = vertexes.insert( Vector3D( hmap.getMin().x, level, hmap.getMin().y ) ); auto v2 = vertexes.insert( Vector3D( hmap.getMin().x, level, hmap.getMax().y + m_step ) ); auto v3 = vertexes.insert( Vector3D( hmap.getMax().x + m_step, level, hmap.getMax().y + m_step ) ); auto v4 = vertexes.insert( Vector3D( hmap.getMax().x + m_step, level, hmap.getMin().y ) ); vec[0] = const_cast<Vector3D*>( &(*v1.first) ); vec[1] = const_cast<Vector3D*>( &(*v2.first) ); vec[2] = const_cast<Vector3D*>( &(*v3.first) ); vec[3] = const_cast<Vector3D*>( &(*v4.first) ); Poly *tri = new Poly( vec, tex, 4, (new Vector3D(0, 1, 0)) ); triangles.insert( std::shared_ptr<Poly>( tri ) ); // (new Vector3D(0, 1, 0)) Нормаль createLinkPolyes( triangles, vecToPoly ); waterMesh = shared_ptr<MeshObject>( new MeshObject( vecToPoly) ); vecToPoly.clear(); createLinkPolyes( triangles, vecToPoly ); waterObstacle = shared_ptr< MeshObstacle>( new MeshObstacle( vecToPoly ) ); }
int main( int argc, char* args[] ) { std::string map; if (argc == 1) { map = std::string("textures/HeightMap2.png"); } else if (argc == 2) { map = std::string(args[1]); } else { printf("Usage: %s [<Height Map>]\n", args[0]); exit(1); } HeightMap thisApp = HeightMap(map.c_str()); thisApp.appInit(); while ( thisApp.appMain() ) {}; return 0; }
void displayTerrain () { glUniform1i (solidColor, 0); glUniformMatrix4fv (vMvp, 1, GL_TRUE, projectionView); glBindVertexArray( hm_vao ); glPrimitiveRestartIndex (PRIMITIVE_RESTART); glDrawArrays( GL_TRIANGLES, 0, hm.sizeOfTriangleVertices () ); //glDrawArrays( GL_LINE_STRIP, 0, hm.getSize () ); //glDrawElements ( GL_TRIANGLE_STRIP, hm.sizeOfTriStripIndices (), GL_UNSIGNED_INT, indices); }
/**Convert an image to a height map. The image is treated as grey-scale. @param border create a height map which is larger than the source image. The source image will be centered in the heightmap which creates a kind of border. This border is filled with by tiling the soure image. If your source image was created to be tilable (it ought to be) then the heightmap will be seamless. The whole point of this is so that you can call HeightMap.blur() without ruining the seamless nature of your heightmap. (After bluring you should ignore the border region) */ HeightMap * imageToHeightMap_tilable(GLImage & img, int border) { HeightMap * hmap = new HeightMap(img.width + border + border, img.height + border + border); for (int y = 0; y < hmap->H; y++) { for (int x = 0; x < hmap->W; x++) { int imgX = infinite_coord_to_finite(x - border, img.width); int imgY = infinite_coord_to_finite(y - border, img.height); //TODO: GLImage should be a class with an inline getPixelPtr(x,y) method. GLubyte * pixel = &img.texels[((imgY * img.width) + imgX) * img.internalFormat]; hmap->set(x, y, pixel[0] / 255.0f); } } return hmap; }
void ShGraph<G>::vertexHeight(const VertexSet &roots, HeightMap &heights) { heights.clear(); VertexPairMap<int> dist; NegativeWeigher<G> weigher; typename VertexSet::const_iterator U, V; floydWarshall(weigher, dist); for(U = verts.begin(); U != verts.end(); ++U) { for(V = roots.begin(); V != roots.end(); ++V) { heights[*U] = std::max(heights[*U], -dist(*V, *U)); } } }
/** * This routine provides the essential cleanup necessary before OTTD can * display the terrain. When generated, the terrain heights can jump more than * one level between tiles. This routine smooths out those differences so that * the most it can change is one level. When OTTD can support cliffs, this * routine may not be necessary. */ static void HeightMapSmoothSlopes(height_t dh_max) { for (int y = 0; y <= (int)_height_map.size_y; y++) { for (int x = 0; x <= (int)_height_map.size_x; x++) { height_t h_max = min(_height_map.height(x > 0 ? x - 1 : x, y), _height_map.height(x, y > 0 ? y - 1 : y)) + dh_max; if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max; } } for (int y = _height_map.size_y; y >= 0; y--) { for (int x = _height_map.size_x; x >= 0; x--) { height_t h_max = min(_height_map.height(x < _height_map.size_x ? x + 1 : x, y), _height_map.height(x, y < _height_map.size_y ? y + 1 : y)) + dh_max; if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max; } } }
/** * Base Perlin noise generator - fills height map with raw Perlin noise. * * This runs several iterations with increasing precision; the last iteration looks at areas * of 1 by 1 tiles, the second to last at 2 by 2 tiles and the initial 2**MAX_TGP_FREQUENCIES * by 2**MAX_TGP_FREQUENCIES tiles. */ static void HeightMapGenerate() { /* Trying to apply noise to uninitialized height map */ assert(_height_map.h != NULL); int start = max(MAX_TGP_FREQUENCIES - (int)min(MapLogX(), MapLogY()), 0); bool first = true; for (int frequency = start; frequency < MAX_TGP_FREQUENCIES; frequency++) { const amplitude_t amplitude = GetAmplitude(frequency); /* Ignore zero amplitudes; it means our map isn't height enough for this * amplitude, so ignore it and continue with the next set of amplitude. */ if (amplitude == 0) continue; const int step = 1 << (MAX_TGP_FREQUENCIES - frequency - 1); if (first) { /* This is first round, we need to establish base heights with step = size_min */ for (int y = 0; y <= _height_map.size_y; y += step) { for (int x = 0; x <= _height_map.size_x; x += step) { height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0; _height_map.height(x, y) = height; } } first = false; continue; } /* It is regular iteration round. * Interpolate height values at odd x, even y tiles */ for (int y = 0; y <= _height_map.size_y; y += 2 * step) { for (int x = 0; x <= _height_map.size_x - 2 * step; x += 2 * step) { height_t h00 = _height_map.height(x + 0 * step, y); height_t h02 = _height_map.height(x + 2 * step, y); height_t h01 = (h00 + h02) / 2; _height_map.height(x + 1 * step, y) = h01; } } /* Interpolate height values at odd y tiles */ for (int y = 0; y <= _height_map.size_y - 2 * step; y += 2 * step) { for (int x = 0; x <= _height_map.size_x; x += step) { height_t h00 = _height_map.height(x, y + 0 * step); height_t h20 = _height_map.height(x, y + 2 * step); height_t h10 = (h00 + h20) / 2; _height_map.height(x, y + 1 * step) = h10; } } /* Add noise for next higher frequency (smaller steps) */ for (int y = 0; y <= _height_map.size_y; y += step) { for (int x = 0; x <= _height_map.size_x; x += step) { _height_map.height(x, y) += RandomHeight(amplitude); } } } }