More PBR improvements. Fix skybox to be a proper skybox

This commit is contained in:
KillzXGaming 2019-05-16 16:01:22 -04:00
parent c061c9b052
commit 304b00fe49
27 changed files with 645 additions and 43 deletions

Binary file not shown.

View file

@ -67,6 +67,8 @@ namespace FirstPlugin
GL.GenBuffers(1, out vbo_position);
GL.GenBuffers(1, out ibo_elements);
TransformBones();
UpdateVertexData();
UpdateTextureMaps();
}
@ -82,6 +84,17 @@ namespace FirstPlugin
GL.DeleteBuffer(ibo_elements);
}
private void TransformBones()
{
foreach (var model in models)
{
foreach (var bone in model.Skeleton.bones)
{
bone.ModelMatrix = ModelTransform;
}
}
}
#region Rendering

View file

@ -492,11 +492,6 @@ namespace Switch_Toolbox.Library
ArrayCount = 1;
if (header.caps2 == (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES)
{
ArrayCount = 6;
}
int DX10HeaderSize = 0;
if (header.ddspf.fourCC == FOURCC_DX10)
{
@ -506,6 +501,11 @@ namespace Switch_Toolbox.Library
ReadDX10Header(reader);
}
if (header.caps2 == (uint)DDS.DDSCAPS2.CUBEMAP_ALLFACES)
{
ArrayCount = 6;
}
bool IsCompressed = false;
bool HasLuminance = false;
bool HasAlpha = false;
@ -678,6 +678,12 @@ namespace Switch_Toolbox.Library
case TEX_FORMAT.BC3_UNORM_SRGB:
pixelInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
break;
case TEX_FORMAT.BC6H_UF16:
pixelInternalFormat = PixelInternalFormat.CompressedRgbBptcUnsignedFloat;
break;
case TEX_FORMAT.BC6H_SF16:
pixelInternalFormat = PixelInternalFormat.CompressedRgbBptcUnsignedFloat;
break;
default:
throw new Exception("Unsupported format! " + dds.Format);
}
@ -693,8 +699,22 @@ namespace Switch_Toolbox.Library
}
else
{
texture.LoadImageData((int)dds.header.width, new SFGraphics.GLObjects.Textures.TextureFormats.TextureFormatUncompressed(PixelInternalFormat.Rgba,
OpenTK.Graphics.OpenGL.PixelFormat.Rgba, OpenTK.Graphics.OpenGL.PixelType.UnsignedByte),
PixelInternalFormat pixelInternalFormat = PixelInternalFormat.Rgba;
PixelType pixelType = PixelType.UnsignedByte;
PixelFormat pixelFormat = PixelFormat.Rgba;
switch (dds.Format)
{
case TEX_FORMAT.R32G32B32A32_FLOAT:
pixelInternalFormat = PixelInternalFormat.Rgba32f;
pixelType = PixelType.Float;
break;
default:
throw new Exception("Unsupported format! " + dds.Format);
}
texture.LoadImageData((int)dds.header.width, new SFGraphics.GLObjects.Textures.TextureFormats.TextureFormatUncompressed(pixelInternalFormat,
pixelFormat, pixelType),
cubemap[0].mipmaps[0],
cubemap[1].mipmaps[0],
cubemap[2].mipmaps[0],

View file

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK.Graphics.OpenGL;
namespace Switch_Toolbox.Library
{
//Class based on https://github.com/ScanMountGoat/SFGraphics/blob/2cba15420b40d42c4254583336dbc3ca6a0d28dc/Projects/SFGraphics/GLObjects/Textures/Texture.cs
//This makes managing textures easier
public class OpenGLTexture
{
public int TexID;
public int Width { get; protected set; }
public int Height { get; protected set; }
public TextureTarget TextureTarget { get; }
private TextureMinFilter minFilter;
public TextureMinFilter MinFilter
{
get { return minFilter; }
set
{
minFilter = value;
SetTexParameter(TextureParameterName.TextureMinFilter, (int)value);
}
}
private TextureMagFilter magFilter;
public TextureMagFilter MagFilter
{
get { return magFilter; }
set
{
magFilter = value;
SetTexParameter(TextureParameterName.TextureMagFilter, (int)value);
}
}
private TextureWrapMode textureWrapS;
public TextureWrapMode TextureWrapS
{
get { return textureWrapS; }
set
{
textureWrapS = value;
SetTexParameter(TextureParameterName.TextureWrapS, (int)value);
}
}
private TextureWrapMode textureWrapT;
public TextureWrapMode TextureWrapT
{
get { return textureWrapT; }
set
{
textureWrapT = value;
SetTexParameter(TextureParameterName.TextureWrapT, (int)value);
}
}
private TextureWrapMode textureWrapR;
public TextureWrapMode TextureWrapR
{
get { return textureWrapR; }
set
{
textureWrapR = value;
SetTexParameter(TextureParameterName.TextureWrapR, (int)value);
}
}
public void Bind()
{
GL.BindTexture(TextureTarget, TexID);
}
private void SetTexParameter(TextureParameterName param, int value)
{
Bind();
GL.TexParameter(TextureTarget, param, value);
}
}
}

View file

@ -37,6 +37,9 @@ namespace Switch_Toolbox.Library
public Quaternion rot = Quaternion.FromMatrix(Matrix3.Zero);
public Matrix4 Transform, invert;
//Used for shifting models with the bones in the shader
public Matrix4 ModelMatrix = Matrix4.Identity;
public Vector3 GetPosition()
{
return pos;

View file

@ -51,6 +51,7 @@ namespace Switch_Toolbox.Library
uniform mat4 bone;
uniform mat4 parent;
uniform mat4 rotation;
uniform mat4 ModelMatrix;
uniform int hasParent;
uniform float scale;
@ -63,7 +64,7 @@ namespace Switch_Toolbox.Library
else
position = bone * rotation * vec4((point.xyz - vec3(0, 1, 0)) * scale, 1);
}
gl_Position = mtxCam * mtxMdl * vec4(position.xyz, 1);
gl_Position = mtxCam * ModelMatrix * mtxMdl * vec4(position.xyz, 1);
}");
@ -236,6 +237,8 @@ namespace Switch_Toolbox.Library
solidColorShaderProgram.SetVector4("boneColor", ColorUtility.ToVector4(boneColor));
solidColorShaderProgram.SetFloat("scale", Runtime.bonePointSize);
solidColorShaderProgram.SetMatrix4x4("ModelMatrix", ref bn.ModelMatrix);
Matrix4 transform = bn.Transform;

View file

@ -43,6 +43,8 @@ namespace Switch_Toolbox.Library.Rendering
if (!Runtime.OpenTKInitialized || !Runtime.PBR.UseSkybox || pass == Pass.TRANSPARENT)
return;
GL.Disable(EnableCap.CullFace);
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Lequal);
@ -56,11 +58,12 @@ namespace Switch_Toolbox.Library.Rendering
// enable seamless cubemap sampling for lower mip levels in the pre-filter map.
GL.Enable(EnableCap.TextureCubeMapSeamless);
Matrix4 proj = Matrix4.Identity;
Matrix4 rot = Matrix4.CreateFromQuaternion(control.ModelMatrix.ExtractRotation());
Matrix4 proj = control.ProjectionMatrix;
// Matrix4 rot = Matrix4.CreateFromQuaternion(control.ModelMatrix.ExtractRotation());
Matrix4 rot = new Matrix4(new Matrix3(control.CameraMatrix));
GL.UniformMatrix4(defaultShaderProgram["projection"], false, ref proj);
GL.UniformMatrix4(defaultShaderProgram["rotView"], false, ref rot);
defaultShaderProgram.SetMatrix4x4("projection", ref proj);
defaultShaderProgram.SetMatrix4x4("rotView", ref rot);
if (Runtime.PBR.UseDiffuseSkyTexture)
{

View file

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GL_EditorFramework.Interfaces;
using GL_EditorFramework.GL_Core;
using OpenTK.Graphics.OpenGL;
using OpenTK;
namespace Switch_Toolbox.Library.Rendering
{
public class PBRMapGenerator
{
public int BrdfLUTMap = -1;
private ShaderProgram BrdfShader;
private int captureFBO = 1;
private int captureRBO = 1;
private bool IsBufferCreated()
{
return (captureFBO != -1 && captureRBO != -1);
}
private void GenerateFrameBuffer()
{
// setup framebuffer
GL.GenFramebuffers(1, out captureFBO);
GL.GenFramebuffers(1, out captureRBO);
}
public void GeneratImageBasedLightingMap()
{
// enable seamless cubemap sampling for lower mip levels in the pre-filter map.
GL.Enable(EnableCap.TextureCubeMapSeamless);
if (!IsBufferCreated())
GenerateFrameBuffer();
}
public void GenerateBrdfMap()
{
if (!IsBufferCreated())
GenerateFrameBuffer();
GL.UseProgram(BrdfShader.program);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
RenderQuad();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
BrdfLUTMap = LoadBrdfLUTTexture();
GL.BindFramebuffer(FramebufferTarget.Framebuffer, captureFBO);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, captureRBO);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthComponent24, 512, 512);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, BrdfLUTMap, 0);
Matrix4 proj = Matrix4.Identity;
}
public static int LoadBrdfLUTTexture()
{
int texture;
GL.GenTextures(1, out texture);
GL.BindTexture(TextureTarget.Texture2D, texture);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rg32f, 512, 512, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rg, PixelType.Float, (IntPtr)0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
return texture;
}
private static void RenderQuad()
{
int quadVAO = 0;
int quadVBO;
if (quadVAO == 0)
{
float[] vertices = {
// positions // texture Coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
};
GL.GenVertexArrays(1, out quadVAO);
GL.GenBuffers(1, out quadVBO);
GL.BindVertexArray(quadVAO);
GL.BindBuffer(BufferTarget.ArrayBuffer, quadVBO);
GL.BufferData(BufferTarget.ArrayBuffer, 4 * vertices.Length, vertices, BufferUsageHint.StaticDraw);
GL.EnableVertexAttribArray(0);
GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 5 * sizeof(float), (IntPtr)0);
GL.EnableVertexAttribArray(1);
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 5 * sizeof(float), (IntPtr)(3 * sizeof(float)));
}
GL.BindVertexArray(quadVAO);
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
GL.BindVertexArray(0);
}
}
}

View file

@ -497,6 +497,7 @@
<Compile Include="Generics\GenericModel.cs" />
<Compile Include="Generics\GenericObject.cs" />
<Compile Include="Generics\GenericTexture.cs" />
<Compile Include="Generics\OpenGLTexture.cs" />
<Compile Include="Generics\RenderableTex.cs" />
<Compile Include="Generics\STBone.cs" />
<Compile Include="Generics\STGenericWrapper.cs" />
@ -622,6 +623,7 @@
<Compile Include="Rendering\DrawableSkybox.cs" />
<Compile Include="Rendering\DrawableFloor.cs" />
<Compile Include="Rendering\DrawableXyzLines.cs" />
<Compile Include="Rendering\PBRMapGenerator.cs" />
<Compile Include="Rendering\ProbeLighting.cs" />
<Compile Include="Rendering\RenderTools.cs" />
<Compile Include="Rendering\ScreenTriangle.cs" />

View file

@ -93,6 +93,8 @@
this.tabPage3 = new System.Windows.Forms.TabPage();
this.stLabel13 = new Switch_Toolbox.Library.Forms.STLabel();
this.botwGamePathTB = new Switch_Toolbox.Library.Forms.STTextBox();
this.stContextMenuStrip1 = new Switch_Toolbox.Library.Forms.STContextMenuStrip(this.components);
this.clearSettingToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.stLabel14 = new Switch_Toolbox.Library.Forms.STLabel();
this.tpGamePathTB = new Switch_Toolbox.Library.Forms.STTextBox();
this.stLabel12 = new Switch_Toolbox.Library.Forms.STLabel();
@ -105,8 +107,6 @@
this.chkDiffyseSkybox = new Switch_Toolbox.Library.Forms.STCheckBox();
this.stLabel16 = new Switch_Toolbox.Library.Forms.STLabel();
this.diffuseCubemapPathTB = new Switch_Toolbox.Library.Forms.STTextBox();
this.stContextMenuStrip1 = new Switch_Toolbox.Library.Forms.STContextMenuStrip(this.components);
this.clearSettingToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.chkUseSkyobx = new Switch_Toolbox.Library.Forms.STCheckBox();
this.stLabel15 = new Switch_Toolbox.Library.Forms.STLabel();
this.specularCubemapPathTB = new Switch_Toolbox.Library.Forms.STTextBox();
@ -130,8 +130,8 @@
((System.ComponentModel.ISupportInitialize)(this.bgGradientBottom)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.bgGradientTop)).BeginInit();
this.tabPage3.SuspendLayout();
this.tabPage4.SuspendLayout();
this.stContextMenuStrip1.SuspendLayout();
this.tabPage4.SuspendLayout();
this.SuspendLayout();
//
// contentContainer
@ -988,6 +988,20 @@
this.botwGamePathTB.TabIndex = 8;
this.botwGamePathTB.Click += new System.EventHandler(this.botwGamePathTB_Click);
//
// stContextMenuStrip1
//
this.stContextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.clearSettingToolStripMenuItem});
this.stContextMenuStrip1.Name = "stContextMenuStrip1";
this.stContextMenuStrip1.Size = new System.Drawing.Size(142, 26);
//
// clearSettingToolStripMenuItem
//
this.clearSettingToolStripMenuItem.Name = "clearSettingToolStripMenuItem";
this.clearSettingToolStripMenuItem.Size = new System.Drawing.Size(141, 22);
this.clearSettingToolStripMenuItem.Text = "Clear Setting";
this.clearSettingToolStripMenuItem.Click += new System.EventHandler(this.clearSettingToolStripMenuItem_Click);
//
// stLabel14
//
this.stLabel14.AutoSize = true;
@ -1098,34 +1112,20 @@
this.stLabel16.AutoSize = true;
this.stLabel16.Location = new System.Drawing.Point(16, 73);
this.stLabel16.Name = "stLabel16";
this.stLabel16.Size = new System.Drawing.Size(129, 13);
this.stLabel16.Size = new System.Drawing.Size(150, 13);
this.stLabel16.TabIndex = 4;
this.stLabel16.Text = "Custom Diffuse Cubemap:";
this.stLabel16.Text = "Diffuse Cubemap (Irradiance) :";
//
// diffuseCubemapPathTB
//
this.diffuseCubemapPathTB.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.diffuseCubemapPathTB.ContextMenuStrip = this.stContextMenuStrip1;
this.diffuseCubemapPathTB.Location = new System.Drawing.Point(160, 71);
this.diffuseCubemapPathTB.Location = new System.Drawing.Point(181, 73);
this.diffuseCubemapPathTB.Name = "diffuseCubemapPathTB";
this.diffuseCubemapPathTB.Size = new System.Drawing.Size(197, 20);
this.diffuseCubemapPathTB.TabIndex = 3;
this.diffuseCubemapPathTB.Click += new System.EventHandler(this.diffuseCubemapPathTBB_Click);
//
// stContextMenuStrip1
//
this.stContextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.clearSettingToolStripMenuItem});
this.stContextMenuStrip1.Name = "stContextMenuStrip1";
this.stContextMenuStrip1.Size = new System.Drawing.Size(142, 26);
//
// clearSettingToolStripMenuItem
//
this.clearSettingToolStripMenuItem.Name = "clearSettingToolStripMenuItem";
this.clearSettingToolStripMenuItem.Size = new System.Drawing.Size(141, 22);
this.clearSettingToolStripMenuItem.Text = "Clear Setting";
this.clearSettingToolStripMenuItem.Click += new System.EventHandler(this.clearSettingToolStripMenuItem_Click);
//
// chkUseSkyobx
//
this.chkUseSkyobx.AutoSize = true;
@ -1142,15 +1142,15 @@
this.stLabel15.AutoSize = true;
this.stLabel15.Location = new System.Drawing.Point(16, 47);
this.stLabel15.Name = "stLabel15";
this.stLabel15.Size = new System.Drawing.Size(138, 13);
this.stLabel15.Size = new System.Drawing.Size(159, 13);
this.stLabel15.TabIndex = 1;
this.stLabel15.Text = "Custom Specular Cubemap:";
this.stLabel15.Text = "Specular Cubemap {Radiance) :";
//
// specularCubemapPathTB
//
this.specularCubemapPathTB.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.specularCubemapPathTB.ContextMenuStrip = this.stContextMenuStrip1;
this.specularCubemapPathTB.Location = new System.Drawing.Point(160, 45);
this.specularCubemapPathTB.Location = new System.Drawing.Point(181, 45);
this.specularCubemapPathTB.Name = "specularCubemapPathTB";
this.specularCubemapPathTB.Size = new System.Drawing.Size(197, 20);
this.specularCubemapPathTB.TabIndex = 0;
@ -1192,9 +1192,9 @@
((System.ComponentModel.ISupportInitialize)(this.bgGradientTop)).EndInit();
this.tabPage3.ResumeLayout(false);
this.tabPage3.PerformLayout();
this.stContextMenuStrip1.ResumeLayout(false);
this.tabPage4.ResumeLayout(false);
this.tabPage4.PerformLayout();
this.stContextMenuStrip1.ResumeLayout(false);
this.ResumeLayout(false);
}

View file

@ -138,15 +138,15 @@ void main()
if (vBone.x != -1.0)
objPos = skin(vPosition, index);
vec4 position = mtxCam * mtxMdl * vec4(objPos.xyz, 1.0);
vec4 position = mtxCam * (mtxMdl * vec4(objPos.xyz, 1.0));
normal = vNormal;
viewNormal = mat3(sphereMatrix) * normal.xyz;
if(vBone.x != -1.0)
normal = normalize((skinNRM(vNormal.xyz, index)).xyz);
if (RigidSkinning == 1)
{
position = mtxCam * mtxMdl * (bones[index.x] * vec4(vPosition, 1.0));
@ -156,9 +156,10 @@ void main()
{
position = mtxCam * mtxMdl * (SingleBoneBindTransform * vec4(vPosition, 1.0));
normal = mat3(SingleBoneBindTransform) * vNormal.xyz * 1;
//normal = normalize(normal);
}
normal = normalize(mat3(mtxMdl) * normal.xyz);
gl_Position =position;
f_texcoord0 = vUV0;

View file

@ -286,11 +286,12 @@ void main()
vec3 V = normalize(I); // view
vec3 L = normalize(specLightDirection); // Light
vec3 H = normalize(specLightDirection + I); // half angle
vec3 R = reflect(I, N); // reflection
vec3 R = reflect(-I, N); // reflection
vec3 f0 = mix(vec3(0.04), albedo, metallic); // dialectric
vec3 kS = FresnelSchlickRoughness(max(dot(N, V), 0.0), f0, roughness);
vec3 kD = 1.0 - kS;
kD *= 1.0 - metallic;
@ -306,7 +307,7 @@ void main()
// Diffuse pass
vec3 diffuseIblColor = texture(irradianceMap, N).rgb;
vec3 diffuseTerm = diffuseIblColor * albedo;
// diffuseTerm *= kD;
diffuseTerm *= kD;
diffuseTerm *= cavity;
diffuseTerm *= ao;
diffuseTerm *= shadow;
@ -323,7 +324,7 @@ void main()
vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg;
vec3 brdfTerm = (kS * envBRDF.x + envBRDF.y);
vec3 specularTerm = specularIblColor * brdfTerm * specIntensity * 0.7f;
vec3 specularTerm = specularIblColor * (kS * brdfTerm.x + brdfTerm.y) * specIntensity;
// Add render passes.
@ -339,6 +340,8 @@ void main()
fragColor.rgb *= min(boneWeightsColored, vec3(1));
// HDR tonemapping
fragColor.rgb = fragColor.rgb / (fragColor.rgb + vec3(1.0));
// Convert back to sRGB.
fragColor.rgb = pow(fragColor.rgb, vec3(1 / gamma));

View file

@ -3,6 +3,7 @@ layout (location = 0) in vec3 aPos;
uniform mat4 projection;
uniform mat4 rotView;
uniform mat4 mtxCam;
out vec3 TexCoords;

View file

@ -0,0 +1,22 @@
#version 330 core
out vec4 FragColor;
in vec3 localPos;
uniform sampler2D equirectangularMap;
const vec2 invAtan = vec2(0.1591, 0.3183);
vec2 SampleSphericalMap(vec3 v)
{
vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
uv *= invAtan;
uv += 0.5;
return uv;
}
void main()
{
vec2 uv = SampleSphericalMap(normalize(localPos)); // make sure to normalize localPos
vec3 color = texture(equirectangularMap, uv).rgb;
FragColor = vec4(color, 1.0);
}

View file

@ -0,0 +1,13 @@
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 localPos;
uniform mat4 projection;
uniform mat4 view;
void main()
{
localPos = aPos;
gl_Position = projection * view * vec4(localPos, 1.0);
}

View file

@ -0,0 +1,113 @@
#version 330 core
out vec2 FragColor;
in vec2 TexCoords;
const float PI = 3.14159265359;
// ----------------------------------------------------------------------------
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
// efficient VanDerCorpus calculation.
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
}
// ----------------------------------------------------------------------------
vec2 Hammersley(uint i, uint N)
{
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
}
// ----------------------------------------------------------------------------
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
{
float a = roughness*roughness;
float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
// from spherical coordinates to cartesian coordinates - halfway vector
vec3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;
// from tangent-space H vector to world-space sample vector
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
return normalize(sampleVec);
}
// ----------------------------------------------------------------------------
float GeometrySchlickGGX(float NdotV, float roughness)
{
// note that we use a different k for IBL
float a = roughness;
float k = (a * a) / 2.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
// ----------------------------------------------------------------------------
float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness)
{
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
return ggx1 * ggx2;
}
// ----------------------------------------------------------------------------
vec2 IntegrateBRDF(float NdotV, float roughness)
{
vec3 V;
V.x = sqrt(1.0 - NdotV*NdotV);
V.y = 0.0;
V.z = NdotV;
float A = 0.0;
float B = 0.0;
vec3 N = vec3(0.0, 0.0, 1.0);
const uint SAMPLE_COUNT = 1024u;
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
{
// generates a sample vector that's biased towards the
// preferred alignment direction (importance sampling).
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
vec3 L = normalize(2.0 * dot(V, H) * H - V);
float NdotL = max(L.z, 0.0);
float NdotH = max(H.z, 0.0);
float VdotH = max(dot(V, H), 0.0);
if(NdotL > 0.0)
{
float G = GeometrySmith(N, V, L, roughness);
float G_Vis = (G * VdotH) / (NdotH * NdotV);
float Fc = pow(1.0 - VdotH, 5.0);
A += (1.0 - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
A /= float(SAMPLE_COUNT);
B /= float(SAMPLE_COUNT);
return vec2(A, B);
}
// ----------------------------------------------------------------------------
void main()
{
vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
FragColor = integratedBRDF;
}

View file

@ -0,0 +1,11 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos, 1.0);
}

View file

@ -0,0 +1,43 @@
#version 330 core
out vec4 FragColor;
in vec3 WorldPos;
uniform samplerCube environmentMap;
const float PI = 3.14159265359;
void main()
{
// The world vector acts as the normal of a tangent surface
// from the origin, aligned to WorldPos. Given this normal, calculate all
// incoming radiance of the environment. The result of this radiance
// is the radiance of light coming from -Normal direction, which is what
// we use in the PBR shader to sample irradiance.
vec3 N = normalize(WorldPos);
vec3 irradiance = vec3(0.0);
// tangent space calculation from origin point
vec3 up = vec3(0.0, 1.0, 0.0);
vec3 right = cross(up, N);
up = cross(N, right);
float sampleDelta = 0.025;
float nrSamples = 0.0;
for(float phi = 0.0; phi < 2.0 * PI; phi += sampleDelta)
{
for(float theta = 0.0; theta < 0.5 * PI; theta += sampleDelta)
{
// spherical to cartesian (in tangent space)
vec3 tangentSample = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
// tangent space to world
vec3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;
irradiance += texture(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
nrSamples++;
}
}
irradiance = PI * irradiance * (1.0 / float(nrSamples));
FragColor = vec4(irradiance, 1.0);
}

View file

@ -0,0 +1,13 @@
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 WorldPos;
uniform mat4 projection;
uniform mat4 view;
void main()
{
WorldPos = aPos;
gl_Position = projection * view * vec4(WorldPos, 1.0);
}

View file

@ -0,0 +1,106 @@
#version 330 core
out vec4 FragColor;
in vec3 WorldPos;
uniform samplerCube environmentMap;
uniform float roughness;
const float PI = 3.14159265359;
// ----------------------------------------------------------------------------
float DistributionGGX(vec3 N, vec3 H, float roughness)
{
float a = roughness*roughness;
float a2 = a*a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH*NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
// ----------------------------------------------------------------------------
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
// efficient VanDerCorpus calculation.
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
}
// ----------------------------------------------------------------------------
vec2 Hammersley(uint i, uint N)
{
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
}
// ----------------------------------------------------------------------------
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness)
{
float a = roughness*roughness;
float phi = 2.0 * PI * Xi.x;
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
// from spherical coordinates to cartesian coordinates - halfway vector
vec3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;
// from tangent-space H vector to world-space sample vector
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, N));
vec3 bitangent = cross(N, tangent);
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
return normalize(sampleVec);
}
// ----------------------------------------------------------------------------
void main()
{
vec3 N = normalize(WorldPos);
// make the simplyfying assumption that V equals R equals the normal
vec3 R = N;
vec3 V = R;
const uint SAMPLE_COUNT = 1024u;
vec3 prefilteredColor = vec3(0.0);
float totalWeight = 0.0;
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
{
// generates a sample vector that's biased towards the preferred alignment direction (importance sampling).
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
vec3 L = normalize(2.0 * dot(V, H) * H - V);
float NdotL = max(dot(N, L), 0.0);
if(NdotL > 0.0)
{
// sample from the environment's mip level based on roughness/pdf
float D = DistributionGGX(N, H, roughness);
float NdotH = max(dot(N, H), 0.0);
float HdotV = max(dot(H, V), 0.0);
float pdf = D * NdotH / (4.0 * HdotV) + 0.0001;
float resolution = 512.0; // resolution of source cubemap (per face)
float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel);
prefilteredColor += textureLod(environmentMap, L, mipLevel).rgb * NdotL;
totalWeight += NdotL;
}
}
prefilteredColor = prefilteredColor / totalWeight;
FragColor = vec4(prefilteredColor, 1.0);
}

View file

@ -0,0 +1,13 @@
#version 330 core
layout (location = 0) in vec3 aPos;
out vec3 WorldPos;
uniform mat4 projection;
uniform mat4 view;
void main()
{
WorldPos = aPos;
gl_Position = projection * view * vec4(WorldPos, 1.0);
}

View file

@ -216,6 +216,30 @@
<None Include="Shader\Legacy\KCL.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\brdf.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\brdf.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\HDR.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\HDR.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\irradianceShader.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\irradianceShader.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\preFilter.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\PBR\preFilter.vert">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Shader\Utility\Utility.frag">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>