[Projekt] breeze 2.0

Hier könnt ihr euch selbst, eure Homepage, euren Entwicklerstammtisch, Termine oder eure Projekte vorstellen.
Forumsregeln
Bitte Präfixe benutzen. Das Präfix "[Projekt]" bewirkt die Aufnahme von Bildern aus den Beiträgen des Themenerstellers in den Showroom. Alle Bilder aus dem Thema Showroom erscheinen ebenfalls im Showroom auf der Frontpage. Es werden nur Bilder berücksichtigt, die entweder mit dem attachement- oder dem img-BBCode im Beitrag angezeigt werden.

Die Bildersammelfunktion muss manuell ausgeführt werden, die URL dazu und weitere Details zum Showroom sind hier zu finden.

This forum is primarily intended for German-language video game developers. Please don't post promotional information targeted at end users.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Ne, keine Achterbahn, das Zeug da:
bridge.png
stone.png
(Shots aus der gescheiterten Devmania-Demo)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
j.klugmann
Establishment
Beiträge: 201
Registriert: 07.07.2010, 13:00
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von j.klugmann »

Nice. Allerdings wäre AA schon nett. :)
Imaging-Software und bald auch Middleware: http://fd-imaging.com
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Im Moment ist die Beleuchtung mit AA vor allem eins: falsch. ;-)

Ich habe gerade eben mal gerichtetes SSAO implementiert, das kommt einer physikalisch motivierten Approximation wesentlich näher und akzeptable Ergebnisse sind tatsächlich wesentlich leichter zu erzielen.
newAO4.png
newAO5.png
Der Shader entspricht jetzt in etwa einem Integral von occluderDir ∙ recieverNormal / (1 + occluderDist²) über die am Normal ausgerichtete Halbkugel, damit kommt das SSAO endlich etwas weg von der Edge Detection im Tiefenpuffer hin zu tatsächlicher Berechnung von Occlusion.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Zudomon
Establishment
Beiträge: 2257
Registriert: 25.03.2009, 07:20
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von Zudomon »

Oh ja! Das ist ne Verbesserung!
Was super ist, das jetzt auf dem zweiten Bild rechts an der Wand neben der Kiste tatsächlich das dahinterliegende unbeleuchtet ist und daneben nur die Schattierung der Kiste ist. Wie du schon sagst... weg vom Edge Detection :D
j.klugmann
Establishment
Beiträge: 201
Registriert: 07.07.2010, 13:00
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von j.klugmann »

Ich meinte Anti-Aliasing.
Imaging-Software und bald auch Middleware: http://fd-imaging.com
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

jesse: Ich auch. ;)

Herrlich, man möchte gar nicht mehr aufhören mit Bilderposten ... :P
newAO6.png
So, nun muss ich aber erstmal wieder hinfort in den drögen Alltag. :(
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4263
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: [Projekt] breeze 2.0

Beitrag von Chromanoid »

sieht sehr geil aus! :)
j.klugmann
Establishment
Beiträge: 201
Registriert: 07.07.2010, 13:00
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von j.klugmann »

Cat: *grummel* Hatte mich verlesen. Bin davon ausgegangen, dass da "AO" stand.
Imaging-Software und bald auch Middleware: http://fd-imaging.com
Benutzeravatar
Schrompf
Moderator
Beiträge: 4884
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von Schrompf »

Ohja, das sieht wirklich gut aus. Machst Du das in voller Bildauflösung oder irgendwie reduziert? So weich, wie das aussieht, stecken da sicher ne Menge Samples dahinter, weswegen ich mir Gedanken über die Performance mache.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Im Moment ist es Vollbild, aber halbe Auflösung sollte gut gehen, da muss ich jedoch das Downsampling noch fixen. Bzgl Samples reichen im Endanwendungsfall mit Texturen und Beleuchtung (z.B. letzter Screenshot) gerade mal 8 pro Pixel + Zentrallookup + Noise-Lookup. Das Blurring braucht natürlich einige Samples, aber genausoviele wie bei jedem anderen SSAO auch, im Moment berechne ich in zwei Richtungen jeweils den Durchschnitt von 8 Pixeln. Am Ende reichen im Gesamtkontext wahrscheinlich auch 4 Pixel, außerdem kostet der Durchschnitt extrem wenig, weil die Samples so schön kohärent sind. (Beim Durchschnitt wird pro Pixel natürlich auch noch der Tiefen-/Normalpuffer gesampelt, um Blurring über Kanten hinweg zu unterbinden.)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

So, AO ist reduziert auf 8 Samples bei halber Auflösung mit anschließendem bilateralen gleitenden Durschnitt von 8 Pixeln und schließlich bilateralem Upsampling für hochaufgelöste Kanten trotz niedrigerer AO-Auflösung. Das ganze läuft auf meiner alten Geforce 8600 in der unfertigen Devmania-Demo mitsamt Deferred Shading und 4-Split-PSSM-Soft-Shadows bei 50 FPS. Jetzt kam ich auch mal dazu, das AO auf die Ambient-Beleuchtung zu begrenzen, damit entfallen endlich auch die dunklen Umrandungen in strahlend hellem Sonnenlicht.

Insgesamt bin ich sehr zufrieden, sowohl die Qualität als auch die Performance sind sehr viel besser als bei meinen Implementierungen in der letzten Engine-Iteration. Zeit, die Engine Feature-complete zu bekommen, und dann endlich mit ner netten Demo zu veröffentlichen ... ;-)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Lazy Updates ... wollte ich in dieser Iteration so gut wie möglich vermeiden, unter anderem weil ein wichtiger Teil des Konzepts ist, den Rendervorgang seiteneffektfrei zu halten, und so ggf. Parallelisierung zu ermöglichen (auch wenn das bei den aktuellen CPU-Framezeiten von 2-3 ms in sehr objektreichen Szenen (1000+) wohl nicht so bald notwendig sein wird). Davon abgesehen verteilt Lazy Evaluation unzählige überflüssige Update-Aufrufe an Stellen, an welchen diese eigentlich nichts zu suchen hätten. Weiterhin reicht bei mehreren abhängigen Größen ein Changed-Flag nicht mehr aus. In der letzten Iteration hatte ich hierzu ein Integer-basiertes Revision-System mit entsprechenden Hilfs-Templates, welches zwar funktionierte, die Update-Logik aber unnötig verkomplizierte.

Nun muss ich aber pro Frame etliche Controllers in Synchronisation mit ihren jeweiligen Entities halten, ohne vorher zu wissen, welche Entities sich verändert haben könnten. Folgende Möglichkeiten kamen mir in den Sinn:
  • Changed-Flags und anschließende Lazy-Evaluation von Matrizen, Bounding Volumes etc. bei Bedarf in den Controllers.
  • Entities bei Veränderung in eine Update-Liste einfügen.
  • Unterscheidung statischer und dynamischer Entities mit entsprechendem Flag.
Die Update-Liste ist mir wesentlich zu viel Verwaltungsaufwand, davon abgesehen, dass bei jedem noch so einfachen Manipulationsaufruf ggf. irgendwelche Objekte in irgendwelche weit entfernten Listen eingetragen werden müssen.

Bleibt für mich im Moment nur die Unterscheidung statischer und dynamischer Entities, womit sich die automatisierte regelmäßige Aktualisierung auf sehr wenige Objekte in der ganzen Szene beschränkt. Dieses Flag lässt sich problemlos zur Laufzeit verändern, womit sich auch zunächst statische Objekte wie beispielsweise zerstörbare Architektur bei Bedarf "aufwecken" ließen. Außerdem hat es den angenehmen Vorteil, dass ich bei der Speicherung des aktuellen Simulationszustands statische Entities außen vor lassen kann, womit auch das Speichern / Laden von Spielständen wesentlich beschleunigt werden sollte.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
j.klugmann
Establishment
Beiträge: 201
Registriert: 07.07.2010, 13:00
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von j.klugmann »

Bei mir entscheidet jeder Controller selber, ob und inwiefern er eine Synchronisation mit dem Rest des Systems braucht. Nachteil ist, dass ich immer über die komplette Liste von Controllers loope, um die entsprechenden Controller zu synchronisieren. Allerdings unterscheide ich zwischen permanenten Controllern und Controllern, die lazy evaluiert werden. Ein Controller ist permanent, sobald er sich bei einer Komponente eingetragen hat, die den Controller verwaltet. Eine Komponente verwaltet dann die einzelnen, spezialisierten Controller und sorgt für die Synchronisation. Alle Controller, die nicht in einer Komponente eingetragen sind, werden nicht ausgewertet und fallen somit weg. Zusätzlich zu lazy und permanten Controllern, gibt es Controller, die ihre Änderungen in Form eines Commits an die Komponente comitten. Der Controller wird dann synchronisiert, wenn die ganze Komponente synchronisiert wird. Letztendlich habe ich folgende Controller:

* Permanente, die bei jedem Komponenten-Update synchronisiert werden
* Lazy-Controller, die nur unter Aufruf einer expliziten Update-Funktion synchronisiert werden
* Semi-Permanente, die ihre Änderungen in Form eines Commits an die jeweilige Komponente markieren und beim Komponenten-Update synchronisiert werden

Bei Semi-Permanenten Controllern wird davon ausgegangen, dass sie komplett ohne Seiteneffekte laufen und somit gut verteilbar sind.
Imaging-Software und bald auch Middleware: http://fd-imaging.com
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

j.klugmann hat geschrieben:Bei mir entscheidet jeder Controller selber, ob und inwiefern er eine Synchronisation mit dem Rest des Systems braucht.
Ja, bei mir auch.
j.klugmann hat geschrieben:Nachteil ist, dass ich immer über die komplette Liste von Controllers loope, um die entsprechenden Controller zu synchronisieren.
Exakt darum geht es, alle Controllers, die sich eingetragen haben, müssen irgendwie synchronisiert werden.
j.klugmann hat geschrieben:Allerdings unterscheide ich zwischen permanenten Controllern und Controllern, die lazy evaluiert werden. Ein Controller ist permanent, sobald er sich bei einer Komponente eingetragen hat, die den Controller verwaltet. Eine Komponente verwaltet dann die einzelnen, spezialisierten Controller und sorgt für die Synchronisation. Alle Controller, die nicht in einer Komponente eingetragen sind, werden nicht ausgewertet und fallen somit weg. Zusätzlich zu lazy und permanten Controllern, gibt es Controller, die ihre Änderungen in Form eines Commits an die Komponente comitten. Der Controller wird dann synchronisiert, wenn die ganze Komponente synchronisiert wird. Letztendlich habe ich folgende Controller:

* Permanente, die bei jedem Komponenten-Update synchronisiert werden
* Lazy-Controller, die nur unter Aufruf einer expliziten Update-Funktion synchronisiert werden
* Semi-Permanente, die ihre Änderungen in Form eines Commits an die jeweilige Komponente markieren und beim Komponenten-Update synchronisiert werden

Bei Semi-Permanenten Controllern wird davon ausgegangen, dass sie komplett ohne Seiteneffekte laufen und somit gut verteilbar sind.
Ohne diese ganzen Unterscheidungen habe ich dennoch mehr oder weniger dieselben Verhaltensmuster. Controllers, welche sich in bestimmten Subsystemen (oder Komponenten) wie dem Rendering angemeldet haben, werden durch diese korrekt angesteuert und sind nicht das Problem. Alle Controllers lassen sich jederzeit gezielt per Synchronize()-Aufruf synchronisieren. Das Problem sind wie gesagt diejenigen Controllers, welche sich auf Verdacht für Synchronisation anmelden müssen, weil nicht klar ist, wann und ob sich Entities ändern. Genau darüber würde das Static-Flag entscheiden, ob ein Controller automatisch jedes Frame synchronisiert wird, oder nur bei manuellem Synchronize()-Aufruf für das jeweilige veränderte Entity.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
j.klugmann
Establishment
Beiträge: 201
Registriert: 07.07.2010, 13:00
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von j.klugmann »

Die Unterscheidung ist rein logisch und ist nicht hardcodiert.
Imaging-Software und bald auch Middleware: http://fd-imaging.com
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Die Arbeit an Editor UI und Serialisierung ist unendlich zermürbend. Ich befinde mich wohl gerade in beiden Bereichen irgendwo auf halber Strecke. Das Studium hat meinen Zeitplan schon wieder um 3 Monate verzögert - Ausgang ungewiss, erster Release nach Vollendung von Serialisierung und Editorbasisfunktionalität angestrebt.
Klicken zum Vergrößern
Klicken zum Vergrößern
Wie zu sehen ist, ist der Ressourcen-Import bereits voll integriert. Dabei steckt die gesamte Funktionalität in einem kleinen Konsolen-Tool (berc), in welchem Assimp die Hauptarbeit leistet und ich anschließend die importierten Daten entweder zum Rendern in handliche Binärformate oder für PhysX in umständliche Objekthierarchien umwandle. Dieses Tool habe ich bisher einfach manuell über die Konsole betrieben, insofern beschränkt sich die Editor-Integration auf eine simple UI und einen entsprechenden Prozessaufruf.

Interessanter ist das Dokumentensystem: Weil in einer solch komplexen UI zwangsläufig unglaublich viel Zustand steckt, habe ich hier versucht, möglichst allen Zustand zu abstrahieren und zu automatisieren. Konkret handelt es sich um einen Zustandsbaum, in dem jeder Knoten für einen Gesamtzustand des Editors steht. Der Zustand eines Knotens setzt sich dabei aus dem Zustand aller Elternknoten und dem Zustand des Knotens selbst zusammen. Die Einzelzustände werden bei Eintritt in genau dieser Reihenfolge angewandt, bei Austritt in umgekehrte Reihenfolge zurückgesetzt.

Wechselt der Editor nun von einem Zustand in einen anderen, zum Beispiel durch Wechsel eines Dokumentes oder eines Tools, werden alle Zustände bis zu dem ersten gemeinsamen Elternknoten zurückgesetzt, und anschließend alle Zustände bis zu dem neuen Knoten angewandt. Sofern bei diesem Wechsel der zuvor aktive Zustand nicht explizit verlassen wurde, merkt sich der jeweilige Elternknoten stets seinen zuletzt aktiven Kindknoten, damit dieser bei Wiedereintritt in den zugehörigen Elternknoten automatisch wiederhergestellt werden kann. Auf diese Weise kann der Editor elegant zwischen ganzen Teilbäumen wechseln: Wechselt der Benutzer das gerade bearbeitete Dokument, aktiviert der Editor den zugehörigen Dokumentenzustand, und dieser stellt rekursiv alle zuletzt aktiv gewesenen Unterzustände wieder her, sodass sich der Benutzer wieder in demselben Tool befindet, in dem er das Dokument verlassen hatte.

Jeder Knoten im Zustandsbaum speichert eine Liste von State-Objekten, die genau die Aufgabe haben, den konkreten Einzelzustand dieses Knotens herzustellen und zurückzusetzen. Das Editor-Framework bietet eine Basisklasse, die das Herstellen und Trennen von Qt-Signal-Verbindungen sowie das Setzen und Zurücksetzen von Qt-Properties automatisiert. Auf diese Weise wird der eigentliche Zustandscode sehr wenig zustandsbehaftet. Leichtsinnsfehler bei der manuellen Herstellung und Wiederaufhebung von Zuständen lassen sich so gut vermeiden.

So schwierig das System zu beschreiben ist, so schwierig stellte es sich auch heraus, diese Ideen wirklich wasserdicht zu implementieren. Die gigantische Vielfalt an Eintritts- und Austrittsmöglichkeiten, insbesondere nicht nur rekursiv, sondern auch durch Einfügen neuer oder Löschen aktiver Zustände, machte diese Aufgabe zu einer der kompliziertesten seit langem. Schlussendlich bin ich mit dem Ergebnis jedoch sehr zufrieden, weil sich der Editor-Code nun sehr sauber gestaltet, ohne dass ich mir noch irgendwelche größeren Gedanken um Zustände machen müsste.

Zusatzanmerkung zum Bild: Wie zu sehen ist, setzt der Editor exakt das Controller-System der Engine um. Alle Informationen zu den jeweiligen Klassen werden dabei direkt aus dem Serialisierungssystem der Engine gezogen, welches inzwischen eine ganze Palette von Reflection-Funktionalität umfasst. Mehr dazu, wenn ich selbst erfolgreich durch diesen Jungle bin.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von Aramis »

Hoert sich wie immer klasse an. Ich weiss noch, dass ich beim letzten etwas komplexeren Editor an dem ich mich versucht habe, ebenfalls ziemlich mit der Zustandsverwaltung zu kaempfen hatte (und nachdem besagtes Projekt eher evolutionaer entstand, hatte ich natuerlich keinen sonderlich abstrakten Ansatz dafuer). Daher: mein aufrichtiges Beileid zum Aufwand, aber ich bin mir sicher, dass es sich rentieren wird.

Nette Assimp-Werbung mal wieder, danke :-)
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

So unspektakulär sieht es aus, wenn zum Ersten Mal ein Gewaltiger Haufen von Reflection- und Editor-Subsystemen erfolgreich zusammenarbeiten. Aber hey, nichts an der Szenen- und Entityerzeugung ist hardcodiert! ;)
editor4.png
Welche Art von Entity erzeugt wird, entscheidet alleine die (generische) Komposition von Controllers an der linken Seite. Zur Integration neuer Controller-Typen reicht die engineseitige Registrierung einer winzigen entsprechenden Factory-Klasse. Jetzt fallen dann erstmal wieder Massen von UI und Interaktionen für Selektion, Transformation, Bearbeiten von Eigenschaften etc. an. :|
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Da sich hier gerade nicht so wahnsinnig viel tut, ein bisschen Bildspam von meiner Seite:
editor7.png
Zu sehen ist eine Anzeige (momentan noch read-only) der Eigenschaften der aktuellen Objektauswahl. Die Eigenschaften werden in weniger als 20 Zeilen Code unabhängig ihres Types gelesen, in Strings umgewandelt und in den Eigenschaftenbaum eingefügt. Der Eigenschaftenbaum spiegelt direkt die Zusammensetzung des Objekts aus Controllern wieder, das heißt das Entity besteht auch engineseitig aus einem Entity mit den angezeigten Entity-Eigenschaften sowie einem angehängen Punktlicht-Controller mit den ebenfalls angezeigten Punktlicht-Eigenschaften. Wie die Undo History unten rechts erahnen lässt, sind jetzt auch Undo und Redo vollständig implementiert. Das Einfügen von links definierten Objekten geschieht per Drag & Drop, Selektions- und Transformationswerkzeuge nach dem Einfügen sind noch nicht implementiert.

Und noch ein Code-Ausschnitt zur Definition von Eigenschaften mit dem nochmals leicht überarbeiteten Reflection-System, weils so Spaß macht. Das ist alles, was pro generisch im Editor konfigurierbarer und in Dateien serialisierbarer Klasse definiert werden muss:

Code: Alles auswählen

const beCore::ReflectionProperties PointLightControllerProperties = beCore::ReflectionProperties::construct_inplace()
	<< beCore::MakeReflectionProperty<float[4]>("color", beCore::Widget::Color)
		.set_setter( BE_CORE_PROPERTY_SETTER_UNION(&PointLightController::SetColor, float) )
		.set_getter( BE_CORE_PROPERTY_GETTER_UNION(&PointLightController::GetColor, float) )
	<< beCore::MakeReflectionProperty<float>("attenuation", beCore::Widget::Raw)
		.set_setter( BE_CORE_PROPERTY_SETTER(&PointLightController::SetAttenuation) )
		.set_getter( BE_CORE_PROPERTY_GETTER(&PointLightController::GetAttenuation) )
	<< beCore::MakeReflectionProperty<float>("attenuation offset", beCore::Widget::Raw)
		.set_setter( BE_CORE_PROPERTY_SETTER(&PointLightController::SetAttenuationOffset) )
		.set_getter( BE_CORE_PROPERTY_GETTER(&PointLightController::GetAttenuationOffset) )
	<< beCore::MakeReflectionProperty<float>("range", beCore::Widget::Slider)
		.set_setter( BE_CORE_PROPERTY_SETTER(&PointLightController::SetRange) )
		.set_getter( BE_CORE_PROPERTY_GETTER(&PointLightController::GetRange) )
		.set_min_value( BE_CORE_PROPERTY_CONSTANT(0.1f) )
		.set_max_value( BE_CORE_PROPERTY_CONSTANT(500.0f) )
		.set_value_step( BE_CORE_PROPERTY_CONSTANT(0.1f) )
	<< beCore::MakeReflectionProperty<bool>("shadow", beCore::Widget::Raw)
		.set_setter( BE_CORE_PROPERTY_SETTER(&PointLightController::EnableShadow) )
		.set_getter( BE_CORE_PROPERTY_GETTER(&PointLightController::IsShadowEnabled) )
	<< beCore::MakeReflectionProperty<uint4>("shadow resolution", beCore::Widget::Raw)
		.set_setter( BE_CORE_PROPERTY_SETTER(&PointLightController::SetShadowResolution) )
		.set_getter( BE_CORE_PROPERTY_GETTER(&PointLightController::GetShadowResolution) );
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Die Definition einer Deferred-Shading-Pipeline in FX-Code:

Code: Alles auswählen

// Bind resources once during setup
#define BE_PERSPECTIVE_SETUP
#define BE_SCENE_SETUP

#include "Engine/Pipeline.fx"
#include "Pipelines/LPR/Scene.fx"
#include "Engine/Perspective.fx"
#include "Engine/Shadow.fx"

/// Geometry pipeline stage.
PipelineStage GeometryPipelineStage
<
	// Layer specifies rendering order
	int Layer = 10;
	string Setup = "PipelineSetup";
>;

/// Shadow pipeline stage.
PipelineStage ShadowPipelineStage
<
	int Layer = 20;
	// Exclude from implicit rendering
	bool Normal = false;
	string Setup = "PipelineSetup";
>;

/// Lighting pipeline stage.
PipelineStage LightingPipelineStage
<
	int Layer = 30;
	string Setup = "PipelineSetup";
>;

/// Default pipeline stage.
PipelineStage DefaultPipelineStage
<
	int Layer = 50;
	string Setup = "PipelineSetup";
>;

/// Background render queue.
RenderQueue BackRenderQueue
<
	int Layer = 5;
>;

/// Default render queue.
RenderQueue DefaultRenderQueue
<
	int Layer = 10;
>;

/// Alpha render queue.
RenderQueue AlphaRenderQueue
<
	int Layer = 25;
	bool DepthSort = true;
>;

/// Default rasterizer state enabling multi-sampling.
RasterizerState DefaultRasterizerState
{
	MultisampleEnable = true;
	AntiAliasedLineEnable = true;
};

/// Default depth-stencil state allowing for additive rendering.
DepthStencilState DefaultDepthStencilState
{
	DepthFunc = Less_Equal;
};

/// Read-only depth-stencil state.
DepthStencilState ReadOnlyDepthStencilState
{
	DepthWriteMask = Zero;
	DepthFunc = Less_Equal;
};

/// Additive blend state.
BlendState DoubleAdditiveBlendState
{
	BlendEnable[0] = true;
	SrcBlend[0] = One;
	DestBlend[0] = One;

	BlendEnable[1] = true;
	SrcBlend[1] = One;
	DestBlend[1] = One;
};

static const String VSDefaultResources[] = { "PerspectiveConstants" };
static const String GSDefaultResources[] = { "PerspectiveConstants" };
static const String PSDefaultResources[] = { "PerspectiveConstants" };

static const String PSLightingResources[] = { "PerspectiveConstants", "SceneGeometryTexture", "SceneDiffuseTexture", "SceneSpecularTexture" };

technique11 PipelineSetup <
	// Enable processing functionality
	bool EnableProcessing = true;
>
{
	// G-Buffer
	pass <
		string PipelineStage = "GeometryPipelineStage";
		
		string Color0 = "SceneGeometryTarget";
		bool bClearColorOnce0 = true;
		float4 ClearColor0 = float4(10000.0f, 0.0f, 0.0f, -1.0f);
		bool bKeepColor0 = true;
		
		string Color1 = "SceneDiffuseTarget";
		bool bClearColorOnce1 = true;
		bool bKeepColor1 = true;
		
		string Color2 = "SceneSpecularTarget";
		bool bClearColorOnce2 = true;
		bool bKeepColor2 = true;
		
		string DepthStencil = "SceneDepthBuffer";
		bool bClearDepthOnce = true;
		bool bClearStencilOnce = true;
		bool bKeepDepthStencil = true;
		
		string VSBindResources[] = VSDefaultResources;
		string GSBindResources[] = GSDefaultResources;
		string PSBindResources[] = PSDefaultResources;
	>
	{
		SetRasterizerState( DefaultRasterizerState );
		SetDepthStencilState( DefaultDepthStencilState, 0 );
		SetBlendState( NULL, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff );
	}

	// Shadow maps
	pass <
		string PipelineStage = "ShadowPipelineStage";
		
		// Do not create multisampled shadow maps
		bool Multisampled = false;
		
		string DepthStencil = "SceneShadowTarget";
		bool bClearDepthOnce = true;
		bool bClearStencilOnce = true;
		bool bKeepDepthStencil = true;
		
		string VSBindResources[] = VSDefaultResources;
		string GSBindResources[] = GSDefaultResources;
		string PSBindResources[] = PSDefaultResources;
	>
	{
		SetRasterizerState( DefaultRasterizerState );
		SetDepthStencilState( DefaultDepthStencilState, 0 );
		SetBlendState( NULL, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff );
	}

	// Lighting (e.g. light bounding volumes to be rendered here)
	pass <
		string PipelineStage = "LightingPipelineStage";
		
		string Color0 = "SceneTarget";
		bool bClearColorOnce0 = true;
		float4 ClearColor0 = 0.0f;
		bool bKeepColor0 = true;
		
		string DepthStencil = "SceneDepthBuffer";
		bool bKeepDepthStencil = true;
		
		string VSBindResources[] = VSDefaultResources;
		string GSBindResources[] = GSDefaultResources;
		string PSBindResources[] = PSLightingResources;
		// No shaders that might indicate use of textures to be bound
		string ForceTextureBinding[] = PSLightingResources;
	>
	{
		SetRasterizerState( NULL );
		SetDepthStencilState( ReadOnlyDepthStencilState, 0 );
		SetBlendState( DoubleAdditiveBlendState, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff );
	}

	// Default stage (forward shading, alpha-transparent geometry, atmospheric effects ...)
	pass <
		string PipelineStage = "DefaultPipelineStage";
		
		string Color0 = "SceneTarget";
		bool bClearColorOnce0 = true;
		bool bKeepColor0 = true;
		
		string DepthStencil = "SceneDepthBuffer";
		bool bKeepDepthStencil = true;
		
		string VSBindResources[] = VSDefaultResources;
		string GSBindResources[] = GSDefaultResources;
		string PSBindResources[] = PSDefaultResources;
	>
	{
		SetRasterizerState( DefaultRasterizerState );
		SetDepthStencilState( DefaultDepthStencilState, 0 );
		SetBlendState( NULL, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff );
	}
}
Definition der notwendigen Puffer / Ressourcen:

Code: Alles auswählen

#ifdef BE_SCENE_SETUP
	#define BE_SCENE_TEXTURE(name) name
#else
	#define BE_SCENE_TEXTURE(name) prebound(name)
#endif

/// Scene texture.
Texture2D BE_SCENE_TEXTURE(SceneTexture) : bindpoint_s(SceneTarget, t15)
<
	string TargetType = "Permanent";
	string Format = "R16G16B16A16F";
>;

/// Scene depth texture.
Texture2D BE_SCENE_TEXTURE(SceneGeometryTexture) : bindpoint_s(SceneGeometryTarget, t14)
<
	string TargetType = "Permanent";
	string Format = "R16G16B16A16F";
>;

/// Scene texture.
Texture2D BE_SCENE_TEXTURE(SceneDiffuseTexture) : bindpoint_s(SceneDiffuseTarget, t13)
<
	string TargetType = "Permanent";
	string Format = "R8G8B8A8U_SRGB";
>;

/// Scene texture.
Texture2D BE_SCENE_TEXTURE(SceneSpecularTexture) : bindpoint_s(SceneSpecularTarget, t12)
<
	string TargetType = "Permanent";
	string Format = "R8G8B8A8U_SRGB";
>;

/// Depth buffer.
Texture2D BE_SCENE_TEXTURE(SceneDepthBuffer) : SceneDepthBuffer
<
	string TargetType = "Permanent";
	string Format = "D24S8";
>;
Hässliche FX-Compiler-Workarounds, die von modifiziertem Effects11-Framework interpretiert werden:

Code: Alles auswählen

/// Binds a shader resource to the given register.
#define bindpoint(reg) register(reg) : bindpoint_##reg

/// Binds a shader resource to the given register.
#define bindpoint_s(semantic, reg) register(reg) : semantic##__bindpoint_##reg

/// Excludes the given variable from resource binding.
#define prebound(name) unmanaged__##name
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Jedes Objekt (Entity, Controller, ...) hat ab sofort eine persistente Identifikationsnummer. Pro Welt-Objekt ist jede Nummer einmalig. Wird ein Objekt unwiderruflich aus der Welt entfernt, so bleibt die zugehörige Nummer dennoch für immer belegt. Selbstverständlich können Objekte zwischenzeitlich aus der Welt herausgenommen und wieder eingefügt werden. Solange sie ihre eigene Nummer kennen, können sie diese beliebig oft erneut selbst belegen. Auf diese Weise überlebt die Nummer auch problemlos Undo/Redo-Operationen im Editor.

Es fiel mir nicht leicht, mich zu diesem Schritt zu entschließen. Die Tatsache, dass jede einmal angeforderte ID für immer belegt sein wird, macht sämtliche Abläufe, die mit Veränderung der Weltstruktur zu tun haben, prinzipiell endlich. Ich habe deshalb letztlich für diese IDs einen 64-Bit-Integer-Typ gewählt, der auch bei ca. 100.000 Objekten in der Welt noch mehrere hundert Billionen Komplettrevisionen des gesamten Weltaufbaus ermöglicht. Damit dürfte das System schlussendlich doch immer nahe genug an der Unendlichkeit bleiben.

Ursprünglich hatte ich das übliche Recyclen von persistenten IDs mittels Free Lists im Kopf. Damit wäre der ID-Vorrat praktisch immer unendlich gewesen. Dafür hätte ich mir jedoch große Probleme bei der getrennten Speicherung von Weltzuständen (Savegames) eingehandelt: Diese Zustände referenzieren persistente IDs, deren Bedeutung auf keinen Fall abhängig von der Weltversion sein sollte. Nur weil durch ID-Recycling an Stelle eines Flugzeuges in neuerer Version nun ein Baum steht, sollte dieser nicht den Zustand des Flugzeugs aus einer älteren Version erben. Bleiben dagegen alle IDs für immer belegt, so können solche Probleme ganz sicher niemals auftreten, alle Weltzustände bleiben automatisch für alle Zeiten kompatibel.

Intern wird die Verwaltung persistenter IDs von einer kleinen Hilfsklasse übernommen, die einen sortierten Vektor von IDs und zugehörigen (streng typisierten) Objektreferenzen verwaltet. Mittels binärer Suche lassen sich in sehr kurzer Zeit die zu den jeweiligen persistenten IDs gehörigen Objekte ausfindig machen.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
Artificial Mind
Establishment
Beiträge: 802
Registriert: 17.12.2007, 17:51
Wohnort: Aachen

Re: [Projekt] breeze 2.0

Beitrag von Artificial Mind »

Klingt nach einer guten Lösung auch wenn der Schritt zur Endlichkeit natürlich immer schwer ist (ich kenne das Gefühl nur zu gut, dass man sich sagt "64bit sollten doch genug sein, oder? ...").

Gibt es nen Grund, warum du dich zur binären Suche entschieden hast, anstatt ner vernünftigen Hashmap?
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Faulheit und die Hoffnung, dass es dank kontinuierlichem linearen Speicherstück nicht viel langsamer ist. Sollte es zum Problem werden, habe ich immer noch zwei Hash-Map-Implementierungen zur Auswahl.

(Binäre Suche ist so schön berechenbar. ;-))
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von dot »

CodingCat hat geschrieben:Faulheit [...]
std::unordered_map ;)
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Trotzdem muss ich dann rumprobieren wegen Hash-Verteilung etc. :-/
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Nachdem ich von groben Bounding-Box-Tests zur Selektion von Objekten die Nase voll hatte (man trifft ja doch nie was man möchte, weil irgendwas Großes in der Nähe steht und mit seiner Box überlappt), habe ich nun endlich eine pixelgenaue Objektselektion. Da ich natürlich viel zu faul bin, hierfür einen vollen CPU-Pfad mit extra Dreieckspuffern und Dreiecksschnitttests einzuführen, habe ich stattdessen einfach einen GPU-Read-Back von Objekt-IDs implementiert. Eventuell gibt der folgende Code ja einen gewissen Einblick in die Zusammenarbeit verschiedener Engine-Komponenten:

Code: Alles auswählen

beEntitySystem::Entity* entityUnderCursor(SceneDocument &document,
					  const QPointF &relativePos, const beScene::PerspectiveDesc &perspective)
{
	using namespace beMath;

	beScene::PerspectiveDesc rayPerspective(perspective);

	// Offset camera to ray perspective
	rayPerspective.ProjMat[2][0] -= 2 * relativePos.x() - 1;
	rayPerspective.ProjMat[2][1] -= -2 * relativePos.y() + 1;
	rayPerspective.ProjMat = mul( rayPerspective.ProjMat, mat_scale<4>(10000.0f, 10000.0f, 1.0f) );
	rayPerspective.ViewProjMat = mul( rayPerspective.ViewMat, rayPerspective.ProjMat );
	rayPerspective.OutputIndex = 0;

	uint4 objectIDStage = document.renderer()->Pipeline()->GetStageID("ObjectIDPipelineStage");

	if (objectIDStage == beScene::InvalidPipelineStage)
	{
		LEAN_LOG_ERROR_MSG("Pipeline stage 'ObjectIDPipelineStage' unavailable, cannot perform entity query.");
		return nullptr;
	}

	// Acquire selection pipe
	beGraphics::TextureTargetDesc selectionPipeDesc(1, 1, 1, beGraphics::Format::R32U, beGraphics::SampleDesc(1));
	lean::resource_ptr<beScene::Pipe> pSelectionPipe = document.renderer()->PipePool()->GetPipe(selectionPipeDesc);
	pSelectionPipe->KeepResults();

	// Perform scene query
	document.renderer()->Pipeline()->AddPerspective(rayPerspective, pSelectionPipe, nullptr, 1U << objectIDStage);
	document.scene()->Render();

	const beGraphics::ColorTextureTarget *pObjectIDTarget = pSelectionPipe->GetColorTarget("ObjectIDTarget");

	// Nothing rendered
	if (!pObjectIDTarget)
		return nullptr;
	
	uint4 selectedObjectID = beEntitySystem::Entity::InvalidID;
	
	// Read back object IDs
	document.renderer()->TargetPool()->ReadBack(
			pObjectIDTarget, &selectedObjectID, sizeof(selectedObjectID),
			document.renderer()->ImmediateContext()
		);

	// Release pipe resources
	pSelectionPipe->KeepResults(false);
	pSelectionPipe->Release();

	return document.world()->GetEntity(selectedObjectID);
}
Nicht unbedingt wunderhübsch, aber kurz und wenig Aufwand. Auf Shader-Seite wurde die Pipeline-Definition dafür minimal erweitert:

Code: Alles auswählen

Texture2D ObjectIDTexture : ObjectIDTarget
<
	string TargetType = "Permanent";
	string Format = "R32U";
>;

pass <
	string PipelineStage = "ObjectIDPipelineStage";

	string Color0 = "ObjectIDTarget";
	float4 ClearColor0 = 4000000000.0f; // UINT CLEAR?!?
	bool bClearColorOnce0 = true;
	bool bKeepColor0 = true;

	string DepthStencil = "SceneDepthBuffer";
	bool bClearDepthOnce = true;
	bool bClearStencilOnce = true;
	bool bKeepDepthStencil = true;

	string VSBindResources[] = VSDefaultResources;
	string GSBindResources[] = GSDefaultResources;
	string PSBindResources[] = PSDefaultResources;
>
{
	SetRasterizerState( DefaultRasterizerState );
	SetDepthStencilState( DefaultDepthStencilState, 0 );
	SetBlendState( NULL, float4(0.0f, 0.0f, 0.0f, 0.0f), 0xffffffff );
}
Für Tipps zum Clearen von Integer-Targets wäre ich dankbar, momentan kriege ich ClearRenderTargetView() mit nichts anderem als Floats gefüttert.
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: [Projekt] breeze 2.0

Beitrag von eXile »

CodingCat hat geschrieben:Für Tipps zum Clearen von Integer-Targets wäre ich dankbar, momentan kriege ich ClearRenderTargetView() mit nichts anderem als Floats gefüttert.
Auch wenn du es vermutlich schon gelesen hast:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb173539.aspx hat geschrieben:Applications that wish to clear a render target to a specific integer value bit pattern should render a screen-aligned quad instead of using this method. The reason for this is because this method accepts as input a floating point value, which may not have the same bit pattern as the original integer.
Alternativ kannst du natürlich auch einfach mit einem passenden float clearen?
Benutzeravatar
dot
Establishment
Beiträge: 1734
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von dot »

Nachdem Direct3D 10+ IEEE 754 floats verlangt, sollte das mit dem zu float gecasteten int aber auch funktionieren. Was schneller ist müsste man wohl austesten.
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

So unsinnig es erscheint: Es wird eben nicht reinterpretiert, sondern wasimmer ich ClearRenderTargetView() übergebe, wird tatsächlich in den entsprechenden Integer-Wert umgewandelt. 4000000000.0f wird also zu 4000000000 und 3.57331108e-43 zu 0. :-/

Mit 4294967295.0f bin ich also dank float-Ungenauigkeit schon wieder bei 0, dagegen wird 4294960000.0f zu 4294960128. (-1.0f wird ebenfalls zu 0.)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Benutzeravatar
CodingCat
Establishment
Beiträge: 1857
Registriert: 02.03.2009, 21:25
Wohnort: Student @ KIT
Kontaktdaten:

Re: [Projekt] breeze 2.0

Beitrag von CodingCat »

Im Rahmen der Transformationstools habe ich die projektive Geometrie für mich entdeckt. Toll, wie einfach sich viele Dinge im Clip Space umsetzen lassen, wenn man ihn mal durchschaut hat.
Nah
Nah
Fern
Fern

Als nächstes steht Synchronisation der UI mit den Objekteigenschaften an. In der letzten Iteration hatte ich hierzu Listener-Mechanismen in das Reflection-System integriert. Damit komme ich jedoch um einigen Overhead pro überwachtem (und nicht überwachtem!) Objekt kaum herum, was mir gerade außerordentlich widerstrebt.

(Das Eigenschaftenfenster ist nebenbei bemerkt immer noch ein einfacher QTreeView, inzwischen jedoch gestylet mittels Qt Style Sheets, sehr feine Sache.)
alphanew.net (last updated 2011-07-02) | auf Twitter | Source Code: breeze 2 | lean C++ library | D3D Effects Lite
Antworten