实时对象绘画

时间:2012-01-10 13:21:28

标签: c++ math 3d textures irrlicht

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

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

  1. 找出哪个对象的三角形用户选择了(光线投射,没有 真的很难)

  2. 找出交点的UV(中心)坐标 那个三角形

  3. 找出每个三角形顶点的

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

  5. 计算交点的纹理图像坐标

  6. 但不知何故,当我在纹理图像的第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坐标(因此,在矮人的斧头的一侧绘制一些东西会在另一侧绘制相同的东西那个斧头的一面)。

    我该怎么做?

1 个答案:

答案 0 :(得分:3)

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

重新解决您的第二个问题&#34;非唯一的顶点UV坐标&#34; 嗯,你是绝对正确的,你需要独特的vertexUV才能使这个工作,这意味着你必须打开你的模型,不要使用共享的uv空间,例如,镜像元素和东西。 (例如左/右靴子 - 如果他们使用相同的紫外线空间,你会在两者上自动绘画,你想要一个是红色而另一个是绿色)。你可以查看&#34; uvlayout&#34; (工具)或uv-unwrap修饰符ind 3ds max。

重新解决第一个也是更重要的问题:&#34; **错误的纹理坐标计算&#34; : 您的baycentric坐标的计算是正确的,但我认为您的输入数据是错误的。我假设你通过使用irrlicht的CollisionManager和TriangleSelector得到了三角形和碰撞点。问题是,三角形顶点的位置(您从collisionTest获得的返回值)位于WorldCoordiates中。但是你需要在ModelCoordinates中进行计算,所以这就是你需要做的事情:

伪代码

  1. 将包含命中三角形网格的节点作为参数添加到getPointUV()
  2. 通过调用node-&gt; getAbsoluteTransformation()[inverse]
  3. 获得逆绝对变换矩阵
  4. 通过此逆矩阵变换三角形的顶点,并将这些值用于方法的其余部分。
  5. 在下面你会发现我的优化方法是为一个非常简单的网格(一个网格,只有一个网格缓冲)。

    代码:

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