Jump to content
  • Advertisement

_RAW_

Member
  • Content Count

    4
  • Joined

  • Last visited

Community Reputation

136 Neutral

About _RAW_

  • Rank
    Newbie
  1. i dont think i just posted "random stuff". i tried to provide as much information as i could and asked some questions, which i hoped someone could answer given the code and screenshots i provided.   "Have you tried manually sending mip map level" see my edit2.   "Your specular textures have a strange edge effect" thats why i posted all my shader code....
  2. Hi everyone,   i am currently implementing image based lighting according to the ue4 document   This is what i have got so far.   Final Image: [attachment=26120:final.PNG]   Albedo: [attachment=26105:albedo.PNG]   Roughness: [attachment=26111:roughness.PNG]   Metallic: [attachment=26110:metallic.PNG]   Specularcolor (Interpolated with the metallic value): [attachment=26117:specular-color.PNG]   env brdf texture: [attachment=26108:env-brdf.PNG]   ibl specular: [attachment=26118:specular-IBL.PNG]   ibl sample color (without multiplying with env brdf): [attachment=26119:specular-ibl-sample-color.PNG]   env brdf texture read with specularcolor: [attachment=26109:env-brdf-read-from-texture.PNG]   diffuse ibl: (as of now i am using the last mip from the specular ibl cube) [attachment=26107:diffuse-ibl.PNG]   Skybox miplevels 0 [attachment=26112:skybox-mip-0.PNG]   1 [attachment=26113:skybox-mip-1.PNG]   3 [attachment=26114:skybox-mip-3.PNG]   4 [attachment=26115:skybox-mip-4.PNG]   5 [attachment=26116:skybox-mip-5.PNG]   I am generating the specular skybox on the gpu. I take in the base cubemap and the current mip level i want to convole and save the results in another 6 2dtextures, from which i create a cubemap texture. The miplevels go down to 1x1 and starting from whatever the input texture size is. Here is the shader code for that (taken from this post) #version 130 uniform samplerCube cubeMap; uniform vec2 pixelsize; varying vec2 outUV; uniform int currentMip; uniform int maximumMips; uniform float cubeSize; /** Defines **/ #define M_PI 3.1415926535897932384626433832795 #define M_PI2 M_PI * 2 #define PI 3.14159265359 #define INVPI 0.31830988618 #define EPS 1e-5 float saturate (float x) { return clamp(x, 0.0, 1.0); } vec3 saturate (vec3 v) { return clamp(v, 0.0, 1.0); } float radicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); return float(bits) * 2.3283064365386963e-10; // / 0x100000000 } // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html vec2 Hammersley(uint i, uint N) { return vec2(float(i)/float(N), radicalInverse_VdC(i)); } vec3 ImportanceSampleGGX( vec2 E, float Roughness, vec3 N ) { float m = Roughness * Roughness; float Phi = 2 * PI * E.x; float CosTheta = sqrt( (1 - E.y) / ( 1 + (m*m - 1) * E.y ) ); float SinTheta = sqrt( 1 - CosTheta * CosTheta ); vec3 H; H.x = SinTheta * cos( Phi ); H.y = SinTheta * sin( Phi ); H.z = CosTheta; vec3 UpVector = abs(N.z) < 0.999 ? vec3(0,0,1) : vec3(1,0,0); vec3 TangentX = normalize( cross( UpVector, N ) ); vec3 TangentY = cross( N, TangentX ); // tangent to world space return TangentX * H.x + TangentY * H.y + N * H.z; } // Ignacio Castano via http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ vec3 fix_cube_lookup_for_lod(vec3 v, float cube_size, float lod) { float M = max(max(abs(v.x), abs(v.y)), abs(v.z)); float scale = 1 - exp2(lod) / cube_size; if (abs(v.x) != M) v.x *= scale; if (abs(v.y) != M) v.y *= scale; if (abs(v.z) != M) v.z *= scale; return v; } vec3 UvAndIndexToBoxCoord(vec2 uv, int face){ vec3 n = vec3(0, 0, 0); vec3 t = vec3(0, 0, 0); // posx (red) if (face == 0) { n = vec3(1, 0, 0); t = vec3(0, 1, 0); } // negx (cyan) else if (face == 1) { n = vec3(-1, 0, 0); t = vec3(0, 1, 0); } // posy (green) else if (face == 2) { n = vec3(0, -1, 0); t = vec3(0, 0, -1); } // negy (magenta) else if (face == 3) { n = vec3(0, 1, 0); t = vec3(0, 0, 1); } // posz (blue) else if (face == 4) { n = vec3(0, 0, -1); t = vec3(0, 1, 0); } // negz (yellow) else { n = vec3(0, 0, 1); t = vec3(0, 1, 0); } vec3 x = cross(n, t); uv = uv * 2 - 1; n = n + t * uv.y + x * uv.x; n.y *= -1; n.z *= -1; return n; } void main(){ vec2 texel = gl_FragCoord.xy * pixelsize; float Roughness = float(currentMip) / float(maximumMips - 1); for(int f = 0; f < 6; f++){ vec3 V = UvAndIndexToBoxCoord(outUV, f); vec3 N = fix_cube_lookup_for_lod(V, cubeSize, currentMip); vec4 totalRadiance = vec4(0, 0, 0, 0); uint maxSamples = 1024u; for(uint i = 0u; i < maxSamples; i++){ vec2 Xi = Hammersley(i, maxSamples); vec3 H = ImportanceSampleGGX(Xi, Roughness, N); vec3 L = 2 * dot(N, H) * H - N; float nDotL = saturate(dot(L, N)); if (nDotL > 0){ vec4 pointRadiance = textureCube(cubeMap, L, 0); totalRadiance.rgb += pointRadiance.rgb * nDotL; totalRadiance.w += nDotL; } } gl_FragData[f] = vec4(totalRadiance.rgb / totalRadiance.w, 1); } }   To generate the ENV texture i simple render a fullscreen quad and save the results in a 2d texture. here is the code. (taken from here and the ue4 document) #version 130 uniform vec2 pixelsize; varying vec2 outUV; uniform int currentMip; uniform int maximumMips; uniform float cubeSize; /** Defines **/ #define M_PI 3.1415926535897932384626433832795 #define M_PI2 M_PI * 2 #define PI 3.14159265359 #define INVPI 0.31830988618 #define EPS 1e-5 float saturate (float x) { return clamp(x, 0.0, 1.0); } vec3 saturate (vec3 v) { return clamp(v, 0.0, 1.0); } float radicalInverse_VdC(uint bits) { bits = (bits << 16u) | (bits >> 16u); bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); return float(bits) * 2.3283064365386963e-10; // / 0x100000000 } // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html vec2 Hammersley(uint i, uint N) { return vec2(float(i)/float(N), radicalInverse_VdC(i)); } vec3 ImportanceSampleGGX( vec2 E, float Roughness, vec3 N ) { float m = Roughness * Roughness; float Phi = 2 * PI * E.x; float CosTheta = sqrt( (1 - E.y) / ( 1 + (m*m - 1) * E.y ) ); float SinTheta = sqrt( 1 - CosTheta * CosTheta ); vec3 H; H.x = SinTheta * cos( Phi ); H.y = SinTheta * sin( Phi ); H.z = CosTheta; vec3 UpVector = abs(N.z) < 0.999 ? vec3(0,0,1) : vec3(1,0,0); vec3 TangentX = normalize( cross( UpVector, N ) ); vec3 TangentY = cross( N, TangentX ); // tangent to world space return TangentX * H.x + TangentY * H.y + N * H.z; } // http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html float GGX(float NdotV, float a){ float k = a / 2; return NdotV / (NdotV * (1.0f - k) + k); } // http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html float G_Smith(float a, float nDotV, float nDotL){ return GGX(nDotL, a * a) * GGX(nDotV, a * a); } vec2 IntegrateBRDF(float Roughness, float NoV ){ vec3 V; V.x = sqrt( 1.0f - NoV * NoV ); // sin V.y = 0; V.z = NoV; // cos float A = 0; float B = 0; uint NumSamples = 1024u; for( uint i = 0u; i < NumSamples; i++){ vec2 Xi = Hammersley(i, NumSamples); vec3 H = ImportanceSampleGGX(Xi, Roughness, vec3(0, 0, 1)); vec3 L = 2 * dot( V, H ) * H - V; float NoL = saturate(L.z); float NoH = saturate(H.z); float VoH = saturate(dot(V, H)); if( NoL > 0 ){ float G = G_Smith( Roughness, NoV, NoL ); float G_Vis = G * VoH / (NoH * NoV); float Fc = pow( 1 - VoH, 5 ); A += (1 - Fc) * G_Vis; B += Fc * G_Vis; } } return vec2( A, B ) / NumSamples; } void main(){ vec2 texel = gl_FragCoord.xy * pixelsize; float nDotV = outUV.x; float Roughness = outUV.y; vec2 integral = IntegrateBRDF(Roughness, nDotV); gl_FragData[0] = vec4(integral.r, integral.g, 0, 1); }   this is how i put everything together to render the "ibl specular"-texture: #version 130 uniform vec2 pixelsize; uniform sampler2D positionTex; // Vertexpositions in ViewSpace uniform sampler2D normalTex; // Normals in ViewSpace uniform sampler2D roughnessTex; // Roughness uniform sampler2D specularTex; // Specularcolor & Specularintensity (Unused) // Inverse Viewmatrix, to transform Positions & Normal back into Worldspace uniform mat4 inverseViewMatrix; uniform sampler2D envBRDFTexture; uniform samplerCube skyboxCube; uniform int maxMipCount; uniform vec3 cameraPosition; /** Defines **/ #define M_PI 3.1415926535897932384626433832795 #define M_PI2 M_PI * 2 #define PI 3.14159265359 #define INVPI 0.31830988618 #define EPS 1e-5 float saturate (float x) { return clamp(x, 0.0, 1.0); } vec3 saturate (vec3 v) { return clamp(v, 0.0, 1.0); } // taken from ue4 float ComputeCubemapMipFromRoughness( float Roughness, float MipCount ){ // Level starting from 1x1 mip float Level = 3 - 1.15 * log2( Roughness ); return MipCount - 1 - Level; } // taken from ue4 vec3 EnvBRDF( vec3 SpecularColor, float Roughness, float NoV ){ vec2 AB = texture2D(envBRDFTexture, vec2(NoV, Roughness), 0).rg; vec3 GF = SpecularColor * AB.x + saturate( 50.0 * SpecularColor.g ) * AB.y; //vec3 GF = SpecularColor * AB.x + AB.y; return GF; } void main(){ vec2 texel = gl_FragCoord.xy * pixelsize; vec3 worldSpaceNormal = normalize(mat3(inverseViewMatrix) * texture2D(normalTex, texel).rgb); vec3 worldSpacePosition = vec3(inverseViewMatrix * texture2D(positionTex, texel)); vec3 incidentVector = normalize(worldSpacePosition - cameraPosition); vec3 reflectedVector = normalize(reflect(incidentVector, worldSpaceNormal)); float Roughness = texture2D(roughnessTex, texel).r; vec3 specularColor = texture2D(specularTex, texel).rgb; // a hack to skip the skybox if(worldSpaceNormal.x == 0 && worldSpaceNormal.y == 0 && worldSpaceNormal.z == 0){ gl_FragData[0] = vec4(0); // Diffuse IBL gl_FragData[1] = vec4(0); // Specular IBL }else{ // use the last mip as diffuselight gl_FragData[0] = vec4(textureCube(skyboxCube, worldSpaceNormal, float(maxMipCount)).rgb, 1); vec3 R = reflectedVector; float AbsoluteSpecularMip = ComputeCubemapMipFromRoughness(Roughness, float(maxMipCount )); vec3 SampleColor = textureCube(skyboxCube, R, AbsoluteSpecularMip).rgb; float NoV = saturate(dot(worldSpaceNormal, -incidentVector)); vec3 result = SampleColor * EnvBRDF(specularColor, Roughness, NoV); //http://marmosetco.tumblr.com/post/81245981087 float horizonOcclusion = 1.3; float horizon = saturate( 1 + horizonOcclusion * dot(R, worldSpaceNormal)); horizon *= horizon; gl_FragData[1] = vec4(horizon * result, 1); } }   the final image gets generated like this: #version 120 uniform sampler2D texture; // albedo uniform sampler2D lightpassDiffuse; // lightpass uniform sampler2D lightpassSpecular; uniform sampler2D ssaotex; uniform sampler2D iblDiffuse; uniform sampler2D iblSpecular; uniform vec2 pixelsize; uniform vec3 ambientLight; varying vec2 outUV; void main(){ vec2 texel = gl_FragCoord.xy * pixelsize; vec3 albedo = texture2D(texture, texel).rgb; vec3 diffuseLight = texture2D(lightpassDiffuse, texel).rgb; vec4 specularTexture = texture2D(lightpassSpecular, texel); vec3 specularLight = specularTexture.rgb; float ssao = texture2D(ssaotex, texel).r; vec3 iblDiffuseLight = texture2D(iblDiffuse, texel).rgb; vec3 iblSpecularLight = texture2D(iblSpecular, texel).rgb; vec3 finalColor = ssao * (albedo * (iblDiffuseLight + diffuseLight) + specularLight + iblSpecularLight); gl_FragData[0] = vec4(finalColor, 1); } my question is: 1. what am i doing wrong? because the final image looks like crap 2. am i creating the cubemap correctly? 3. why are there white spots on the specular- / diffuse-ibl texture? (they do not only appear on normalmapped materials) 4. also there is a huge gap between the transition of roughness = 0, to roughness = 0.03 for example. why is that? (see ibl sample color-texture) am i retrieving the miplevel from the roughness correctly?   ps: 1. i have not done any conversion to linearspace or gammspace. i want to fix this before i move on 2. as of now the input image for the cubemap is not HDR.   edit: i now use hdr input textures.   here are more screenshots to illustrate 3.) diffuse ibl [attachment=26127:ibl-diffuse-normalmapped.PNG] specular ibl [attachment=26128:ibl-specular-normalmapped.PNG]   diffuse ibl [attachment=26126:diffuse-ibl-error.PNG] specular ibl [attachment=26129:specular-ibl-error.PNG]   edit2: after capping the miplevels with glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, maximumMipLevel - 1); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LOD, maximumMipLevel - 1); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, maximumMipLevel - 1); the artefacts disappear from the cubemap. the diffuse looks nice now, but i obviously can't access the mips for the specular. any idea why this artefacts occur and how to fix that? if i dont cap the miplevels and move closer to an object, the diffuse ibl starts gets all weired.   [attachment=26130:artefact1.PNG] [attachment=26131:artefact2.PNG]  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!