Muepe32
Erfahrenes Mitglied
Hallo zusammen,
Hier im Forum gab es in der letzten Zeit erfreulicherweise vermehrt Postings in meinem Lieblingsthema, der 3D-Programmierung. Ich selbst bin da hauptsätzlich in DirectX aktiv aber habe natürlich auch Erfahrung mit OpenGL. Da ich jemand bin, der sehr gerne Libraries für andere schreibt und das auch präferiert mit Unterstützung von .NET habe ich mir gedachte ich entwickle auch mal eine kleine Bibliothek um OpenGL in .NET verwenden zu können. Das Verwenden an sich war ja eine leichte Aufgabe (P-Invoke) und bisschen abtippen, daher habe ich mich entschlossen das ganze etwas auszuweiten.
So gliedert sich das ganze momentan eigentlich in 3 Level:
1. Einfach alle Funktionen importiert, die zu OpenGL gehören sowie dynamisches Laden diverser sehr oft verwendeter Extensions (sofern sie vorhanden sind).
2. Diverse Wrapperklassen, die es gerade für Einsteiger leichter machen, da viele Kontrollen vorhanden sind und so Fehler gleich erkannt werden können. Von den meisten Klassen gibt es verschiedene Versionen mit verschiedenen "Sicherheitsstufen". So verlässt sich ein UncheckedVertexBuffer völlig darauf, dass der User weiss, welches die richtigen Eingaben sind, ein VertexBuffer jedoch prüft alles (natürlich mit der entsprechenden Performanceverbrennung) noch nach.
3. Ein UserControl, das einem die Erstellung des Kontexts und andere nützliche Dinge in einfacher Weise zur Verfügung stellt.
So kann eigentlich dann jeder für sich bestimmen, bis zu welchem Level er gerne Unterstützung haben möchte.
Nun auch noch ein paar Spezifikationen, was denn bisher so alles vorhanden ist (ich bin erst seit 3 Tagen dran, ist daher noch nicht alle Welt
):
Texturen
- Die Klasse Texture2D kann Texturen laden aus Dateien, dem Speicher, einer Resource in der Exe oder allgemein einem Stream (Netzwerkstream, ...). Unterstützt werden dabei die Formate PNG, JPG, GIF, TIFF, EXIF und BMP. Für DDS (DirectDraw Surface) sind auch die gängigsten Umwandlungen bereits vorhanden (inklusive der komprimierten Formate).
- Die Klasse SpriteList bietet die Möglichkeit einfach 2D-Objekte zu cachen und dann in einem Batch zu zeichnen. Dabei werden Modi wie AlphaBlend und ColorBlend unterstützt. Ein Beispiel wäre folgendermassen:
Ein Aufruf der Form list.BatchDraw zeichnet nun all das, was zwischen CaptureBatch und EndBatch aufgenommen wurde.
Primitive
Für das Zeichnen von Primitiven habe ich Teile der Konzepte von DirectX als Inspiration genommen, da ich diese eigentlich äusserst komfortabel finde.
Wesentlich für das Zeichnen sind grundsätzlich dabei 2 Klassen:
IndexBuffer
VertexBuffer
Der VertexBuffer hält Positionsdaten, Farbdaten, Texturkoordinaten und Normalen. Da es jedoch mühsam (und teilweise auch einfach unpassend) ist diese immer alle anzugeben ist das natürlich auch nicht nötig. Es wird dabei ein Konzept ähnlich dem FVF in DirectX verwendet. Man definiert structs, welche durch Attribute angeben, welche Daten wo und wie vorhanden sind. Beispielsweise folgende struct definiert einen Vertex der Position und Farbe hat:
Durch die Attribute kann man angeben, um wie viele Komponenten es sich handelt und wie das Offset vom Anfang der struct zum ersten Element dieser Kategorie ist. Dadurch kann man theoretisch auch unzählige andere Dinge reinpacken, man muss nur sagen, wo die richtigen Daten zu finden sind. Interessant ist es zum Beispiel auch, wenn man in obigem Beispiel für die Farbe ein Offset von 0 angibt, dann wird die Position als Farbe verwendet, was durchaus lustige (und schöne) Ergebnisse bringt.
Solche Vertices kann man nun in den VertexBuffer einspeisen. Auch das geht denkbar einfach:
Wer nun keine Indices verwenden möchte kann den Inhalt des Vertexbuffers einfach über DrawElements zeichnen lassen (mit entsprechendem Offset und Anzahl Vertices bzw Primitivetype).
Wer aber Indices verwenden möchte zum Zeichnen kann nun noch einen IndexBuffer definieren. Da ist nicht wahnsinnig viel zu sagen, ein Beispiel hier:
VertexBuffer bietet dann die Methode DrawIndexedElements welche einen IndexBuffer erwartet.
Alles zusammen sähe dann beispielsweise so aus:
Mit folgendem Ergebnis:
(Oder mit dem Offset der Farbe auf 0 gestellt:
)
Nun meine Frage an euch:
Habt ihr Vorschläge, spontane Ideen, Kommentare oder Meinungen zu dem gezeigten (oder auch anderem)? Wenn ja, bitte postet diese doch, denn ich merke, dass mir das Projekt sehr viel Spass macht und habe daher auch vor da noch einiges zu verwirklichen
Viele Grüsse und besten Dank schon jetzt
Muepe
Hier im Forum gab es in der letzten Zeit erfreulicherweise vermehrt Postings in meinem Lieblingsthema, der 3D-Programmierung. Ich selbst bin da hauptsätzlich in DirectX aktiv aber habe natürlich auch Erfahrung mit OpenGL. Da ich jemand bin, der sehr gerne Libraries für andere schreibt und das auch präferiert mit Unterstützung von .NET habe ich mir gedachte ich entwickle auch mal eine kleine Bibliothek um OpenGL in .NET verwenden zu können. Das Verwenden an sich war ja eine leichte Aufgabe (P-Invoke) und bisschen abtippen, daher habe ich mich entschlossen das ganze etwas auszuweiten.
So gliedert sich das ganze momentan eigentlich in 3 Level:
1. Einfach alle Funktionen importiert, die zu OpenGL gehören sowie dynamisches Laden diverser sehr oft verwendeter Extensions (sofern sie vorhanden sind).
2. Diverse Wrapperklassen, die es gerade für Einsteiger leichter machen, da viele Kontrollen vorhanden sind und so Fehler gleich erkannt werden können. Von den meisten Klassen gibt es verschiedene Versionen mit verschiedenen "Sicherheitsstufen". So verlässt sich ein UncheckedVertexBuffer völlig darauf, dass der User weiss, welches die richtigen Eingaben sind, ein VertexBuffer jedoch prüft alles (natürlich mit der entsprechenden Performanceverbrennung) noch nach.
3. Ein UserControl, das einem die Erstellung des Kontexts und andere nützliche Dinge in einfacher Weise zur Verfügung stellt.
So kann eigentlich dann jeder für sich bestimmen, bis zu welchem Level er gerne Unterstützung haben möchte.
Nun auch noch ein paar Spezifikationen, was denn bisher so alles vorhanden ist (ich bin erst seit 3 Tagen dran, ist daher noch nicht alle Welt

Texturen
- Die Klasse Texture2D kann Texturen laden aus Dateien, dem Speicher, einer Resource in der Exe oder allgemein einem Stream (Netzwerkstream, ...). Unterstützt werden dabei die Formate PNG, JPG, GIF, TIFF, EXIF und BMP. Für DDS (DirectDraw Surface) sind auch die gängigsten Umwandlungen bereits vorhanden (inklusive der komprimierten Formate).
- Die Klasse SpriteList bietet die Möglichkeit einfach 2D-Objekte zu cachen und dann in einem Batch zu zeichnen. Dabei werden Modi wie AlphaBlend und ColorBlend unterstützt. Ein Beispiel wäre folgendermassen:
C#:
texture = Texture2D.FromImageFile(@"C:\Users\Admin\Desktop\Beatle-Icon.png");
list = new SpriteList();
list.CaptureBatch(SpriteFlags.ColorBlend);
list.DrawTexture(Vector2.Zero, texture);
list.EndBatch();
Ein Aufruf der Form list.BatchDraw zeichnet nun all das, was zwischen CaptureBatch und EndBatch aufgenommen wurde.
Primitive
Für das Zeichnen von Primitiven habe ich Teile der Konzepte von DirectX als Inspiration genommen, da ich diese eigentlich äusserst komfortabel finde.
Wesentlich für das Zeichnen sind grundsätzlich dabei 2 Klassen:
IndexBuffer
VertexBuffer
Der VertexBuffer hält Positionsdaten, Farbdaten, Texturkoordinaten und Normalen. Da es jedoch mühsam (und teilweise auch einfach unpassend) ist diese immer alle anzugeben ist das natürlich auch nicht nötig. Es wird dabei ein Konzept ähnlich dem FVF in DirectX verwendet. Man definiert structs, welche durch Attribute angeben, welche Daten wo und wie vorhanden sind. Beispielsweise folgende struct definiert einen Vertex der Position und Farbe hat:
C#:
[StructLayout(LayoutKind.Sequential)]
[VertexElementPosition(ElementType.Vector3, 0)]
[VertexElementColor(ElementType.Vector3, 12)]
public struct VertexPositionColor
{
public float X, Y, Z;
public float R, G, B;
public VertexPositionColor(float x, float y, float z, GLColor color)
{
X = x;
Y = y;
Z = z;
R = color.R / 255.0f;
G = color.G / 255.0f;
B = color.B / 255.0f;
}
}
Durch die Attribute kann man angeben, um wie viele Komponenten es sich handelt und wie das Offset vom Anfang der struct zum ersten Element dieser Kategorie ist. Dadurch kann man theoretisch auch unzählige andere Dinge reinpacken, man muss nur sagen, wo die richtigen Daten zu finden sind. Interessant ist es zum Beispiel auch, wenn man in obigem Beispiel für die Farbe ein Offset von 0 angibt, dann wird die Position als Farbe verwendet, was durchaus lustige (und schöne) Ergebnisse bringt.
Solche Vertices kann man nun in den VertexBuffer einspeisen. Auch das geht denkbar einfach:
C#:
buffer = new VertexBuffer();
VertexPositionColor[] vertices = new VertexPositionColor[]
{
new VertexPositionColor(-1, 1, 0, Color.Green),
new VertexPositionColor(-1, -1, 0, Color.Red),
new VertexPositionColor(1, -1, 0, Color.Blue),
new VertexPositionColor(1, 1, 0, Color.Chartreuse),
};
buffer.SetData(vertices);
Wer nun keine Indices verwenden möchte kann den Inhalt des Vertexbuffers einfach über DrawElements zeichnen lassen (mit entsprechendem Offset und Anzahl Vertices bzw Primitivetype).
Wer aber Indices verwenden möchte zum Zeichnen kann nun noch einen IndexBuffer definieren. Da ist nicht wahnsinnig viel zu sagen, ein Beispiel hier:
C#:
indexBuffer = new IndexBuffer();
byte[] indices = new byte[6]
{
0, 1, 2,
0, 2, 3
};
indexBuffer.SetIndices(indices);
VertexBuffer bietet dann die Methode DrawIndexedElements welche einen IndexBuffer erwartet.
Alles zusammen sähe dann beispielsweise so aus:
C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenSL.GL.Wrappers.Drawing;
using OpenSL.GL.Wrappers.Textures;
using OpenSL.GL.Wrappers.Objects;
using OpenSL.GL.Wrappers;
namespace TestApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
glControl1.RenderMode = OpenSL.UserControls.RenderMode.Timer;
glControl1.OnRender += new Action(glControl1_OnRender);
}
Texture2D texture;
VertexBuffer buffer;
IndexBuffer indexBuffer;
SpriteList list;
void glControl1_OnRender()
{
buffer.DrawIndexedElements(indexBuffer, PrimitiveType.TriangleList);
list.BatchDraw();
}
private void Form1_Shown(object sender, EventArgs e)
{
texture = Texture2D.FromImageFile(@"C:\Users\Admin\Desktop\Beatle-Icon.png");
list = new SpriteList();
list.CaptureBatch(SpriteFlags.ColorBlend);
list.DrawTexture(Vector2.Zero, texture);
list.EndBatch();
buffer = new VertexBuffer();
VertexPositionColor[] vertices = new VertexPositionColor[]
{
new VertexPositionColor(-1, 1, 0, Color.Green),
new VertexPositionColor(-1, -1, 0, Color.Red),
new VertexPositionColor(1, -1, 0, Color.Blue),
new VertexPositionColor(1, 1, 0, Color.Chartreuse),
};
indexBuffer = new IndexBuffer();
byte[] indices = new byte[6]
{
0, 1, 2,
0, 2, 3
};
indexBuffer.SetIndices(indices);
buffer.SetData(vertices);
}
}
}
Mit folgendem Ergebnis:

(Oder mit dem Offset der Farbe auf 0 gestellt:

Nun meine Frage an euch:
Habt ihr Vorschläge, spontane Ideen, Kommentare oder Meinungen zu dem gezeigten (oder auch anderem)? Wenn ja, bitte postet diese doch, denn ich merke, dass mir das Projekt sehr viel Spass macht und habe daher auch vor da noch einiges zu verwirklichen

Viele Grüsse und besten Dank schon jetzt
Muepe