diff --git a/.vs/Switch_Toolbox/v15/.suo b/.vs/Switch_Toolbox/v15/.suo index bf033ec9..ef2dd498 100644 Binary files a/.vs/Switch_Toolbox/v15/.suo and b/.vs/Switch_Toolbox/v15/.suo differ diff --git a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide index 11aed00e..48160b39 100644 Binary files a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide and b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide differ diff --git a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm index c027fd38..04c0b39c 100644 Binary files a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm and b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-shm differ diff --git a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal index 3348179f..c0deabbf 100644 Binary files a/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal and b/.vs/Switch_Toolbox/v15/Server/sqlite3/storage.ide-wal differ diff --git a/Switch_FileFormatsMain/GL/BFRES_Render.cs b/Switch_FileFormatsMain/GL/BFRES_Render.cs index 6368bc82..8ecc804c 100644 --- a/Switch_FileFormatsMain/GL/BFRES_Render.cs +++ b/Switch_FileFormatsMain/GL/BFRES_Render.cs @@ -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 diff --git a/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache b/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache index e71cf8f5..5bda6efb 100644 Binary files a/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache and b/Switch_FileFormatsMain/obj/Release/DesignTimeResolveAssemblyReferences.cache differ diff --git a/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache b/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache index 08423834..2450413e 100644 Binary files a/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache and b/Switch_FileFormatsMain/obj/Release/Switch_FileFormatsMain.csprojAssemblyReference.cache differ diff --git a/Switch_Toolbox_Library/FileFormats/DDS.cs b/Switch_Toolbox_Library/FileFormats/DDS.cs index 0c036127..d3095399 100644 --- a/Switch_Toolbox_Library/FileFormats/DDS.cs +++ b/Switch_Toolbox_Library/FileFormats/DDS.cs @@ -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], diff --git a/Switch_Toolbox_Library/Generics/OpenGLTexture.cs b/Switch_Toolbox_Library/Generics/OpenGLTexture.cs new file mode 100644 index 00000000..5f55d1c4 --- /dev/null +++ b/Switch_Toolbox_Library/Generics/OpenGLTexture.cs @@ -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); + } + } +} diff --git a/Switch_Toolbox_Library/Generics/STBone.cs b/Switch_Toolbox_Library/Generics/STBone.cs index ec11513c..85a1d118 100644 --- a/Switch_Toolbox_Library/Generics/STBone.cs +++ b/Switch_Toolbox_Library/Generics/STBone.cs @@ -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; diff --git a/Switch_Toolbox_Library/Generics/STSkeleton.cs b/Switch_Toolbox_Library/Generics/STSkeleton.cs index c3d90b0e..4b5276bc 100644 --- a/Switch_Toolbox_Library/Generics/STSkeleton.cs +++ b/Switch_Toolbox_Library/Generics/STSkeleton.cs @@ -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,7 +237,9 @@ 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; solidColorShaderProgram.SetMatrix4x4("bone", ref transform); diff --git a/Switch_Toolbox_Library/Rendering/DrawableSkybox.cs b/Switch_Toolbox_Library/Rendering/DrawableSkybox.cs index 25120071..b528bff2 100644 --- a/Switch_Toolbox_Library/Rendering/DrawableSkybox.cs +++ b/Switch_Toolbox_Library/Rendering/DrawableSkybox.cs @@ -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) { diff --git a/Switch_Toolbox_Library/Rendering/PBRMapGenerator.cs b/Switch_Toolbox_Library/Rendering/PBRMapGenerator.cs new file mode 100644 index 00000000..b5b8bebe --- /dev/null +++ b/Switch_Toolbox_Library/Rendering/PBRMapGenerator.cs @@ -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); + } + } +} diff --git a/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj b/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj index 520bec3f..974d79ea 100644 --- a/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj +++ b/Switch_Toolbox_Library/Switch_Toolbox_Library.csproj @@ -497,6 +497,7 @@ + @@ -622,6 +623,7 @@ + diff --git a/Toolbox/GUI/Settings.Designer.cs b/Toolbox/GUI/Settings.Designer.cs index 0a67c54a..175d3327 100644 --- a/Toolbox/GUI/Settings.Designer.cs +++ b/Toolbox/GUI/Settings.Designer.cs @@ -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); } diff --git a/Toolbox/Shader/Bfres/BFRES.vert b/Toolbox/Shader/Bfres/BFRES.vert index 081b1836..eb6dcfef 100644 --- a/Toolbox/Shader/Bfres/BFRES.vert +++ b/Toolbox/Shader/Bfres/BFRES.vert @@ -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; diff --git a/Toolbox/Shader/Bfres/BFRES_PBR.frag b/Toolbox/Shader/Bfres/BFRES_PBR.frag index fa50c0d1..3b4e338f 100644 --- a/Toolbox/Shader/Bfres/BFRES_PBR.frag +++ b/Toolbox/Shader/Bfres/BFRES_PBR.frag @@ -286,10 +286,11 @@ 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)); diff --git a/Toolbox/Shader/HDRSkyBox/HDRSkyBox.vert b/Toolbox/Shader/HDRSkyBox/HDRSkyBox.vert index 72667164..4dfcea30 100644 --- a/Toolbox/Shader/HDRSkyBox/HDRSkyBox.vert +++ b/Toolbox/Shader/HDRSkyBox/HDRSkyBox.vert @@ -3,6 +3,7 @@ layout (location = 0) in vec3 aPos; uniform mat4 projection; uniform mat4 rotView; +uniform mat4 mtxCam; out vec3 TexCoords; diff --git a/Toolbox/Shader/PBR/HDR.frag b/Toolbox/Shader/PBR/HDR.frag new file mode 100644 index 00000000..8ec8f754 --- /dev/null +++ b/Toolbox/Shader/PBR/HDR.frag @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/HDR.vert b/Toolbox/Shader/PBR/HDR.vert new file mode 100644 index 00000000..7cdc81f3 --- /dev/null +++ b/Toolbox/Shader/PBR/HDR.vert @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/brdf.frag b/Toolbox/Shader/PBR/brdf.frag new file mode 100644 index 00000000..524f2859 --- /dev/null +++ b/Toolbox/Shader/PBR/brdf.frag @@ -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; +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/brdf.vert b/Toolbox/Shader/PBR/brdf.vert new file mode 100644 index 00000000..553e3a65 --- /dev/null +++ b/Toolbox/Shader/PBR/brdf.vert @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/irradianceShader.frag b/Toolbox/Shader/PBR/irradianceShader.frag new file mode 100644 index 00000000..6ba88776 --- /dev/null +++ b/Toolbox/Shader/PBR/irradianceShader.frag @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/irradianceShader.vert b/Toolbox/Shader/PBR/irradianceShader.vert new file mode 100644 index 00000000..9d789e76 --- /dev/null +++ b/Toolbox/Shader/PBR/irradianceShader.vert @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/preFilter.frag b/Toolbox/Shader/PBR/preFilter.frag new file mode 100644 index 00000000..edc1e59a --- /dev/null +++ b/Toolbox/Shader/PBR/preFilter.frag @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Shader/PBR/preFilter.vert b/Toolbox/Shader/PBR/preFilter.vert new file mode 100644 index 00000000..9d789e76 --- /dev/null +++ b/Toolbox/Shader/PBR/preFilter.vert @@ -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); +} \ No newline at end of file diff --git a/Toolbox/Toolbox.csproj b/Toolbox/Toolbox.csproj index 7e38127a..51d17027 100644 --- a/Toolbox/Toolbox.csproj +++ b/Toolbox/Toolbox.csproj @@ -216,6 +216,30 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest