tBane Temat założony przez niniejszego użytkownika |
[Irrlicht] Generowanie trójwymiarowej siatki heksagonalnej » 2024-03-03 21:37:13 Aby dodać wysokość do mapy heksagonalnej (sześciokątnej) należy podzielić ją na składowe i na nich operować. Między kafelkami mapy powstaną wtedy tarasy (terraces) dzięki którym osiągniemy łagone i płynne przejście z jednego do drugiego kafelka. Tym sposobem dzielimy sześciokąt na sześć trójkątów wychodzących z jego środka, a następnie każdy taki trójkąt dzielimy na trójkąt wewnętrzny oraz quad zewnętrzny. Trójkąt wewnętrzny będzie miał teksturę odpowiednią dla danego pola, zaś quad zewnętrzny będzie zawierał zarówno teksturę własnego kafelka jak i sąsiedniego. Istotne zmienne dla siatki: float outerRadius = 10.0f; float innerRadius = outerRadius * 0.866025404f; float heightStep = 6.0f; float tileBaseFactor = 0.8f;
float hexVertices[ ] = { 0.0f, outerRadius, innerRadius, outerRadius * 0.5f, innerRadius, - outerRadius * 0.5f, 0.0f, - outerRadius, - innerRadius, - outerRadius * 0.5f, - innerRadius, outerRadius * 0.5f, 0.0f, outerRadius };
const u16 hexIndices[ 18 ] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 1 };
float texture_uv[ ] { 0.0f, 0.5f, 0.5f, 0.25f, 0.5f, - 0.25f, 0.0f, - 0.5f, - 0.5f, - 0.25f, - 0.5f, 0.25f, 0.0f, 0.5f, };
render, kolizje oraz tworzenie mesh: void HexTile::render() { IVideoDriver * driver = smgr->getVideoDriver(); driver->setMaterial( baseMeshBuffer->Material ); driver->setTransform( video::ETS_WORLD, AbsoluteTransformation ); driver->drawMeshBuffer( baseMeshBuffer ); for( int i = 0; i < 6; i++ ) { driver->setMaterial( sidesMeshBuffer[ i ]->Material ); driver->setTransform( video::ETS_WORLD, AbsoluteTransformation ); driver->drawMeshBuffer( sidesMeshBuffer[ i ] ); } }
void HexTile::generateTerrainMesh() { SColor color = SColor( 255, 255, 255, 255 ); baseMeshBuffer = new SMeshBuffer(); baseMeshBuffer->Indices.set_used( 18 ); for( u32 i = 0; i < 18; ++i ) baseMeshBuffer->Indices[ i ] = hexIndices[ i ]; baseMeshBuffer->Vertices.push_back( S3DVertex( 0, 0, 0, 0, 0, 0, color, 0, 0 ) ); for( int i = 0; i < 6; i++ ) { baseMeshBuffer->Vertices.push_back( S3DVertex( hexVertices[ 2 * i ] * tileBaseFactor, 0.0f, hexVertices[ 2 * i + 1 ] * tileBaseFactor, 0, 0, 0, color, texture_uv[ 2 * i ], texture_uv[ 2 * i + 1 ] ) ); baseMeshBuffer->BoundingBox.addInternalPoint( vector3df( hexVertices[ 2 * i ] * tileBaseFactor, 0, hexVertices[ 2 * i + 1 ] * tileBaseFactor ) ); } baseMeshBuffer->Material.Wireframe = false; baseMeshBuffer->Material.Lighting = false; baseMeshBuffer->Material.setTexture( 0, getTexture( ttype ) ); baseMesh = new SMesh(); baseMesh->addMeshBuffer( baseMeshBuffer ); baseMesh->recalculateBoundingBox(); for( int i = 0; i < 6; i++ ) { sidesMeshBuffer[ i ] = new SMeshBuffer(); sidesMeshBuffer[ i ]->Indices.set_used( 6 ); sidesMeshBuffer[ i ]->Indices[ 0 ] = 0; sidesMeshBuffer[ i ]->Indices[ 1 ] = 1; sidesMeshBuffer[ i ]->Indices[ 2 ] = 2; sidesMeshBuffer[ i ]->Indices[ 3 ] = 0; sidesMeshBuffer[ i ]->Indices[ 4 ] = 2; sidesMeshBuffer[ i ]->Indices[ 5 ] = 3; float h; if( neighbours[ i ] != nullptr ) h = float( neighbours[ i ]->height - this->height ) * heightStep * 0.5f; else h = 0.0f; sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 * i ] * tileBaseFactor, 0.0f, hexVertices[ 2 * i + 1 ] * tileBaseFactor, 0, 0, 0, color, 0, 0 ) ); sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 * i ], h, hexVertices[ 2 * i + 1 ], 0, 0, 0, color, texture_uv[ 2 * i ], texture_uv[ 2 * i + 1 ] ) ); sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 *( i + 1 ) ], h, hexVertices[ 2 *( i + 1 ) + 1 ], 0, 0, 0, color, texture_uv[ 2 * i ], texture_uv[ 2 * i + 1 ] ) ); sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 *( i + 1 ) ] * tileBaseFactor, 0.0f, hexVertices[ 2 *( i + 1 ) + 1 ] * tileBaseFactor, 0, 0, 0, color, 0, 0 ) ); sidesMeshBuffer[ i ]->Material.Wireframe = false; sidesMeshBuffer[ i ]->Material.Lighting = false; sidesMeshBuffer[ i ]->Material.setTexture( 0, getTexture( ttype ) ); sidesMesh[ i ] = new SMesh(); sidesMesh[ i ]->addMeshBuffer( sidesMeshBuffer[ i ] ); sidesMesh[ i ]->recalculateBoundingBox(); } vector3df pos = hexToGlobal( x, z ); pos.Y = float( height ) * heightStep; setPosition( pos ); }
void HexMap::addTriangleSelector() { ITriangleSelector * selector; for( auto & t: tiles ) { selector = smgr->createTriangleSelector( t->baseMesh, t ); t->setTriangleSelector( selector ); selector->drop(); } }
do poprawy:-współrzędne tekstur dla boków kafelków ( jakoś obliczyć tylko jak ? ) -napisać łączenie kafelków ( terraces ) i skąd się biorą te "puste" trójkąty ? -napisać kolizje boków kafelków z kursorem (można się obejść bez ale wypadałoby ) -optymalizacja ( mapa 40x40, zaledwie 75 FPS - spadek 300 FPS - cel to mapa 100x80 ) -mapa jest małoczytelna, wypadałoby dla poprawy przejrzystości dodać chociaż cieniowanie próbuję to odwzorować ( bez cyferek rzecz jasna ;-) ) |
|
pekfos |
» 2024-03-04 17:40:15 Geometria na obrazku referencyjnym nie zgadza się z koncepcją na pierwszym rysunku. Zauważ że w miejscu gdzie stykają się 3 sześciokąty masz 1 trójkąt, a w u ciebie schodzą się w punkt. Koncepcja przejść między kaflami wydaje mi się nie mieć sensu. Przykładowo woda nie wspina się po ścianie do połowy wysokości, tylko raczej zostaje na dole. Może byłoby prościej i bardziej realistycznie jakby przyjąć że kafel o większej wysokości dyktuje teksturę stoku. Ustawianie przejścia między teksturami na połowę wysokości może też wyglądać dziwnie gdy masz duży rozstrzał różnic wysokości, jak na przykład na załączonym obrazku referencyjnym. -współrzędne tekstur dla boków kafelków ( jakoś obliczyć tylko jak ? ) Efekt wygląda jakbyś współrzędne tekstury miał ustawione dla wewnętrznego sześciokąta, a zewnętrzny powtarza 1 piksel. Powinieneś raczej mierzyć teksturę by pokrywała się z zewnętrznym sześciokątem. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-03-05 03:55:35 Geometria na obrazku referencyjnym nie zgadza się z koncepcją na pierwszym rysunku. Zauważ że w miejscu gdzie stykają się 3 sześciokąty masz 1 trójkąt, a w u ciebie schodzą się w punkt. No właśnie to zauważyłem, po wygenerowaniu mapy. Gdy wysokość trzech kafelków nie jest taka sama generuje się dodatkowy trójkąt. A wodę planuję inaczej dodać. Każdy kafelek będzie posiadał informację czy zawiera wodę, a jeżeli tak to woda będzie generowana z pół wysokości wyżej jako sześciokątny shader. ( drawHexWater(x, y+waterHeight, z); ) Na razie próbuję w ogóle jakoś ogarnąć, by tekstury rysowało, póżniej będę to pielęgnował, ale najpierw musi działać. |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-03-05 04:34:25 Dokładniej przyjrzałem się generowanej mapie i zlokalizowałem błąd. Jednak nie generują się dodatkowe trójkąty a źle obliczana jest wysokość dla boków sześciokątów. Próbowałem dla lewej oraz prawej strony wyliczyć wysokość w ten sposób ale coś nie działa: float hleft, hright; int h1, h2, h3;
h1 = height; if( neighbours[ getDirection( i - 1 ) ] != nullptr ) h2 = neighbours[ getDirection( i - 1 ) ]->height; else h2 = h1;
if( neighbours[ getDirection( i ) ] != nullptr ) h3 = neighbours[ getDirection( i ) ]->height; else h3 = h1;
hleft = float( max( h1, h2, h3 ) - min( h1, h2, h3 ) );
h1 = height; if( neighbours[ getDirection( i + 1 ) ] != nullptr ) h2 = neighbours[ getDirection( i + 1 ) ]->height; else h2 = h1;
if( neighbours[ getDirection( i ) ] != nullptr ) h3 = neighbours[ getDirection( i ) ]->height; else h3 = h1;
hright = float( max( h1, h2, h3 ) - min( h1, h2, h3 ) );
sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 * i ] * tileBaseFactor, height * heightStep, hexVertices[ 2 * i + 1 ] * tileBaseFactor, 0, 0, 0, color, 0, 0 ) ); sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 * i ], hleft * heightStep, hexVertices[ 2 * i + 1 ], 0, 0, 0, color, texture_uv[ 2 * i ], texture_uv[ 2 * i + 1 ] ) ); sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 *( i + 1 ) ], hright * heightStep, hexVertices[ 2 *( i + 1 ) + 1 ], 0, 0, 0, color, texture_uv[ 2 * i ], texture_uv[ 2 * i + 1 ] ) ); sidesMeshBuffer[ i ]->Vertices.push_back( S3DVertex( hexVertices[ 2 *( i + 1 ) ] * tileBaseFactor, height * heightStep, hexVertices[ 2 *( i + 1 ) + 1 ] * tileBaseFactor, 0, 0, 0, color, 0, 0 ) );
|
|
pekfos |
» 2024-03-05 17:54:57 hright = float( max( h1, h2, h3 ) - min( h1, h2, h3 ) );
Nie powinna to być średnia? |
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-03-05 21:59:21 Jeżeli są to 3 pola obok siebie o wysokości 3, 3 i 1 to wysokość średnia wynosi 2 czyli max(3,3,1) - min(3,3,1) = 3 - 1 = 2 a nie 7/3 |
|
pekfos |
» 2024-03-05 22:11:01 Średnia zamiast samej różnicy. Bo teraz 8,8,6 da też 2 zamiast 7. hright = 0.5f *( max( h1, h2, h3 ) + min( h1, h2, h3 ) );
|
|
tBane Temat założony przez niniejszego użytkownika |
» 2024-03-06 02:30:07 Teraz działa ;-) Ale jednak nie tak jak powinno - złą metodę wymyśliłem. Quady wystają tworząc trójkąty prostopadłe do kafelka jak na obrazku poniżej. Czyli chyba wracamy do pierwotnej metody (drugi obrazek) i trzeba jakoś znaleźć te trójkąty. float h; if( neighbours[ i ] != nullptr ) h = float( neighbours[ i ]->height + this->height ) * 0.5f; else h = height;
|
|
« 1 » 2 3 4 |