Живопись объекта в реальном времени - PullRequest
3 голосов
/ 10 января 2012

Я пытаюсь выполнить рисование в реальном времени текстуры объекта.Сейчас используем Irrlicht, но это не имеет большого значения.

Пока у меня есть правильные координаты UV, используя этот алгоритм:

  1. выяснить, какой треугольник объектавыбранный пользователем (радиопередача, ничего сложного)

  2. узнать координаты UV (барицентрические) точки пересечения этого треугольника

  3. найтиКоординаты UV (текстуры) каждой вершины треугольника

  4. определяют координаты UV (текстуры) точки пересечения

  5. вычисляют координаты изображения текстуры дляточка пересечения

Но каким-то образом, когда я рисую в точке, которую я получил на 5-м шаге на изображении текстуры, я получаю совершенно неверные результаты.Таким образом, при рисовании прямоугольника в точке курсора его координата X (или Z) инвертируется:

enter image description here

enter image description here

Вот код iЯ использую для получения координат текстуры:

core::vector2df getPointUV(core::triangle3df tri, core::vector3df p)
{
    core::vector3df 
    v0 = tri.pointC - tri.pointA,
    v1 = tri.pointB - tri.pointA,
    v2 = p - tri.pointA;

    float dot00 = v0.dotProduct(v0),
    dot01 = v0.dotProduct(v1),
    dot02 = v0.dotProduct(v2),
    dot11 = v1.dotProduct(v1),
    dot12 = v1.dotProduct(v2);

    float invDenom = 1.f / ((dot00 * dot11) - (dot01 * dot01)),
    u = (dot11 * dot02 - dot01 * dot12) * invDenom,
    v = (dot00 * dot12 - dot01 * dot02) * invDenom;

    scene::IMesh* m = Mesh->getMesh(((scene::IAnimatedMeshSceneNode*)Model)->getFrameNr());

    core::array<video::S3DVertex> VA, VB, VC;
    video::SMaterial Material;

    for (unsigned int i = 0; i < m->getMeshBufferCount(); i++)
    {
    scene::IMeshBuffer* mb = m->getMeshBuffer(i);
    video::S3DVertex* vertices = (video::S3DVertex*) mb->getVertices();

    for (unsigned long long v = 0; v < mb->getVertexCount(); v++)
    {
        if (vertices[v].Pos == tri.pointA)
        VA.push_back(vertices[v]); else
        if (vertices[v].Pos == tri.pointB)
        VB.push_back(vertices[v]); else
        if (vertices[v].Pos == tri.pointC)
        VC.push_back(vertices[v]);

        if (vertices[v].Pos == tri.pointA || vertices[v].Pos == tri.pointB || vertices[v].Pos == tri.pointC)
        Material = mb->getMaterial();

        if (VA.size() > 0 && VB.size() > 0 && VC.size() > 0)
        break;
    }

    if (VA.size() > 0 && VB.size() > 0 && VC.size() > 0)
        break;
    }

    core::vector2df 
    A = VA[0].TCoords,
    B = VB[0].TCoords,
    C = VC[0].TCoords;

    core::vector2df P(A + (u * (C - A)) + (v * (B - A)));
    core::dimension2du Size = Material.getTexture(0)->getSize();
    CursorOnModel = core::vector2di(Size.Width * P.X, Size.Height * P.Y);
    int X = Size.Width * P.X, Y = Size.Height * P.Y;

    // DRAWING SOME RECTANGLE    
    Material.getTexture(0)->lock(true);
    Device->getVideoDriver()->setRenderTarget(Material.getTexture(0), true, true, 0);
        Device->getVideoDriver()->draw2DRectangle(video::SColor(255, 0, 100, 75), core::rect<s32>((X - 10), (Y - 10), 
            (X + 10), (Y + 10)));
    Device->getVideoDriver()->setRenderTarget(0, true, true, 0);
    Material.getTexture(0)->unlock();

    return core::vector2df(X, Y);
}

Я просто хочу, чтобы мой объект можно было рисовать в реальном времени.Мои текущие проблемы: неправильный расчет координат текстуры и неуникальные координаты UV вершины (поэтому, если что-то нарисовать на одной стороне топора карлика, то на другой сторонеэтот топор).

Как мне это сделать?

1 Ответ

3 голосов
/ 01 марта 2012

Я смог использовать вашу кодовую базу и заставить ее работать на меня.

Ваша вторая проблема "Неуникальные координаты вершины UV": Ну, вы абсолютно правы, вам нужны уникальные vertexUV, чтобы это работало, а это значит, что вам нужно развернуть свои модели и не использовать совместно используемое ультрафиолетовое пространство, например, для зеркальные элементы и прочее. (например, левая / правая загрузка - если они используют одно и то же ультрафиолетовое пространство, вы будете рисовать автоматически на обоих, где вы хотите, чтобы один был красным, а другой зеленым). Вы можете проверить "uvlayout" (инструмент) или модификатор uv-unwrap ind 3ds max.

По первой и более важной проблеме: "** неправильный расчет координат текстуры" : расчет ваших байцентрических координат верен, но, как я полагаю, ваши входные данные неверны. Я предполагаю, что вы получите треугольник и коллизионную точку, используя ColrlisionManager и TriangleSelector в irrlicht. Проблема в том, что позиции вершин треугольника (которые вы получаете в качестве возвращаемого значения из collisionTest) находятся в WorldCoordiates. Но они понадобятся вам в ModelCoordinates для расчета, поэтому вот что вам нужно сделать:

псевдокод

  1. добавить узел, который содержит сетку треугольника попадания, в качестве параметра для getPointUV ()
  2. получить обратную матрицу absoluteTransformation-Matrix, вызвав node-> getAbsoluteTransformation () [inverse]
  3. Преобразуйте вершины треугольника с помощью этой обратной матрицы и используйте эти значения для остальной части метода.

Ниже вы найдете мой оптимизированный метод, который делает его для очень простого меша (один меш, только один меш).

Код:

irr::core::vector2df getPointUV(irr::core::triangle3df tri, irr::core::vector3df p, irr::scene::IMeshSceneNode* pMeshNode, irr::video::IVideoDriver* pDriver)
{
    irr::core::matrix4 inverseTransform(
    pMeshNode->getAbsoluteTransformation(),
      irr::core::matrix4::EM4CONST_INVERSE);

    inverseTransform.transformVect(tri.pointA);
    inverseTransform.transformVect(tri.pointB);
    inverseTransform.transformVect(tri.pointC);

    irr::core::vector3df 
    v0 = tri.pointC - tri.pointA,
    v1 = tri.pointB - tri.pointA,
    v2 = p - tri.pointA;

    float dot00 = v0.dotProduct(v0),
    dot01 = v0.dotProduct(v1),
    dot02 = v0.dotProduct(v2),
    dot11 = v1.dotProduct(v1),
    dot12 = v1.dotProduct(v2);

    float invDenom = 1.f / ((dot00 * dot11) - (dot01 * dot01)),
    u = (dot11 * dot02 - dot01 * dot12) * invDenom,
    v = (dot00 * dot12 - dot01 * dot02) * invDenom;

    irr::video::S3DVertex A, B, C;
    irr::video::S3DVertex* vertices = static_cast<irr::video::S3DVertex*>(
      pMeshNode->getMesh()->getMeshBuffer(0)->getVertices());

    for(unsigned int i=0; i < pMeshNode->getMesh()->getMeshBuffer(0)->getVertexCount(); ++i)
    {
      if( vertices[i].Pos == tri.pointA)
      {
        A = vertices[i];
      }
      else if( vertices[i].Pos == tri.pointB)
      {
        B = vertices[i];
      }
      else if( vertices[i].Pos == tri.pointC)
      {
        C = vertices[i];
      }
    }

    irr::core::vector2df t2 = B.TCoords - A.TCoords;
    irr::core::vector2df t1 = C.TCoords - A.TCoords;

    irr::core::vector2df uvCoords = A.TCoords + t1*u + t2*v;

    return uvCoords;
}
...