Frage

Ich implementieren einen Javascript-Software-Renderer (für akademische Zwecke).Es übernimmt die Darstellung eines 3D-Objekts als Dreiecke und die perspektivische Projektion vom 3D-Raum in den 2D-Raum.

Bisher habe ich das verwendet lineTo Und fillRect um die Eckpunkte und Linien auf dem Bildschirm darzustellen.Ich habe es sogar benutzt lineTo um die Dreiecksfüllung der Scanlinie durchzuführen.(Sie können sich das Projekt ansehen Hier)

Bisher waren die FPS recht gut.Aber der letzte Teil der Aufgabe besteht darin, z-Buffering zu implementieren :P.Meines Wissens nach besteht die einzige Möglichkeit, dies zu tun, darin, meine Dreiecke nicht mehr mit zu füllen lineTo und füllen Sie sie entweder mit einem Array aus 1-Pixel-Linien oder einem Array aus 1-Pixel-Quadraten.(Denn bevor ich jedes „Pixel“ zeichne, muss ich den Tiefenpuffer überprüfen und sehen, ob ich es tatsächlich zeichnen sollte oder nicht.)

Das Problem besteht darin, dass das Füllen von Dreiecken mit winzigen Rechtecken oder Linien LANGSAM ist.Bringt alles auf 2 FPS herunter.Meine Frage ist also: Gibt es eine Methode, ein Pixel anstelle einer winzigen Linie zu zeichnen (was möglicherweise schneller ist)?

Was kann ich alternativ noch tun, um die Sache zu beschleunigen?Mein Ziel ist es, dass es sich schnell genug dreht, um das Prinzip zu demonstrieren.(6-10fps würden ausreichen)

Prost.

[BEARBEITEN] Während ich auf eine Antwort warte, werde ich meine Dreiecksfüllfunktionen ändern, um 4 Pixel große „Pixel“ anstelle von 1 Pixel zu zeichnen.Aber das wird zackig aussehen...

War es hilfreich?

Lösung

Schauen Sie sich das an: http://jsfiddle.net/ZXjAM/2/

// points 0,1,2,3 front face
var fAvgZ = (cube.processPoints[0].colorZ + 
    cube.processPoints[1].colorZ + 
    cube.processPoints[2].colorZ + 
    cube.processPoints[3].colorZ) / 4 / 20;

// points 0,2,4,6 top
var tAvgZ = (cube.processPoints[0].colorZ + 
    cube.processPoints[2].colorZ + 
    cube.processPoints[4].colorZ + 
    cube.processPoints[6].colorZ) / 4 / 20;

// points 4,5,6,7 rear
var reAvgZ = (cube.processPoints[4].colorZ + 
    cube.processPoints[5].colorZ + 
    cube.processPoints[6].colorZ + 
    cube.processPoints[7].colorZ) / 4 / 20;

// points 1,3,5,7 bottom
var bAvgZ = (cube.processPoints[1].colorZ + 
    cube.processPoints[3].colorZ + 
    cube.processPoints[5].colorZ + 
    cube.processPoints[7].colorZ) / 4 / 20;

// points 2,3,6,7 right side
var rAvgZ = (cube.processPoints[2].colorZ + 
    cube.processPoints[3].colorZ + 
    cube.processPoints[6].colorZ + 
    cube.processPoints[7].colorZ) / 4 / 20;

// points 0,1,4,5 left side
var lAvgZ = (cube.processPoints[0].colorZ + 
    cube.processPoints[1].colorZ + 
    cube.processPoints[4].colorZ + 
    cube.processPoints[5].colorZ) / 4 / 20;

var layers = [{key:0, val:fAvgZ},
          {key:1, val:fAvgZ},
          {key:2, val:tAvgZ},
          {key:3, val:tAvgZ},
          {key:4, val:reAvgZ},
          {key:5, val:reAvgZ},
          {key:6, val:bAvgZ},
          {key:7, val:bAvgZ},
          {key:8, val:rAvgZ},
          {key:9, val:rAvgZ},
          {key:10, val:lAvgZ},
          {key:11, val:lAvgZ}];

var outLay = layers.sort(function(a,b){
    return (a.val - b.val);
});

for(var i = 0; i < outLay.length; i++)
{
    var k = outLay[i].key;
    ...
}

Dies ist keineswegs die effizienteste Methode zum Mitteln/Sortieren der Punktwerte und kann wahrscheinlich mit weniger Codezeilen unter Verwendung der bereits vorhandenen Eigenschaften des Würfels durchgeführt werden, aber das Grundkonzept bleibt dasselbe.

Ich finde den durchschnittlichen Z-Index und verwende ihn, um die Schichtreihenfolge anzunehmen.Natürlich wird das nicht für alles funktionieren, aber für einfache Polyeder sollte es ausreichen.

Dies kann vereinfacht werden zu:

var layers = [];
for (var i = 0; i < cube.sides.length; i++){
    var side = cube.sides[i];
    var avg = (cube.processPoints[side.a].colorZ + 
               cube.processPoints[side.b].colorZ + 
               cube.processPoints[side.c].colorZ) / 3 / 20;                   
    layers.push({key:i, val:avg});
}

var outLay = layers.sort(function(a,b){
    return (a.val - b.val);
});

Es scheint einige Randfälle zu geben, in denen es zu Problemen bei der schnellen Bestellung kommt.

Dies scheint genauer zu sein: http://jsfiddle.net/ZXjAM/4/

var layers = [];
for (var i = 0; i < 12; ++i){
    var side1 = cube.sides[i];
    var side2 = cube.sides[++i];
    var avg = (cube.processPoints[side1.a].colorZ + 
               cube.processPoints[side1.b].colorZ + 
               cube.processPoints[side1.c].colorZ + 
               cube.processPoints[side2.a].colorZ + 
               cube.processPoints[side2.b].colorZ + 
               cube.processPoints[side2.c].colorZ) / 6;                   
    layers.push({key:i-1, val:avg});
    layers.push({key:i, val:avg});
}

var outLay = layers.sort(function(a,b){
    return (a.val - b.val);
});
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top