Frage

In einem 3D -Motor, an dem ich arbeite, habe ich erfolgreich einen Würfel in 3D gezogen. Die einzige Methode, um die Seiten zu füllen, besteht darin, für mich entweder eine feste Farbe oder einen Gradienten zu verwenden. Um die Dinge aufregender zu machen, würde ich gerne Texturzuordnung mit einer einfachen Bitmap implementieren.

Der Punkt ist, dass ich kaum Artikel oder Codeproben zum Thema Bildmanipulation in JavaScript finden kann. Darüber hinaus scheint die Bildunterstützung in HTML5 -Leinwand auf Beschneidung beschränkt zu sein.

Wie könnte ich eine Bitmap strecken, damit eine rechteckige Bitmap ein unreguläres Würfelgesicht füllen kann? In 2D ist ein projiziertes quadratisches Würfelgesicht aufgrund der Perspektive nicht von einer quadratischen Form, daher muss ich es dehnen, um es in jedes Viereck zu passen.

Hoffentlich verdeutlicht dieses Bild meinen Standpunkt. Das linke Gesicht ist jetzt mit einem weißen/schwarzen Gradienten gefüllt. Wie könnte ich es mit einer Bitmap füllen, nachdem es texturgestopft wurde?

Cube

Hat jemand irgendwelche Tipps zur perspektivischen Texturzuordnung (oder zum Bildmanipulation) mit JavaScript und HTML5 -Leinwand?

Bearbeiten: Ich habe es zum Laufen gebracht, dank 6502!

Es ist jedoch eher CPU -intensiv, also würde ich gerne Optimierungsideen hören.

Ergebnis mit der Technik von 6502 - Texturbild verwendet

War es hilfreich?

Lösung

Ich denke, Sie werden nie ein genaues Ergebnis erzielen ... Ich habe einige Zeit damit verbracht, wie man 3D -Grafiken mithilfe von Canvas -2D -Kontext durchführt, und fand es lebensfähig, eine Gouraud -Schattierung von Texturzuordnung durchzuführen, indem sie geeignete 2D -Gradienten und -Matrizen berechnen:

  • Feste Polygone sind natürlich einfach
  • Die Gouraud -Füllung ist nur für eine Komponente möglich (dh Sie können kein Dreieck haben, bei dem jeder Scheitelpunkt eine willkürliche RGB ist, die mit einer bilinearen Interpolation gefüllt ist. Sie können diese Füllung jedoch mit drei beliebigen Farbtönen einer einzelnen Farbe durchführen).
  • Die lineare Texturzuordnung kann mithilfe von Clipping und Bildzeichnung erfolgen

Ich würde eine perspektive korrekte Texturzuordnung mithilfe von Mesh-Unterteilung (wie auf PS1) implementieren.

Ich fand jedoch viele Probleme ... zum Beispiel Bildzeichnung mit einer Matrix-Transformation (für die Texturzuordnung erforderlich) ist für Chrome und IMO recht ungenau, es ist unmöglich, ein pixel genaues Ergebnis zu erzielen. Im Allgemeinen gibt es keine Möglichkeit, das Antialiasing beim Zeichnen auf eine Leinwand auszuschalten, und dies bedeutet, dass Sie sich bei der Unterteilung in Dreiecken sichtbare durchsichtige durchdachte Linien erhalten. Ich fand auch, dass Multipass-Rendering bei Chrome wirklich schlecht funktioniert (wahrscheinlich wegen der Implementierung des HW-Accterated-Renderings).

Im Allgemeinen ist diese Art von Rendering sicherlich ein Stress für Webbrowser, und anscheinend werden diese Anwendungsfälle (zum Beispiel seltsame Matrizen) nicht sehr gut getestet. Ich konnte sogar Firefox so schlecht krachen, dass es das gesamte X Susbsystem auf meinem Ubuntu niedergeschlagen hat.

Sie können die Ergebnisse meiner Bemühungen sehen hier oder als Video hier... IMO beeindruckt sicherlich, dass dies in einem Browser ohne Verwendung von 3D -Erweiterungen erfolgen kann, aber ich denke nicht, dass aktuelle Probleme in Zukunft behoben werden.

Wie auch immer, die Grundidee, die zum Zeichnen eines Bildes verwendet wurde, so dass die 4 Ecken in bestimmten Pixel -Position enden, besteht darin, zwei Dreiecke zu zeichnen, von denen jede bilineare Interpolation verwendet.

Im folgenden Code gehe ich davon aus, dass Sie ein Bildobjekt haben texture und 4 Ecken von jeweils ein Objekt mit Feldern x,y,u,v wo x,y sind Pixelkoordinaten auf der Ziel -Leinwand und u,v sind Pixelkoordinaten auf texture:

function textureMap(ctx, texture, pts) {
    var tris = [[0, 1, 2], [2, 3, 0]]; // Split in two triangles
    for (var t=0; t<2; t++) {
        var pp = tris[t];
        var x0 = pts[pp[0]].x, x1 = pts[pp[1]].x, x2 = pts[pp[2]].x;
        var y0 = pts[pp[0]].y, y1 = pts[pp[1]].y, y2 = pts[pp[2]].y;
        var u0 = pts[pp[0]].u, u1 = pts[pp[1]].u, u2 = pts[pp[2]].u;
        var v0 = pts[pp[0]].v, v1 = pts[pp[1]].v, v2 = pts[pp[2]].v;

        // Set clipping area so that only pixels inside the triangle will
        // be affected by the image drawing operation
        ctx.save(); ctx.beginPath(); ctx.moveTo(x0, y0); ctx.lineTo(x1, y1);
        ctx.lineTo(x2, y2); ctx.closePath(); ctx.clip();

        // Compute matrix transform
        var delta = u0*v1 + v0*u2 + u1*v2 - v1*u2 - v0*u1 - u0*v2;
        var delta_a = x0*v1 + v0*x2 + x1*v2 - v1*x2 - v0*x1 - x0*v2;
        var delta_b = u0*x1 + x0*u2 + u1*x2 - x1*u2 - x0*u1 - u0*x2;
        var delta_c = u0*v1*x2 + v0*x1*u2 + x0*u1*v2 - x0*v1*u2
                      - v0*u1*x2 - u0*x1*v2;
        var delta_d = y0*v1 + v0*y2 + y1*v2 - v1*y2 - v0*y1 - y0*v2;
        var delta_e = u0*y1 + y0*u2 + u1*y2 - y1*u2 - y0*u1 - u0*y2;
        var delta_f = u0*v1*y2 + v0*y1*u2 + y0*u1*v2 - y0*v1*u2
                      - v0*u1*y2 - u0*y1*v2;

        // Draw the transformed image
        ctx.transform(delta_a/delta, delta_d/delta,
                      delta_b/delta, delta_e/delta,
                      delta_c/delta, delta_f/delta);
        ctx.drawImage(texture, 0, 0);
        ctx.restore();
    }
}

Diese hässlichen seltsamen Formeln für all diese "Delta" -Variablen werden verwendet, um zwei lineare Systeme von drei Gleichungen in drei Unbekannten zu lösen Cramers Methode und Sarrus Schema für 3x3 -Determinanten.

Insbesondere suchen wir nach den Werten von a, b, ... f so dass die folgenden Gleichungen zufrieden sind

a*u0 + b*v0 + c = x0
a*u1 + b*v1 + c = x1
a*u2 + b*v2 + c = x2

d*u0 + e*v0 + f = y0
d*u1 + e*v1 + f = y1
d*u2 + e*v2 + f = y2

delta ist die Determinante der Matrix

u0  v0  1
u1  v1  1
u2  v2  1

und zum Beispiel delta_a ist die Determinante derselben Matrix, wenn Sie die erste Spalte durch ersetzen x0, x1, x2. Mit diesen können Sie berechnen a = delta_a / delta.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top