2012-01-10 3 views
2

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

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

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

  2. не узнать УФ (барицентрических) координат точки пересечения на , что треугольник

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

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

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

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

enter image description here

enter image description here

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

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); 
} 

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

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

+0

ммм ... Для того, чтобы иметь единственную вершину UV координат вам необходимо изменить текстуру, скопируйте область модифицированную и нанесение на правой трис- с новым УФ, Дон» ты? – LBarret

+0

я думаю нет. потому что, прежде всего, мне нужно определить область рисования. и это требует уникальных UVs;) – shybovycha

ответ

3

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

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

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

псевдокода:

  1. добавить узел, который содержит сетку хитового треугольника в качестве параметра getPointUV ()
  2. получить обратную absoluteTransformation-матрицу с помощью вызова node-> getAbsoluteTransformation() [обратного]
  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; 
} 
+0

Thx для редактирования mr. Мэтт Фенвик :) +1 – Imm0

Смежные вопросы