Oder soll ich mal schnell nebenbei DayZ 2 entwickeln?
Fertigstellung irgendwann 2060 wenn ich so abgurke wie Bohemia -na dann mal los.
Erstmal juckt allen Grafik, ich weiß nicht wieso. Es ist eine Disziplin von vielen und wird von vielen Devs und Spielern fast als das einzige Kriterium gesehen.
Neuerdings habe ich bei Steam Sims kostenlos testen können. Der erste Gamebreaking Glitch war nach unter einer Stunde Spiel bereits entdeckt.
Selbst Spielstand war kaputt Grafik ist nicht alles.
Whatever. Hauptsache das Spiel sieht gut dabei aus.
Erster wichtiger Punkt: Materialworkflow und "physical based rendering" kurz PBR.
Ja da kommt RTX wunderbar zur Geltung! Es geht hierbei um nichts anderes, als das der Bildaufbau von jedem Frame über sowas wie Photonen geschieht, die dann realistisch an der Oberfläche dann entweder geschluckt oder reflektiert werden. Auch ist es so, dass ein Objekt immer von seiner eigenen Umgebung beleuchtet wird. Konventionelle Materialien und Renderings kommen an die Grenze
Hier ist mal ein PBR Workflow, in OpenGl realisiert:
Die Reflektionen, die das Objekt abbildet entspricht der Umgebung. an der oberen Seite der Kassette wird die Reflektion blau wirken, weil der Himmel reflektiert wird. An der unteren Seite eher rötlich weil der Boden relektiert wird.
Es sind gar keine Lichtquellen verbaut. Es gibt also noch gar kein Licht und Schattensystem, dennoch sind die Materialen amtlich von der Umgebung beeinflusst.
Und wer sich so richtig interessiert, dieser OpenGl Shader sorgt für den Materialeffekt auf der Kassette:
#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#endif
#define PI 3.1415926
#define PI2 6.2831853
uniform sampler2D texture0; // diffuse
/*
albedo = r
albedo = g
albedo = b
metallic = a
*/
uniform sampler2D texture1; // normal
/*
normal = r
normal = g
ao = b
roughness = a
*/
uniform sampler2D texture2; // reflection
// uniform sampler2D texture3; // lightmap
uniform sampler2D texture3; // specular
varying vec2 uv0Varying;
varying vec3 normalVarying;
varying vec3 binormalVarying;
varying vec3 tangentVarying;
varying vec3 posVarying;
uniform vec3 agk_CameraPos;
uniform float gamma;
varying mediump vec3 lightVarying;
mediump vec3 GetPSLighting( mediump vec3 normal, highp vec3 pos );
mediump vec3 ApplyFog( mediump vec3 color, highp vec3 pointPos );
#define expo vec2(1.04, 82.0)
#define LOG(a,b) (log((b)) / log((a)) )
vec3 unpack(vec4 rgbe) {
float fExp = rgbe.a * 256.0 - expo.y;
float fScale = pow(expo.x, fExp);
vec3 erg = rgbe.rgb*fScale;
return erg;
}
vec3 fresnel(vec3 sc, float roughness, vec3 n, vec3 l) {
float gloss = 1.0-roughness;
return sc + (max(vec3(gloss,gloss,gloss), sc) - sc) * pow(1.0 - clamp(dot(l, n),0.0,1.0), 5.0);
}
vec3 ibl_specDir ( vec3 N , vec3 R , float roughness ) {
float gloss = 1.0-roughness;
float lerpFactor = clamp(gloss * (sqrt(gloss) + roughness) - 0.41, 0.0, 1.0);
return normalize( mix(N , R , lerpFactor ));
}
vec2 vec2lat(vec3 vc) {
vec2 rt = vec2(0,0);
float theta = acos(vc.y);
float phi = atan(-vc.x, -vc.z);
rt = vec2((PI + phi) / PI2, theta / PI);
rt.y = rt.y*0.99+0.01;
rt.x = 0.75-rt.x;
rt.x += step(rt.x, 0.0);
return rt;
}
vec3 tonemapACES( vec3 x ) {
float a = 2.51;
float b = 0.03;
float c = 2.43;
float d = 0.59;
float e = 0.14;
x *= 0.6;
vec3 xx = clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
return pow(xx, vec3(0.454545));
}
void main() {
vec3 norm = normalize(normalVarying);
vec3 nb = normalize(binormalVarying);
vec3 nt = normalize(tangentVarying);
vec3 V = normalize(agk_CameraPos-posVarying);
mediump vec3 color = texture2D(texture0, uv0Varying).rgb;
color = ApplyFog( color, posVarying );
vec4 cl = vec4(color,texture2D(texture0, uv0Varying).a); // albedo
cl.rgb = pow(cl.rgb, vec3(2.2)); // to linear space
vec4 nr = texture2D(texture1, uv0Varying).rgba; // normal + AO + roughness
float roughness = nr.a;
float bumpiness = 2.0; // normalmapping
nr.rg -= vec2(0.5);
vec2 bump = nr.rg*bumpiness;
vec3 N = normalize(norm + bump.r * nt - bump.g * nb);
mediump vec3 light = lightVarying + GetPSLighting( norm, posVarying );
float specular = texture2D(texture3, uv0Varying).r;
float metallic = texture2D(texture0, uv0Varying).a;
vec3 specCol = mix(texture2D(texture3, uv0Varying).rgb*0.5, cl.rgb, metallic ); // calculate correct f0 reflection color based on metallic channel
cl.rgb = mix(cl.rgb, vec3(0.01), -cl.a);
// metals have no diffuse
// unpack( texture2D(texture3, uv0Varying, -8.0).rgba )
cl.rgb *= vec3(0.2) * nr.b; // get diffuse lighting from probe and attentuate it with the AO value.
// fetch reflection
vec3 rview = reflect(-V, N); // reflect view ray
rview = ibl_specDir ( N , rview , roughness ); // bend the reflection ray to account for probes being in the center of the object
// instead of on the surface, also amplify the bending on rough surfaces to simulate microfaceting
vec2 rt2 = vec2lat(rview); // convert vec to texture coords
float miplev = clamp( pow(roughness, 1.4), 0.0, 1.0) * 7.0; // calculate mip levels from roughness
float mipfrac = fract(miplev);
miplev = floor(miplev);
rt2.y = rt2.y * 0.125 + miplev * 0.125;
vec3 refl = unpack( texture2D(texture2, rt2, -8.0).rgba ) * nr.b; // get reflections
rt2.y += 0.125;
vec3 refl2 = unpack( texture2D(texture2, rt2, -8.0).rgba ) * nr.b;
refl = mix(refl, refl2, mipfrac); // mix for final value
specCol = fresnel(specCol, roughness, N, V) * refl; // Fresnel
gl_FragColor = vec4(tonemapACES((cl.rgb*light+specCol)*gamma), 1.0);
}
Alles anzeigen
Keine Sorge, das ist Low Level Code, der darf einem die Haare zu Kopfe stehen lassen - So mag das die Grafikkarte^^
Ja hier ist State of the Art GPU Physik verbaut^^ Dieser Code wird in einem Pixelshader für jeden Pixel einmal ausgeführt.
Bei einer Texturgröße von 2048x2048 Pixel wird dieser Code 4194304 mal ausgeführt, pro Frame, pro Objekt.
stellt dabei den RGBA Farbwert eines einzigen Pixels da, das ist auch die einzige notwendige Ausgabe aus einem solchen Shader.
Dieser Wert wird jeweils als Float weitergereicht!
Ein Varying Eingangswert, zum Beispiel:
Stellt dabei jeweils die Koordinate für den Pixel entsprechend einen Wert als Eingang, der variiert.
Der einfachste Shader Code sieht im übrigen so aus:
Jeder Pixel wird als absolut weiß ausgegeben, unabhängig von Position oder sonstigem.
PS: Ein Shader ist ein Code, der an die Grafikkarte geschickt wird und auf Shaderkernen ausgeführt wird. Jeder Shaderkern ist eine eigene CPU mit kleinem instruktionsset. Shader müssen dabei maximalst optimiert sein, damit der Shader performant läuft. Es werden meist tausende Shader gleichzeitig berechnet, mit jeweils millionen Berechnungen.
Wir nutzen heutzutage Grafikkarten dekadent zum Darstellen von Unterhaltung, die in den 90er Jahren noch als Supercomputer galten, also sollten wir schon mal das Beste da raus holen müssen.
Der Shader oben ist nicht absolut optimiert, schon gar nicht auf Durchsichtigkeit von Materialien, läuft aber schon performant und macht nahezu alles.
Solch ein Shader muss für die Zukunft nur minimal angepasst werden, wenn sich die Art und Weiße der Grafikkartenansteuerung ändert. Wenn die Berechnungen stimmen, ist alles nur noch eine Frage von der Auflösung der Materialien. Physik stimmt!