#0 

07-06-2010 18:44:31

ordiman85
Petit nouveau
Date d'inscription: 07-06-2010
Messages: 2

Bonjour,

Je débute sur irrlicht.

J'ai dérivé un ISceneNode pour créer un objet personnalisé (TubeSceneNode) et j'aimerais le texturer. J'ai essayé de modifier "m_material" sans succès.
J'aimerais de votre aide svp pour m'expliquer comment je pourrais faire.

Mon programme affiche un tube formé à partir de quelques points, le chemin du tube est calculé par l'interpolation de Hermite. Vous pouvez vous déplacer avec la caméra FPS standard.

Voici le code complet :

Code c++ :


#include <irrlicht.h>
#include <cmath>

using namespace irr;

/**
* Stocke une liste de points et calcule un chemin fluide par interpolation de Hermite
*/

class Path3D
{
public:
    /*
        Hermite interpolation
        Tension: 1 is high, 0 normal, -1 is low
        Bias: 0 is even,
            positive is towards first segment,
            negative towards the other
        Source:
            http://local.wasp.uwa.edu.au/~pbourke/m … rpolation/
    */

    Path3D(double tension = 0, double bias = 0) :
        m_tension(tension), m_bias(bias)
    {
    }

    void push(const core::vector3df& v)
    {
        m_array.push_back(v);
    }

    int size() const
    {
        return m_array.size();
    }

    /**
     * mu : Partie entière = n° intervalle, partie décimale = pourcentage parcouru dans l'intervalle
     */

    core::vector3df getPoint(double mu) const
    {
        core::vector3df v1, v2, v3, v4;
        int index;
        double mu_interval, intpart;

        mu_interval = modf(mu, &intpart);
        index = (int)intpart;

        return getPoint(index, mu_interval);
    }

    /**
     * index : n° intervalle
     * mu : pourcentage parcouru dans l'intervalle
     */

    core::vector3df getPoint(int index, double mu) const
    {
        core::vector3df v1, v2, v3, v4;

        v1 = getVectorById(index - 1);
        v2 = getVectorById(index);
        v3 = getVectorById(index + 1);
        v4 = getVectorById(index + 2);

        return HermiteInterpolateVector(v1, v2, v3, v4, mu);
    }

private:
    core::vector3df getVectorById(int id) const
    {
        if (m_array.empty())
            return core::vector3df(0, 0, 0);
        else
            return m_array[id % m_array.size()];
    }

    core::vector3df HermiteInterpolateVector(
            const core::vector3df& v1,
            const core::vector3df& v2,
            const core::vector3df& v3,
            const core::vector3df& v4,
            double mu) const
    {
        core::vector3df w;
        w.X = HermiteInterpolate(v1.X, v2.X, v3.X, v4.X, mu);
        w.Y = HermiteInterpolate(v1.Y, v2.Y, v3.Y, v4.Y, mu);
        w.Z = HermiteInterpolate(v1.Z, v2.Z, v3.Z, v4.Z, mu);
        return w;
    }

    double HermiteInterpolate(double y0, double y1, double y2, double y3, double mu) const
    {
        double m0, m1, mu2, mu3;
        double a0, a1, a2, a3;

        mu2 = mu * mu;
        mu3 = mu2 * mu;
        m0  = (y1 - y0)*(1 + m_bias)*(1 - m_tension)/2;
        m0 += (y2 - y1)*(1 - m_bias)*(1 - m_tension)/2;
        m1  = (y2 - y1)*(1 + m_bias)*(1 - m_tension)/2;
        m1 += (y3 - y2)*(1 - m_bias)*(1 - m_tension)/2;
        a0 =  2*mu3 - 3*mu2 + 1;
        a1 =    mu3 - 2*mu2 + mu;
        a2 =    mu3 -   mu2;
        a3 = -2*mu3 + 3*mu2;

        return (a0*y1 + a1*m0 + a2*m1 + a3*y2);
    }

private:
    double m_tension;
    double m_bias;
    core::array<core::vector3df> m_array;
};


/**
* Fabrique un tube à partir d'une liste de points (Path3D) en les reliant avec des virages arrondis
* path : L'objet Path3D contenant la liste des points
* radius : Le rayon du tube
* pathDivide : Le nombre de sections entre 2 points (minimum: 1, un grand nombre augmente le détail)
* ringDivide : Le nombre de côtés d'une section du tube (minimum: 8, un grand nombre augmente le détail)
*/

class TubeSceneNode : public scene::ISceneNode
{
public:
    TubeSceneNode(scene::ISceneNode *parent, scene::ISceneManager *mgr, s32 id, const Path3D& path, int radius, int pathDivide = 16, int ringDivide = 16)
        : scene::ISceneNode(parent, mgr, id)
    {
        core::vector3df u, v, A, B, dir, pt;

        m_material.Wireframe = false;
        m_material.Lighting = false;
        m_material.BackfaceCulling = false;

        // Calcule le nombre de cercles composant le tube
        m_ringDivide = ringDivide;
        m_verticesCount = path.size() * pathDivide * m_ringDivide;
        m_vertices = new video::S3DVertex[m_verticesCount];

        for (int i = 0; i < path.size(); i++)
        {
            for (int j = 0; j < pathDivide; j++)
            {
                // Calcule le vecteur directeur entre 2 points distincts
                A = path.getPoint(f64(i) + ( f64(j) / f64(pathDivide) ));
                B = path.getPoint(f64(i) + ( f64(j + 1) / f64(pathDivide) ));
                dir = (B - A).normalize();

                // Construit une nouvelle base (dir, u, v)
                u = (core::vector3df(dir.Y, -dir.X, 0)).normalize();
                v = (dir.crossProduct(u)).normalize();

                int indexRef = i * pathDivide * m_ringDivide + j * m_ringDivide;

                for (int k = 0; k < m_ringDivide; k++)
                {
                    // Définit les points d'un cercle entourant le vecteur directeur, qui fera partie du tube matériel
                    double teta = k * 2.0 * M_PI / m_ringDivide;
                    pt = A + ( radius * cos(teta) ) * u + ( radius * sin(teta) ) * v;
                    m_vertices[indexRef + k] = video::S3DVertex(pt, core::vector3df(0, 0, 0), video::SColor(128, 128, 255, 255), core::vector2d< f32 >(0, 0));
                }
            }
        }
    }

    virtual void OnRegisterSceneNode()
    {
        if (IsVisible)
            SceneManager->registerNodeForRendering(this);
        ISceneNode::OnRegisterSceneNode();
    }

    virtual void render()
    {
        u16 indices[6*m_verticesCount];
        video::IVideoDriver* driver;

        // Relie la moitié des triangles
        for (int i = 0; i < m_verticesCount; i++)
        {
            indices[3*i] = i % m_verticesCount;
            indices[3*i + 1] = ( i + 1 ) % m_verticesCount;
            indices[3*i + 2] = ( i + m_ringDivide ) % m_verticesCount;
        }

        // Relie l'autre moitié
        int j = m_verticesCount * 3;
        for (int i = 0; i < m_verticesCount; i++)
        {
            indices[j + 3*i] = ( i + 1 ) % m_verticesCount;
            indices[j + 3*i + 1] = ( i + m_ringDivide ) % m_verticesCount;
            indices[j + 3*i + 2] = ( i + m_ringDivide + 1 ) % m_verticesCount;
        }

        driver = SceneManager->getVideoDriver();
        driver->setMaterial(m_material);
        driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
        driver->drawIndexedTriangleList(m_vertices, m_verticesCount, &indices[0], m_verticesCount*2);
    }

    virtual const core::aabbox3d<f32>& getBoundingBox() const
    {
        return m_box;
    }

    virtual u32 getMaterialCount() const
    {
        return 1;
    }

    virtual video::SMaterial& getMaterial(u32 i)
    {
        return m_material;
    }

private:
    core::aabbox3d<irr::f32>    m_box;
    video::SMaterial            m_material;
    video::S3DVertex            *m_vertices;
    int                         m_verticesCount;
    int                         m_pathDivide;
    int                         m_ringDivide;
};


/**
* Dessine seulement des traits des traits qui suivent le tunnel (pour débug)
*/

void drawTubeLines(video::IVideoDriver *driver, const Path3D &path, int precision)
{
    core::vector3df w1, w2;
    core::vector3df u, v, w;

    for (int i = 0; i < path.size(); i++)
    {
        for (int j = 0; j <= precision - 1; j++)
        {
            w1 = path.getPoint(i, f64(j) / f64(precision));
            w2 = path.getPoint(i, f64(j + 1) / f64(precision));
            driver->draw3DLine(w1, w2, video::SColor(0, 255*( f64(j) / f64(precision) ), 255*( f64(j) / f64(precision) ), 0 ));

            // Nouvelle base
            u = (w2 - w1).normalize();
            v = (core::vector3df(u.Y, -u.X, 0)).normalize();
            w = (u.crossProduct(v)).normalize();

            // Repère local (u, v, w)
            driver->draw3DLine(w1, w1 + 40 * u, video::SColor(0, 128, 0, 0 ));
            driver->draw3DLine(w1, w1 + 40 * v, video::SColor(0, 0, 128, 0 ));
            driver->draw3DLine(w1, w1 + 40 * w, video::SColor(0, 0, 0, 128 ));

            // Dessine un cercle
            int radius = 80;
            int circleDetail = 16;
            for (int k = 0; k < circleDetail; k++)
            {
                double teta = k * 2 * M_PI / circleDetail;
                double teta2 = (k + 1) * 2 * M_PI / circleDetail;

                core::vector3df u1, u2;
                u1 = w1 + radius * cos(teta) * v + radius * sin(teta) * w;
                u2 = w1 + radius * cos(teta2) * v + radius * sin(teta2) * w;
                driver->draw3DLine(u1, u2, video::SColor(0, 0, 128, 128 ));
            }
        }
    }
}


int main(void)
{
    IrrlichtDevice *device;
    video::IVideoDriver *driver;
    scene::ISceneManager *sceneManager;
    gui::IGUIEnvironment *gui;
    scene::ICameraSceneNode *camera;
    gui::IGUIStaticText *coordText;
    Path3D path;

    device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(800, 600), 32, false, false, false, 0);

    driver          = device->getVideoDriver();
    sceneManager    = device->getSceneManager();
    gui             = device->getGUIEnvironment();
    camera          = sceneManager->addCameraSceneNodeFPS();

    // Pour afficher les coordonnées
    coordText = gui->addStaticText(L"Coordonnees", core::rect<s32>(10, 10, 100, 45), true, true, 0, -1, true);

    // Le chemin suivi par le tube
    path.push(core::vector3df(80, 80, 80));
    path.push(core::vector3df(500, 200, 200));
    path.push(core::vector3df(500, 1000, 0));
    path.push(core::vector3df(200, 1000, 600));

    // Création du tube
    TubeSceneNode *tube = new TubeSceneNode(sceneManager->getRootSceneNode(), sceneManager, 666, path, 80);
    tube->drop();

    // Pour affichage des coordonnées
    core::vector3df posCam;
    wchar_t buffer[128];

    // Pour le dessin des lignes servant pour le débug
    video::SMaterial material;
    material.Lighting = false;

    while (device->run())
    {
        driver->beginScene(true, true, video::SColor(255, 255, 255, 255));

        sceneManager->drawAll();
        gui->drawAll();

        driver->setMaterial(material);

        // Dessin d'un repère orthonormé (x, y, z)
        driver->draw3DLine(core::vector3df(0, 0, 0), core::vector3df(100, 0, 0), video::SColor(0, 255, 0, 0));
        driver->draw3DLine(core::vector3df(0, 0, 0), core::vector3df(0, 100, 0), video::SColor(0, 0, 255, 0));
        driver->draw3DLine(core::vector3df(0, 0, 0), core::vector3df(0, 0, 100), video::SColor(0, 0, 0, 255));

        // Débug (commenter pour ne pas afficher les lignes de débug)
        drawTubeLines(driver, path, 16);

        driver->endScene();

        // Actualise les coordonnées et les affiche
        posCam = camera->getPosition();
        swprintf(buffer, 128, L"X : %f\nY : %f\nZ : %f", posCam.X, posCam.Y, posCam.Z);
        coordText->setText(buffer);
    }

    device->drop();
    return 0;
}



Merci.

Cordialement, Charly

Hors ligne


#1 

09-06-2010 19:33:14

ordiman85
Petit nouveau
Date d'inscription: 07-06-2010
Messages: 2

C'est bon j'ai trouvé, autant pour moi.

J'ai créé un CMeshBuffer avec les vertices et indices et puis j'ai fabriqué un SMesh à partir du CMeshBuffer et je l'ai ajouté à la scène en appliquant scene->setMaterialTexture().

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
881 membres
1426 sujets
11116 messages
Dernier membre inscrit: Bidule
15 invités en ligne
Aucun membre connecté
RSS Feed