Shader in Java schreiben - Tools?

Die fehlende IDE-Bindung zwischen Shadern und CPU-seitigen Programmen nervt mich seit Beginn an.
Weswegen ich angefangen habe einen Parser zu schreiben der Java-Programme zu OGL Shader kompilieren kann.

Bisher funktioniert das auf meine eigenen Anwendungsfälle ganz gut.
Bis der Parser die Vollreife erlangt um jeden Use-Case von Shadern abzudecken benötigt das Projekt aber noch eine Menge Arbeit und Zeit.

Deswegen ist meine Frage ob ich mir da nicht unnötige Arbeit mache und statt Shader in einem Textprogramm zu tippen es bessere fertige Alternativen gibt?

Alternativen, die keine Engines oder Rendering Libraries sind?

Alle :smiley:
Welche Rendering Libraries gibt es denn für Java die einem die Shader-Bindung erleichtern?

Mir ist nicht ganz klar, was der Funktionsumfang sein soll. Das ist ja das schwierige: Wie soll etwas aussehen, was die gleichen Möglichkeiten bietet, wie ein handgedengelter Shader, und nicht drauf rausläuft, dass man genau den eben schreibt und lädt? Jede Abstraktion (aka Vereinfachung) versteckt irgendwas, was irgendjemand vielleicht gerade braucht (oder zumindest haben will). Ich hatte ja mal Rendering - eine Java/OpenGL rendering library gebastelt, aber etwas professionelles wie JME sollte doch die nötige Nachhaltigkeit versprechen…?!

Ich dachte mehr so an automatische Programm<->Shader Kopplung.
Vorgeschriebene Pipelines sind zwar ganz nett, nehmen aber die Möglichkeit Shader selber zu schreiben.

Der Punkt ist doch der, egal wie der Shader aussieht, der Compiler bzw. das Programm auf CPU Seite weiß davon nichts.
Die Kopplung mit OGL gleicht eher der Datenübertragung per UDP statt SIMON.

Genau diese Einschränkungen waren für mich damals der Grund, diese Rendering-Library zu basteln!

Der Shader kann frei programmiert werden. Jeder kann beliebige Uniforms und Attributes definieren und verwenden. Das ist faktisch die Schnittstelle. Bei Code wie

attribute vec3 positions;
attribute vec3 normals;
uniform float intensity;

void main() { .... }

muss man in GL grundsätzlich (und hier im Pseudocode, um zu verdeutlichen, dass das sprachunabhängig ist) sowas machen wie

setAttribute(getLocation(shader, "positions"), positionsBufferId);
setAttribute(getLocation(shader, "normals"), normalsBufferId);
setUniform(getLocation(shader, "intesity"), intensity);

Und das ist ein Krampf. Und das Problem ist: Es funktioniert nicht. Mist, woran liegt das jetzt? Naja, ganz einfach: Die Uniform heißt "intensity", und nicht "intesity" :wink:

Das Problem ist ja gerade, dass zwischen dem Shader-Code und dem Host-Code keine Verbindung besteht. Die Information über die Attributes und Uniforms, die im Shader vorkommen, ist auf der Host-Seite nicht vorhanden. Die Einzige (theoretische!) Möglichkeit, dort “programmatisch” ranzukommen, wäre, den Shadercode zu parsen, und im AST dann die UniformVariableDeclaration-Objekte zu untersuchen, um rauszufinden, wie die Variablen heißen.

Die idealistische Vorstellung, einen Shader mit sowas wie

float positions[] = ...;
float normals[] = ...;
float intensity = 41.999f;
callShader(shader, positions, normals, intensity);

aufrufen zu können, scheitert gerade an dieser fehlenden Verbindung, bzw. daran, dass das schon von der darunter liegenden Schicht (also OpenGL) nicht in dieser Form angeboten wird.

Aber selbst wenn man das alles wüßte, dann wüßte man nichts über die Semantik der Shader-Inputs. Die Verdrahtung wird immer von demjenigen gemacht werden müssen, der weiß, welchen Shader er lädt, welche Uniforms+Attributes der Shader hat, und mit welchen Daten die gefüttert werden müssen.

(Kleiner Abstecher: Die Schwierigkeiten, die damit verbunden sind, wurden schon an anderer Stelle deutlich. Das ganze Konzept der technique-Objekte in glTF ist ein Versuch, dieses Problem zu lösen. Eigentlich war das “ganz gut”, im Rahmen dessen, was überhaupt möglich ist. Leider wird das ganze mit glTF 2.0 zu einer Extension - ein Tribut an Vulkan, DirectX und andere Graphics-APIs…)


<selfPromotion>

Die Möglichkeit, diese Verdrahtung flexibel zu machen, war die Intention hinter der connect-Methode die ich in der Rendering-Library gebastelt hatte. Die bekommt die Information über den Parameter (d.h. den Shaderparameter), und das Attribute (d.h. die Daten, die für diesen Parameter bestimmt sind). Man kann da entweder defaults verwenden,

builder.connect(Parameters.VERTEX_POSITION, Attributes.VERTICES); 

oder was spezielles, eigenes. Wenn man also einen Shader hat, der ein Attribute vec3 mySpecificStuff erwartet, dann kann man die Daten für mySpecificStuff in ein GraphicsObject legen, und dann eben sagen

builder.connect( 
    Parameters.create("mySpecificStuff", ParameterType.TUPLE3F)
    Attributes.create("mySpecificStuff", DataBufferType.FLOAT, 3));

womit dann in Zukunft bei jedem Programmaufruf die Attribute-Location-Jongliererei intern übernommen und die Daten für den eigentlichen Rendering-Call vorbereitet werden.

Aber das alles war ziemlich “naiv”, und ich bin nicht auf dem neuesten Stand von allen Details - UBOs und layout-specifier in Shadern … und … ausführlich “getestet” ist das auch nicht, d.h. es gibt sicher vieles, was damit nur unzureichend abgebildet werden kann.

</selfPromotion>

Aus deinem Text geht eindeutig hervor wir denken auf der gleichen Wellenlänge.
Ich schaue mir deine Library mal an. So wie ich das verstehe geht deine Library den Weg GLSL->Java.
Mein Ansatz ging Java->GLSL um auch Vererbung, Interfaces etc. Nutzen zu können.

Weiß aber genau was du meinst, es gibt viele Möglichkeiten in OGL die bedacht werden müssen, gerade wenn du UBOs ansprichst.
Programming Artists oder wie die Berufssparte heißt, die mehr machen wie
gl_Position = matrix * vertexCoord;
werden da wohl kaum glücklich mit ihrem herumgehacke und Performance Optimizations.

PS: Gibt es keine Java Tags mehr hier im Forum? Oder gibt es irgendwo einen erweiterten Editor?