Ich baue ja gerade den Dom neu, der soll was hermachen, also will ich ein paar schicke bling-bling Effekte haben. Das Dach im Original ist aus Metall, dieses typisch grün-blaue Kufperdach. In echt sieht es eher matt aus, aber es geht mir ja um schicke Optik und nicht um Realismus, also muss es funkeln. Das Dach ist groß und immer sichtbar, also idealer Kandidat für ein besonderes Material.
Nun gut, hier der aktuelle Stand:
Und als Video: Aktuell benutze ich als Standard-Modell das "Frostbite-BRDF"-Modell was im Grunde wie Phong, nur in netter ist: Man hat für eine Lichtrichtung diffuse und spekulare Komponenten, es ist energieerhaltend und man hat Roughness und Metalicity als Parameter.
Komplexe Reflexionen gehen ja Richtung Environment-Mapping, also hab ich damit angefangen.
Frage 1: Benutzt man noch Cube-Maps? Die sind nervig, weil ich sie intern anders anlegen muss, als herkömmliche Texturen, ich habe auch 6 statt 1 Datei, brauche ein konsistentes Namensschema, und all so Kram. Die Alternative wäre Longitude/Latitude-Projektion (oder wie auch immer man das nennt), also das, was man z.B. bei den Polyhaven HDRs Standardmäßig bekommt. Ich kann aus einem 3D Richtungsvektor recht unproblematisch die Texturkoordinaten berechnen, nicht so effizient wie beim Cube-Mapping, aber vermutlich spielt das keine Rolle. Wegen der Pole ist wohl auch die Pixeldichte weniger effizient, aber dafür ist die Handhabung so super bequem.
Das Problem ist nun, dass man die BRDF ja pro Lichtrichtung auswerten muss, also in der Regel einmal für die Sonne. Physikalisch korrekt wäre es nun, die BRDF für jeden Pixel der Environment-Map auszuwerten und alles zu addieren, was natürlich viel zu teuer ist. Es gibt gewiss sehr clevere Methoden das effizient anzunähern, aber naja, ich will nicht viel mehr als 1-2 Tage hierauf verwenden. Also wird es auf irgendeinen unphysikalischen Hack hinauslaufen, muss ja nur gut aussehen. Hier also der Code:
Code: Alles auswählen
vec3 desaturate(vec3 color, float factor)
{
vec3 lum = vec3(0.299, 0.587, 0.114);
vec3 gray = vec3(dot(lum, color));
return mix(color, gray, factor);
}
.....
(1) vec3 custom_normal = mix(normalize(mesh_normal), normal_map, 0.4);
(2) vec3 reflected = reflect(view_direction_world, custom_normal );
(3) vec2 ref_uv = direction_to_long_lat(reflected);
(4) vec3 reflection_color = desaturate(texture(environment_map, ref_uv).rgb, 0.9);
(5) color_output *= vec4(0.85) + vec4(pow(reflection_color, vec3(2.0)), 0)*0.5;
- Das Modell hat eine Normalmap. Verwende ich diese direkt, ist die Reflexion des Himmels sehr hochfrequent, man sieht viel Gegrissel aber keine Wolkenformen mehr. Ich wollte aber gerne, dass man auf einer großen, geraden Dachfläche an verschiedenen Stellen verschiedene Strukturen sieht (sieht man im Video leicht), also interpoliere ich zwischen der Mesh-Normalen und der Normal-Map (Zeile 1). Effektiv verringert sich damit der Einfluss der Normalmap und ich sehe größere Details.
- Dann berechne ich ganz normal die Reflexion und die Texturkoordinate (Zeile 2-3).
- Die Colormap vom Dach ist grünlich, reflektiere ich blauen Himmel ergibt sich eine starke Farbverschiebung. Ich hätte jetzt entsprechend die Colormap anpassen können, aber natürlich hängt das auch von der verwendeten Environment-Map ab, und physikalisch korrekt ist es eh schon nicht mehr. Stattdessen hab ich die Reflexionsfarbe desaturiert (Zeile 4), somit ändert sich die Helligkeit, aber nicht die Farbe. Aktuell steht der Faktor auf 0.9, d.h. fast komplett Graustufen. Damit ist der Farbstich Geschichte.
- Erst hab ich die Reflexion addiert (Intuition: Ist ja zusätzliches Licht). Das wurde zu hell. Ich kann die ursprüngliche Farbe vorher abdunkeln, um die Helligkeit auszugleichen. In beiden Fällen addiere ich aber im Wesentlichen Grau, das ganze Dach sieht damit irgendwie entsättigt aus. Stattdessen Multipliziere ich die Farben jetzt (Zeile 5). Dadurch bleibt das Grün knallig und man hat einen angenehmen Kontrast. Physikalisch kann ich das aber nicht rechtfertigen :D
Frage 2: Was kann ich hier noch ändern, bzw. besser machen?
Ich denke, man könnte Bloom und HDR einbauen. Das würde aber die gesamte Szene betreffen und meine Pipeline ist aktuell nicht darauf ausgelegt. Ich könnte vermutlich auch eine Roughness-Map verwenden, allerdings sieht man den Dom halt meistens als ein Gebäude von vielen, das man so weit reinzoomt, dass man einzelne Schindeln gut erkennt, passiert selten, und es soll halt Hauptsächlich aus der Standardansicht gut aussehen. Mal sehen.
Zum Abschluss aber doch nochmal eine Detailansicht, in der man gut die einzelnen Wolken erkennt.