3

オブジェクト テクスチャにリアルタイム ペイントを実行しようとしています。今のところ 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 座標(したがって、ドワーフの斧の片側に何かを描画すると、その斧の反対側にも同じものが描画されます)。

どうすればいいですか?

4

1 に答える 1

3

私はあなたのコードベースを使用して、それを私のために機能させることができました。

2番目の問題「非一意の頂点UV座標」について: これは絶対に正しいです。これを機能させるには、一意の頂点UVが必要です。つまり、モデルをアンラップし、共有UVスペースを使用しないでください。ミラーリングされた要素など。(たとえば、左/右のブート-同じuvスペースを使用している場合は、両方に自動的にペイントします。一方を赤にし、もう一方を緑にします)。「uvlayout」(ツール)またはuv-unwrap修飾子ind3dsmaxをチェックアウトできます。

最初のより重要な問題について:「**間違ったテクスチャ座標計算」:ベイセントリック座標の計算は正しいですが、入力データが間違っていると思います。irrlichtのCollisionManagerとTriangleSelectorを使用して、三角形とcollisionPointを取得すると仮定します。問題は、三角形の頂点の位置(collisionTestから戻り値として取得)がWorldCoordiatesにあることです。ただし、計算にはModelCoordinatesで必要になるため、次のようにする必要があります。

擬似コード

  1. ヒットした三角形のメッシュを含むノードをパラメーターとしてgetPointUV()に追加します。
  2. node-> getAbsoluteTransformation()[inverse]を呼び出して、逆absoluteTransformation-Matrixを取得します。
  3. この逆行列によって三角形の頂点を変換し、メソッドの残りの部分でそれらの値を使用します。

以下に、非常に単純なメッシュ(1つのメッシュ、1つのメッシュバッファーのみ)に対して最適化された方法を示します。

コード:

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;
}
于 2012-03-01T12:55:25.533 に答える