Рисование объектов в реальном времени

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

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

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

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

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

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

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

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

введите описание изображения здесь

введите описание изображения здесь

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

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-координаты вершины (таким образом, если нарисовать что-то с одной стороны топора дварфа, то будет нарисовано то же самое с другой. сторона топора).

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


person shybovycha    schedule 10.01.2012    source источник
comment
ммм ... Чтобы иметь уникальные UV-координаты вершин, вам нужно изменить текстуру, скопировать измененную область и применить к правому трису с новым UV, не так ли?   -  person LBarret    schedule 11.01.2012
comment
думаю, нет. потому что в первую очередь мне нужно определить регион рисования. и для этого требуются уникальные UVs;)   -  person shybovycha    schedule 11.01.2012
comment
Я нашел репо и рад этому, но, пожалуйста, добавьте лицензию. Я подумал, может быть, вы перешли на Ruby, так как я нашел moo3d, но программа по следующему URL выглядит правильно: github.com/shybovycha / irrPaint3D Если вы не добавите лицензию, это не будет считаться разрешением: selectalicense.com/no-permission (кроме вставленных вами фрагментов и ответчиков, которые получают лицензию на stackoverflow). Программа очень полезна, так как Blender неточно обрезает мазки по сравнению с режимом ближайшего пикселя в Irrlicht, например, в Minetest. Лицензия позволит другим использовать и улучшать программу.   -  person Poikilos    schedule 31.03.2021


Ответы (1)


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

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

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

псевдокод:

  1. добавить узел, содержащий сетку треугольника попадания, в качестве параметра в getPointUV ()
  2. получить обратную матрицу absoluteTransformation, вызвав 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;
}
person Imm0    schedule 01.03.2012
comment
Я применил аналогичный подход с представлением векторов в виде суммы двух других векторов (все в контексте одного треугольника), и поскольку векторы являются относительными, нет необходимости в преобразованиях обратной матрицы (или любой другой матрицы) (ура!). Кратко описал подход в моем блоге шибовыча .github.io / 2021/05/04 / - person shybovycha; 04.05.2021