#0 

10-09-2011 01:42:10

LCmaster
Membre
Date d'inscription: 03-01-2009
Messages: 20

Bonsoir à tous,

ça fait un moment que je ne suis pas passé par ici, mais me voilà à nouveau, et je ne viens pas les mains vides (heureusement). Après quelques recherches je suis tombé sur cette page, le code proposé marche, mais je le trouve limité car la déformation se fait point par point, ce qui peut vite devenir extrêmement chiant. Alors j'ai pensé à ajouter à ce code la possibilité d'utiliser des "brushes" pour faciliter la tâche. Et voici le résultat :

Code c++ :

#include <irr/irrlicht.h>

using namespace irr;


video::IImage* heightmap;
video::IImage* brush;

scene::ITerrainSceneNode* terrain;

/*==============================================================================
  Receiver class
==============================================================================*/

class MyEventReceiver : public IEventReceiver {
    bool KeyIsDown[KEY_KEY_CODES_COUNT];
    bool LEFTBUTTONCLICKED;
    bool RIGHTBUTTONCLICKED;

    public:
        virtual bool OnEvent(const SEvent& event){
            if (event.EventType == irr::EET_KEY_INPUT_EVENT)
                KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

            if(event.EventType == EET_MOUSE_INPUT_EVENT){
                if(event.MouseInput.Event==EMIE_LMOUSE_PRESSED_DOWN) LEFTBUTTONCLICKED = true;
                else if(event.MouseInput.Event==EMIE_LMOUSE_LEFT_UP) LEFTBUTTONCLICKED = false;
                else if(event.MouseInput.Event==EMIE_RMOUSE_PRESSED_DOWN) RIGHTBUTTONCLICKED = true;
                else if(event.MouseInput.Event==EMIE_RMOUSE_LEFT_UP) RIGHTBUTTONCLICKED = false;
            }

            return false;
        }

        virtual bool IsKeyDown(EKEY_CODE keyCode) const { return KeyIsDown[keyCode]; }
        virtual bool IsLMBDown() const { return LEFTBUTTONCLICKED; }
        virtual bool IsRMBDown() const { return RIGHTBUTTONCLICKED; }

        MyEventReceiver(){
            for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
                KeyIsDown[i] = false;

            LEFTBUTTONCLICKED = RIGHTBUTTONCLICKED = false;
        }
};

/*==============================================================================
  Raise or lower terrain (selected vertice)
==============================================================================*/

void RaiseTerrainVertex(s32 index, f32 step, bool up){
    scene::IMesh* pMesh = terrain->getMesh();

    s32 heightmapWidth = heightmap->getDimension().Width;
    s32 heightmapHeight = heightmap->getDimension().Height;

    s32 b;
    for (b=0; b<pMesh->getMeshBufferCount(); ++b){
        scene::IMeshBuffer* pMeshBuffer = pMesh->getMeshBuffer(b);
        // skip mesh buffers that are not the right type
        if (pMeshBuffer->getVertexType() != video::EVT_2TCOORDS) continue;

        video::S3DVertex2TCoords* pVertices = (video::S3DVertex2TCoords*)pMeshBuffer->getVertices();

        s32 brushWidth = brush->getDimension().Width;
        s32 brushHeight = brush->getDimension().Height;

        for(int y = 0; y < brushHeight; y++){
            for(int x = 0; x < brushWidth; x++){
                video::SColor brushPixel = brush->getPixel(x, y);

                if((index-(brushWidth/2)-((brushWidth/2)*heightmapWidth) + (x+(y*heightmapWidth))) >= 0){
                    f32 hy = pVertices[index-(brushWidth/2)-((brushWidth/2)*heightmapWidth) + (x+(y*heightmapWidth))].Pos.Y;
                    f32 bp = brushPixel.getRed()/255.0*step;
                    bp = (up)?bp:-bp;

                    if(bp > 0 && hy+bp <= 255)
                        pVertices[index-(brushWidth/2)-((brushWidth/2)*heightmapWidth) + (x+(y*heightmapWidth))].Pos.Y = hy+bp;
                }
            }
        }
    }

    // force terrain render buffer to reload
    terrain->setPosition(terrain->getPosition());
}

/*==============================================================================
  Save file
==============================================================================*/

void save (video::IVideoDriver* driver){
    s32 heightmapWidth = heightmap->getDimension().Width;
    s32 heightmapHeight = heightmap->getDimension().Height;

    const core::dimension2d<u32> dim (heightmapWidth, heightmapHeight);
    video::IImage *img = driver->createImage(video::ECF_A8R8G8B8, dim);

    video::S3DVertex2TCoords* verts = (video::S3DVertex2TCoords*)terrain->getMesh()->getMeshBuffer(0)->getVertices();

    for (u32 y= 0, i = 0; y < heightmapHeight; y++){
        for(u32 x = 0; x < heightmapWidth; i++, x++){
            u8 py = (u8)verts[i].Pos.Y;
            img->setPixel((heightmapHeight-1)-y, x, video::SColor(0, py, py, py));
        }
    }

    driver->writeImageToFile(img, "heightmap.bmp", 0);
    img->drop();
}


int main(){
    MyEventReceiver receiver;

    IrrlichtDevice* device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(800, 600), 32, false, true, false, &receiver);

    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();

    device->getCursorControl()->setVisible(false);

    io::path heightmapFile = "heightmap.bmp";
    heightmap = driver->createImageFromFile(heightmapFile);
    brush = driver->createImageFromFile("brush.png");

    terrain = smgr->addTerrainSceneNode(heightmapFile, 0, -1, core::vector3df(0, 0, 0));
    terrain->setScale(core::vector3df(32, 5, 32));
    terrain->setMaterialFlag(video::EMF_LIGHTING, false);

    terrain->setPosition(terrain->getPosition());

    scene::ITriangleSelector* selector = smgr->createTerrainTriangleSelector(terrain, 0);

    // Arrow
    scene::ISceneNode* arrow = smgr->addAnimatedMeshSceneNode(smgr->addArrowMesh("arrow", video::SColor(255, 255, 0, 0), video::SColor(255, 0, 255, 0)), NULL);
    arrow->setMaterialFlag(video::EMF_LIGHTING, false);
    arrow->setScale(core::vector3df(10, 10, 10));
    arrow->setRotation(core::vector3df(0,0,180));

    scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(0, 100.0f, .1f);
    cam->setPosition(core::vector3df(-100,500,100));
    cam->setTarget(core::vector3df(0,0,0));

    ITimer* irrTimer = device->getTimer();
    u32 then = 0, then30 = 0;
    char c[24];
    f32 step = 2.f;
    bool wireframe = false;

    while(device->run()){
        if(device->isWindowActive()){
            u32 now = irrTimer->getTime();

            if (then30 < now){
                if(receiver.IsKeyDown(irr::KEY_ESCAPE)) break;

                if (receiver.IsKeyDown(irr::KEY_KEY_W) && then < now){
                    wireframe = !wireframe;
                    terrain->setMaterialFlag(video::EMF_WIREFRAME, wireframe);

                    then = now + 300;
                }

                if (receiver.IsKeyDown(irr::KEY_F4) && then < now){
                    step += 1.f;

                    then = now + 100;
                } else if (receiver.IsKeyDown(irr::KEY_F5) && then < now && step > 0){
                    step -= 1.f;

                    then = now + 100;
                }

                if(receiver.IsKeyDown(irr::KEY_KEY_S))
                    save (driver);

                // move the arrow to the nearest vertex ...
                //400, 300 si la résolution utilisée est 800x600
                const core::position2di clickPosition = core::position2di(400, 300);
                const core::line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(clickPosition, cam);
                core::vector3df pos;
                core::triangle3df Tri;

                const scene::ISceneNode* out;
                if (smgr->getSceneCollisionManager()->getCollisionPoint(ray, selector, pos, Tri, out)){
                    //arrow->setPosition(pos);
                    static const s32 scale = 32; // terrain is scaled 32X
                    static const s32 size = 512; // heightmap is 256X256 pixels
                    s32 x = (s32)(pos.X / scale);
                    s32 z = (s32)(pos.Z / scale);
                    s32 index = x * size + z;

                    // ... Move it if clicked
                    if(receiver.IsLMBDown() || receiver.IsRMBDown() && then < now){
                        RaiseTerrainVertex(index, step, receiver.IsLMBDown());
                        then = now + 100;
                    }

                    x *= scale;
                    z *= scale;

                    arrow->setPosition(core::vector3df(x, terrain->getHeight(x, z) + 20, z));
                }

                driver->beginScene(true, true, video::SColor(255, 255, 255, 255));
                smgr->drawAll();
                driver->endScene();

                then30 = now + 30;
            }
        }
    }

    heightmap->drop();
    brush->drop();

    device->closeDevice();
    device->drop();

    return 0;
}



Heightmap utilisée : http://ompldr.org/vYWExZg (Hé oui, un grand carré noir...)
Brush de test :

Voilà, ceci fait ça vous laisse la possibilité de faire des brushes des formes et tailles que vous voulez.

Hors ligne


#1 

10-09-2011 17:42:38

Magun
SleekThink Producer
Lieu: Punakha
Date d'inscription: 18-11-2007
Messages: 904
Corrections: 2
Site web

merci pour cette routine, ce seras surment intéressant pour les nouveaux venue wink

Hors ligne


#2 

09-12-2011 16:08:48

katsankat
Membre
Date d'inscription: 24-02-2007
Messages: 43

Salut j'ai écrit le code d'origine. Merci à toi d'avoir cité la source, et pour les brushes beau boulot.

Hors ligne


#3 

12-12-2011 19:14:38

katsankat
Membre
Date d'inscription: 24-02-2007
Messages: 43

Une petite fonction qui dessine un cercle autour de la zone sous la souris.
L'appeler dans le main avec circle(x,z, 20, 256); juste avant le if( receiver->IsLMBDown() || receiver->IsRMBDown())
Tracera un cercle fait de 20 segments, diamètre 256 unités.

Code:

*==============================================================================

==============================================================================*/
void Ligne(vector3df from, vector3df to, SColor couleur)
{
    matrix4 mat;
    device->getVideoDriver()->setTransform(ETS_WORLD, mat);
    device->getVideoDriver()->draw3DLine(from, to, couleur);
}
/*==============================================================================

==============================================================================*/
void circle(f32 cx, f32 cz, u32 verts, f32 radius)
{
  SColor color(255,255,255,255);
  vector3df p1;
  vector3df p2;
  s32 n;
  f32 above = 10.f;

  for (n = verts; 0 <= n; --n)
  {
    const f32 a = (core::PI * 2.f) * n / verts;

    const f32 x = cx + sinf(a) * radius;
    const f32 z = cz + cosf(a) * radius;

    if (n==verts)
      p1 = vector3df(x, terrain->getHeight(x,z)+above, z);
    else
    {
      p2 = vector3df(x, terrain->getHeight(x,z)+above, z);
      Ligne(p1, p2, color);
      p1.X = p2.X;
      p1.Y = p2.Y;
      p1.Z = p2.Z;
    }
  }
}

Dernière modification par katsankat (12-12-2011 19:16:05)

Hors ligne


Options Liens officiels Caractéristiques Statistiques Communauté
Corrections
irrlicht
irrklang
irredit
irrxml
xhtml 1.0
css 2.1
Propulsé par FluxBB
Traduit par FluxBB.fr
Analysé par
880 membres
1424 sujets
11113 messages
Dernier membre inscrit: mandrifidy
29 invités en ligne
Aucun membre connecté
RSS Feed