Wie kann ich ein perspektivisch korrektes Quad zeichnen?

7

Ich versuche ein Quad in 2D zu zeichnen (in SharpDX, aber das ist im Grunde XNA). Aber die Texturkorrektur funktioniert nicht und ich bekomme nur ein affines strukturiertes Quad.

Geben Sie hier die Bildbeschreibung ein

Ich benutze es BasicEffect, um es zu rendern.

BasicTextureEffect = new BasicEffect(Device)
{
    Alpha = 1.0f,

    TextureEnabled = true,
    LightingEnabled = false,
    VertexColorEnabled = true,

    Projection = Matrix.OrthoOffCenterLH(0.0f, ScreenWidth, ScreenHeight, 0.0f, 0.0f, 1.0f),
};

Es ist ein isometrisches 2D-Spiel. Ich habe Pseudo-3D-Koordinaten in der isometrischen Welt (es ist ein Schatten auf dem Boden) in den Bildschirmraum konvertiert und dann mit gerendert DrawQuad.

Muss ich die Ansicht (oder Projektion?) Irgendwie einrichten, um echtes 3D zu erhalten (die isometrische Kamera emulieren), und dieses Quad stattdessen in 3D-Koordinaten zeichnen? Wie schließlich? Oder gibt es eine Möglichkeit, dies in 2D zu korrigieren?

Aktualisieren:

Ich habe den eigentlichen Teil-Screenshot hochgeladen (Abbildung A), damit Sie sehen können, dass er fast gleich ist. (Ich habe es ein bisschen geschnitten, aber es geht alles bis zur Ecke)

Abbildung A.Abbildung B.
            Abbildung A Abbildung B.

Update 2:

Ich kann jetzt bestätigen, dass SharpDX (XNA) BasicEffectdies mit einfachem UW-Mapping (4 Ecken eines Quadrats) und einfach macht DrawQuad. Ich habe es vorübergehend geändert, um den Mittelpunkt einzuschließen, und ich zeichne 4 Dreiecke anstelle von 2 (Abbildung B). Dies reduziert den Effekt auf ein Minimum, aber es ist immer noch da. Es muss noch gelöst werden, da ich es nicht nur im Schatten verwenden werde.

SmartK8
quelle
Warum funktioniert die Korrektur der Texturperspektive nicht?
Konzept3d
Ich weiß es wirklich nicht. Der Effekt (auf bereits kaum sichtbaren Schatten) wurde nur zufällig bemerkt, als ich ihn in Schachbrettstruktur änderte. Es ist überhaupt nicht ausgesprochen, aber es ist definitiv als affin erkennbar. Sie können mir keine Frage stellen, die ich im Grunde stelle. Warum funktioniert es nicht IST die Frage? :)
SmartK8
Ähnlich zu dieser Frage von SO: stackoverflow.com/questions/15242507/…
Seth Battin
Ich habe das tatsächlich gelesen, konnte aber nicht abschließen, was in DirectX zu tun ist. Es scheint OpenGL-spezifisch zu sein, ebenso wie die vorgestellte Lösung.
SmartK8
3
Haben Sie tatsächlich Nathan Reeds Artikel darüber gefunden? reedbeta.com/blog/2012/05/26/quadrilateral-interpolation-part-1
Seth Battin

Antworten:

7

Ich habe den Shader gemäß dem von Seth Battin vorgeschlagenen Artikel geändert . Jetzt führt es eine perspektivisch korrekte Quad-Texturierung durch. Puh, Speck geliefert:

Geben Sie hier die Bildbeschreibung ein

Für die zukünftigen Generationen kann das nie passieren. Die Eingabe erfolgt in Form der Linienscheitelpunkte A1 / A2, B1 / B2, die Diagonalen erzeugen (statt sequentieller Scheitelpunkte):

public static Vector3 DrawPerspectiveCorrectQuad(VertexWithPerspective v1, VertexWithPerspective v2, VertexWithPerspective v3, VertexWithPerspective v4)
{
    // detects intersection of two diagonal lines
    Single divisor = (v4.Position.Y - v3.Position.Y) * (v2.Position.X - v1.Position.X) - (v4.Position.X - v3.Position.X) * (v2.Position.Y - v1.Position.Y);
    Single ua = ((v4.Position.X - v3.Position.X) * (v1.Position.Y - v3.Position.Y) - (v4.Position.Y - v3.Position.Y) * (v1.Position.X - v3.Position.X)) / divisor;
    Single ub = ((v2.Position.X - v1.Position.X) * (v1.Position.Y - v3.Position.Y) - (v2.Position.Y - v1.Position.Y) * (v1.Position.X - v3.Position.X)) / divisor;

    // calculates the intersection point
    Single centerX = v1.Position.X + ua * (v2.Position.X - v1.Position.X);
    Single centerY = v1.Position.Y + ub * (v2.Position.Y - v1.Position.Y);
    Vector3 center = new Vector3(centerX, centerY, 0.5f);

    // determines distances to center for all vertexes
    Single d1 = (v1.Position - center).Length();
    Single d2 = (v2.Position - center).Length();
    Single d3 = (v3.Position - center).Length();
    Single d4 = (v4.Position - center).Length();

    // calculates quotients used as w component in uvw texture mapping
    v1.TextureCoordinate *= Single.IsNaN(d2) || d2 == 0.0f ? 1.0f : (d1 + d2)/d2;
    v2.TextureCoordinate *= Single.IsNaN(d1) || d1 == 0.0f ? 1.0f : (d2 + d1)/d1;
    v3.TextureCoordinate *= Single.IsNaN(d4) || d4 == 0.0f ? 1.0f : (d3 + d4)/d4;
    v4.TextureCoordinate *= Single.IsNaN(d3) || d3 == 0.0f ? 1.0f : (d4 + d3)/d3;

    // this is just PrimitiveBatch<VertexWithPerspective>
    // where VertexWithPerspective is basically VertexPositionTextureColor
    // with Vector3 (uvw) instead of Vector2 (uv) for texture coordinates
    // note: you need to create VertexWithPerspective yourself (decompilation ftw)
    PerspectivePrimitives.DrawQuad(v1, v3, v2, v4);
}
SmartK8
quelle