2012-01-10 25 views
2

我正在尝试对对象纹理执行实时绘画。现在使用Irrlicht,但这并不重要。实时对象绘画

到目前为止,我已经得到了使用该算法正确的UV坐标:

  1. 找出哪些对象的三角用户选择(光线投射,什么 真的很难)

  2. 找出UV (baricentric)坐标上的交点 即三角形

  3. 找出每个三角形顶点的UV(纹理)坐标

  4. 找出UV(纹理)交点坐标

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

我只是想让我的对象实时绘制。我目前的问题是:错误的纹理坐标计算非唯一的顶点UV坐标(所以,在矮人的斧头的一侧绘制东西会在该斧头的另一侧绘制相同的东西)。

我应该怎么做?

+0

嗯...要具有独特的顶点的UV坐标你需要改变纹理,复制修改并应用到右三新UV的区域,不要你呢? – LBarret 2012-01-11 17:52:57

+0

我认为不是。因为首先,我需要确定绘画区域。它需要独特的UV;) – shybovycha 2012-01-11 19:58:12

回答

3

我能够使用您的代码库并让它为我工作。

回复你的第二个问题,“非唯一顶点的UV坐标”: 那么你是绝对正确的,你需要独特vertexUVs得到这个工作,这意味着你必须解开你的模型并没有利用共享uv空间的例如镜像元素和东西。 (例如,左/右引导 - 如果他们使用相同的UV空间,则会在两个位置自动绘制,其中一个是红色,另一个是绿色)。您可以查看“uvlayout”(工具)或uv-unwrap修饰符ind 3ds max。

回复第一,更重要的问题:“**质地错座标计算”: 你baycentric坐标的计算是正确的,但我想你输入的数据是错误的。我假设你通过使用irrlicht的CollisionManager和TriangleSelector来获得三角形和collisionPoint。问题是,三角形顶点的位置(作为collisionTest的返回值)位于WorldCoordiates中。但是,你需要他们ModelCoordinates进行计算,那么这里就是你需要做什么:

  1. 添加包含命中三角形作为参数传递给getPointUV的网格节点( )
  2. 通过调用node-> getAbsoluteTransformation()[inverse]获得反向absoluteTransformation-Matrix
  3. 通过此逆矩阵转换三角形的顶点并将这些值用于该方法的其余部分。

下面你会发现我的优化方法,它适用于一个非常简单的网格(一个网格,只有一个meshbuffer)。

代码:

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编辑先生。 Matt Fenwick :) +1 – Imm0 2012-03-01 16:26:28