From f0ffc1746c5052279d6820cff69a85b701a3aff1 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Thu, 30 Jul 2020 17:57:57 -0700 Subject: [PATCH 01/16] start implementing PBR effect --- Effects/PBREffect.cs | 160 +++++++++++++++++++++++++++++++ Effects/pbr.fx | 217 +++++++++++++++++++++++++++++++++++++++++++ Effects/pbr.fxo | Bin 0 -> 7240 bytes Importer.cs | 4 +- MeshPart.cs | 4 +- 5 files changed, 380 insertions(+), 5 deletions(-) create mode 100644 Effects/PBREffect.cs create mode 100644 Effects/pbr.fx create mode 100644 Effects/pbr.fxo diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs new file mode 100644 index 0000000..be79d33 --- /dev/null +++ b/Effects/PBREffect.cs @@ -0,0 +1,160 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Smuggler +{ + public struct PBRLight + { + public Vector3 direction; + public Vector3 radiance; + + public PBRLight(Vector3 direction, Vector3 radiance) + { + this.direction = direction; + this.radiance = radiance; + } + } + + public class PBRLightCollection + { + readonly EffectParameter directionParam; + readonly EffectParameter radianceParam; + + private readonly Vector3[] directions = new Vector3[PBREffect.NUM_LIGHTS]; + private readonly Vector3[] radiances = new Vector3[PBREffect.NUM_LIGHTS]; + + public PBRLightCollection(EffectParameter directionParam, EffectParameter radianceParam) + { + this.directionParam = directionParam; + this.radianceParam = radianceParam; + } + + public PBRLightCollection(PBRLightCollection other) + { + for (int i = 0; i < PBREffect.NUM_LIGHTS; i++) + { + directions[i] = other.directions[i]; + radiances[i] = other.radiances[i]; + } + } + + public PBRLight this[int index] + { + get + { + return new PBRLight(directions[index], radiances[index]); + } + + set + { + directions[index] = value.direction; + radiances[index] = value.radiance; + directionParam.SetValue(directions); + radianceParam.SetValue(radiances); + } + } + } + + public class PBREffect : Effect + { + public static readonly int NUM_LIGHTS = 3; + + readonly EffectParameter viewProjectionParam; + readonly EffectParameter sceneRotationParam; + readonly EffectParameter eyePositionParam; + readonly EffectParameter specularTextureLevelsParam; + + readonly EffectParameter albedoTextureParam; + + Matrix world = Matrix.Identity; + Matrix view = Matrix.Identity; + Matrix projection = Matrix.Identity; + Vector3 eyePosition = Vector3.Zero; + int specularTextureLevels = 0; + + public Matrix World + { + get { return world; } + set + { + world = value; + sceneRotationParam.SetValue(world); + } + } + + public Matrix View + { + get { return view; } + set + { + view = value; + viewProjectionParam.SetValue(projection * view); + eyePositionParam.SetValue(Matrix.Invert(view).Backward); + } + } + + public Matrix Projection + { + get { return projection; } + set + { + projection = value; + viewProjectionParam.SetValue(projection * view); + } + } + + public PBRLightCollection Lights { get; } + + public int SpecularTextureLevels + { + get { return specularTextureLevels; } + set + { + specularTextureLevels = value; + specularTextureLevelsParam.SetValue(specularTextureLevels); + } + } + + public Texture2D AlbedoTexture + { + get { return albedoTextureParam.GetValueTexture2D(); } + set { albedoTextureParam.SetValue(value); } + } + + public PBREffect(GraphicsDevice graphicsDevice, byte[] effectCode) : base(graphicsDevice, effectCode) + { + viewProjectionParam = Parameters["viewProjectionMatrix"]; + sceneRotationParam = Parameters["sceneRotationMatrix"]; + + eyePositionParam = Parameters["eyePosition"]; + specularTextureLevelsParam = Parameters["specularTextureLevels"]; + + Lights = new PBRLightCollection(Parameters["directions"], Parameters["radiance"]); + } + + protected PBREffect(PBREffect cloneSource) : base(cloneSource) + { + viewProjectionParam = Parameters["viewProjectionMatrix"]; + sceneRotationParam = Parameters["sceneRotationMatrix"]; + + eyePositionParam = Parameters["eyePosition"]; + specularTextureLevelsParam = Parameters["specularTextureLevels"]; + + World = cloneSource.World; + View = cloneSource.View; + Projection = cloneSource.Projection; + Lights = new PBRLightCollection(cloneSource.Lights); + } + + public override Effect Clone() + { + return new PBREffect(this); + } + + // FIXME: do param applications here for performance + protected override void OnApply() + { + base.OnApply(); + } + } +} diff --git a/Effects/pbr.fx b/Effects/pbr.fx new file mode 100644 index 0000000..71b2b02 --- /dev/null +++ b/Effects/pbr.fx @@ -0,0 +1,217 @@ +// Physically Based Rendering +// Copyright (c) 2017-2018 Michał Siejak + +// Physically Based shading model: Lambetrtian diffuse BRDF + Cook-Torrance microfacet specular BRDF + IBL for ambient. + +// This implementation is based on "Real Shading in Unreal Engine 4" SIGGRAPH 2013 course notes by Epic Games. +// See: http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf + +static const float PI = 3.141592; +static const float Epsilon = 0.00001; + +static const uint NumLights = 3; + +// Constant normal incidence Fresnel factor for all dielectrics. +static const float3 Fdielectric = 0.04; + +// UNIFORM CONSTANTS +float4x4 viewProjectionMatrix; +float4x4 sceneRotationMatrix; + +float3 direction[NumLights]; +float3 radiance[NumLights]; + +float3 eyePosition; +int specularTextureLevels; + +struct VertexShaderInput +{ + float3 position : POSITION; + float3 normal : NORMAL; + float3 tangent : TANGENT; + float3 binormal : BINORMAL; + float2 texcoord : TEXCOORD; +}; + +struct PixelShaderInput +{ + float4 pixelPosition : SV_POSITION; + float3 position : POSITION1; + float2 texcoord : TEXCOORD0; + float3 T : TEXCOORD1; + float3 B : TEXCOORD2; + float3 N : TEXCOORD3; +}; + +sampler albedoTexture : register(s0); +sampler normalTexture : register(s1); +sampler metalnessTexture : register(s2); +sampler roughnessTexture : register(s3); +sampler specularTexture : register(s4); +sampler irradianceTexture : register(s5); +sampler specularBRDF_LUT : register(s6); + +// GGX/Towbridge-Reitz normal distribution function. +// Uses Disney's reparametrization of alpha = roughness^2. +float ndfGGX(float cosLh, float roughness) +{ + float alpha = roughness * roughness; + float alphaSq = alpha * alpha; + + float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; + return alphaSq / (PI * denom * denom); +} + +// Single term for separable Schlick-GGX below. +float gaSchlickG1(float cosTheta, float k) +{ + return cosTheta / (cosTheta * (1.0 - k) + k); +} + +// Schlick-GGX approximation of geometric attenuation function using Smith's method. +float gaSchlickGGX(float cosLi, float cosLo, float roughness) +{ + float r = roughness + 1.0; + float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. + return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); +} + +// Shlick's approximation of the Fresnel factor. +float3 fresnelSchlick(float3 F0, float cosTheta) +{ + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); +} + +// Vertex shader +PixelShaderInput main_vs(VertexShaderInput vin) +{ + PixelShaderInput vout; + vout.position = mul(sceneRotationMatrix, float4(vin.position, 1.0)).xyz; + vout.texcoord = float2(vin.texcoord.x, 1.0-vin.texcoord.y); + + // Pass tangent space basis vectors (for normal mapping). + float3 worldTangent = mul(vin.tangent, (float3x3) sceneRotationMatrix); + vout.T = normalize(worldTangent); + + float3 worldBinormal = mul(vin.binormal, (float3x3) sceneRotationMatrix); + vout.B = normalize(worldBinormal); + + float3 worldNormal = mul(vin.normal, (float3x3) sceneRotationMatrix); + vout.N = normalize(worldNormal); + + float4x4 mvpMatrix = mul(viewProjectionMatrix, sceneRotationMatrix); + vout.pixelPosition = mul(mvpMatrix, float4(vin.position, 1.0)); + return vout; +} + +// Pixel shader +float4 main_ps(PixelShaderInput pin) : SV_Target0 +{ + // Sample input textures to get shading model params. + float3 albedo = tex2D(albedoTexture, pin.texcoord).rgb; + float metalness = tex2D(metalnessTexture, pin.texcoord).r; + float roughness = tex2D(roughnessTexture, pin.texcoord).r; + + // Outgoing light direction (vector from world-space fragment position to the "eye"). + float3 Lo = normalize(eyePosition - pin.position); + + // tranpose to transform tangent space => world + float3x3 TBN = transpose(float3x3(normalize(pin.T), normalize(pin.B), normalize(pin.N))); + + // Get current fragment's normal and transform to world space. + float3 tangentNormal = normalize(2.0 * tex2D(normalTexture, pin.texcoord).rgb - 1.0); + + // world normal + float3 N = normalize(mul(TBN, tangentNormal)); + + // Angle between surface normal and outgoing light direction. + float cosLo = max(0.0, dot(N, Lo)); + + // Specular reflection vector. + float3 Lr = 2.0 * cosLo * N - Lo; + + // Fresnel reflectance at normal incidence (for metals use albedo color). + float3 F0 = lerp(Fdielectric, albedo, metalness); + + // Direct lighting calculation for analytical lights. + float3 directLighting = 0.0; + for(uint i=0; iCS;8OLWo>|GlZ(-KN31uQiZMM9C&7SUY5I3XmGD;X!2a;TIp_CgjpUTfD0 zLF(a+#IX_!^nk==E%kux9y#;?DiT8CSP3L@jL>`Nu?G%~RQcuqo0(^KcGvl65;6Ad z`+UvwHP6gD@04bW!?!EWHy&m6H$4`9s(R3$w0%hmZnm1gSnafb-rU%2wYOhy>~>nW z&}(+@Bu1W=-Q&{P-Dqw%*V?;{#4I*T>WloSfg8;e9`Z9Q{${HaLP^GEkEw4)Iy#Nb zR%3gkiD~oY{irXc0b83B(EMd{wcTwIou5B=A0^`e4Sh~lmCMBkHtFB?Gr4%wPyviIyM7CXDrS|CM0S2Zn~G(&Yi!y zvVIvhdB*Pen!&aCBk0qjtv0&d(~-BjyyiYH7(Lj=EV>rdt-U4S_lD^CvHF}%u;3-Z zZzOn6@OugV55akYSLNJ^BzKE~&n5U9f_D=9ZNdEn|Fhr^6Z|8=pCY8J+SNm`{S4vY8Q*~>pzenIE~N=5se9^h&V z)YK;eP*>7wsYeAT^z`DQpA`J6`lhE%OHT3YCsQYv6*nc?bM9RjYJc*yvS_o8+|urN zT1m9&!CL%8w6aEHo1A0gxSmi-?wETC2h?8kH0(a_Rw9i#sHhT3?pe1LX>aLSb~VwQ zdq;34V04`x98}$$`22-7+_Mf2O5SepC$c}&Bi(mQm)RLtG`Y4WeVf<|4kl$r_m)Y% ztzf6I=2I*kH?emdp?_jcKS0KIiSZnpj>wPu>%jrDmCnUZ_v$NG7v1ZvjZVAU{^{<* zOKaa+xUh0*W#Q7b#%8m#aJGGYr?n;E%&C{poI3NJmruQN`t)h{W9O#oZoYqK{^FAI z{5{S5_tlr6&xj8E-rv9ZUAOwTA2AQmXFc65iT44t*?+(Imv8uzFJ;cvdcad+DrXTc zWvZW{RW2SjlVry8LzeuPIJ&V$3tsUzJYd2l;(3 zXMDzJX=zw3n|66$_;2bSuX{Q8HSafg;cej?ba3h1Lznr+*pjP9-||d*lVU3gFBHpu zKlon9rtfL&6~zv}?8*Z^zL#B9_`2`pVki@6$OM~(WcFoeeb4M*m!9JCv9I@%@{gaR zJnSH=8u0NECoyR!%`{hvKgYL4*_jh&L)flJoxoi}B(5BomuLD1(UC-;SNiM{7PdxM-6Fv97lBrKx+Xtv&2gW41J zPRf^=CYSUbTVCt9lC%ODr^gR^(-N1PbIUB)^HISTcueJsk5w{@QfY8V;iWUvmv z<)5b=k*mQvu-t@Pgf*MiF!@C$#2Vl*f5aNc)H>)=gN;_z`qkF4B1o zv|&ChUaOmckLHrvv-d)}=USbv5B8<>U4f2(@B7*fIAg%qecgn$7RKBDS=Ras{^j0o zT%Uuw3Ha##$vm*eSc~kRX>KeRz-xu-qRdtMi8tvv|p8XGtUzb+b zet4-=zHe{7?%%imwX5PS4+F?<4XIC!zdz-`JwbJ=3D`&}F)vfl)BaJ8b zIW(gI*Z5HzmwhIXy{y?nHrQTTFda4?apN1TePKec)|hXMhfgydRd;{Asci6JG`24W zRo>sZ2tSHmi;XAw8PCJ%p4^geE#k)QFL#l76mMKp2W zoP90v;c4dV>xtep50IZEXS!GMjrx7uoROc8)#lZBLvk0y-H{7-MjvYzj8X|6z8CNr7{2M&nPo&bc&Z!xQFN1oaoy50q8mKb4gM&)$*JiM vxt&*@)7<(qVBd}8cAm4MXv5s9CZs3N^bOc2|IDY(Z#|tkmAn7+sjL41pLhSJ literal 0 HcmV?d00001 diff --git a/Importer.cs b/Importer.cs index 1369802..43ae13c 100644 --- a/Importer.cs +++ b/Importer.cs @@ -147,9 +147,7 @@ namespace Smuggler /* TODO: We need a new Effect subclass to support some GLTF features */ - var effect = new BasicEffect(graphicsDevice); - effect.EnableDefaultLighting(); - effect.PreferPerPixelLighting = true; + var effect = new PBREffect(graphicsDevice, File.ReadAllBytes("Effects/pbr.fxo")); return new MeshPart( vertexBuffer, diff --git a/MeshPart.cs b/MeshPart.cs index b68bfab..bc019ea 100644 --- a/MeshPart.cs +++ b/MeshPart.cs @@ -8,10 +8,10 @@ namespace Smuggler public IndexBuffer IndexBuffer { get; } public VertexBuffer VertexBuffer { get; } public Triangle[] Triangles { get; } - public BasicEffect Effect { get; } + public PBREffect Effect { get; } public Vector3[] Positions { get; } - public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, BasicEffect effect) + public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, PBREffect effect) { VertexBuffer = vertexBuffer; IndexBuffer = indexBuffer; From 466f35b1eea2dbd0e2c4d4db1860e5da2604ae4b Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Fri, 31 Jul 2020 00:20:07 -0700 Subject: [PATCH 02/16] rewrite PBREffect --- Effects/Macros.fxh | 57 +++++ Effects/PBREffect.cs | 276 ++++++++++++++++------ Effects/pbr.fx | 551 +++++++++++++++++++++++++++++-------------- Effects/pbr.fxo | Bin 7240 -> 8060 bytes 4 files changed, 629 insertions(+), 255 deletions(-) create mode 100644 Effects/Macros.fxh diff --git a/Effects/Macros.fxh b/Effects/Macros.fxh new file mode 100644 index 0000000..91d1702 --- /dev/null +++ b/Effects/Macros.fxh @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------------- +// Macros.fxh +// +// Microsoft XNA Community Game Platform +// Copyright (C) Microsoft Corporation. All rights reserved. +//----------------------------------------------------------------------------- + +#ifdef SM4 + + +// Macros for targetting shader model 4.0 (DX11) + +#define BEGIN_CONSTANTS cbuffer Parameters : register(b0) { +#define MATRIX_CONSTANTS }; cbuffer ProjectionMatrix : register(b1) { +#define END_CONSTANTS }; + +#define _vs(r) +#define _ps(r) +#define _cb(r) : packoffset(r) + +#define DECLARE_TEXTURE(Name, index) \ + Texture2D Name : register(t##index); \ + sampler Name##Sampler : register(s##index) + +#define DECLARE_CUBEMAP(Name, index) \ + TextureCube Name : register(t##index); \ + sampler Name##Sampler : register(s##index) + +#define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord) +#define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord) +#define SAMPLE_CUBEMAP_LOD(Name, texCoord) Name.SampleLevel(Name##Sampler, texCoord.xyz, texCoord.w) + +#else + + +// Macros for targetting shader model 2.0 (DX9) + +#define BEGIN_CONSTANTS +#define MATRIX_CONSTANTS +#define END_CONSTANTS + +#define _vs(r) : register(vs, r) +#define _ps(r) : register(ps, r) +#define _cb(r) + +#define DECLARE_TEXTURE(Name, index) \ + texture2D Name; \ + sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); }; + +#define DECLARE_CUBEMAP(Name, index) \ + textureCUBE Name; \ + sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); }; + +#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord) +#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord) +#define SAMPLE_CUBEMAP_LOD(Name, texCoord) texCUBElod(Name##Sampler, texCoord) +#endif diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index be79d33..b50d027 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -6,71 +6,48 @@ namespace Smuggler public struct PBRLight { public Vector3 direction; - public Vector3 radiance; + public Vector3 colour; - public PBRLight(Vector3 direction, Vector3 radiance) + public PBRLight(Vector3 direction, Vector3 colour) { this.direction = direction; - this.radiance = radiance; - } - } - - public class PBRLightCollection - { - readonly EffectParameter directionParam; - readonly EffectParameter radianceParam; - - private readonly Vector3[] directions = new Vector3[PBREffect.NUM_LIGHTS]; - private readonly Vector3[] radiances = new Vector3[PBREffect.NUM_LIGHTS]; - - public PBRLightCollection(EffectParameter directionParam, EffectParameter radianceParam) - { - this.directionParam = directionParam; - this.radianceParam = radianceParam; - } - - public PBRLightCollection(PBRLightCollection other) - { - for (int i = 0; i < PBREffect.NUM_LIGHTS; i++) - { - directions[i] = other.directions[i]; - radiances[i] = other.radiances[i]; - } - } - - public PBRLight this[int index] - { - get - { - return new PBRLight(directions[index], radiances[index]); - } - - set - { - directions[index] = value.direction; - radiances[index] = value.radiance; - directionParam.SetValue(directions); - radianceParam.SetValue(radiances); - } + this.colour = colour; } } public class PBREffect : Effect { - public static readonly int NUM_LIGHTS = 3; + readonly EffectParameter modelParam; + readonly EffectParameter viewParam; + readonly EffectParameter projectionParam; + readonly EffectParameter lightDirParam; + readonly EffectParameter lightColourParam; + readonly EffectParameter normalScaleParam; + readonly EffectParameter emissiveFactorParam; + readonly EffectParameter occlusionStrengthParam; + readonly EffectParameter metallicRoughnessValuesParam; + readonly EffectParameter baseColorFactorParam; + readonly EffectParameter cameraLookParam; - readonly EffectParameter viewProjectionParam; - readonly EffectParameter sceneRotationParam; - readonly EffectParameter eyePositionParam; - readonly EffectParameter specularTextureLevelsParam; - - readonly EffectParameter albedoTextureParam; + readonly EffectParameter baseColourTextureParam; + readonly EffectParameter normalTextureParam; + readonly EffectParameter emissionTextureParam; + readonly EffectParameter occlusionTextureParam; + readonly EffectParameter metallicRoughnessTextureParam; + readonly EffectParameter envDiffuseTextureParam; + readonly EffectParameter brdfLutTextureParam; + readonly EffectParameter envSpecularTextureParam; Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; - Vector3 eyePosition = Vector3.Zero; - int specularTextureLevels = 0; + PBRLight light = new PBRLight(); + float normalScale = 1; + Vector3 emissiveFactor; + float occlusionStrength; + Vector2 metallicRoughnessValue; + Vector4 baseColorFactor; + Vector3 cameraLook; public Matrix World { @@ -78,7 +55,7 @@ namespace Smuggler set { world = value; - sceneRotationParam.SetValue(world); + modelParam.SetValue(world); } } @@ -88,8 +65,7 @@ namespace Smuggler set { view = value; - viewProjectionParam.SetValue(projection * view); - eyePositionParam.SetValue(Matrix.Invert(view).Backward); + viewParam.SetValue(view); } } @@ -99,51 +75,201 @@ namespace Smuggler set { projection = value; - viewProjectionParam.SetValue(projection * view); + projectionParam.SetValue(value); } } - public PBRLightCollection Lights { get; } - - public int SpecularTextureLevels + public PBRLight Light { - get { return specularTextureLevels; } + get { return light; } + set + { + light = value; + lightDirParam.SetValue(light.direction); + lightColourParam.SetValue(light.colour); + } + } + + public float NormalScale + { + get { return normalScale; } + set + { + normalScale = value; + normalScaleParam.SetValue(normalScale); + } + } + + public Vector3 EmissiveFactor + { + get { return emissiveFactor; } + set + { + emissiveFactor = value; + emissiveFactorParam.SetValue(emissiveFactor); + } + } + + public float OcclusionStrength + { + get { return occlusionStrength; } + set + { + occlusionStrength = value; + occlusionStrengthParam.SetValue(occlusionStrength); + } + } + + public Vector2 MetallicRoughnessValue + { + get { return metallicRoughnessValue; } set { - specularTextureLevels = value; - specularTextureLevelsParam.SetValue(specularTextureLevels); + metallicRoughnessValue = value; + metallicRoughnessValuesParam.SetValue(metallicRoughnessValue); } } - public Texture2D AlbedoTexture + public Vector4 BaseColorFactor { - get { return albedoTextureParam.GetValueTexture2D(); } - set { albedoTextureParam.SetValue(value); } + get { return baseColorFactor; } + set + { + baseColorFactor = value; + baseColorFactorParam.SetValue(baseColorFactor); + } + } + + public Vector3 CameraLook + { + get { return cameraLook; } + set + { + cameraLook = value; + cameraLookParam.SetValue(cameraLook); + } + } + + public Texture2D BaseColourTexture + { + get { return baseColourTextureParam.GetValueTexture2D(); } + set { baseColourTextureParam.SetValue(value); } + } + + public Texture2D NormalTexture + { + get { return normalTextureParam.GetValueTexture2D(); } + set { normalTextureParam.SetValue(value); } + } + + public Texture2D EmissionTexture + { + get { return emissionTextureParam.GetValueTexture2D(); } + set { emissionTextureParam.SetValue(value); } + } + + public Texture2D OcclusionTexture + { + get { return occlusionTextureParam.GetValueTexture2D(); } + set { occlusionTextureParam.SetValue(value); } + } + + public Texture2D MetallicRoughnessTexture + { + get { return metallicRoughnessTextureParam.GetValueTexture2D(); } + set { metallicRoughnessTextureParam.SetValue(value); } + } + + public TextureCube EnvDiffuseTexture + { + get { return envDiffuseTextureParam.GetValueTextureCube(); } + set { envDiffuseTextureParam.SetValue(value); } + } + + public Texture2D BRDFLutTexture + { + get { return brdfLutTextureParam.GetValueTexture2D(); } + set { brdfLutTextureParam.SetValue(value); } + } + + public TextureCube EnvSpecularTexture + { + get { return envSpecularTextureParam.GetValueTextureCube(); } + set { envSpecularTextureParam.SetValue(value); } } public PBREffect(GraphicsDevice graphicsDevice, byte[] effectCode) : base(graphicsDevice, effectCode) { - viewProjectionParam = Parameters["viewProjectionMatrix"]; - sceneRotationParam = Parameters["sceneRotationMatrix"]; + modelParam = Parameters["model"]; + viewParam = Parameters["view"]; + projectionParam = Parameters["param"]; - eyePositionParam = Parameters["eyePosition"]; - specularTextureLevelsParam = Parameters["specularTextureLevels"]; + lightDirParam = Parameters["lightDir"]; + lightColourParam = Parameters["lightColour"]; - Lights = new PBRLightCollection(Parameters["directions"], Parameters["radiance"]); + normalScaleParam = Parameters["normalScale"]; + emissiveFactorParam = Parameters["emissiveFactor"]; + occlusionStrengthParam = Parameters["occlusionStrength"]; + metallicRoughnessValuesParam = Parameters["metallicRoughnessValues"]; + baseColorFactorParam = Parameters["baseColorFactor"]; + cameraLookParam = Parameters["camera"]; + + baseColourTextureParam = Parameters["baseColourTexture"]; + normalTextureParam = Parameters["normalTexture"]; + emissionTextureParam = Parameters["emissionTexture"]; + occlusionTextureParam = Parameters["occlusionTexture"]; + metallicRoughnessTextureParam = Parameters["metallicRoughnessTexture"]; + envDiffuseTextureParam = Parameters["envDiffuseTexture"]; + brdfLutTextureParam = Parameters["brdfLutTexture"]; + envSpecularTextureParam = Parameters["envSpecularTexture"]; } protected PBREffect(PBREffect cloneSource) : base(cloneSource) { - viewProjectionParam = Parameters["viewProjectionMatrix"]; - sceneRotationParam = Parameters["sceneRotationMatrix"]; + modelParam = Parameters["model"]; + viewParam = Parameters["view"]; + projectionParam = Parameters["param"]; - eyePositionParam = Parameters["eyePosition"]; - specularTextureLevelsParam = Parameters["specularTextureLevels"]; + lightDirParam = Parameters["lightDir"]; + lightColourParam = Parameters["lightColour"]; + + normalScaleParam = Parameters["normalScale"]; + emissiveFactorParam = Parameters["emissiveFactor"]; + occlusionStrengthParam = Parameters["occlusionStrength"]; + metallicRoughnessValuesParam = Parameters["metallicRoughnessValues"]; + baseColorFactorParam = Parameters["baseColorFactor"]; + cameraLookParam = Parameters["camera"]; + + baseColourTextureParam = Parameters["baseColourTexture"]; + normalTextureParam = Parameters["normalTexture"]; + emissionTextureParam = Parameters["emissionTexture"]; + occlusionTextureParam = Parameters["occlusionTexture"]; + metallicRoughnessTextureParam = Parameters["metallicRoughnessTexture"]; + envDiffuseTextureParam = Parameters["envDiffuseTexture"]; + brdfLutTextureParam = Parameters["brdfLutTexture"]; + envSpecularTextureParam = Parameters["envSpecularTexture"]; World = cloneSource.World; View = cloneSource.View; Projection = cloneSource.Projection; - Lights = new PBRLightCollection(cloneSource.Lights); + + Light = cloneSource.Light; + + NormalScale = cloneSource.normalScale; + EmissiveFactor = cloneSource.EmissiveFactor; + OcclusionStrength = cloneSource.OcclusionStrength; + MetallicRoughnessValue = cloneSource.MetallicRoughnessValue; + BaseColorFactor = cloneSource.BaseColorFactor; + CameraLook = cloneSource.CameraLook; + + BaseColourTexture = cloneSource.BaseColourTexture; + NormalTexture = cloneSource.NormalTexture; + EmissionTexture = cloneSource.EmissionTexture; + OcclusionTexture = cloneSource.OcclusionTexture; + MetallicRoughnessTexture = cloneSource.MetallicRoughnessTexture; + EnvDiffuseTexture = cloneSource.EnvDiffuseTexture; + BRDFLutTexture = cloneSource.BRDFLutTexture; + EnvSpecularTexture = cloneSource.EnvSpecularTexture; } public override Effect Clone() diff --git a/Effects/pbr.fx b/Effects/pbr.fx index 71b2b02..ca57701 100644 --- a/Effects/pbr.fx +++ b/Effects/pbr.fx @@ -1,217 +1,408 @@ -// Physically Based Rendering -// Copyright (c) 2017-2018 Michał Siejak -// Physically Based shading model: Lambetrtian diffuse BRDF + Cook-Torrance microfacet specular BRDF + IBL for ambient. +#include "Macros.fxh" -// This implementation is based on "Real Shading in Unreal Engine 4" SIGGRAPH 2013 course notes by Epic Games. -// See: http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf +#define NORMALS +#define UV -static const float PI = 3.141592; -static const float Epsilon = 0.00001; - -static const uint NumLights = 3; - -// Constant normal incidence Fresnel factor for all dielectrics. -static const float3 Fdielectric = 0.04; - -// UNIFORM CONSTANTS -float4x4 viewProjectionMatrix; -float4x4 sceneRotationMatrix; - -float3 direction[NumLights]; -float3 radiance[NumLights]; - -float3 eyePosition; -int specularTextureLevels; +// A constant buffer that stores the three basic column-major matrices for composing geometry. +cbuffer ModelViewProjectionConstantBuffer : register(b0) +{ + matrix model; + matrix view; + matrix projection; +}; +// Per-vertex data used as input to the vertex shader. struct VertexShaderInput { - float3 position : POSITION; - float3 normal : NORMAL; - float3 tangent : TANGENT; - float3 binormal : BINORMAL; - float2 texcoord : TEXCOORD; + float4 position : POSITION; +#ifdef NORMALS + float3 normal : NORMAL; +#endif +#ifdef UV + float2 texcoord : TEXCOORD0; +#endif }; +// Per-pixel color data passed through the pixel shader. struct PixelShaderInput { - float4 pixelPosition : SV_POSITION; - float3 position : POSITION1; - float2 texcoord : TEXCOORD0; - float3 T : TEXCOORD1; - float3 B : TEXCOORD2; - float3 N : TEXCOORD3; + float4 position : SV_POSITION; + float3 poswithoutw : POSITION1; + +#ifdef NORMALS + float3 normal : NORMAL; +#endif + + float2 texcoord : TEXCOORD0; }; -sampler albedoTexture : register(s0); -sampler normalTexture : register(s1); -sampler metalnessTexture : register(s2); -sampler roughnessTexture : register(s3); -sampler specularTexture : register(s4); -sampler irradianceTexture : register(s5); -sampler specularBRDF_LUT : register(s6); - -// GGX/Towbridge-Reitz normal distribution function. -// Uses Disney's reparametrization of alpha = roughness^2. -float ndfGGX(float cosLh, float roughness) +PixelShaderInput main_vs(VertexShaderInput input) { - float alpha = roughness * roughness; - float alphaSq = alpha * alpha; + PixelShaderInput output; - float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; - return alphaSq / (PI * denom * denom); + // Transform the vertex position into projected space. + float4 pos = mul(input.position, model); + output.poswithoutw = float3(pos.xyz) / pos.w; + +#ifdef NORMALS + // If we have normals... + output.normal = normalize(mul(float4(input.normal.xyz, 0.0), model)); +#endif + +#ifdef UV + output.texcoord = input.texcoord; +#else + output.texcoord = float2(0.0f, 0.0f); +#endif + +#ifdef HAS_NORMALS +#ifdef HAS_TANGENTS + vec3 normalW = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0))); + vec3 tangentW = normalize(vec3(u_ModelMatrix * vec4(a_Tangent.xyz, 0.0))); + vec3 bitangentW = cross(normalW, tangentW) * a_Tangent.w; + v_TBN = mat3(tangentW, bitangentW, normalW); +#else // HAS_TANGENTS != 1 + v_Normal = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0))); +#endif +#endif + + // Transform the vertex position into projected space. + pos = mul(pos, view); + pos = mul(pos, projection); + output.position = pos; + + return output; } -// Single term for separable Schlick-GGX below. -float gaSchlickG1(float cosTheta, float k) +// +// This fragment shader defines a reference implementation for Physically Based Shading of +// a microfacet surface material defined by a glTF model. +// +// References: +// [1] Real Shading in Unreal Engine 4 +// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf +// [2] Physically Based Shading at Disney +// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf +// [3] README.md - Environment Maps +// https://github.com/KhronosGroup/glTF-WebGL-PBR/#environment-maps +// [4] "An Inexpensive BRDF Model for Physically based Rendering" by Christophe Schlick +// https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf + +#define NORMALS +#define UV +#define HAS_NORMALS +#define USE_IBL +#define USE_TEX_LOD + +DECLARE_TEXTURE(baseColourTexture, 0); +DECLARE_TEXTURE(normalTexture, 1); +DECLARE_TEXTURE(emissionTexture, 2); +DECLARE_TEXTURE(occlusionTexture, 3); +DECLARE_TEXTURE(metallicRoughnessTexture, 4); +DECLARE_CUBEMAP(envDiffuseTexture, 8); +DECLARE_TEXTURE(brdfLutTexture, 9); +DECLARE_CUBEMAP(envSpecularTexture, 10); + +cbuffer cbPerFrame : register(b0) { - return cosTheta / (cosTheta * (1.0 - k) + k); + float3 lightDir; + float3 lightColour; +}; + +cbuffer cbPerObject : register(b1) +{ + float normalScale; + float3 emissiveFactor; + float occlusionStrength; + float2 metallicRoughnessValues; + float4 baseColorFactor; + float3 camera; + + // debugging flags used for shader output of intermediate PBR variables + float4 scaleDiffBaseMR; + float4 scaleFGDSpec; + float4 scaleIBLAmbient; +}; + +#ifdef HAS_NORMALS +#ifdef HAS_TANGENTS +varying mat3 v_TBN; +#else +#endif +#endif + +// Encapsulate the various inputs used by the various functions in the shading equation +// We store values in this struct to simplify the integration of alternative implementations +// of the shading terms, outlined in the Readme.MD Appendix. +struct PBRInfo +{ + float NdotL; // cos angle between normal and light direction + float NdotV; // cos angle between normal and view direction + float NdotH; // cos angle between normal and half vector + float LdotH; // cos angle between light direction and half vector + float VdotH; // cos angle between view direction and half vector + float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) + float metalness; // metallic value at the surface + float3 reflectance0; // full reflectance color (normal incidence angle) + float3 reflectance90; // reflectance color at grazing angle + float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) + float3 diffuseColor; // color contribution from diffuse lighting + float3 specularColor; // color contribution from specular lighting +}; + +static const float M_PI = 3.141592653589793; +static const float c_MinRoughness = 0.04; + +float4 SRGBtoLINEAR(float4 srgbIn) +{ +#ifdef MANUAL_SRGB +#ifdef SRGB_FAST_APPROXIMATION + float3 linOut = pow(srgbIn.xyz,float3(2.2, 2.2, 2.2)); +#else //SRGB_FAST_APPROXIMATION + float3 bLess = step(float3(0.04045, 0.04045, 0.04045), srgbIn.xyz); + float3 linOut = lerp(srgbIn.xyz / float3(12.92, 12.92, 12.92), pow((srgbIn.xyz + float3(0.055, 0.055, 0.055)) / float3(1.055, 1.055, 1.055), float3(2.4, 2.4, 2.4)), bLess); +#endif //SRGB_FAST_APPROXIMATION + return float4(linOut,srgbIn.w);; +#else //MANUAL_SRGB + return srgbIn; +#endif //MANUAL_SRGB } -// Schlick-GGX approximation of geometric attenuation function using Smith's method. -float gaSchlickGGX(float cosLi, float cosLo, float roughness) +// Find the normal for this fragment, pulling either from a predefined normal map +// or from the interpolated mesh normal and tangent attributes. +float3 getNormal(float3 position, float3 normal, float2 uv) { - float r = roughness + 1.0; - float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. - return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); + // Retrieve the tangent space matrix +#ifndef HAS_TANGENTS + float3 pos_dx = ddx(position); + float3 pos_dy = ddy(position); + float3 tex_dx = ddx(float3(uv, 0.0)); + float3 tex_dy = ddy(float3(uv, 0.0)); + float3 t = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y); + +#ifdef HAS_NORMALS + float3 ng = normalize(normal); +#else + float3 ng = cross(pos_dx, pos_dy); +#endif + + t = normalize(t - ng * dot(ng, t)); + float3 b = normalize(cross(ng, t)); + row_major float3x3 tbn = float3x3(t, b, ng); + +#else // HAS_TANGENTS + mat3 tbn = v_TBN; +#endif + +#ifdef HAS_NORMALMAP + float3 n = SAMPLE_TEXTURE(normalTexture, uv).rgb; + + // Need to check the multiplication is equivalent.. + n = normalize(mul(((2.0 * n - 1.0) * float3(normalScale, normalScale, 1.0)), tbn)); +#else + float3 n = tbn[2].xyz; +#endif + + return n; } -// Shlick's approximation of the Fresnel factor. -float3 fresnelSchlick(float3 F0, float cosTheta) +#ifdef USE_IBL +// Calculation of the lighting contribution from an optional Image Based Light source. +// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1]. +// See our README.md on Environment Maps [3] for additional discussion. +float3 getIBLContribution(PBRInfo pbrInputs, float3 n, float3 reflection) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); + float mipCount = 9.0; // resolution of 512x512 + float lod = (pbrInputs.perceptualRoughness * mipCount); + + // retrieve a scale and bias to F0. See [1], Figure 3 + float2 val = float2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness); + float3 brdf = SRGBtoLINEAR(SAMPLE_TEXTURE(brdfLutTexture, val)).rgb; + + float3 diffuseLight = SRGBtoLINEAR(SAMPLE_CUBEMAP(envDiffuseTexture, n)).rgb; + +#ifdef USE_TEX_LOD + float4 reflectionWithLOD = float4(reflection, 0); + float3 specularLight = SRGBtoLINEAR(SAMPLE_CUBEMAP_LOD(envSpecularTexture, reflectionWithLOD)).rgb; +#else + float3 specularLight = SRGBtoLINEAR(SAMPLE_CUBEMAP(envSpecularTexture, reflection)).rgb; +#endif + + float3 diffuse = diffuseLight * pbrInputs.diffuseColor; + float3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y); + + // For presentation, this allows us to disable IBL terms + diffuse *= scaleIBLAmbient.x; + specular *= scaleIBLAmbient.y; + + return diffuse + specular; +} +#endif + +// Basic Lambertian diffuse +// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog +// See also [1], Equation 1 +float3 diffuse(PBRInfo pbrInputs) +{ + return pbrInputs.diffuseColor / M_PI; } -// Vertex shader -PixelShaderInput main_vs(VertexShaderInput vin) +// The following equation models the Fresnel reflectance term of the spec equation (aka F()) +// Implementation of fresnel from [4], Equation 15 +float3 specularReflection(PBRInfo pbrInputs) { - PixelShaderInput vout; - vout.position = mul(sceneRotationMatrix, float4(vin.position, 1.0)).xyz; - vout.texcoord = float2(vin.texcoord.x, 1.0-vin.texcoord.y); - - // Pass tangent space basis vectors (for normal mapping). - float3 worldTangent = mul(vin.tangent, (float3x3) sceneRotationMatrix); - vout.T = normalize(worldTangent); - - float3 worldBinormal = mul(vin.binormal, (float3x3) sceneRotationMatrix); - vout.B = normalize(worldBinormal); - - float3 worldNormal = mul(vin.normal, (float3x3) sceneRotationMatrix); - vout.N = normalize(worldNormal); - - float4x4 mvpMatrix = mul(viewProjectionMatrix, sceneRotationMatrix); - vout.pixelPosition = mul(mvpMatrix, float4(vin.position, 1.0)); - return vout; + return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); } -// Pixel shader -float4 main_ps(PixelShaderInput pin) : SV_Target0 +// This calculates the specular geometric attenuation (aka G()), +// where rougher material will reflect less light back to the viewer. +// This implementation is based on [1] Equation 4, and we adopt their modifications to +// alphaRoughness as input as originally proposed in [2]. +float geometricOcclusion(PBRInfo pbrInputs) { - // Sample input textures to get shading model params. - float3 albedo = tex2D(albedoTexture, pin.texcoord).rgb; - float metalness = tex2D(metalnessTexture, pin.texcoord).r; - float roughness = tex2D(roughnessTexture, pin.texcoord).r; + float NdotL = pbrInputs.NdotL; + float NdotV = pbrInputs.NdotV; + float r = pbrInputs.alphaRoughness; - // Outgoing light direction (vector from world-space fragment position to the "eye"). - float3 Lo = normalize(eyePosition - pin.position); + float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); + float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); + return attenuationL * attenuationV; +} - // tranpose to transform tangent space => world - float3x3 TBN = transpose(float3x3(normalize(pin.T), normalize(pin.B), normalize(pin.N))); +// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) +// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz +// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. +float microfacetDistribution(PBRInfo pbrInputs) +{ + float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; + float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; + return roughnessSq / (M_PI * f * f); +} - // Get current fragment's normal and transform to world space. - float3 tangentNormal = normalize(2.0 * tex2D(normalTexture, pin.texcoord).rgb - 1.0); - - // world normal - float3 N = normalize(mul(TBN, tangentNormal)); - - // Angle between surface normal and outgoing light direction. - float cosLo = max(0.0, dot(N, Lo)); - - // Specular reflection vector. - float3 Lr = 2.0 * cosLo * N - Lo; +float4 main_ps(PixelShaderInput input) : SV_TARGET +{ + // Metallic and Roughness material properties are packed together + // In glTF, these factors can be specified by fixed scalar values + // or from a metallic-roughness map + float perceptualRoughness = metallicRoughnessValues.y; + float metallic = metallicRoughnessValues.x; - // Fresnel reflectance at normal incidence (for metals use albedo color). - float3 F0 = lerp(Fdielectric, albedo, metalness); +#ifdef HAS_METALROUGHNESSMAP + // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. + // This layout intentionally reserves the 'r' channel for (optional) occlusion map data + float4 mrSample = SAMPLE_TEXTURE(metallicRoughnessTexture, input.texcoord); - // Direct lighting calculation for analytical lights. - float3 directLighting = 0.0; - for(uint i=0; i*eZNzSN85JOOwjHt``kUg=J-jKMyG_Ic>Kd>(K zBR*~^-vhAcnywY<`BJI4JXhYhvASNU)g(FS6HF~NjymxNHX@DbL)hOz%cA!<|ALJ; zxb|88@x)qZ9T(PbUMya}zELZ5KnbQzWq$&;;>WwN7mXji$!}bh)sqY z%aiCt=9Oz`$GL;co~6`Jsd0?YMxwnt1Ll|WrGm9*-=?xZDh_k#&VieSOZnw`87OH- z`aq4`I-kPsh3+p%PtI&!6hiV+RyI=%s_hru>_GOFWy0d8SdU*kS4h{e9J&<)pVm*^sHzb~QBnd4kk)=>2VC~u<(ao}mlkN6l z`<9tmxG?=P#0Ttzj(#bFvY$YA4@?3l9=i|FY%M}a0zqKDW=^sLG=XaZC@Jz8ly+0N zCNY!1eAWDb9iWoc4MO*-eZHe^8@dE$MiUvkV|7DTcK|*8{nqM+yL5lDx=fcYepUrQ z5n!j$|50@GeQ<9tW#=74MOe2`eWblAQS)yKz}Ds`+cTOWbRegu9AErEZ`#VXn++HI?I=iGZ< zw_|lK4z!AA`j5Bn{BzQUI5!m!^^>vRyz%!R@BE=#|7gPey# z-uasPOul#~>iN)@oRj2*7&D6o-#MAPTxp|u85fvJ7e?BVB*t-ZwJ*kHev_s%AI>|2 zMxt#z=W)N1bHT-NNbM>}jqeNp!+n zrPuey=&lRNC4F#R;~4Z>YYe^~yD(@x+E&MKIqmEZjh$HK9!~R-_$Z~@`aux=jNB4F*J=}CQ zrZLdrw+F$G+p+zyZ#94uL(}ln3X`VAdQIY~19CgWJ*kN~Ky}i}cy#{wPmdOv6@Ar&~>8#JXDhv|kgCe{00-T6{7G zz}m5&nDKTI0$mtkoE2Mm#f>fx1}%Ud;l`$V%L>pDG%5hY1tgmp7JPa4YdGVCeddSA-*9tSvP%V z7#LdN0P2QwXWg=<;0w*=8t;@CzuUY5`y}jH%Y(koSUa?*j`4jhg&D-7Kh`1Z9_Lk) zHlphXPdx0yJX0KpcW; zD7UFocI_TJ$(gpp_uk0P)w`YB)(Nbe;2i=siK%T2#&&EvxU>zv1vr~@e>jA?5bqh z*jnFCCLZU{$vod$4f=C3&ze?){uqyECuH0Dv5Zc3=LP4&^N;<`)?y8@XZ=`5N)6KI~m9D_ZK0K;k$SAn?dx8 qk@JuBiiozHL;SZ%`o#Ga5$!mKuHQW&(~kR7h<2QteAm&x0sk9jwc3RM literal 7240 zcmchbO>CS;8OLWo>|GlZ(-KN31uQiZMM9C&7SUY5I3XmGD;X!2a;TIp_CgjpUTfD0 zLF(a+#IX_!^nk==E%kux9y#;?DiT8CSP3L@jL>`Nu?G%~RQcuqo0(^KcGvl65;6Ad z`+UvwHP6gD@04bW!?!EWHy&m6H$4`9s(R3$w0%hmZnm1gSnafb-rU%2wYOhy>~>nW z&}(+@Bu1W=-Q&{P-Dqw%*V?;{#4I*T>WloSfg8;e9`Z9Q{${HaLP^GEkEw4)Iy#Nb zR%3gkiD~oY{irXc0b83B(EMd{wcTwIou5B=A0^`e4Sh~lmCMBkHtFB?Gr4%wPyviIyM7CXDrS|CM0S2Zn~G(&Yi!y zvVIvhdB*Pen!&aCBk0qjtv0&d(~-BjyyiYH7(Lj=EV>rdt-U4S_lD^CvHF}%u;3-Z zZzOn6@OugV55akYSLNJ^BzKE~&n5U9f_D=9ZNdEn|Fhr^6Z|8=pCY8J+SNm`{S4vY8Q*~>pzenIE~N=5se9^h&V z)YK;eP*>7wsYeAT^z`DQpA`J6`lhE%OHT3YCsQYv6*nc?bM9RjYJc*yvS_o8+|urN zT1m9&!CL%8w6aEHo1A0gxSmi-?wETC2h?8kH0(a_Rw9i#sHhT3?pe1LX>aLSb~VwQ zdq;34V04`x98}$$`22-7+_Mf2O5SepC$c}&Bi(mQm)RLtG`Y4WeVf<|4kl$r_m)Y% ztzf6I=2I*kH?emdp?_jcKS0KIiSZnpj>wPu>%jrDmCnUZ_v$NG7v1ZvjZVAU{^{<* zOKaa+xUh0*W#Q7b#%8m#aJGGYr?n;E%&C{poI3NJmruQN`t)h{W9O#oZoYqK{^FAI z{5{S5_tlr6&xj8E-rv9ZUAOwTA2AQmXFc65iT44t*?+(Imv8uzFJ;cvdcad+DrXTc zWvZW{RW2SjlVry8LzeuPIJ&V$3tsUzJYd2l;(3 zXMDzJX=zw3n|66$_;2bSuX{Q8HSafg;cej?ba3h1Lznr+*pjP9-||d*lVU3gFBHpu zKlon9rtfL&6~zv}?8*Z^zL#B9_`2`pVki@6$OM~(WcFoeeb4M*m!9JCv9I@%@{gaR zJnSH=8u0NECoyR!%`{hvKgYL4*_jh&L)flJoxoi}B(5BomuLD1(UC-;SNiM{7PdxM-6Fv97lBrKx+Xtv&2gW41J zPRf^=CYSUbTVCt9lC%ODr^gR^(-N1PbIUB)^HISTcueJsk5w{@QfY8V;iWUvmv z<)5b=k*mQvu-t@Pgf*MiF!@C$#2Vl*f5aNc)H>)=gN;_z`qkF4B1o zv|&ChUaOmckLHrvv-d)}=USbv5B8<>U4f2(@B7*fIAg%qecgn$7RKBDS=Ras{^j0o zT%Uuw3Ha##$vm*eSc~kRX>KeRz-xu-qRdtMi8tvv|p8XGtUzb+b zet4-=zHe{7?%%imwX5PS4+F?<4XIC!zdz-`JwbJ=3D`&}F)vfl)BaJ8b zIW(gI*Z5HzmwhIXy{y?nHrQTTFda4?apN1TePKec)|hXMhfgydRd;{Asci6JG`24W zRo>sZ2tSHmi;XAw8PCJ%p4^geE#k)QFL#l76mMKp2W zoP90v;c4dV>xtep50IZEXS!GMjrx7uoROc8)#lZBLvk0y-H{7-MjvYzj8X|6z8CNr7{2M&nPo&bc&Z!xQFN1oaoy50q8mKb4gM&)$*JiM vxt&*@)7<(qVBd}8cAm4MXv5s9CZs3N^bOc2|IDY(Z#|tkmAn7+sjL41pLhSJ From f18a8f38be2766f8f4e674f53d88f44fc62caaab Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Fri, 31 Jul 2020 01:55:29 -0700 Subject: [PATCH 03/16] more PBR implementation --- Effects/PBREffect.cs | 21 ++---- Effects/{pbr.fx => PBREffect.fx} | 0 Effects/{pbr.fxo => PBREffect.fxb} | Bin Importer.cs | 117 ++++++++++++++++++++++++++--- Model.cs | 12 --- Resources.cs | 33 ++++++++ Smuggler.csproj | 6 ++ 7 files changed, 153 insertions(+), 36 deletions(-) rename Effects/{pbr.fx => PBREffect.fx} (100%) rename Effects/{pbr.fxo => PBREffect.fxb} (100%) create mode 100644 Resources.cs diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index b50d027..4472bd7 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -47,7 +47,6 @@ namespace Smuggler float occlusionStrength; Vector2 metallicRoughnessValue; Vector4 baseColorFactor; - Vector3 cameraLook; public Matrix World { @@ -66,6 +65,11 @@ namespace Smuggler { view = value; viewParam.SetValue(view); + cameraLookParam.SetValue(-new Vector3( + view.M13, + view.M23, + view.M33 + )); } } @@ -140,16 +144,6 @@ namespace Smuggler } } - public Vector3 CameraLook - { - get { return cameraLook; } - set - { - cameraLook = value; - cameraLookParam.SetValue(cameraLook); - } - } - public Texture2D BaseColourTexture { get { return baseColourTextureParam.GetValueTexture2D(); } @@ -198,11 +192,11 @@ namespace Smuggler set { envSpecularTextureParam.SetValue(value); } } - public PBREffect(GraphicsDevice graphicsDevice, byte[] effectCode) : base(graphicsDevice, effectCode) + public PBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.PBREffect) { modelParam = Parameters["model"]; viewParam = Parameters["view"]; - projectionParam = Parameters["param"]; + projectionParam = Parameters["projection"]; lightDirParam = Parameters["lightDir"]; lightColourParam = Parameters["lightColour"]; @@ -260,7 +254,6 @@ namespace Smuggler OcclusionStrength = cloneSource.OcclusionStrength; MetallicRoughnessValue = cloneSource.MetallicRoughnessValue; BaseColorFactor = cloneSource.BaseColorFactor; - CameraLook = cloneSource.CameraLook; BaseColourTexture = cloneSource.BaseColourTexture; NormalTexture = cloneSource.NormalTexture; diff --git a/Effects/pbr.fx b/Effects/PBREffect.fx similarity index 100% rename from Effects/pbr.fx rename to Effects/PBREffect.fx diff --git a/Effects/pbr.fxo b/Effects/PBREffect.fxb similarity index 100% rename from Effects/pbr.fxo rename to Effects/PBREffect.fxb diff --git a/Importer.cs b/Importer.cs index 43ae13c..8cda1cc 100644 --- a/Importer.cs +++ b/Importer.cs @@ -32,14 +32,6 @@ namespace Smuggler var model = new Model(meshes.ToArray()); - /* TODO: BasicEffect only supports one texture but GLTF supports several */ - - if (sharpModel.LogicalTextures.Count > 0) - { - var fnaTexture = Texture2D.FromStream(graphicsDevice, sharpModel.LogicalTextures[0].PrimaryImage.Content.Open()); - model.SetTexture(fnaTexture); - } - return model; } @@ -145,9 +137,114 @@ namespace Smuggler ImportVertexPositionTexture(primitive, vertexBuffer, indices, positions); } - /* TODO: We need a new Effect subclass to support some GLTF features */ + var effect = new PBREffect(graphicsDevice); - var effect = new PBREffect(graphicsDevice, File.ReadAllBytes("Effects/pbr.fxo")); + if (primitive.Material != null) + { + var normalChannel = primitive.Material.FindChannel("Normal"); + if (normalChannel.HasValue) + { + if (normalChannel.Value.Texture != null) + { + effect.NormalTexture = Texture2D.FromStream( + graphicsDevice, + normalChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + + effect.NormalScale = normalChannel.Value.Parameter.X; + } + + var occlusionChannel = primitive.Material.FindChannel("Occlusion"); + if (occlusionChannel.HasValue) + { + if (occlusionChannel.Value.Texture != null) + { + effect.OcclusionTexture = Texture2D.FromStream( + graphicsDevice, + occlusionChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + + effect.OcclusionStrength = occlusionChannel.Value.Parameter.X; + } + + var emissiveChannel = primitive.Material.FindChannel("Emissive"); + if (emissiveChannel.HasValue) + { + if (emissiveChannel.Value.Texture != null) + { + effect.EmissionTexture = Texture2D.FromStream( + graphicsDevice, + emissiveChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + + var parameter = emissiveChannel.Value.Parameter; + + effect.EmissiveFactor = new Vector3( + parameter.X, + parameter.Y, + parameter.Z + ); + } + + var baseColorChannel = primitive.Material.FindChannel("BaseColor"); + if (baseColorChannel.HasValue) + { + if (baseColorChannel.Value.Texture != null) + { + effect.BaseColourTexture = Texture2D.FromStream( + graphicsDevice, + baseColorChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + + var parameter = emissiveChannel.Value.Parameter; + + effect.BaseColorFactor = new Vector4( + parameter.X, + parameter.Y, + parameter.Z, + parameter.W + ); + } + + var metallicRoughnessChannel = primitive.Material.FindChannel("MetallicRoughness"); + if (metallicRoughnessChannel.HasValue) + { + if (metallicRoughnessChannel.Value.Texture != null) + { + effect.MetallicRoughnessTexture = Texture2D.FromStream( + graphicsDevice, + metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + + var parameter = metallicRoughnessChannel.Value.Parameter; + + effect.MetallicRoughnessValue = new Vector2( + parameter.X, + parameter.Y + ); + } + } + + effect.Light = new PBRLight(new Vector3(-0.5f, -0.5f, -0.5f), Color.White.ToVector3()); + + /* FIXME: how to load cube maps from GLTF? */ + /* + var diffuseChannel = primitive.Material.FindChannel("Diffuse"); + if (diffuseChannel.HasValue) + { + } + + var specularChannel = primitive.Material.FindChannel("SpecularGlossiness"); + if (specularChannel.HasValue) + { + } + */ + return new MeshPart( vertexBuffer, diff --git a/Model.cs b/Model.cs index ed3ec25..eeba250 100644 --- a/Model.cs +++ b/Model.cs @@ -13,18 +13,6 @@ namespace Smuggler Meshes = meshes; } - public void SetTexture(Texture2D texture) - { - foreach (var mesh in Meshes) - { - foreach (var meshPart in mesh.MeshParts) - { - meshPart.Effect.TextureEnabled = true; - meshPart.Effect.Texture = texture; - } - } - } - public void Draw(GraphicsDevice graphicsDevice, Matrix world, Matrix view, Matrix projection) { foreach (var mesh in Meshes) diff --git a/Resources.cs b/Resources.cs new file mode 100644 index 0000000..53fc5ea --- /dev/null +++ b/Resources.cs @@ -0,0 +1,33 @@ +using System.IO; + +namespace Smuggler +{ + internal class Resources + { + public static byte[] PBREffect + { + get + { + if (pbrEffect == null) + { + pbrEffect = GetResource("PBREffect"); + } + return pbrEffect; + } + } + + private static byte[] pbrEffect; + + private static byte[] GetResource(string name) + { + Stream stream = typeof(Resources).Assembly.GetManifestResourceStream( + "Smuggler.Resources." + name + ".fxb" + ); + using (MemoryStream ms = new MemoryStream()) + { + stream.CopyTo(ms); + return ms.ToArray(); + } + } + } +} diff --git a/Smuggler.csproj b/Smuggler.csproj index fafb0a4..59eef25 100644 --- a/Smuggler.csproj +++ b/Smuggler.csproj @@ -17,5 +17,11 @@ + + + + Smuggler.Resources.PBREffect.fxb + + From 37b45caea2436205472b0db639f970ae3ad249cf Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Fri, 31 Jul 2020 13:57:07 -0700 Subject: [PATCH 04/16] minor PBR effect tweak --- Effects/PBREffect.fx | 2 +- Effects/PBREffect.fxb | Bin 8060 -> 7552 bytes Importer.cs | 7 +++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index ca57701..9d49a36 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -92,7 +92,7 @@ PixelShaderInput main_vs(VertexShaderInput input) #define NORMALS #define UV #define HAS_NORMALS -#define USE_IBL +// #define USE_IBL #define USE_TEX_LOD DECLARE_TEXTURE(baseColourTexture, 0); diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index 3a2f02cb8b8597c6a34ceba7917ec82d8724180d..c6d92be11767fad03ad71c8ec1136836565fdd26 100644 GIT binary patch delta 1088 zcmY*YO=}cE5Url=b%*)fgq>YY0ve(ai8m1sqNsr!BnJft1uyy!^cQUB7)1>9ADDxu z*~`j;=*g=GFMv)uX^(LmbozvF&#vR zAt)NiT6;{iVtAi%fPI)Zit2-$>dIjaT)xVwtS~;*2gt8E?5EMSF|V<2&Y+O@c+GW+ z^dir29SLrQV;oQq>()fnh_2hOO&_;ro)0O#~@i03poHZBG$cg{G2XlXPZAqanb5E(eA@IG*y z0>@%xc&c1T#2iWdk8^6hd$;fQPBa-S%23B<8q>x6JM6|?!?BFM3ykZOE93&kaEt4A zj=g(~x~%xK;3hS40<3}2G=x#dSL8X#VT^yS%6%%XZp>mB5gKSYSsc4WC(Z(H3h`np z$b0K26GO1B`1=DVc}nz-#SqaipT`Hc6*~sE%!8>_aRGs4VrsvxjndeACCH`r_u7_9 X?YZ@>B3;Tf+;%`=X!6;E^&R~WIflCRbnm7*whqq~AXz=EJ4LKpb~F5C#x@%!#f(sshlJ?A^$`R=**obckm%kRB>yXlLF z9mm`8qD$LnT-i8-09-H-UYHVM#$4-opBgMaPybw&Sv&0eoZFEg3SrQ?SXK zFgy>~QMsM+=9Szkk?LwdG$t8Gg!6fET1uBcE+>s27Fh`thwzF8>6QBnkVnSRH{?tx=T zIi!YzmH1VoM}HD=TS~_Fyk6wO7s(jDCq15V76KLyZ*>CcMx(fg4T6%tScwhs4ii}n zb}n5RK9^x(w66`<+9^(dSJBie1N{~fFltf z0z(+OvI)q >*)h|^E`wwH3L#r9|6<1(f*%%z_- zZSI*@AfJA@jd?*oAuN_FR+xi0d+(z6F7PaR&)Yjl;9Mldajw{655;t&d*E|cI7_*7 zRyYde6Jr7NY5O>jdYmQBZrjI!4D`VaY!<{IZt5_x1P)t6tj|LMD56DC(;fzTGcPGC@o^zuNPEN SAF3b2f1_Se!FsDc?)(Sf-wz@H diff --git a/Importer.cs b/Importer.cs index 8cda1cc..ce4b783 100644 --- a/Importer.cs +++ b/Importer.cs @@ -200,7 +200,7 @@ namespace Smuggler ); } - var parameter = emissiveChannel.Value.Parameter; + var parameter = baseColorChannel.Value.Parameter; effect.BaseColorFactor = new Vector4( parameter.X, @@ -230,7 +230,10 @@ namespace Smuggler } } - effect.Light = new PBRLight(new Vector3(-0.5f, -0.5f, -0.5f), Color.White.ToVector3()); + effect.Light = new PBRLight( + new Vector3(0.5f, 0.5f, -0.5f), + new Vector3(10f, 10f, 10f) + ); /* FIXME: how to load cube maps from GLTF? */ /* From 4b36860b6288b1cd27b78c210699fa54c66df50c Mon Sep 17 00:00:00 2001 From: Evan Hemsley <2342303+ehemsley@users.noreply.github.com> Date: Sat, 1 Aug 2020 03:23:20 -0700 Subject: [PATCH 05/16] trying stuff but the shading still seems to be model-relative --- Effects/PBREffect.cs | 260 ++++++++++--------- Effects/PBREffect.fx | 457 ++++++++-------------------------- Effects/PBREffect.fxb | Bin 7552 -> 8852 bytes Effects/ReferencePBREffect.fx | 410 ++++++++++++++++++++++++++++++ Importer.cs | 163 ++++++------ Smuggler.csproj | 3 +- 6 files changed, 743 insertions(+), 550 deletions(-) create mode 100644 Effects/ReferencePBREffect.fx diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 4472bd7..ba73003 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -5,48 +5,81 @@ namespace Smuggler { public struct PBRLight { - public Vector3 direction; - public Vector3 colour; + public Vector3 position; + public Vector3 color; - public PBRLight(Vector3 direction, Vector3 colour) + public PBRLight(Vector3 position, Vector3 colour) { - this.direction = direction; - this.colour = colour; + this.position = position; + this.color = colour; + } + } + + public class PBRLightCollection + { + private readonly Vector3[] positions = new Vector3[4]; + private readonly Vector3[] colors = new Vector3[4]; + + readonly EffectParameter lightPositionsParam; + readonly EffectParameter lightColorsParam; + + public PBRLightCollection(EffectParameter lightPositionsParam, EffectParameter lightColorsParam) + { + this.lightPositionsParam = lightPositionsParam; + this.lightColorsParam = lightColorsParam; + } + + public PBRLight this[int i] + { + get { return new PBRLight(positions[i], colors[i]); } + set + { + positions[i] = value.position; + colors[i] = value.color; + lightPositionsParam.SetValue(positions); + lightColorsParam.SetValue(colors); + } } } public class PBREffect : Effect { - readonly EffectParameter modelParam; - readonly EffectParameter viewParam; - readonly EffectParameter projectionParam; - readonly EffectParameter lightDirParam; - readonly EffectParameter lightColourParam; - readonly EffectParameter normalScaleParam; - readonly EffectParameter emissiveFactorParam; - readonly EffectParameter occlusionStrengthParam; - readonly EffectParameter metallicRoughnessValuesParam; - readonly EffectParameter baseColorFactorParam; - readonly EffectParameter cameraLookParam; + EffectParameter worldParam; + EffectParameter viewParam; + EffectParameter projectionParam; + EffectParameter worldViewProjectionParam; + EffectParameter worldInverseTransposeParam; - readonly EffectParameter baseColourTextureParam; - readonly EffectParameter normalTextureParam; - readonly EffectParameter emissionTextureParam; - readonly EffectParameter occlusionTextureParam; - readonly EffectParameter metallicRoughnessTextureParam; - readonly EffectParameter envDiffuseTextureParam; - readonly EffectParameter brdfLutTextureParam; - readonly EffectParameter envSpecularTextureParam; + EffectParameter baseColorTextureParam; + EffectParameter normalTextureParam; + EffectParameter emissionTextureParam; + EffectParameter occlusionTextureParam; + EffectParameter metallicRoughnessTextureParam; + EffectParameter envDiffuseTextureParam; + EffectParameter brdfLutTextureParam; + EffectParameter envSpecularTextureParam; + + EffectParameter lightPositionsParam; + EffectParameter lightColorsParam; + + EffectParameter albedoParam; + EffectParameter metallicParam; + EffectParameter roughnessParam; + EffectParameter aoParam; + + EffectParameter eyePositionParam; Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; - PBRLight light = new PBRLight(); - float normalScale = 1; - Vector3 emissiveFactor; - float occlusionStrength; - Vector2 metallicRoughnessValue; - Vector4 baseColorFactor; + PBRLightCollection pbrLightCollection; + + Vector3 albedo; + float metallic; + float roughness; + float ao; + + // FIXME: lazily set properties for performance public Matrix World { @@ -54,7 +87,9 @@ namespace Smuggler set { world = value; - modelParam.SetValue(world); + worldParam.SetValue(world); + worldViewProjectionParam.SetValue(world * view * projection); + worldInverseTransposeParam.SetValue(Matrix.Transpose(Matrix.Invert(world))); } } @@ -65,11 +100,8 @@ namespace Smuggler { view = value; viewParam.SetValue(view); - cameraLookParam.SetValue(-new Vector3( - view.M13, - view.M23, - view.M33 - )); + worldViewProjectionParam.SetValue(world * view * projection); + eyePositionParam.SetValue(Matrix.Invert(view).Translation); } } @@ -79,75 +111,61 @@ namespace Smuggler set { projection = value; - projectionParam.SetValue(value); + projectionParam.SetValue(projection); + worldViewProjectionParam.SetValue(world * view * projection); } } - public PBRLight Light + public PBRLightCollection Lights { - get { return light; } - set - { - light = value; - lightDirParam.SetValue(light.direction); - lightColourParam.SetValue(light.colour); - } + get { return pbrLightCollection; } + internal set { pbrLightCollection = value; } } - public float NormalScale + public Vector3 Albedo { - get { return normalScale; } + get { return albedo; } set { - normalScale = value; - normalScaleParam.SetValue(normalScale); + albedo = value; + albedoParam.SetValue(albedo); } } - public Vector3 EmissiveFactor + public float Metallic { - get { return emissiveFactor; } - set - { - emissiveFactor = value; - emissiveFactorParam.SetValue(emissiveFactor); - } - } - - public float OcclusionStrength - { - get { return occlusionStrength; } + get { return metallic; } set { - occlusionStrength = value; - occlusionStrengthParam.SetValue(occlusionStrength); + metallic = value; + metallicParam.SetValue(metallic); } } - public Vector2 MetallicRoughnessValue + public float Roughness { - get { return metallicRoughnessValue; } + get { return roughness; } set { - metallicRoughnessValue = value; - metallicRoughnessValuesParam.SetValue(metallicRoughnessValue); + roughness = value; + roughnessParam.SetValue(roughness); } } - public Vector4 BaseColorFactor + public float AO { - get { return baseColorFactor; } + get { return ao; } set { - baseColorFactor = value; - baseColorFactorParam.SetValue(baseColorFactor); + ao = value; + aoParam.SetValue(ao); } } public Texture2D BaseColourTexture { - get { return baseColourTextureParam.GetValueTexture2D(); } - set { baseColourTextureParam.SetValue(value); } + get { return baseColorTextureParam.GetValueTexture2D(); } + set { baseColorTextureParam.SetValue(value); } } public Texture2D NormalTexture @@ -194,66 +212,31 @@ namespace Smuggler public PBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.PBREffect) { - modelParam = Parameters["model"]; - viewParam = Parameters["view"]; - projectionParam = Parameters["projection"]; + CacheEffectParameters(null); - lightDirParam = Parameters["lightDir"]; - lightColourParam = Parameters["lightColour"]; - - normalScaleParam = Parameters["normalScale"]; - emissiveFactorParam = Parameters["emissiveFactor"]; - occlusionStrengthParam = Parameters["occlusionStrength"]; - metallicRoughnessValuesParam = Parameters["metallicRoughnessValues"]; - baseColorFactorParam = Parameters["baseColorFactor"]; - cameraLookParam = Parameters["camera"]; - - baseColourTextureParam = Parameters["baseColourTexture"]; - normalTextureParam = Parameters["normalTexture"]; - emissionTextureParam = Parameters["emissionTexture"]; - occlusionTextureParam = Parameters["occlusionTexture"]; - metallicRoughnessTextureParam = Parameters["metallicRoughnessTexture"]; - envDiffuseTextureParam = Parameters["envDiffuseTexture"]; - brdfLutTextureParam = Parameters["brdfLutTexture"]; - envSpecularTextureParam = Parameters["envSpecularTexture"]; + pbrLightCollection = new PBRLightCollection( + Parameters["LightPositions"], + Parameters["LightColors"] + ); } protected PBREffect(PBREffect cloneSource) : base(cloneSource) { - modelParam = Parameters["model"]; - viewParam = Parameters["view"]; - projectionParam = Parameters["param"]; - - lightDirParam = Parameters["lightDir"]; - lightColourParam = Parameters["lightColour"]; - - normalScaleParam = Parameters["normalScale"]; - emissiveFactorParam = Parameters["emissiveFactor"]; - occlusionStrengthParam = Parameters["occlusionStrength"]; - metallicRoughnessValuesParam = Parameters["metallicRoughnessValues"]; - baseColorFactorParam = Parameters["baseColorFactor"]; - cameraLookParam = Parameters["camera"]; - - baseColourTextureParam = Parameters["baseColourTexture"]; - normalTextureParam = Parameters["normalTexture"]; - emissionTextureParam = Parameters["emissionTexture"]; - occlusionTextureParam = Parameters["occlusionTexture"]; - metallicRoughnessTextureParam = Parameters["metallicRoughnessTexture"]; - envDiffuseTextureParam = Parameters["envDiffuseTexture"]; - brdfLutTextureParam = Parameters["brdfLutTexture"]; - envSpecularTextureParam = Parameters["envSpecularTexture"]; + CacheEffectParameters(cloneSource); World = cloneSource.World; View = cloneSource.View; Projection = cloneSource.Projection; - Light = cloneSource.Light; + Lights = new PBRLightCollection( + Parameters["LightPositions"], + Parameters["LightColors"] + ); - NormalScale = cloneSource.normalScale; - EmissiveFactor = cloneSource.EmissiveFactor; - OcclusionStrength = cloneSource.OcclusionStrength; - MetallicRoughnessValue = cloneSource.MetallicRoughnessValue; - BaseColorFactor = cloneSource.BaseColorFactor; + for (int i = 0; i < 4; i++) + { + Lights[i] = cloneSource.Lights[i]; + } BaseColourTexture = cloneSource.BaseColourTexture; NormalTexture = cloneSource.NormalTexture; @@ -263,6 +246,11 @@ namespace Smuggler EnvDiffuseTexture = cloneSource.EnvDiffuseTexture; BRDFLutTexture = cloneSource.BRDFLutTexture; EnvSpecularTexture = cloneSource.EnvSpecularTexture; + + Albedo = cloneSource.Albedo; + Metallic = cloneSource.Metallic; + Roughness = cloneSource.Roughness; + AO = cloneSource.AO; } public override Effect Clone() @@ -275,5 +263,33 @@ namespace Smuggler { base.OnApply(); } + + void CacheEffectParameters(PBREffect cloneSource) + { + worldParam = Parameters["World"]; + viewParam = Parameters["View"]; + projectionParam = Parameters["Projection"]; + worldViewProjectionParam = Parameters["WorldViewProjection"]; + worldInverseTransposeParam = Parameters["WorldInverseTranspose"]; + + baseColorTextureParam = Parameters["BaseColorTexture"]; + normalTextureParam = Parameters["NormalTexture"]; + emissionTextureParam = Parameters["EmissionTexture"]; + occlusionTextureParam = Parameters["OcclusionTexture"]; + metallicRoughnessTextureParam = Parameters["MetallicRoughnessTexture"]; + envDiffuseTextureParam = Parameters["EnvDiffuseTexture"]; + brdfLutTextureParam = Parameters["BrdfLutTexture"]; + envSpecularTextureParam = Parameters["EnvSpecularTexture"]; + + lightPositionsParam = Parameters["LightPositions"]; + lightColorsParam = Parameters["LightColors"]; + + albedoParam = Parameters["Albedo"]; + metallicParam = Parameters["Metallic"]; + roughnessParam = Parameters["Roughness"]; + aoParam = Parameters["AO"]; + + eyePositionParam = Parameters["EyePosition"]; + } } } diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index 9d49a36..e26bd49 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -1,408 +1,159 @@ +#include "Macros.fxh" //from FNA -#include "Macros.fxh" +static const float PI = 3.141592653589793; -#define NORMALS -#define UV +// Transformation Matrices -// A constant buffer that stores the three basic column-major matrices for composing geometry. -cbuffer ModelViewProjectionConstantBuffer : register(b0) -{ - matrix model; - matrix view; - matrix projection; -}; +float4x4 World; +float4x4 View; +float4x4 Projection; + +float4x4 WorldViewProjection; +float4x3 WorldInverseTranspose; + +// Samplers + +DECLARE_TEXTURE(BaseColorTexture, 0); +DECLARE_TEXTURE(NormalTexture, 1); +DECLARE_TEXTURE(EmissionTexture, 2); +DECLARE_TEXTURE(OcclusionTexture, 3); +DECLARE_TEXTURE(MetallicRoughnessTexture, 4); +DECLARE_CUBEMAP(EnvDiffuseTexture, 8); +DECLARE_TEXTURE(BrdfLutTexture, 9); +DECLARE_CUBEMAP(EnvSpecularTexture, 10); + +// Light Info +float3 LightPositions[4]; +float3 LightColors[4]; + +// PBR Values +float3 Albedo; +float Metallic; +float Roughness; +float AO; + +float3 EyePosition; -// Per-vertex data used as input to the vertex shader. struct VertexShaderInput { - float4 position : POSITION; -#ifdef NORMALS - float3 normal : NORMAL; -#endif -#ifdef UV - float2 texcoord : TEXCOORD0; -#endif + float4 Position : POSITION; + float3 Normal : NORMAL; + float2 TexCoord : TEXCOORD0; }; -// Per-pixel color data passed through the pixel shader. struct PixelShaderInput { - float4 position : SV_POSITION; - float3 poswithoutw : POSITION1; - -#ifdef NORMALS - float3 normal : NORMAL; -#endif - - float2 texcoord : TEXCOORD0; + float4 Position : SV_POSITION; + float2 TexCoord : TEXCOORD0; + float3 PositionWS : TEXCOORD1; + float3 NormalWS : TEXCOORD2; }; PixelShaderInput main_vs(VertexShaderInput input) { PixelShaderInput output; - // Transform the vertex position into projected space. - float4 pos = mul(input.position, model); - output.poswithoutw = float3(pos.xyz) / pos.w; - -#ifdef NORMALS - // If we have normals... - output.normal = normalize(mul(float4(input.normal.xyz, 0.0), model)); -#endif - -#ifdef UV - output.texcoord = input.texcoord; -#else - output.texcoord = float2(0.0f, 0.0f); -#endif - -#ifdef HAS_NORMALS -#ifdef HAS_TANGENTS - vec3 normalW = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0))); - vec3 tangentW = normalize(vec3(u_ModelMatrix * vec4(a_Tangent.xyz, 0.0))); - vec3 bitangentW = cross(normalW, tangentW) * a_Tangent.w; - v_TBN = mat3(tangentW, bitangentW, normalW); -#else // HAS_TANGENTS != 1 - v_Normal = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0))); -#endif -#endif - - // Transform the vertex position into projected space. - pos = mul(pos, view); - pos = mul(pos, projection); - output.position = pos; + output.PositionWS = mul(input.Position, World).xyz; + output.TexCoord = input.TexCoord; + output.NormalWS = normalize(mul(WorldInverseTranspose, input.Normal)); + output.Position = mul(input.Position, WorldViewProjection); return output; } -// -// This fragment shader defines a reference implementation for Physically Based Shading of -// a microfacet surface material defined by a glTF model. -// -// References: -// [1] Real Shading in Unreal Engine 4 -// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf -// [2] Physically Based Shading at Disney -// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf -// [3] README.md - Environment Maps -// https://github.com/KhronosGroup/glTF-WebGL-PBR/#environment-maps -// [4] "An Inexpensive BRDF Model for Physically based Rendering" by Christophe Schlick -// https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf - -#define NORMALS -#define UV -#define HAS_NORMALS -// #define USE_IBL -#define USE_TEX_LOD - -DECLARE_TEXTURE(baseColourTexture, 0); -DECLARE_TEXTURE(normalTexture, 1); -DECLARE_TEXTURE(emissionTexture, 2); -DECLARE_TEXTURE(occlusionTexture, 3); -DECLARE_TEXTURE(metallicRoughnessTexture, 4); -DECLARE_CUBEMAP(envDiffuseTexture, 8); -DECLARE_TEXTURE(brdfLutTexture, 9); -DECLARE_CUBEMAP(envSpecularTexture, 10); - -cbuffer cbPerFrame : register(b0) +float3 FresnelSchlick(float cosTheta, float3 F0) { - float3 lightDir; - float3 lightColour; -}; - -cbuffer cbPerObject : register(b1) -{ - float normalScale; - float3 emissiveFactor; - float occlusionStrength; - float2 metallicRoughnessValues; - float4 baseColorFactor; - float3 camera; - - // debugging flags used for shader output of intermediate PBR variables - float4 scaleDiffBaseMR; - float4 scaleFGDSpec; - float4 scaleIBLAmbient; -}; - -#ifdef HAS_NORMALS -#ifdef HAS_TANGENTS -varying mat3 v_TBN; -#else -#endif -#endif - -// Encapsulate the various inputs used by the various functions in the shading equation -// We store values in this struct to simplify the integration of alternative implementations -// of the shading terms, outlined in the Readme.MD Appendix. -struct PBRInfo -{ - float NdotL; // cos angle between normal and light direction - float NdotV; // cos angle between normal and view direction - float NdotH; // cos angle between normal and half vector - float LdotH; // cos angle between light direction and half vector - float VdotH; // cos angle between view direction and half vector - float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) - float metalness; // metallic value at the surface - float3 reflectance0; // full reflectance color (normal incidence angle) - float3 reflectance90; // reflectance color at grazing angle - float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) - float3 diffuseColor; // color contribution from diffuse lighting - float3 specularColor; // color contribution from specular lighting -}; - -static const float M_PI = 3.141592653589793; -static const float c_MinRoughness = 0.04; - -float4 SRGBtoLINEAR(float4 srgbIn) -{ -#ifdef MANUAL_SRGB -#ifdef SRGB_FAST_APPROXIMATION - float3 linOut = pow(srgbIn.xyz,float3(2.2, 2.2, 2.2)); -#else //SRGB_FAST_APPROXIMATION - float3 bLess = step(float3(0.04045, 0.04045, 0.04045), srgbIn.xyz); - float3 linOut = lerp(srgbIn.xyz / float3(12.92, 12.92, 12.92), pow((srgbIn.xyz + float3(0.055, 0.055, 0.055)) / float3(1.055, 1.055, 1.055), float3(2.4, 2.4, 2.4)), bLess); -#endif //SRGB_FAST_APPROXIMATION - return float4(linOut,srgbIn.w);; -#else //MANUAL_SRGB - return srgbIn; -#endif //MANUAL_SRGB + return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); } -// Find the normal for this fragment, pulling either from a predefined normal map -// or from the interpolated mesh normal and tangent attributes. -float3 getNormal(float3 position, float3 normal, float2 uv) +float DistributionGGX(float3 N, float3 H, float roughness) { - // Retrieve the tangent space matrix -#ifndef HAS_TANGENTS - float3 pos_dx = ddx(position); - float3 pos_dy = ddy(position); - float3 tex_dx = ddx(float3(uv, 0.0)); - float3 tex_dy = ddy(float3(uv, 0.0)); - float3 t = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y); + float a = roughness * roughness; + float a2 = a * a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH * NdotH; -#ifdef HAS_NORMALS - float3 ng = normalize(normal); -#else - float3 ng = cross(pos_dx, pos_dy); -#endif + float num = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; - t = normalize(t - ng * dot(ng, t)); - float3 b = normalize(cross(ng, t)); - row_major float3x3 tbn = float3x3(t, b, ng); - -#else // HAS_TANGENTS - mat3 tbn = v_TBN; -#endif - -#ifdef HAS_NORMALMAP - float3 n = SAMPLE_TEXTURE(normalTexture, uv).rgb; - - // Need to check the multiplication is equivalent.. - n = normalize(mul(((2.0 * n - 1.0) * float3(normalScale, normalScale, 1.0)), tbn)); -#else - float3 n = tbn[2].xyz; -#endif - - return n; + return num / denom; } -#ifdef USE_IBL -// Calculation of the lighting contribution from an optional Image Based Light source. -// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1]. -// See our README.md on Environment Maps [3] for additional discussion. -float3 getIBLContribution(PBRInfo pbrInputs, float3 n, float3 reflection) +float GeometrySchlickGGX(float NdotV, float roughness) { - float mipCount = 9.0; // resolution of 512x512 - float lod = (pbrInputs.perceptualRoughness * mipCount); - - // retrieve a scale and bias to F0. See [1], Figure 3 - float2 val = float2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness); - float3 brdf = SRGBtoLINEAR(SAMPLE_TEXTURE(brdfLutTexture, val)).rgb; + float r = (roughness + 1.0); + float k = (r * r) / 8.0; - float3 diffuseLight = SRGBtoLINEAR(SAMPLE_CUBEMAP(envDiffuseTexture, n)).rgb; + float num = NdotV; + float denom = NdotV * (1.0 - k) + k; -#ifdef USE_TEX_LOD - float4 reflectionWithLOD = float4(reflection, 0); - float3 specularLight = SRGBtoLINEAR(SAMPLE_CUBEMAP_LOD(envSpecularTexture, reflectionWithLOD)).rgb; -#else - float3 specularLight = SRGBtoLINEAR(SAMPLE_CUBEMAP(envSpecularTexture, reflection)).rgb; -#endif - - float3 diffuse = diffuseLight * pbrInputs.diffuseColor; - float3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y); - - // For presentation, this allows us to disable IBL terms - diffuse *= scaleIBLAmbient.x; - specular *= scaleIBLAmbient.y; - - return diffuse + specular; -} -#endif - -// Basic Lambertian diffuse -// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog -// See also [1], Equation 1 -float3 diffuse(PBRInfo pbrInputs) -{ - return pbrInputs.diffuseColor / M_PI; + return num / denom; } -// The following equation models the Fresnel reflectance term of the spec equation (aka F()) -// Implementation of fresnel from [4], Equation 15 -float3 specularReflection(PBRInfo pbrInputs) +float GeometrySmith(float3 N, float3 V, float3 L, float roughness) { - return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); + 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; } -// This calculates the specular geometric attenuation (aka G()), -// where rougher material will reflect less light back to the viewer. -// This implementation is based on [1] Equation 4, and we adopt their modifications to -// alphaRoughness as input as originally proposed in [2]. -float geometricOcclusion(PBRInfo pbrInputs) +// The case where we have no texture maps for any PBR data +float4 None(PixelShaderInput input) : SV_TARGET { - float NdotL = pbrInputs.NdotL; - float NdotV = pbrInputs.NdotV; - float r = pbrInputs.alphaRoughness; + float3 N = normalize(input.NormalWS); + float3 V = normalize(EyePosition - input.PositionWS); - float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); - float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); - return attenuationL * attenuationV; -} + float3 Lo = float3(0.0, 0.0, 0.0); -// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) -// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz -// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. -float microfacetDistribution(PBRInfo pbrInputs) -{ - float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; - float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; - return roughnessSq / (M_PI * f * f); -} + for (int i = 0; i < 4; i++) + { + float3 lightDir = LightPositions[i] - input.PositionWS; + float3 L = normalize(lightDir); + float3 H = normalize(V + L); -float4 main_ps(PixelShaderInput input) : SV_TARGET -{ - // Metallic and Roughness material properties are packed together - // In glTF, these factors can be specified by fixed scalar values - // or from a metallic-roughness map - float perceptualRoughness = metallicRoughnessValues.y; - float metallic = metallicRoughnessValues.x; + float distance = length(lightDir); + float attenuation = 1.0 / (distance * distance); + float3 radiance = LightColors[i] * attenuation; -#ifdef HAS_METALROUGHNESSMAP - // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. - // This layout intentionally reserves the 'r' channel for (optional) occlusion map data - float4 mrSample = SAMPLE_TEXTURE(metallicRoughnessTexture, input.texcoord); + float3 F0 = float3(0.04, 0.04, 0.04); + F0 = lerp(F0, Albedo, Metallic); + float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - // Had to reverse the order of the channels here - TODO: investigate.. - perceptualRoughness = mrSample.g * perceptualRoughness; - metallic = mrSample.b * metallic; -#endif + float NDF = DistributionGGX(N, H, Roughness); + float G = GeometrySmith(N, V, L, Roughness); - perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); - metallic = clamp(metallic, 0.0, 1.0); + float3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); + float3 specular = numerator / max(denominator, 0.001); - // Roughness is authored as perceptual roughness; as is convention, - // convert to material roughness by squaring the perceptual roughness [2]. - float alphaRoughness = perceptualRoughness * perceptualRoughness; + float3 kS = F; + float3 kD = float3(1.0, 1.0, 1.0) - kS; - // The albedo may be defined from a base texture or a flat color + kD *= 1.0 - Metallic; -#ifdef HAS_BASECOLORMAP - float4 baseColor = SRGBtoLINEAR(SAMPLE_TEXTURE(baseColourTexture, input.texcoord)) * baseColorFactor; -#else - float4 baseColor = baseColorFactor; -#endif + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * Albedo / PI + specular) * radiance * NdotL; + } - float3 f0 = float3(0.04, 0.04, 0.04); - float3 diffuseColor = baseColor.rgb * (float3(1.0, 1.0, 1.0) - f0); + float3 ambient = float3(0.03, 0.03, 0.03) * Albedo * AO; + float3 color = ambient + Lo; - diffuseColor *= 1.0 - metallic; - - float3 specularColor = lerp(f0, baseColor.rgb, metallic); - - // Compute reflectance. - float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); - - // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. - // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. - float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); - float3 specularEnvironmentR0 = specularColor.rgb; - float3 specularEnvironmentR90 = float3(1.0, 1.0, 1.0) * reflectance90; - - float3 n = getNormal(input.poswithoutw, input.normal, input.texcoord); // normal at surface point - float3 v = normalize(camera - input.poswithoutw); // Vector from surface point to camera - - float3 l = normalize(lightDir); // Vector from surface point to light - float3 h = normalize(l + v); // Half vector between both l and v - float3 reflection = -normalize(reflect(v, n)); - - float NdotL = clamp(dot(n, l), 0.001, 1.0); - float NdotV = abs(dot(n, v)) + 0.001; - float NdotH = clamp(dot(n, h), 0.0, 1.0); - float LdotH = clamp(dot(l, h), 0.0, 1.0); - float VdotH = clamp(dot(v, h), 0.0, 1.0); - - PBRInfo pbrInputs; - pbrInputs.NdotL = NdotL; - pbrInputs.NdotV = NdotV; - pbrInputs.NdotH = NdotH; - pbrInputs.LdotH = LdotH; - pbrInputs.VdotH = VdotH; - pbrInputs.perceptualRoughness = perceptualRoughness; - pbrInputs.metalness = metallic; - pbrInputs.reflectance0 = specularEnvironmentR0; - pbrInputs.reflectance90 = specularEnvironmentR90; - pbrInputs.alphaRoughness = alphaRoughness; - pbrInputs.diffuseColor = diffuseColor; - pbrInputs.specularColor = specularColor; - - // Calculate the shading terms for the microfacet specular shading model - float3 F = specularReflection(pbrInputs); - - float G = geometricOcclusion(pbrInputs); - float D = microfacetDistribution(pbrInputs); - - // Calculation of analytical lighting contribution - float3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); - float3 specContrib = F * G * D / (4.0 * NdotL * NdotV); - float3 color = NdotL * lightColour * (diffuseContrib + specContrib); - - - // Calculate lighting contribution from image based lighting source (IBL) -#ifdef USE_IBL - color += getIBLContribution(pbrInputs, n, reflection); -#endif - - // Apply optional PBR terms for additional (optional) shading -#ifdef HAS_OCCLUSIONMAP - float ao = SAMPLE_TEXTURE(occlusionTexture, input.texcoord).r; - color = lerp(color, color * ao, occlusionStrength); -#endif - -#ifdef HAS_EMISSIVEMAP - float3 emissive = SRGBtoLINEAR(SAMPLE_TEXTURE(emissionTexture, input.texcoord)).rgb * emissiveFactor; - color += emissive; -#endif - - // This section uses lerp to override final color for reference app visualization - // of various parameters in the lighting equation. - color = lerp(color, F, scaleFGDSpec.x); - color = lerp(color, float3(G, G, G), scaleFGDSpec.y); - color = lerp(color, float3(D, D, D), scaleFGDSpec.z); - color = lerp(color, specContrib, scaleFGDSpec.w); - color = lerp(color, diffuseContrib, scaleDiffBaseMR.x); - color = lerp(color, baseColor.rgb, scaleDiffBaseMR.y); - color = lerp(color, float3(metallic, metallic, metallic), scaleDiffBaseMR.z); - color = lerp(color, float3(perceptualRoughness, perceptualRoughness, perceptualRoughness), scaleDiffBaseMR.w); + color = color / (color + float3(1.0, 1.0, 1.0)); + float exposureConstant = 1.0 / 2.2; + color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); return float4(color, 1.0); } Technique PBR { - Pass pass1 - { - VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 main_ps(); - } + Pass Pass1 + { + VertexShader = compile vs_3_0 main_vs(); + PixelShader = compile ps_3_0 None(); + } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index c6d92be11767fad03ad71c8ec1136836565fdd26..bcc23fa9549d9cd0d2f7e549485601743026db86 100644 GIT binary patch literal 8852 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 literal 7552 zcmcIpPiP$H75`>;6Unh-$*J19C8T>$!Rf)+Negx{m2A0A4GL`Zr|1^1rLnbPrCoMc zu4r=@6Bi8aVcX`ALk>gHp-7?VDB3`KFf@libI2jk9#oivp%7fi!G@yg@ArM*n|(8q z;|rbHMBMZaCFyw$?gx z;d*ba6GHY3kowz7pS2f1ATyxK200LSfp>u40K3ocY<;EO3_Da6Klf?uf%P~JTy1q$ z>dpPRTwnqon49*_PeNYwE6IqD zJIePF=yOe1!d|`EY%I>S)^0AZhTX0d2V;^`qUm+Iuj_15LajT>v-aFCSbw664zL09~E7xtoaszHAm$T{!xE6HF?=C-Z;KMVN? z@Oo$I#`Ib*OGa|3u)#dA-^GW>c-6W59lk#Sehu=x&p{$GpL5DLbNC7n`Omh)#kFRA zu)!slzS3vUiyx2~=vo`^2%j4EOU|k z#{Dw@Wsi-2_0sgkmFtagwP(*y)`B(~xJF#tqMS?9u6Mg<{aEeNjClbxYs_!o9e8Miepm4yfld_vZ_uaIeP97}Q}K5|Z!3Nm^k<46MbR#> za2}eVBgJok{z&n|n9%d85a&QIDgGVM?2+zr6>tuL$gC0{e!*vyLF4r6jTxss*fG3J_V1H;Qta?xoXa zYVP8t=fOUt7G(589#H)k{zSkMqSCexjDg$05>7$Nc7QSP17HamYZ-gDgv_;VVr9p3 zvf|kiV5bJy8MHeH{CTqF^r-7VpW(%`BX<_GyRX0e`Wf?TW3kifwr=#Qr)FNP{%Cr3 zx;ndDUkW?bsn$xnfv3yr`O`0*KYjjtFP(n*?AfzsYinyS-3w|nKb#Fp3s?5ii&_2t ziWDeg{cZgMQ~eP10q)4>&!S zAHtg6`jeMsFFj^zGqYD|FTiI40a+g{+e^P=rlzmXjfv9#@w)TE&;R+_&ZiSD#QDi$ zsGp7f{*{0HbmLEX`GW~BpV&*I;L5`E)VHBfHnmueN6w4S0tCvqX9=<=12dZGa$Jr% z+VNSOKwb6>WSOqWI8I&OUkH@b2mFpwP7s;U&e!A@^2NQb=R;qV5l9O#W)%qEHJQ6y zsiSGJ3rstgBlQRpIZ{V#zqKCxOL2l~}rt)a8A)=!-f8juVUH(yttI z{hH4OVhbGSIy?Z30MgW$*RV_@W+ZMs_tqbP-!~?j_}j?UNy6(I>4WA z*&`~5F!MfX%p(dwk6ZZ==%kMvARdNJ5|vHD{wd=r0DKzZ*)K-^5S_F+T@#vW8 z$9PKo73YL!9*jM*$e83y(4}qJaPE&R?{Yj2KCyfmKE|P6@jCPsz}D9%a{L%;6;*() zekbfWdFBFh_}jcaVm4#PSHREzV#G+j=x@`ai(m3JvUBk@qL2B=)yUCqp3e5*u}bEb z^F;ZOE3aeh+zisC&gOwSc+ZUOe1@qbIVBN$$_x+N_2t?qU7qLAv1e*v?=y+@?ao~0q)Tc|D!+?tVGsd1C_j zbNk)T)$&KO@rvbn?z-_|%X5#ov$4F3y!-52_OCoo8UV%*{oR|oqg3)hUH)E^|6Ser zCassandra Lugo and Evan Hemsley 2020 true Smuggler + AnyCPU;x86 @@ -15,7 +16,7 @@ - + From 0ea3484ec3f0942f4fc45de806a20d9461af049a Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Sat, 1 Aug 2020 13:43:04 -0700 Subject: [PATCH 06/16] i think the lighting works now --- Effects/PBREffect.cs | 24 +++++++++++++++++++----- Effects/PBREffect.fx | 12 ++++++------ Effects/PBREffect.fxb | Bin 8852 -> 8844 bytes Importer.cs | 26 +++++++++++++------------- 4 files changed, 38 insertions(+), 24 deletions(-) diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index ba73003..852bde2 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -88,8 +88,14 @@ namespace Smuggler { world = value; worldParam.SetValue(world); - worldViewProjectionParam.SetValue(world * view * projection); - worldInverseTransposeParam.SetValue(Matrix.Transpose(Matrix.Invert(world))); + + Matrix.Multiply(ref world, ref view, out Matrix worldView); + Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); + worldViewProjectionParam.SetValue(worldViewProj); + + Matrix.Invert(ref world, out Matrix worldInverse); + Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose); + worldInverseTransposeParam.SetValue(worldInverseTranspose); } } @@ -100,8 +106,13 @@ namespace Smuggler { view = value; viewParam.SetValue(view); - worldViewProjectionParam.SetValue(world * view * projection); - eyePositionParam.SetValue(Matrix.Invert(view).Translation); + + Matrix.Multiply(ref world, ref view, out Matrix worldView); + Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); + worldViewProjectionParam.SetValue(worldViewProj); + + Matrix.Invert(ref view, out Matrix inverseView); + eyePositionParam.SetValue(inverseView.Translation); } } @@ -112,7 +123,10 @@ namespace Smuggler { projection = value; projectionParam.SetValue(projection); - worldViewProjectionParam.SetValue(world * view * projection); + + Matrix.Multiply(ref world, ref view, out Matrix worldView); + Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); + worldViewProjectionParam.SetValue(worldViewProj); } } diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index e26bd49..28dd3b5 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -52,10 +52,10 @@ struct PixelShaderInput PixelShaderInput main_vs(VertexShaderInput input) { PixelShaderInput output; - + output.PositionWS = mul(input.Position, World).xyz; output.TexCoord = input.TexCoord; - output.NormalWS = normalize(mul(WorldInverseTranspose, input.Normal)); + output.NormalWS = normalize(mul(input.Normal, (float3x3)WorldInverseTranspose)); output.Position = mul(input.Position, WorldViewProjection); return output; @@ -107,6 +107,9 @@ float4 None(PixelShaderInput input) : SV_TARGET float3 N = normalize(input.NormalWS); float3 V = normalize(EyePosition - input.PositionWS); + float3 F0 = float3(0.04, 0.04, 0.04); + F0 = lerp(F0, Albedo, Metallic); + float3 Lo = float3(0.0, 0.0, 0.0); for (int i = 0; i < 4; i++) @@ -119,12 +122,9 @@ float4 None(PixelShaderInput input) : SV_TARGET float attenuation = 1.0 / (distance * distance); float3 radiance = LightColors[i] * attenuation; - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, Albedo, Metallic); - float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - float NDF = DistributionGGX(N, H, Roughness); float G = GeometrySmith(N, V, L, Roughness); + float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); float3 numerator = NDF * G * F; float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index bcc23fa9549d9cd0d2f7e549485601743026db86..2a7a43f902c350f774e6f67a1944209a06d98c3f 100644 GIT binary patch delta 773 zcmcgpJxF6g5T1G2XCj(pUp5IzGcD|YK`*ybHHs?B1nchQi-|Y;|W+rGQ zyOGYtH=yKCm)T+3&uY?IqoJDK!xRO9p>^G#Hm{KVRL>f+nGR|>F?LlOy4JINst4bC z1ZroZ{a^&^(Dnfm2r28qgIfsT`QX_cgl*yKPg_TwH%?mdEb777~g%SVK!R zExyvkgrbwy@{~mh_&xeLbbZHP60TdGlBcniT6|5mqOI$;s3L=JMNXqW*CdJis9K5Na9xtb%CoqJ_^7_A+2r|z z^U(QzGS4e%Rw4?SDlVW4f0!sJ5xXg(45&u$*x!-XO4$xLlyy7TPcyA0)FSU|5qb=W zaYnZ7!fNEm_l{fzJb-f{jZuH@CJ~3gCfWs8dfBh{7szShS>;J)(4?7QdGRZ!$Bz0Y``^ Date: Mon, 3 Aug 2020 12:34:19 -0700 Subject: [PATCH 07/16] pushing latest even though still broken --- Effects/PBREffect.cs | 24 +++---- Effects/PBREffect.fx | 163 +++++++++++++++++++++++++++++++++++------- Effects/PBREffect.fxb | Bin 8844 -> 7536 bytes Importer.cs | 28 ++++---- 4 files changed, 159 insertions(+), 56 deletions(-) diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 852bde2..5920c2e 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -45,12 +45,10 @@ namespace Smuggler public class PBREffect : Effect { EffectParameter worldParam; - EffectParameter viewParam; - EffectParameter projectionParam; EffectParameter worldViewProjectionParam; EffectParameter worldInverseTransposeParam; - EffectParameter baseColorTextureParam; + EffectParameter albedoTextureParam; EffectParameter normalTextureParam; EffectParameter emissionTextureParam; EffectParameter occlusionTextureParam; @@ -105,7 +103,6 @@ namespace Smuggler set { view = value; - viewParam.SetValue(view); Matrix.Multiply(ref world, ref view, out Matrix worldView); Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); @@ -122,7 +119,6 @@ namespace Smuggler set { projection = value; - projectionParam.SetValue(projection); Matrix.Multiply(ref world, ref view, out Matrix worldView); Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); @@ -176,10 +172,10 @@ namespace Smuggler } } - public Texture2D BaseColourTexture + public Texture2D AlbedoTexture { - get { return baseColorTextureParam.GetValueTexture2D(); } - set { baseColorTextureParam.SetValue(value); } + get { return albedoTextureParam.GetValueTexture2D(); } + set { albedoTextureParam.SetValue(value); } } public Texture2D NormalTexture @@ -252,7 +248,7 @@ namespace Smuggler Lights[i] = cloneSource.Lights[i]; } - BaseColourTexture = cloneSource.BaseColourTexture; + AlbedoTexture = cloneSource.AlbedoTexture; NormalTexture = cloneSource.NormalTexture; EmissionTexture = cloneSource.EmissionTexture; OcclusionTexture = cloneSource.OcclusionTexture; @@ -281,12 +277,10 @@ namespace Smuggler void CacheEffectParameters(PBREffect cloneSource) { worldParam = Parameters["World"]; - viewParam = Parameters["View"]; - projectionParam = Parameters["Projection"]; worldViewProjectionParam = Parameters["WorldViewProjection"]; worldInverseTransposeParam = Parameters["WorldInverseTranspose"]; - baseColorTextureParam = Parameters["BaseColorTexture"]; + albedoTextureParam = Parameters["AlbedoTexture"]; normalTextureParam = Parameters["NormalTexture"]; emissionTextureParam = Parameters["EmissionTexture"]; occlusionTextureParam = Parameters["OcclusionTexture"]; @@ -298,9 +292,9 @@ namespace Smuggler lightPositionsParam = Parameters["LightPositions"]; lightColorsParam = Parameters["LightColors"]; - albedoParam = Parameters["Albedo"]; - metallicParam = Parameters["Metallic"]; - roughnessParam = Parameters["Roughness"]; + albedoParam = Parameters["AlbedoValue"]; + metallicParam = Parameters["MetallicValue"]; + roughnessParam = Parameters["RoughnessValue"]; aoParam = Parameters["AO"]; eyePositionParam = Parameters["EyePosition"]; diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index 28dd3b5..7944e13 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -2,18 +2,9 @@ static const float PI = 3.141592653589793; -// Transformation Matrices - -float4x4 World; -float4x4 View; -float4x4 Projection; - -float4x4 WorldViewProjection; -float4x3 WorldInverseTranspose; - // Samplers -DECLARE_TEXTURE(BaseColorTexture, 0); +DECLARE_TEXTURE(AlbedoTexture, 0); DECLARE_TEXTURE(NormalTexture, 1); DECLARE_TEXTURE(EmissionTexture, 2); DECLARE_TEXTURE(OcclusionTexture, 3); @@ -22,17 +13,28 @@ DECLARE_CUBEMAP(EnvDiffuseTexture, 8); DECLARE_TEXTURE(BrdfLutTexture, 9); DECLARE_CUBEMAP(EnvSpecularTexture, 10); -// Light Info -float3 LightPositions[4]; -float3 LightColors[4]; +BEGIN_CONSTANTS -// PBR Values -float3 Albedo; -float Metallic; -float Roughness; -float AO; + // PBR Values + float3 AlbedoValue _ps(c0) _cb(c0); + float MetallicValue _ps(c1) _cb(c1); + float RoughnessValue _ps(c2) _cb(c2); + float AO _ps(c3) _cb(c3); -float3 EyePosition; + // Light Info + float3 LightPositions[4] _ps(c4) _cb(c4); + float3 LightColors[4] _ps(c8) _cb(c8); + + float3 EyePosition _ps(c12) _cb(c12); + + float4x4 World _vs(c0) _cb(c16); + float4x4 WorldInverseTranspose _vs(c4) _cb(c20); + +MATRIX_CONSTANTS + + float4x4 WorldViewProjection _vs(c8) _cb(c0); + +END_CONSTANTS struct VertexShaderInput { @@ -43,7 +45,7 @@ struct VertexShaderInput struct PixelShaderInput { - float4 Position : SV_POSITION; + float4 Position : SV_Position; float2 TexCoord : TEXCOORD0; float3 PositionWS : TEXCOORD1; float3 NormalWS : TEXCOORD2; @@ -55,7 +57,7 @@ PixelShaderInput main_vs(VertexShaderInput input) output.PositionWS = mul(input.Position, World).xyz; output.TexCoord = input.TexCoord; - output.NormalWS = normalize(mul(input.Normal, (float3x3)WorldInverseTranspose)); + output.NormalWS = normalize(mul(input.Normal, WorldInverseTranspose)); output.Position = mul(input.Position, WorldViewProjection); return output; @@ -104,11 +106,15 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness) // The case where we have no texture maps for any PBR data float4 None(PixelShaderInput input) : SV_TARGET { + float3 albedo = AlbedoValue; + float metallic = MetallicValue; + float roughness = RoughnessValue; + float3 N = normalize(input.NormalWS); float3 V = normalize(EyePosition - input.PositionWS); float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, Albedo, Metallic); + F0 = lerp(F0, albedo, metallic); float3 Lo = float3(0.0, 0.0, 0.0); @@ -122,8 +128,8 @@ float4 None(PixelShaderInput input) : SV_TARGET float attenuation = 1.0 / (distance * distance); float3 radiance = LightColors[i] * attenuation; - float NDF = DistributionGGX(N, H, Roughness); - float G = GeometrySmith(N, V, L, Roughness); + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); float3 numerator = NDF * G * F; @@ -133,13 +139,116 @@ float4 None(PixelShaderInput input) : SV_TARGET float3 kS = F; float3 kD = float3(1.0, 1.0, 1.0) - kS; - kD *= 1.0 - Metallic; + kD *= 1.0 - metallic; float NdotL = max(dot(N, L), 0.0); - Lo += (kD * Albedo / PI + specular) * radiance * NdotL; + Lo += (kD * albedo / PI + specular) * radiance * NdotL; } - float3 ambient = float3(0.03, 0.03, 0.03) * Albedo * AO; + float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; + float3 color = ambient + Lo; + + color = color / (color + float3(1.0, 1.0, 1.0)); + float exposureConstant = 1.0 / 2.2; + color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); + + return float4(color, 1.0); +} + +float4 AlbedoMapPS(PixelShaderInput input) : SV_TARGET +{ + float3 albedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord).rgb; + float metallic = MetallicValue; + float roughness = RoughnessValue; + + float3 N = normalize(input.NormalWS); + float3 V = normalize(EyePosition - input.PositionWS); + + float3 F0 = float3(0.04, 0.04, 0.04); + F0 = lerp(F0, albedo, metallic); + + float3 Lo = float3(0.0, 0.0, 0.0); + + for (int i = 0; i < 4; i++) + { + float3 lightDir = LightPositions[i] - input.PositionWS; + float3 L = normalize(lightDir); + float3 H = normalize(V + L); + + float distance = length(lightDir); + float attenuation = 1.0 / (distance * distance); + float3 radiance = LightColors[i] * attenuation; + + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + + float3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); + float3 specular = numerator / max(denominator, 0.001); + + float3 kS = F; + float3 kD = float3(1.0, 1.0, 1.0) - kS; + + kD *= 1.0 - metallic; + + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * albedo / PI + specular) * radiance * NdotL; + } + + float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; + float3 color = ambient + Lo; + + color = color / (color + float3(1.0, 1.0, 1.0)); + float exposureConstant = 1.0 / 2.2; + color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); + + return float4(color, 1.0); +} + +float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET +{ + float3 albedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord).rgb; + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; + float metallic = metallicRoughness.r; + float roughness = metallicRoughness.g; + + float3 N = normalize(input.NormalWS); + float3 V = normalize(EyePosition - input.PositionWS); + + float3 F0 = float3(0.04, 0.04, 0.04); + F0 = lerp(F0, albedo, metallic); + + float3 Lo = float3(0.0, 0.0, 0.0); + + for (int i = 0; i < 4; i++) + { + float3 lightDir = LightPositions[i] - input.PositionWS; + float3 L = normalize(lightDir); + float3 H = normalize(V + L); + + float distance = length(lightDir); + float attenuation = 1.0 / (distance * distance); + float3 radiance = LightColors[i] * attenuation; + + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + + float3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); + float3 specular = numerator / max(denominator, 0.001); + + float3 kS = F; + float3 kD = float3(1.0, 1.0, 1.0) - kS; + + kD *= 1.0 - metallic; + + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * albedo / PI + specular) * radiance * NdotL; + } + + float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; float3 color = ambient + Lo; color = color / (color + float3(1.0, 1.0, 1.0)); diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index 2a7a43f902c350f774e6f67a1944209a06d98c3f..f4d7e8f6229ee25ccab1dffddf3f77c33b212d84 100644 GIT binary patch literal 7536 zcmds+O>A6O702H^kL^if$LR-95E2$-VWf&Cr3)6N;Gg-wS4@1A?!+?jD& zDuph%%FR3H+;h+U-+TY}y!*zbeZ6}(C$ms^lvTfKYWTmT{|~Ajum7mJ(l}dvZGEFz zmA+pU-!)Y)xde~lHlD<|7KLZ^oLBvV>OjmhOPAN`)h2EpBlN+bGNuZS?>Cy4m+GT9 z?&1^+xIBj2c&0f1D*cu!I0jCJ=%%yg#11Y$9egm zRsGUv%mRtW_(KvK+e4}^EHBqLQXsN9mMJzQmWrMp$89_b>3h?ava9--Y{PLKjK?^Z z#NH?WFRMOZU0$0zYZotWw5okjj_E1L70Z;K9>;AwQ%qCxuc$KTk+=>jfCcax?LT?;b;9QBo{d<-eu+MYRsb>;v)n+(}}C;Sp8gKeJX{-l#7% zN3blgn6bclkK;C;DVD?XpH=;e?4xn}cz{8_tt7tNWG)JOVL9T(rTRuSL;GCj^=k0l+4_Tw*DZ0zmm#}IqXBZm0I2RIgLuUuMR zY_w|YN-V8@tlb9?pS29}Pd4g}W~;#Y7)dIYy|B~o)azA875Z_!ewOrO-pTUDXrKK- z$d?+;`ih=lVVr;d560oFgmIo*y;5x|BQ%#*TWgJ0H5qq>gBQz#n%|>}7sh?DR{il} zv+-(mnVk-KobxrjhU6`HF>Gf^7MEJBqp@xA#OZM6;3D~sb4?%exR)ame&~vxZ>e?? z{T<2OM1NGl<_H+eG0F8r|E=U3iGEA+-9(?$<~^O{;R}-AO7!<7-%j*9l4sfUSk6km zl;~~A*Ax8%$sZ^BlqUS0WTEPkf1c>qB;QQ*+mi1j`jpPtTs&t$cuMkOqHjsQk?0>w zo=UhmCwV^6Hzi+B^osa&IN{VgQD(`mN15gLHG`|PW&4ThZ%oauO5RfCJA6m6 zNm=*0OhTckR zt(U+3@{#QM+H$keYFu2Oojd)_*=HBdEX#5!Nfw7iwMo4ayB%eeUx}~MEAs1xDjvxNz1P<9 z$hBiZ7EePz?D(2qQOqnT7eE z(D?EZhHeMEERxtx_GXPVZXrB=NEX1^U*zf_9%lMdH4*t_wuVa{fJo9%fzJ3+$Df)xvSy+2-h;xCdGU5{0y&UwcoTU_Ho&KrKqNzQpNFg|-rzm&t+7zZ1C z1}i>rILhkV=do;`3y=3dKpvB4nTzun*>jw8CVf{pXKWoTho?ODJs93|=dri@{@LEc z3Epp`{Oa@6I4i%%Ti3~#gZx7Gb0Mx3=c0dx2G0e2bWZli8$5@^^!F{k{=Q`%&LP(B z|AEKi#OK1}1Chtv*@p9RCN4NP$;a@9yI7i!{a%*(!ef0E1Wr4T^Njm|^<}^C&y|;` z@D82!l*ewv?tPG*$KIZ{SxzRNy*sijQ(V7WlqCE8#AH7s_>(7x+Zhi&>Gi|2;BnOD z&;7&hnTCfLet)nz_3_&p&<>AT^L~HJbD8d*nK0(rwJ>hnmm(iqAMPLK-`}@x$JW8_ z6!EU1F*wiLA-{6(Nbe%OA< zC2};g&t!3_okuzP?AkXhK4VcX$!9Xkd0XFvyZUW~ z9J4F#Y{D_q^Pp>Qqh1cW&Ps=z#Q9X)Cb`vg_|@Iy?rS<6>u&PBY&tya>gOYiXXm@y zhOd)hPIkUI4`AY)(*~9-V&lGRx?$rR*>uCkJ;L;g`gb?U$MB803-=}rgJ@N2ezbXUzk$DTs_{RWh0U@6 literal 8844 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 LYWvQ<-$&)&@6x%I diff --git a/Importer.cs b/Importer.cs index ff13912..64f65f7 100644 --- a/Importer.cs +++ b/Importer.cs @@ -192,13 +192,13 @@ namespace Smuggler var albedoChannel = primitive.Material.FindChannel("BaseColor"); if (albedoChannel.HasValue) { - //if (albedoChannel.Value.Texture != null) - //{ - // effect.BaseColourTexture = Texture2D.FromStream( - // graphicsDevice, - // albedoChannel.Value.Texture.PrimaryImage.Content.Open() - // ); - //} + if (albedoChannel.Value.Texture != null) + { + effect.AlbedoTexture = Texture2D.FromStream( + graphicsDevice, + albedoChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } var parameter = albedoChannel.Value.Parameter; @@ -212,13 +212,13 @@ namespace Smuggler var metallicRoughnessChannel = primitive.Material.FindChannel("MetallicRoughness"); if (metallicRoughnessChannel.HasValue) { - //if (metallicRoughnessChannel.Value.Texture != null) - //{ - // effect.MetallicRoughnessTexture = Texture2D.FromStream( - // graphicsDevice, - // metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() - // ); - //} + if (metallicRoughnessChannel.Value.Texture != null) + { + effect.MetallicRoughnessTexture = Texture2D.FromStream( + graphicsDevice, + metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } var parameter = metallicRoughnessChannel.Value.Parameter; From 5465b13b9da1323292ebcdca28499740d24a6b21 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 16:27:59 -0700 Subject: [PATCH 08/16] basic PBR is working! --- Effects/PBREffect.fx | 12 ++++++------ Effects/PBREffect.fxb | Bin 7536 -> 7636 bytes Importer.cs | 30 ++++++++++++++++-------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index 7944e13..ca66512 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -55,11 +55,11 @@ PixelShaderInput main_vs(VertexShaderInput input) { PixelShaderInput output; - output.PositionWS = mul(input.Position, World).xyz; output.TexCoord = input.TexCoord; - output.NormalWS = normalize(mul(input.Normal, WorldInverseTranspose)); - + output.PositionWS = mul(input.Position, World).xyz; + output.NormalWS = mul(input.Normal, WorldInverseTranspose); output.Position = mul(input.Position, WorldViewProjection); + return output; } @@ -104,7 +104,7 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness) } // The case where we have no texture maps for any PBR data -float4 None(PixelShaderInput input) : SV_TARGET +float4 None(PixelShaderInput input) : SV_TARGET0 { float3 albedo = AlbedoValue; float metallic = MetallicValue; @@ -208,7 +208,7 @@ float4 AlbedoMapPS(PixelShaderInput input) : SV_TARGET float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET { - float3 albedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord).rgb; + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; float metallic = metallicRoughness.r; float roughness = metallicRoughness.g; @@ -263,6 +263,6 @@ Technique PBR Pass Pass1 { VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 None(); + PixelShader = compile ps_3_0 AlbedoMetallicRoughnessMapPS(); } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index f4d7e8f6229ee25ccab1dffddf3f77c33b212d84..217a521768636b170ebc8c9919761b087ead88ba 100644 GIT binary patch literal 7636 zcmeI1L2R7G6~||HKYKU9!9Z!7R!Cj7Ik*xkNy~u)rB32VAerJOF>pWv*WTbo8?Uu% zhamN^6+QHTRJZjZhaSFG9FR9sbLasfRgEgtQz~&QYB?Cm2M!!Kq*9QoZ2!NRdEbuL zPEnA{iLsvNy*F>(d-LYa`{w($bZBt3o#wWqesV^5qVPmjNq$+T{_P#TwHB6I*6GLKL>_dMSveaZg(y&wD$UO z3!&KX%XAozKK0{0(KiJ6u}kMZemu;?*v8b~CpdGl+3hylE9QyCqnF5zOYXD$cwX}7 z1z+E*v+%@p{3+25?|#8Ei;J!G)DiK_mkBl`wwij=V?26P+TQGl*cKcWZ&a^2V>+f2 z-G?Oq4Z+imwS`uzxp=m{{_^rlquaIMXv}=dlX>t=pU|SEK3$glnxL-HJLxyy@Pobo zAhB_e=m!L6RxZsnFI-sfHik}_PmhvZu}!EqJ;tL?eVUMbO~9J>=rw0FW@~FD`j3b| zDLB_Th3;cEbc?IP%C?l6Zq6!{t_S(qN?u*a6#Vf^GXK{xzfl*7b+>xe4;XNMoN&6k(g z=GxunnhHyIsB8NG^bw8f8yxnJ;jaTP7 z?N=I$?6j}roUhRsQn$#9Q9dD=Tj+LA#IdB&XhvI3c?lal-K%jH~s;`^qGbO_Qi^=CXw<*&;taP&3|RBw=MRxIK8)oj!l^6!*YCGAJHPiTA?#TjFhsF6)$* zRCTWie@j3PVW*^#_tew21!XrO-uK-*z?WIx65ER2C=G(|S4bE~~GI zQxflraGL6FA8yJ21>WfYeeae1en0bmFf+8Yu9dt_^oEw!N*hbkB}#q1ZluolNA=q? ztavWPC$l|4N7u31eenk`9(PYS7d!24`@&j%>g;#xPtKm3t)E+7SZZ|Yr`s1-o4Q=r zPaOZ=3D^ILb4rWJ+_~Og1V8%ML$c*vm7aAX2q_VQX^9@Y@- zo4ol(3~is;W9$7xV|bEPOuVneeUXdsXw96ZQrj@<-$FwsO`tCOzW$ z_356H)g%-0i84RoZkk=j+=Zp1) zT-idu-}@-z`9qz=-p8AH9DHD%A&1Qe z_Lf-2bENS>4v)3LBcIu0WXNG~bf;4&gi`Q+NGl-d(H#r2%0){Q1#f!9<{;AhSg(u(9{#dkujP) z9v#Og>Y^S$8XMN*NQ;-=3p1mmPH5`2-SN=j>vxZOOw4V*)nncboctiJ*p2&A)MIG* z>&NjMnmYyZ(A>?T74E&^E`iP6HCbzxnee{BJr0~_TDW_LybeCW+v%}U(80e! zK71Dm^*NORxB6`Jc)shM-p^xw;XP$Xy61CzAx}zLU%<=4!?RTH&cZE@#3-zp`(SuS za{g|pcXM<_JQF^g!*k+@>~J^Ki@Csvv@OOmNZ zyxdb>Z|mES^1ZaJz26Y%ehXdpwDvaAnWvSXIdw>1JhnBq!TmPSWl!_|9q7!{+#ArR zy5Q&QZV~CApZDl69`y744|L7TQ%A`e{Fm(wvV>ewein^=yVGwH$lA9qCLqh)-M@JR zow^$r4LQ}4y}#3lhfeueG-N;PcP!>qiy6U>`$dobUWN#=+Owje|31O!Z->Y!uth^o VXKnZIlA@7g%$mvV`rf6%{{kwpxr+b* literal 7536 zcmds+O>A6O702H^kL^if$LR-95E2$-VWf&Cr3)6N;Gg-wS4@1A?!+?jD& zDuph%%FR3H+;h+U-+TY}y!*zbeZ6}(C$ms^lvTfKYWTmT{|~Ajum7mJ(l}dvZGEFz zmA+pU-!)Y)xde~lHlD<|7KLZ^oLBvV>OjmhOPAN`)h2EpBlN+bGNuZS?>Cy4m+GT9 z?&1^+xIBj2c&0f1D*cu!I0jCJ=%%yg#11Y$9egm zRsGUv%mRtW_(KvK+e4}^EHBqLQXsN9mMJzQmWrMp$89_b>3h?ava9--Y{PLKjK?^Z z#NH?WFRMOZU0$0zYZotWw5okjj_E1L70Z;K9>;AwQ%qCxuc$KTk+=>jfCcax?LT?;b;9QBo{d<-eu+MYRsb>;v)n+(}}C;Sp8gKeJX{-l#7% zN3blgn6bclkK;C;DVD?XpH=;e?4xn}cz{8_tt7tNWG)JOVL9T(rTRuSL;GCj^=k0l+4_Tw*DZ0zmm#}IqXBZm0I2RIgLuUuMR zY_w|YN-V8@tlb9?pS29}Pd4g}W~;#Y7)dIYy|B~o)azA875Z_!ewOrO-pTUDXrKK- z$d?+;`ih=lVVr;d560oFgmIo*y;5x|BQ%#*TWgJ0H5qq>gBQz#n%|>}7sh?DR{il} zv+-(mnVk-KobxrjhU6`HF>Gf^7MEJBqp@xA#OZM6;3D~sb4?%exR)ame&~vxZ>e?? z{T<2OM1NGl<_H+eG0F8r|E=U3iGEA+-9(?$<~^O{;R}-AO7!<7-%j*9l4sfUSk6km zl;~~A*Ax8%$sZ^BlqUS0WTEPkf1c>qB;QQ*+mi1j`jpPtTs&t$cuMkOqHjsQk?0>w zo=UhmCwV^6Hzi+B^osa&IN{VgQD(`mN15gLHG`|PW&4ThZ%oauO5RfCJA6m6 zNm=*0OhTckR zt(U+3@{#QM+H$keYFu2Oojd)_*=HBdEX#5!Nfw7iwMo4ayB%eeUx}~MEAs1xDjvxNz1P<9 z$hBiZ7EePz?D(2qQOqnT7eE z(D?EZhHeMEERxtx_GXPVZXrB=NEX1^U*zf_9%lMdH4*t_wuVa{fJo9%fzJ3+$Df)xvSy+2-h;xCdGU5{0y&UwcoTU_Ho&KrKqNzQpNFg|-rzm&t+7zZ1C z1}i>rILhkV=do;`3y=3dKpvB4nTzun*>jw8CVf{pXKWoTho?ODJs93|=dri@{@LEc z3Epp`{Oa@6I4i%%Ti3~#gZx7Gb0Mx3=c0dx2G0e2bWZli8$5@^^!F{k{=Q`%&LP(B z|AEKi#OK1}1Chtv*@p9RCN4NP$;a@9yI7i!{a%*(!ef0E1Wr4T^Njm|^<}^C&y|;` z@D82!l*ewv?tPG*$KIZ{SxzRNy*sijQ(V7WlqCE8#AH7s_>(7x+Zhi&>Gi|2;BnOD z&;7&hnTCfLet)nz_3_&p&<>AT^L~HJbD8d*nK0(rwJ>hnmm(iqAMPLK-`}@x$JW8_ z6!EU1F*wiLA-{6(Nbe%OA< zC2};g&t!3_okuzP?AkXhK4VcX$!9Xkd0XFvyZUW~ z9J4F#Y{D_q^Pp>Qqh1cW&Ps=z#Q9X)Cb`vg_|@Iy?rS<6>u&PBY&tya>gOYiXXm@y zhOd)hPIkUI4`AY)(*~9-V&lGRx?$rR*>uCkJ;L;g`gb?U$MB803-=}rgJ@N2ezbXUzk$DTs_{RWh0U@6 diff --git a/Importer.cs b/Importer.cs index 64f65f7..97f8a03 100644 --- a/Importer.cs +++ b/Importer.cs @@ -218,6 +218,7 @@ namespace Smuggler graphicsDevice, metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() ); + System.Console.WriteLine(effect.MetallicRoughnessTexture.Width); } var parameter = metallicRoughnessChannel.Value.Parameter; @@ -231,24 +232,24 @@ namespace Smuggler effect.AO = 1f; effect.Lights[0] = new PBRLight( - new Vector3(-10f, 10f, -10f), + new Vector3(-10f, 10f, -5f), new Vector3(300f, 300f, 300f) ); - // effect.Lights[1] = new PBRLight( - // new Vector3(10f, 10f, 10f), - // new Vector3(300f, 300f, 300f) - // ); + effect.Lights[1] = new PBRLight( + new Vector3(10f, 10f, 5f), + new Vector3(300f, 300f, 300f) + ); - // effect.Lights[2] = new PBRLight( - // new Vector3(-10f, -10f, 10f), - // new Vector3(300f, 300f, 300f) - // ); + effect.Lights[2] = new PBRLight( + new Vector3(-10f, -10f, 5f), + new Vector3(300f, 300f, 300f) + ); - // effect.Lights[3] = new PBRLight( - // new Vector3(10f, -10f, 10f), - // new Vector3(300f, 300f, 300f) - // ); + effect.Lights[3] = new PBRLight( + new Vector3(10f, -10f, 5f), + new Vector3(300f, 300f, 300f) + ); /* FIXME: how to load cube maps from GLTF? */ /* @@ -311,7 +312,7 @@ namespace Smuggler for (int i = 0; i < normals.Length; i++) { var normal = normalAccessor[i]; - normals[i] = -new Vector3(normal.X, normal.Z, normal.Y); + normals[i] = new Vector3(-normal.X, -normal.Z, normal.Y); } return normals; @@ -415,6 +416,7 @@ namespace Smuggler uint[] indices, Vector3[] positions ) { + System.Console.WriteLine("normals"); var normals = Normals(primitive); var texcoords = TexCoords(primitive); From 75114d77ef4dce1a9934842c53399079286a1ce4 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 16:47:08 -0700 Subject: [PATCH 09/16] add normal map sampling --- Effects/PBREffect.fx | 74 ++++++++++++++++++++++++++++++++++++++++-- Effects/PBREffect.fxb | Bin 7636 -> 7940 bytes Importer.cs | 26 +++++++-------- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index ca66512..1ea26fa 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -57,7 +57,7 @@ PixelShaderInput main_vs(VertexShaderInput input) output.TexCoord = input.TexCoord; output.PositionWS = mul(input.Position, World).xyz; - output.NormalWS = mul(input.Normal, WorldInverseTranspose); + output.NormalWS = mul(input.Normal, (float3x3)WorldInverseTranspose).xyz; output.Position = mul(input.Position, WorldViewProjection); return output; @@ -103,6 +103,24 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness) return ggx1 * ggx2; } +// Easy trick to get tangent-normals to world-space to keep PBR code simplified. +float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal) +{ + float3 tangentNormal = SAMPLE_TEXTURE(NormalTexture, texCoords).xyz * 2.0 - 1.0; + + float3 Q1 = ddx(worldPos); + float3 Q2 = ddy(worldPos); + float2 st1 = ddx(texCoords); + float2 st2 = ddy(texCoords); + + float3 N = normalize(normal); + float3 T = normalize(Q1*st2.y - Q2*st1.y); + float3 B = -normalize(cross(N, T)); + float3x3 TBN = float3x3(T, B, N); + + return normalize(mul(tangentNormal, TBN)); +} + // The case where we have no texture maps for any PBR data float4 None(PixelShaderInput input) : SV_TARGET0 { @@ -258,11 +276,63 @@ float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET return float4(color, 1.0); } +float4 AlbedoMetallicRoughnessNormalMapPS(PixelShaderInput input) : SV_TARGET +{ + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; + float metallic = metallicRoughness.r; + float roughness = metallicRoughness.g; + + float3 N = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); + float3 V = normalize(EyePosition - input.PositionWS); + + float3 F0 = float3(0.04, 0.04, 0.04); + F0 = lerp(F0, albedo, metallic); + + float3 Lo = float3(0.0, 0.0, 0.0); + + for (int i = 0; i < 4; i++) + { + float3 lightDir = LightPositions[i] - input.PositionWS; + float3 L = normalize(lightDir); + float3 H = normalize(V + L); + + float distance = length(lightDir); + float attenuation = 1.0 / (distance * distance); + float3 radiance = LightColors[i] * attenuation; + + float NDF = DistributionGGX(N, H, roughness); + float G = GeometrySmith(N, V, L, roughness); + float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); + + float3 numerator = NDF * G * F; + float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); + float3 specular = numerator / max(denominator, 0.001); + + float3 kS = F; + float3 kD = float3(1.0, 1.0, 1.0) - kS; + + kD *= 1.0 - metallic; + + float NdotL = max(dot(N, L), 0.0); + Lo += (kD * albedo / PI + specular) * radiance * NdotL; + } + + float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; + float3 color = ambient + Lo; + + color = color / (color + float3(1.0, 1.0, 1.0)); + float exposureConstant = 1.0 / 2.2; + color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); + + return float4(color, 1.0); +} + Technique PBR { Pass Pass1 { VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 AlbedoMetallicRoughnessMapPS(); + PixelShader = compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS(); } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index 217a521768636b170ebc8c9919761b087ead88ba..f901f3efcd0aefef3522815494b3ebe31d5492d9 100644 GIT binary patch literal 7940 zcmeHMPl%+|5r5y;-%j`L_ByLEYQjRAWDgUNxSM#$L3IDjg2EUlyW1)#=wznX>Cihp zbkA%QJba5H9u{ol96WgVCU^+bbJ#-;B8Ds?0bv6{1jTrmKnDWJ!NUf2FWdfpRjPk@N#i3yKcJ}mkMRFC^rNj`H5S^Z8_%z- zb{fFUi4&592wF{$2EKI#11=U2ZixWHTKiLjqa}op$`9-8nng z+G)pCGWkZkOo!3<4DI+U@XP45W1G$~cHB!r-*(}-AN|DHX1CjHFPSCgk2K(&0N+>H z@g(?9qu;$#XKsn<_(PzZwA;}io1bs3hK7J*m6_UdzsOO0;VoP#m5DGTICGkpN_7TWYY_*c+t7`>5x zvyFCe?>`Ub*bDp)^bX0Pv>) zeg$xio9^3bz>5K%0^SVp&jEiC;8iU6=YgYIfL{&pw*g-Y@J|6>3Ggb;*pxqKG~s^0 zvjM&a_+o&60k|5(<`m%R0Pg|b4Dbr#>0l63?|7Il+w?Hq@mo%gmV)*o`WuS6HvzAq z^F7XY1>=H^?-MreI~#K}8(5{8$>yqHi)4I=X0$~X6s6(t`tTKZ{PfXdtONhWLC~nr z*M&9K3BLy(aBG`iij? zgOcEF{i3H`z_SEO1llHGw)cbJCBxMf%kF7QP{eB|06>?#&i$o{& zY76tHjRheT%y#qONbc{C>bLh={;u+GYkRAXu48OXJ7&Gh-DiIG%pvz^bH3B=w$H58 zrcVC2_VCQ9ncAtvxrIijcD#LdxrxHOcKFaw4!iy@okK`XW?bRlCLcM1$AiwL50M^$ z{+G*D($LdC?fK+KeDuoeBz+&~uf6}D2kv|KpU|Q02M7a9 zkYYc33P)+=${vo>*u&uNxyocl9>P%oCxAgjD34;~r5Fe&E zrZFNwV9YIYq?1?i3T$xF$!l^PgKZ+W8}mGkG1v#bLGP)Yuihgc>C}mnk#el$`6#3M z>OI6#LcWsND7@zndS1#A<~U%{nF#NPz&}bUOFVWTLZ0|QWOsoEI6Vd%5;w^;!B>OK z_&FB2dKS5jjCPVAK0BYdI^pn%Im;OgygO9mSjy>aC+*jI7UgVK&yd~hV?46VK==cyk!)-oD-~+Cg{JK_M zFEWtulHYtn9^&k@nL0TKeE^bI!?e>>YF$ z`bi@XZ8VrXipRo_^<~7(7UK{6A@k$qfVmiB*Tg4q8RtGvpFD~Ab)5FpbDw)2@o{9`Db%f;nlg!nC*U;RNu8=q$T3?Bf}68NM%a8HH6wVU%$gWZ}~d;fekErwx?Z1DzD|Hqfq&G|t1Eha8vBt2oa~VK>fa zR^;7Ccxh)ju*=rK`8XEZZ0q3|`{m=C}%RNLvw7&aTYx7?dBhDqaE zNMk(HPVz8@3Dc)x98Y{haSU5B+VO21S9sRHjbp^6-jvox%Ktd7o9hJdn|RZ1WX56O2*kM#_8~JJxiTk9&UJeV}p9f5^P# zLA{;V6e?3EP56mdP!k%?`kysM$=Q34-(Y+nYrV{UAWRzT3VlzvyfouBOa+#AB)ZhFS5=rTLk-@et-b%+E$+JmC&R9?TPg}BSWnAU|6WQx7e8fYKZ%=*t&B8<6IVUWl%qYhu@JK z>%$>9edGO$!3VGaSGtb-m+Ace4gSyXUp@m2-$EgV@c&snm(eex^A4qi`x2x5 zS!jCKVl=&D?e|OI#P^PaZMUS2zf&D|<9Y5TZyox5|DB)W?m_MX;1BpxVVtiNcML+u zLddg4e$sJ|;^7E9We>+G;(7~rWvHW~E$n>{JySdu95LqcL~z7L#<~!D8){Jl4T_6U(1SE^je*gdg literal 7636 zcmeI1L2R7G6~||HKYKU9!9Z!7R!Cj7Ik*xkNy~u)rB32VAerJOF>pWv*WTbo8?Uu% zhamN^6+QHTRJZjZhaSFG9FR9sbLasfRgEgtQz~&QYB?Cm2M!!Kq*9QoZ2!NRdEbuL zPEnA{iLsvNy*F>(d-LYa`{w($bZBt3o#wWqesV^5qVPmjNq$+T{_P#TwHB6I*6GLKL>_dMSveaZg(y&wD$UO z3!&KX%XAozKK0{0(KiJ6u}kMZemu;?*v8b~CpdGl+3hylE9QyCqnF5zOYXD$cwX}7 z1z+E*v+%@p{3+25?|#8Ei;J!G)DiK_mkBl`wwij=V?26P+TQGl*cKcWZ&a^2V>+f2 z-G?Oq4Z+imwS`uzxp=m{{_^rlquaIMXv}=dlX>t=pU|SEK3$glnxL-HJLxyy@Pobo zAhB_e=m!L6RxZsnFI-sfHik}_PmhvZu}!EqJ;tL?eVUMbO~9J>=rw0FW@~FD`j3b| zDLB_Th3;cEbc?IP%C?l6Zq6!{t_S(qN?u*a6#Vf^GXK{xzfl*7b+>xe4;XNMoN&6k(g z=GxunnhHyIsB8NG^bw8f8yxnJ;jaTP7 z?N=I$?6j}roUhRsQn$#9Q9dD=Tj+LA#IdB&XhvI3c?lal-K%jH~s;`^qGbO_Qi^=CXw<*&;taP&3|RBw=MRxIK8)oj!l^6!*YCGAJHPiTA?#TjFhsF6)$* zRCTWie@j3PVW*^#_tew21!XrO-uK-*z?WIx65ER2C=G(|S4bE~~GI zQxflraGL6FA8yJ21>WfYeeae1en0bmFf+8Yu9dt_^oEw!N*hbkB}#q1ZluolNA=q? ztavWPC$l|4N7u31eenk`9(PYS7d!24`@&j%>g;#xPtKm3t)E+7SZZ|Yr`s1-o4Q=r zPaOZ=3D^ILb4rWJ+_~Og1V8%ML$c*vm7aAX2q_VQX^9@Y@- zo4ol(3~is;W9$7xV|bEPOuVneeUXdsXw96ZQrj@<-$FwsO`tCOzW$ z_356H)g%-0i84RoZkk=j+=Zp1) zT-idu-}@-z`9qz=-p8AH9DHD%A&1Qe z_Lf-2bENS>4v)3LBcIu0WXNG~bf;4&gi`Q+NGl-d(H#r2%0){Q1#f!9<{;AhSg(u(9{#dkujP) z9v#Og>Y^S$8XMN*NQ;-=3p1mmPH5`2-SN=j>vxZOOw4V*)nncboctiJ*p2&A)MIG* z>&NjMnmYyZ(A>?T74E&^E`iP6HCbzxnee{BJr0~_TDW_LybeCW+v%}U(80e! zK71Dm^*NORxB6`Jc)shM-p^xw;XP$Xy61CzAx}zLU%<=4!?RTH&cZE@#3-zp`(SuS za{g|pcXM<_JQF^g!*k+@>~J^Ki@Csvv@OOmNZ zyxdb>Z|mES^1ZaJz26Y%ehXdpwDvaAnWvSXIdw>1JhnBq!TmPSWl!_|9q7!{+#ArR zy5Q&QZV~CApZDl69`y744|L7TQ%A`e{Fm(wvV>ewein^=yVGwH$lA9qCLqh)-M@JR zow^$r4LQ}4y}#3lhfeueG-N;PcP!>qiy6U>`$dobUWN#=+Owje|31O!Z->Y!uth^o VXKnZIlA@7g%$mvV`rf6%{{kwpxr+b* diff --git a/Importer.cs b/Importer.cs index 97f8a03..adc5dfb 100644 --- a/Importer.cs +++ b/Importer.cs @@ -141,19 +141,17 @@ namespace Smuggler if (primitive.Material != null) { - //var normalChannel = primitive.Material.FindChannel("Normal"); - //if (normalChannel.HasValue) - //{ - // if (normalChannel.Value.Texture != null) - // { - // effect.NormalTexture = Texture2D.FromStream( - // graphicsDevice, - // normalChannel.Value.Texture.PrimaryImage.Content.Open() - // ); - // } - - // effect.NormalScale = normalChannel.Value.Parameter.X; - //} + var normalChannel = primitive.Material.FindChannel("Normal"); + if (normalChannel.HasValue) + { + if (normalChannel.Value.Texture != null) + { + effect.NormalTexture = Texture2D.FromStream( + graphicsDevice, + normalChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } + } //var occlusionChannel = primitive.Material.FindChannel("Occlusion"); //if (occlusionChannel.HasValue) @@ -218,7 +216,6 @@ namespace Smuggler graphicsDevice, metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() ); - System.Console.WriteLine(effect.MetallicRoughnessTexture.Width); } var parameter = metallicRoughnessChannel.Value.Parameter; @@ -416,7 +413,6 @@ namespace Smuggler uint[] indices, Vector3[] positions ) { - System.Console.WriteLine("normals"); var normals = Normals(primitive); var texcoords = TexCoords(primitive); From 964e02c5705db9dd84f11e73dcc763481e50fda2 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 17:35:42 -0700 Subject: [PATCH 10/16] fist attempt at multiple pixel shader paths --- Effects/PBREffect.cs | 62 ++++++++++- Effects/PBREffect.fx | 250 +++++++++++++++++++----------------------- Effects/PBREffect.fxb | Bin 7940 -> 37732 bytes 3 files changed, 168 insertions(+), 144 deletions(-) diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 5920c2e..0d477b3 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -67,6 +67,8 @@ namespace Smuggler EffectParameter eyePositionParam; + EffectParameter shaderIndexParam; + Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; @@ -77,6 +79,10 @@ namespace Smuggler float roughness; float ao; + bool albedoTextureEnabled = false; + bool metallicRoughnessMapEnabled = false; + bool normalMapEnabled = false; + // FIXME: lazily set properties for performance public Matrix World @@ -175,13 +181,22 @@ namespace Smuggler public Texture2D AlbedoTexture { get { return albedoTextureParam.GetValueTexture2D(); } - set { albedoTextureParam.SetValue(value); } + set + { + albedoTextureParam.SetValue(value); + albedoTextureEnabled = value != null; + System.Console.WriteLine(albedoTextureEnabled); + } } public Texture2D NormalTexture { get { return normalTextureParam.GetValueTexture2D(); } - set { normalTextureParam.SetValue(value); } + set + { + normalTextureParam.SetValue(value); + normalMapEnabled = value != null; + } } public Texture2D EmissionTexture @@ -199,7 +214,11 @@ namespace Smuggler public Texture2D MetallicRoughnessTexture { get { return metallicRoughnessTextureParam.GetValueTexture2D(); } - set { metallicRoughnessTextureParam.SetValue(value); } + set + { + metallicRoughnessTextureParam.SetValue(value); + metallicRoughnessMapEnabled = value != null; + } } public TextureCube EnvDiffuseTexture @@ -271,7 +290,40 @@ namespace Smuggler // FIXME: do param applications here for performance protected override void OnApply() { - base.OnApply(); + int shaderIndex = 0; + + if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) + { + System.Console.WriteLine("all enabled"); + shaderIndex = 7; + } + else if (metallicRoughnessMapEnabled && normalMapEnabled) + { + shaderIndex = 6; + } + else if (albedoTextureEnabled && normalMapEnabled) + { + shaderIndex = 5; + } + else if (albedoTextureEnabled && metallicRoughnessMapEnabled) + { + shaderIndex = 4; + } + else if (normalMapEnabled) + { + shaderIndex = 3; + } + else if (metallicRoughnessMapEnabled) + { + shaderIndex = 2; + } + else if (albedoTextureEnabled) + { + shaderIndex = 1; + } + + System.Console.WriteLine(shaderIndex); + shaderIndexParam.SetValue(shaderIndex); } void CacheEffectParameters(PBREffect cloneSource) @@ -298,6 +350,8 @@ namespace Smuggler aoParam = Parameters["AO"]; eyePositionParam = Parameters["EyePosition"]; + + shaderIndexParam = Parameters["ShaderIndex"]; } } } diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index 1ea26fa..08fabd7 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -121,15 +121,15 @@ float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal) return normalize(mul(tangentNormal, TBN)); } -// The case where we have no texture maps for any PBR data -float4 None(PixelShaderInput input) : SV_TARGET0 -{ - float3 albedo = AlbedoValue; - float metallic = MetallicValue; - float roughness = RoughnessValue; - - float3 N = normalize(input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); +float4 ComputeColor( + float3 worldPosition, + float3 worldNormal, + float3 albedo, + float metallic, + float roughness +) { + float3 V = normalize(EyePosition - worldPosition); + float3 N = worldNormal; float3 F0 = float3(0.04, 0.04, 0.04); F0 = lerp(F0, albedo, metallic); @@ -138,7 +138,7 @@ float4 None(PixelShaderInput input) : SV_TARGET0 for (int i = 0; i < 4; i++) { - float3 lightDir = LightPositions[i] - input.PositionWS; + float3 lightDir = LightPositions[i] - worldPosition; float3 L = normalize(lightDir); float3 H = normalize(V + L); @@ -173,166 +173,136 @@ float4 None(PixelShaderInput input) : SV_TARGET0 return float4(color, 1.0); } +// The case where we have no texture maps for any PBR data +float4 None(PixelShaderInput input) : SV_TARGET0 +{ + return ComputeColor( + input.PositionWS, + input.NormalWS, + AlbedoValue, + MetallicValue, + RoughnessValue + ); +} + float4 AlbedoMapPS(PixelShaderInput input) : SV_TARGET { - float3 albedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord).rgb; - float metallic = MetallicValue; - float roughness = RoughnessValue; + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; - float3 N = normalize(input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); + return ComputeColor( + input.PositionWS, + input.NormalWS, + albedo, + MetallicValue, + RoughnessValue + ); +} - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); +float4 MetallicRoughnessPS(PixelShaderInput input) : SV_TARGET +{ + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float3 Lo = float3(0.0, 0.0, 0.0); + return ComputeColor( + input.PositionWS, + input.NormalWS, + AlbedoValue, + metallicRoughness.r, + metallicRoughness.g + ); +} - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - input.PositionWS; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); +float4 NormalPS(PixelShaderInput input) : SV_TARGET +{ + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - - float3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - float3 specular = numerator / max(denominator, 0.001); - - float3 kS = F; - float3 kD = float3(1.0, 1.0, 1.0) - kS; - - kD *= 1.0 - metallic; - - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; - float3 color = ambient + Lo; - - color = color / (color + float3(1.0, 1.0, 1.0)); - float exposureConstant = 1.0 / 2.2; - color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); - - return float4(color, 1.0); + return ComputeColor( + input.PositionWS, + normal, + AlbedoValue, + MetallicValue, + RoughnessValue + ); } float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET { float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float metallic = metallicRoughness.r; - float roughness = metallicRoughness.g; - float3 N = normalize(input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); + return ComputeColor( + input.PositionWS, + input.NormalWS, + albedo, + metallicRoughness.r, + metallicRoughness.g + ); +} - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); +float4 AlbedoNormalPS(PixelShaderInput input) : SV_TARGET +{ + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float3 Lo = float3(0.0, 0.0, 0.0); + return ComputeColor( + input.PositionWS, + normal, + albedo, + MetallicValue, + RoughnessValue + ); +} - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - input.PositionWS; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); +float4 MetallicRoughnessNormalPS(PixelShaderInput input) : SV_TARGET +{ + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - - float3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - float3 specular = numerator / max(denominator, 0.001); - - float3 kS = F; - float3 kD = float3(1.0, 1.0, 1.0) - kS; - - kD *= 1.0 - metallic; - - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; - float3 color = ambient + Lo; - - color = color / (color + float3(1.0, 1.0, 1.0)); - float exposureConstant = 1.0 / 2.2; - color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); - - return float4(color, 1.0); + return ComputeColor( + input.PositionWS, + normal, + AlbedoValue, + metallicRoughness.r, + metallicRoughness.g + ); } float4 AlbedoMetallicRoughnessNormalMapPS(PixelShaderInput input) : SV_TARGET { float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float metallic = metallicRoughness.r; - float roughness = metallicRoughness.g; + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float3 N = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); - - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); - - float3 Lo = float3(0.0, 0.0, 0.0); - - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - input.PositionWS; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); - - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - - float3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - float3 specular = numerator / max(denominator, 0.001); - - float3 kS = F; - float3 kD = float3(1.0, 1.0, 1.0) - kS; - - kD *= 1.0 - metallic; - - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; - float3 color = ambient + Lo; - - color = color / (color + float3(1.0, 1.0, 1.0)); - float exposureConstant = 1.0 / 2.2; - color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); - - return float4(color, 1.0); + return ComputeColor( + input.PositionWS, + normal, + albedo, + metallicRoughness.r, + metallicRoughness.g + ); } +PixelShader PSArray[8] = +{ + compile ps_3_0 None(), + + compile ps_3_0 AlbedoMapPS(), + compile ps_3_0 MetallicRoughnessPS(), + compile ps_3_0 NormalPS(), + + compile ps_3_0 AlbedoMetallicRoughnessMapPS(), + compile ps_3_0 AlbedoNormalPS(), + compile ps_3_0 MetallicRoughnessNormalPS(), + + compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS() +}; + +int ShaderIndex = 0; + Technique PBR { - Pass Pass1 + Pass { VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS(); + PixelShader = (PSArray[ShaderIndex]); } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index f901f3efcd0aefef3522815494b3ebe31d5492d9..a4ca2d7cf6fe43feeab8564aee8983a09a57cc8c 100644 GIT binary patch literal 37732 zcmeI5Ux?kub;sx4z0zIVvgD*`>$HZ5W*;0dshs4Y4{jpMc8Ec46w8|!60j9%6>nH; z#jfPo5ZWseN*`RhP5cl_AATx%a3$0FArB_F#1zvu;I^RzYT7)g^cF&!2S2!AL-F?e zneXrXeslkNB{0s zx_9ZT3n!KzS$O))*_8#AZ&m{Kv{HP!$^?$6;~N~`uQQ+1_x(!0sx*T0=&>hHFD|-z6PCQTa6`=orB{g^s)ESbuiu`!=Nq zo?KjAU0gmDlmtHp1?+CYU5SoI1^C+heHWvtCmg-c4et8N@`5ED2K7PxN`{D+kuS~zoTX=(BJ!^>yC_Qa`$)zx5* z+JdI4=to`PQ?~h(G(9c&GfMl_x)J`M4LVr+pA}==qVflo9ys;X{fj40o?TsNi3*xN zg>coMJ^BtjQO9>l(;mUkDlz8?yg`iGVs1+X{##YQPwCLgiIa!Vo@s~)T3#t&k@vu% zZ1X8;`JUjPQ~EWvj^b_XN7G`?E&0}qK0{0bRy59?TIr-mRA?gNU^N8xGr4> z{O~g4zi)YId1bYs^LCU}{h3BP{T_H`A*jmz*k0c*`Z4cvgMGnX7V}DV9QGQAJVNw2& zklh)BsQ#exOGWw5m4C4)zoz_KMfpw%$~}e7e_Z)zi}I_=zh0EzRDM4KR(~E*{)wVI zQ2vFY{4?d>D9U@ph~Fugw50qW73J?M|4LDQUHLbQ@*eHyJL^3S37=B_NKt-H`4@}w z8_Mq~_Q9RX-(Qs1lz*Wp&q@yF3R(E3@@qx;W#wNl%5w;lKCtwTIuEFXVgO2i&IqkB(j?-Z!4e_TEF_mWpH_SjmH8;jWs8l9SBu-KnE~ z<{|iL*PKT1QwI$ABM%H^`jfx4=4VUGD6gO=*4uK1j3lwCJ4h*=gV&F0d?_Z%N-h6u zm|V}8F3)Eem+3<}Wt_Xy-hmLQyjJO3JnOR-TC2BJKR=Ld&;tf|#_grGJQwy4YYZH; z0kb;|Gi{7x`O7?4eY@_A(XaWy+DM&O%mw(q#sKF&t*L2cJ%+iCF@QlPL|>LQ#xxDy zi!}|+T%Zy9_DLSv{mT4?8E=dM9UjMfwpZ*?_89P_zUJYw*Ngp4U)q@CXdC@#3mxJz zV?rnOvo+8AnU~OHT&z7hM|ju3&0gMUUQ1`!}=c>kJ0LQYz%k~?5IA*?!cB@%j4GT(&%HCX}4Z%*UkDEx|uin z7(I#oK%P2uFlTnm&GwY-S;h<-M80FDA#^Qe=o!_=+4d3MQXjva$HA`9c(M($EmL{! z*4J8}s?^{6WEYlp2zmGco$@9#KIeU2JKvtGoCEGZWPY{ZlIN;?S8elkeNTC>L!2G* zu`9(j#iEYdI2XygkMr)sT;!N%y4KenJDSBo&p!D#8lU_{0gn6Rf2q3XRXxoo7cY`% zY~nTczxSx_6EtMs{WcGt@X7B`p64aRZ^9@4W?lDeuG0=ptxx`Ex$bIx@;YQ4q2-Gg zFZL3&@t;4Xe;z(_w7sAFbw%zfiN}wWJ`;XB{x^R7Kfbo-VCl0{j~_4CgQd?-J$^jC zd+D>=M^6I@PVKKF^R4f${hjN@@wGI&uR<3gzxeUmdpF#VFULd&k@|>Zt*hDF8~O2q zo$%xF3+HnGQ9r(fosk~E=LsJYohByagl=*BbU$8vs{$taKqEN7$$29kkzt~adiq3J zdL!%2D3@*EWSjM@Ybw^qe*C=f$JjlMGwH`m=T_#I+f_afE!6dr{g?9mqE2m@wrG#? zxF3(74G-h|#V^OlhKI)A6P{6jg+37%X!GU;z8LV*ixu-XE&1$LeakE8!5@rJe_9-u!njKc?{_wG#?+$j?y1$=# z%3JsEPWCOZA<*&B$9ea0-hH6G?K7`EmsHggA02O@O?8$04$*QU`&qN9OQMl^Q4fFE zv&hwK%@1Id&-@7f;jiK=`HZuCdaYP@`_+4E{vnI-8l2(dGKSAW?1P9MV2?OE?_dEsy$K#129)Y=_SUosJz0E9ksQW%Ld<3$%s*kGxZM z?7+4|=of4e#UyK3cx%|`OTXAF>}AFaeWRGR_%o+uK85X9>W-*uZ9m&9p*x}-zDHin z6;5IiJ-!F!UY};G0^|O`+jeg8O~wvluj$0re3H@y@yxo;_^E4g(%#yt^r7t70X!#P z%C!CV`OH`34H)tGT#Vs$TF>p!Nf~)#9gy*e9l-;5j*K(Mka60H$Bo8uEDNj`{bF5_ zS+61dwHyZwa$V;||1j?jV2Bl{e%oRNA-6Yc9B4H^hN59dZg=F?`sixpR(t4%$n7n) z+_pYuE4SEtp+o&#rjzA5^liwxZ2`l!`nOx_gwfbQ=v#1yE@IzMX3v!RHtMKHmfEsy zwJ4WurM^X%T}j^pV>#^&N_`u+p%J}jT{@rj9=1*BciKZ2)-ama)?x#r`gVG3AjX&$ z8$jQ3Rx%Ila?0XE6?|ciwcgD(vF!}&V03iMbv#xOHpfP>f>F8Nt8;fvb02D~r2o;! zZLA>bc#cPmqSVpk&4cZa2N3_j_Scq$989jdbb1FwX z;CsqHuk=!`b3EYHy6&gB&hdb#yOitvjQ$tO|DV!5!Wr>^!^%_l6@AMONgX}6Cq}^M z{q{V*c@jSssu+(`Z1EBOMSS&+eD(14Q}K+xtNPO4S6hBYPb{GH_v0Bov4GOwXC1cU z^Y`9|K7Uuf(_GdqSN8dVMOWePpub6nRGz7Qzn*+Q>$aZS{5%hRGLzx$bIa!`U|a`G z`13p`7tCd!T+9lE;{@t_><$-cRGq`tPX@yC%7{O+#!%({S2|7047 zyYt+Fu^2!6^YD#*UN+A;b06mIK7LLbWndYXGVu=l6wXi9%<&KVcN#L++o$xif45^F za5us}88lEPM!;IdvsPja)G>~Iu3osbZY5}IWQh=CCxD(+DPMV z1)UXihOLJ!2Ck3;>_f`753%9kx%WPFhCK+40qefKj3@kYWGwmyZCX3^$^N29=;Zct zA4eViq7V7l$I)K4v5%P#S%It|K2X517c*OyVJ!; zPWKP{w(Zl(aK_QdFzb*sM|d8xp!^M$;h=%Fg_oraQ^(w>L!O}%7-X6}JjX^1+Drc& zo&w{Pn*9~{V&3Dj8f!uOcw5NvH2<7&cI3E|=V@}??+oO;1LABvW^l|v5?ElCE z6J_*q8yi55iCIH)z)$L9U_u`oXRD86j236F#_5=UH{qLyK92i>x2ldY|0|CRjMkvh z$L@o@XuVjstIt~Hd35PF2>;yiP-w(vh-dj-!OsuupW8O195zLgZl%oHqH8I4<$GgO z*iM5V*2k0shCJh-kFmMX(P8U^4Wf=!zynA8rtX*R6z6Zuv;4iHMM+09YklQs`K&X( z`-cQPY@X%+LGvvCpEPNFcgcU_yZ^oFxKAIx`zy--MCp=}c$F0QN%-W{;e&URefOxF zg^|g=JMU%8DV@l5vbyD`pQ-D_T_2c{+`T#g$c{S|0xf+&! zeus;^ge;Lr1a#!V{3llzoy;6&~8be6??3%e4}r{{I9nO@536G`s`baOtQnMb?IdT+t^5q71X@Mby$ zJ3nB2>UP!sP}|-<#}8SAhum*~hxqf@H@j6P&H)dZKkd6G@K1Yh!Mvb9@Wi8;ziFXu z)IXyf>&@Cb?vQjeaxQa!dw$A$3+8_f1Dx1Qveu%)SHVWWFASfC zaj7?6_SEFvgHjIQJ@YNs9lj9{qMml*^RV_hl?TWkWn|B?Y8!1%i;TU5ziU{_Y1x;2 z$ZcP|WxUw?JWJxfJc;#)XG_XA`#9>_XG^|&fDOocMmy^idG@jKHG535;(h05RhIKM z-~e*EPKavv-dA#**1^NcX+}YSXW$VWFFhQeQzP&DSEX+%f!C1hM`g#3KTi}Z^OS)rDZu34i9_zD^<9KgjM~;#E9XTGCscV(v zGS;!3a(t!t7D|1L4#HLl+bd+>=eG56tDn1Br-VL6S4CfVmGa)Su7X#TX;-Gv$5BUp z^f3PjdFIv~~-h%Cr(EqfL>f@_1tf`-tw?RyKQKDONv zFxJQIT?EmvsaS_X29@m{Ka(L3KW#tx%yZsnvGYFXyzcl?oLyJ*-on=IDL@yo4u0q2 zE)ni~3hjFff2~Q6-%}vQu+cpQZGt2@%JBwe($BaY!MmVP5 zXHd+h8OJ`E&!X_@6|1hSlcxFjK09WT?WJQ?l>PRMQ=(qiUD>Zcq&Z&8dkj*U6>;x=>I}4=I)lhx{ym1ce^TC+kUdagFF?Eg zImi6Ucmic?BG$~$`zPZGz|f9;1wXKcjIWb%0N)oQpp!9U4&-TL-;`~Ur+vIF=v2Q7 zdA(U%P5=XZ)@NeW4rLV*fLK(2Bho>lJm3 z8GXoyj)?ZMZM*MEK%3XT2OW71K`%OtIubO6PGg>?vF+2!Fz~Gmvkpmfgy$g(%4fL; z$BmHTpndRtDe`@%W>S5*pcHl25On> zWO?#lvrI}pvpns{vG>zv1V4jyW4RYne~hwG(n|7@zkwjQUs~ z$9OHyp4z}UdRM~w`0{rpTAk1RiqX3geZ5n_S;{5Mm=dBC%_?Ts1mEMPBZ z!6xrVKo>Csei!r659pu#TL*vG+>iM0j_YKDH1{L^Q*|$^Jnepj)+G@$cuU`WhzUf@ zfV&XfU6{*tju{+K{-BbWC^+Ab(94~ZSI6#9ygSK31-KRe3%?&2Zvux;ed~ z^49K0j5*}*!Pvr$zB}P~!{ptG_?-kT!9lHPzCZDW6n82n;|ArzzPsq<* zChjzNkNdg(mnCYo&oFVP0XXa}>#^avxf+)JOrCc8shk(U{#dZS(?B_?+)-IDxi9(( z-E~M}tGJ8W+dB;r8)eV(%slj)bcmj@`%VLNYS2s*x+V0CbQidCeMzHWwFNi#yAh$+ z>bcfF&Ey$EyY*<>=DFr~ek=PYewGDIt#6ahmkOHT!}vW5=0oadz8ZJTkNTjC`Eg$a z+~G$#t{dkzeG@73kh3;?AIQ0ug1>wMZ3!9#e-be6AbnQaM%#62X*+? zj34b$#^;BB@DZNv5>Mb+Jn!(m3G)n|&`un_#7~`YlX8FZeqKtM*hBd{5e+RFKKKbe zjIYSAX!ZEWgX1yj9K7aSc6$;GcN)$A8b)=d!DaSE#FW74_gfALXTRQG@jDT-8ndsy zy4%s66}^4II^R=1;zoXFku#ffllTfaohN?9^AqZO%EKRM->d#>qBGWpy93A;w!-?k z@I|4Ux$s;V9u_fzjHmVkGY@EoXRL8N4{CX6{!mZ5;`~j#gfWs*yr&ssV1q*|IFLQj zmu0&23mKDg#B7AC@lAQJGvX_ur?7qLL)o(EF~CvASFnX`Cwp)E`Jm+#So+eA43}+@ zr+vJQdDZ>L2k8xOEM0>QMgJ=gIH@BMxmxZUMDfnUfSa;xA_t;;| zk9!dGkNs7{)b-KFIH1veD7U|NLcWw~c+4E&Gvl(p$~Q7iSv=3};G`V#7JOjdA@ji_ z^8}i`zeDC}hX%$BnGYJq<15JUM)4J77@E!Vmi98f!dSqN`eU+st#V9!Wk-%f=62+m zy>LC{xQwrCryLVsnI^~Bd*k|;JwqM(IB9QLH>SEj`q_KU_(tz%%p}?qx}>t+;4Yq@ ztD!6Of8Ac%Z#}_dCr7*@%3;5`3_fk|8rF6<_^_W!d&qU;xUB1G6CU-6_7;ZCU8H9a5gt*m1}jJS+7xG*M>ly;jhefB&(f&U2d{U-25W{h*t>y7Y&y z<^eI63peCW##Vnj0=kH=@Ha>DA9={}mG=FUf7W6WbLs2r4q){82h}~V?})Fwpgi%G z*K(aKI<>rB*Zn-#?NQy;{e6eHlR?adPo;0|HT}0czjs32=I?1Z5;6W8k>&44z8iio za6)|S?*Sq;$6m99|-U>b{=PP>L=d;h_h(Q3$eBAC>!y%P>wQt@2 z4hQ}SXM)cK?q3j>AO%mr8FlFWh-=_e3+A%#rf_$GvnBcjO>rKh`y(C@xS|YAz&k#I zj}^a(;rl2m>vuTpyYEVzvG`!j!+s}q>Ys5$dt2uD1an-=eB3QqpJ8ujyN39I=oU`m z0sMUl#~@1l)ByvHk(d6j%fu=CP66#fOTZWW$m8SR`|S4Lsu0Um<~J}V-$w~P)iA*2 zF|SvP+BQ@jz1j@pPHCH~L#v=dv!E^#}yRgTGI9A&J8 zPBjhc)5bn(`>CPB<E5JSXPk|xzud^Hz`(WL7FX)SW$a@+<@ic>OG3w5r`pa4Tg>NM`#T%~J53+sQ=?}}eeAuvJ^DClJn4i% zX|qtrd1L+UJTOs4AGhtDoQGy~i~COMW7|>jjx0D^eH`PpID0kD(YqzKDK3Avq}BP8 zcT0SZj{Xh@HU;_#zLRI3@s6cbq3D?QI~G3$oP<79%dRiPrLY0Vv z4E4?DO{KVJqJ}O1O^t|yyZ{~gysYntgK)ou&*tMG@BKR^?}ix3M)yqOy%sIWL5W^- z&*VnD*Rm5Y;aN2P$JT$l1784NoHOIy950bvZ8}~8Ec3yCh*-xVmA4Wv37%XoUP8)v~lEAf5yhP`4#rYTQDxcRmoa-VUQrZR)qwu=g&QX5g z^5)_t@R2dEHeRALI%r+h)8i$q{ngwN^AD8q;ALbG|A==Bf?T)>)`>7{79D50Rw;Fq~Jmz=t8yRLD zQoWwYeJwvXREC2F))v{QX~;56UC14A7}gjVWSD#zd!gTW>;)K7e@s@*i>sI8h`sE{ z@#bPLJ94}=IUbL_Y?mBQi@n@byw_9eWBbCs`!}ck7DgG>9da>z7M=gw*`J^iI3Jff8Nk%pFZ#|KFmGxchG6( zo%MIt?{DV&A2g~C-sSnGwEy3f*K@}_-x>Y;xbml!Ud(kp3El^ry1&bHejn;_<$?Rs z^2*YQbn)VhAba{RXjaoTeKOt$Pd&A;vbyld%CS?crt9<=Cbx@UGC+wbV-E{SKRKB+VmTxQSRol-kq=8d%29w1wKhd z?vIV{vhnLosLRHW?d0~^49^*)by2K#=90!#y-n$XCl^;sP;iQ|%?CL7 ZuW95?mCC@;7N3B-cj>DOCzjiR{~rKB*}DJ$ delta 167 zcmaE|jH$(rjgj;JzXR+W+3MI?1sNC^1SSRwvkCzj{6K~x8;}u@SX^ufq**|0ryvF? zAk7HG+(0b6*^y&0quma6AR7ok!fT*xCLntfNDv4bfMPX3JQ>1em;q!@0b&jypNnDg jtiB*dhRM3MT1*O0CKqx^Pgal$*nFh+hQQ_<{XNV8On@G_ From 3f8949558546486e65e7fac97a38eec178f14d2b Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 17:36:23 -0700 Subject: [PATCH 11/16] delete old pbr effect code --- Effects/ReferencePBREffect.fx | 410 ---------------------------------- 1 file changed, 410 deletions(-) delete mode 100644 Effects/ReferencePBREffect.fx diff --git a/Effects/ReferencePBREffect.fx b/Effects/ReferencePBREffect.fx deleted file mode 100644 index 61609b9..0000000 --- a/Effects/ReferencePBREffect.fx +++ /dev/null @@ -1,410 +0,0 @@ - -#include "Macros.fxh" - -#define NORMALS -#define UV -#define HAS_BASECOLORMAP - -// A constant buffer that stores the three basic column-major matrices for composing geometry. -cbuffer ModelViewProjectionConstantBuffer : register(b0) -{ - matrix model; - matrix view; - matrix projection; -}; - -// Per-vertex data used as input to the vertex shader. -struct VertexShaderInput -{ - float4 position : POSITION; -#ifdef NORMALS - float3 normal : NORMAL; -#endif -#ifdef UV - float2 texcoord : TEXCOORD0; -#endif -}; - -// Per-pixel color data passed through the pixel shader. -struct PixelShaderInput -{ - float4 position : SV_POSITION; - float4 positionWS : TEXCOORD1; - float3 normalWS : TEXCOORD2; - -#ifdef NORMALS - float3 normal : NORMAL; -#endif - - float2 texcoord : TEXCOORD0; -}; - -PixelShaderInput main_vs(VertexShaderInput input) -{ - PixelShaderInput output; - - // Transform the vertex position into projected space. - float4 pos = mul(input.position, model); - -#ifdef NORMALS - // If we have normals... - output.normal = normalize(mul(float4(input.normal.xyz, 0.0), model)); -#endif - -#ifdef UV - output.texcoord = input.texcoord; -#else - output.texcoord = float2(0.0f, 0.0f); -#endif - -#ifdef HAS_NORMALS -#ifdef HAS_TANGENTS - vec3 normalW = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0))); - vec3 tangentW = normalize(vec3(u_ModelMatrix * vec4(a_Tangent.xyz, 0.0))); - vec3 bitangentW = cross(normalW, tangentW) * a_Tangent.w; - v_TBN = mat3(tangentW, bitangentW, normalW); -#else // HAS_TANGENTS != 1 - v_Normal = normalize(vec3(u_ModelMatrix * vec4(a_Normal.xyz, 0.0))); -#endif -#endif - - // Transform the vertex position into projected space. - pos = mul(pos, view); - pos = mul(pos, projection); - output.position = pos; - - return output; -} - -// -// This fragment shader defines a reference implementation for Physically Based Shading of -// a microfacet surface material defined by a glTF model. -// -// References: -// [1] Real Shading in Unreal Engine 4 -// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf -// [2] Physically Based Shading at Disney -// http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf -// [3] README.md - Environment Maps -// https://github.com/KhronosGroup/glTF-WebGL-PBR/#environment-maps -// [4] "An Inexpensive BRDF Model for Physically based Rendering" by Christophe Schlick -// https://www.cs.virginia.edu/~jdl/bib/appearance/analytic%20models/schlick94b.pdf - -#define NORMALS -#define UV -#define HAS_NORMALS -// #define USE_IBL -#define USE_TEX_LOD - -DECLARE_TEXTURE(baseColourTexture, 0); -DECLARE_TEXTURE(normalTexture, 1); -DECLARE_TEXTURE(emissionTexture, 2); -DECLARE_TEXTURE(occlusionTexture, 3); -DECLARE_TEXTURE(metallicRoughnessTexture, 4); -DECLARE_CUBEMAP(envDiffuseTexture, 8); -DECLARE_TEXTURE(brdfLutTexture, 9); -DECLARE_CUBEMAP(envSpecularTexture, 10); - -cbuffer cbPerFrame : register(b0) -{ - float3 lightDir; - float3 lightColour; -}; - -cbuffer cbPerObject : register(b1) -{ - float normalScale; - float3 emissiveFactor; - float occlusionStrength; - float2 metallicRoughnessValues; - float4 baseColorFactor; - float3 camera; - - // debugging flags used for shader output of intermediate PBR variables - float4 scaleDiffBaseMR; - float4 scaleFGDSpec; - float4 scaleIBLAmbient; -}; - -#ifdef HAS_NORMALS -#ifdef HAS_TANGENTS -varying mat3 v_TBN; -#else -#endif -#endif - -// Encapsulate the various inputs used by the various functions in the shading equation -// We store values in this struct to simplify the integration of alternative implementations -// of the shading terms, outlined in the Readme.MD Appendix. -struct PBRInfo -{ - float NdotL; // cos angle between normal and light direction - float NdotV; // cos angle between normal and view direction - float NdotH; // cos angle between normal and half vector - float LdotH; // cos angle between light direction and half vector - float VdotH; // cos angle between view direction and half vector - float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) - float metalness; // metallic value at the surface - float3 reflectance0; // full reflectance color (normal incidence angle) - float3 reflectance90; // reflectance color at grazing angle - float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) - float3 diffuseColor; // color contribution from diffuse lighting - float3 specularColor; // color contribution from specular lighting -}; - -static const float M_PI = 3.141592653589793; -static const float c_MinRoughness = 0.04; - -float4 SRGBtoLINEAR(float4 srgbIn) -{ -#ifdef MANUAL_SRGB -#ifdef SRGB_FAST_APPROXIMATION - float3 linOut = pow(srgbIn.xyz,float3(2.2, 2.2, 2.2)); -#else //SRGB_FAST_APPROXIMATION - float3 bLess = step(float3(0.04045, 0.04045, 0.04045), srgbIn.xyz); - float3 linOut = lerp(srgbIn.xyz / float3(12.92, 12.92, 12.92), pow((srgbIn.xyz + float3(0.055, 0.055, 0.055)) / float3(1.055, 1.055, 1.055), float3(2.4, 2.4, 2.4)), bLess); -#endif //SRGB_FAST_APPROXIMATION - return float4(linOut,srgbIn.w);; -#else //MANUAL_SRGB - return srgbIn; -#endif //MANUAL_SRGB -} - -// Find the normal for this fragment, pulling either from a predefined normal map -// or from the interpolated mesh normal and tangent attributes. -float3 getNormal(float3 position, float3 normal, float2 uv) -{ - // Retrieve the tangent space matrix -#ifndef HAS_TANGENTS - float3 pos_dx = ddx(position); - float3 pos_dy = ddy(position); - float3 tex_dx = ddx(float3(uv, 0.0)); - float3 tex_dy = ddy(float3(uv, 0.0)); - float3 t = (tex_dy.y * pos_dx - tex_dx.y * pos_dy) / (tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y); - -#ifdef HAS_NORMALS - float3 ng = normalize(normal); -#else - float3 ng = cross(pos_dx, pos_dy); -#endif - - t = normalize(t - ng * dot(ng, t)); - float3 b = normalize(cross(ng, t)); - row_major float3x3 tbn = float3x3(t, b, ng); - -#else // HAS_TANGENTS - mat3 tbn = v_TBN; -#endif - -#ifdef HAS_NORMALMAP - float3 n = SAMPLE_TEXTURE(normalTexture, uv).rgb; - - // Need to check the multiplication is equivalent.. - n = normalize(mul(((2.0 * n - 1.0) * float3(normalScale, normalScale, 1.0)), tbn)); -#else - float3 n = tbn[2].xyz; -#endif - - return n; -} - -#ifdef USE_IBL -// Calculation of the lighting contribution from an optional Image Based Light source. -// Precomputed Environment Maps are required uniform inputs and are computed as outlined in [1]. -// See our README.md on Environment Maps [3] for additional discussion. -float3 getIBLContribution(PBRInfo pbrInputs, float3 n, float3 reflection) -{ - float mipCount = 9.0; // resolution of 512x512 - float lod = (pbrInputs.perceptualRoughness * mipCount); - - // retrieve a scale and bias to F0. See [1], Figure 3 - float2 val = float2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness); - float3 brdf = SRGBtoLINEAR(SAMPLE_TEXTURE(brdfLutTexture, val)).rgb; - - float3 diffuseLight = SRGBtoLINEAR(SAMPLE_CUBEMAP(envDiffuseTexture, n)).rgb; - -#ifdef USE_TEX_LOD - float4 reflectionWithLOD = float4(reflection, 0); - float3 specularLight = SRGBtoLINEAR(SAMPLE_CUBEMAP_LOD(envSpecularTexture, reflectionWithLOD)).rgb; -#else - float3 specularLight = SRGBtoLINEAR(SAMPLE_CUBEMAP(envSpecularTexture, reflection)).rgb; -#endif - - float3 diffuse = diffuseLight * pbrInputs.diffuseColor; - float3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y); - - // For presentation, this allows us to disable IBL terms - diffuse *= scaleIBLAmbient.x; - specular *= scaleIBLAmbient.y; - - return diffuse + specular; -} -#endif - -// Basic Lambertian diffuse -// Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog -// See also [1], Equation 1 -float3 diffuse(PBRInfo pbrInputs) -{ - return pbrInputs.diffuseColor / M_PI; -} - -// The following equation models the Fresnel reflectance term of the spec equation (aka F()) -// Implementation of fresnel from [4], Equation 15 -float3 specularReflection(PBRInfo pbrInputs) -{ - return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); -} - -// This calculates the specular geometric attenuation (aka G()), -// where rougher material will reflect less light back to the viewer. -// This implementation is based on [1] Equation 4, and we adopt their modifications to -// alphaRoughness as input as originally proposed in [2]. -float geometricOcclusion(PBRInfo pbrInputs) -{ - float NdotL = pbrInputs.NdotL; - float NdotV = pbrInputs.NdotV; - float r = pbrInputs.alphaRoughness; - - float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); - float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); - return attenuationL * attenuationV; -} - -// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) -// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz -// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. -float microfacetDistribution(PBRInfo pbrInputs) -{ - float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; - float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; - return roughnessSq / (M_PI * f * f); -} - -float4 main_ps(PixelShaderInput input) : SV_TARGET -{ - // Metallic and Roughness material properties are packed together - // In glTF, these factors can be specified by fixed scalar values - // or from a metallic-roughness map - float perceptualRoughness = metallicRoughnessValues.y; - float metallic = metallicRoughnessValues.x; - -#ifdef HAS_METALROUGHNESSMAP - // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. - // This layout intentionally reserves the 'r' channel for (optional) occlusion map data - float4 mrSample = SAMPLE_TEXTURE(metallicRoughnessTexture, input.texcoord); - - // Had to reverse the order of the channels here - TODO: investigate.. - perceptualRoughness = mrSample.g * perceptualRoughness; - metallic = mrSample.b * metallic; -#endif - - perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); - metallic = clamp(metallic, 0.0, 1.0); - - // Roughness is authored as perceptual roughness; as is convention, - // convert to material roughness by squaring the perceptual roughness [2]. - float alphaRoughness = perceptualRoughness * perceptualRoughness; - - // The albedo may be defined from a base texture or a flat color - -#ifdef HAS_BASECOLORMAP - float4 baseColor = SRGBtoLINEAR(SAMPLE_TEXTURE(baseColourTexture, input.texcoord)) * baseColorFactor; -#else - float4 baseColor = baseColorFactor; -#endif - - float3 f0 = float3(0.04, 0.04, 0.04); - float3 diffuseColor = baseColor.rgb * (float3(1.0, 1.0, 1.0) - f0); - - diffuseColor *= 1.0 - metallic; - - float3 specularColor = lerp(f0, baseColor.rgb, metallic); - - // Compute reflectance. - float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); - - // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. - // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. - float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); - float3 specularEnvironmentR0 = specularColor.rgb; - float3 specularEnvironmentR90 = float3(1.0, 1.0, 1.0) * reflectance90; - - float3 n = getNormal(input.poswithoutw, input.normal, input.texcoord); // normal at surface point - float3 v = normalize(camera - input.poswithoutw); // Vector from surface point to camera - - float3 l = normalize(lightDir); // Vector from surface point to light - float3 h = normalize(l + v); // Half vector between both l and v - float3 reflection = -normalize(reflect(v, n)); - - float NdotL = clamp(dot(n, l), 0.001, 1.0); - float NdotV = abs(dot(n, v)) + 0.001; - float NdotH = clamp(dot(n, h), 0.0, 1.0); - float LdotH = clamp(dot(l, h), 0.0, 1.0); - float VdotH = clamp(dot(v, h), 0.0, 1.0); - - PBRInfo pbrInputs; - pbrInputs.NdotL = NdotL; - pbrInputs.NdotV = NdotV; - pbrInputs.NdotH = NdotH; - pbrInputs.LdotH = LdotH; - pbrInputs.VdotH = VdotH; - pbrInputs.perceptualRoughness = perceptualRoughness; - pbrInputs.metalness = metallic; - pbrInputs.reflectance0 = specularEnvironmentR0; - pbrInputs.reflectance90 = specularEnvironmentR90; - pbrInputs.alphaRoughness = alphaRoughness; - pbrInputs.diffuseColor = diffuseColor; - pbrInputs.specularColor = specularColor; - - // Calculate the shading terms for the microfacet specular shading model - float3 F = specularReflection(pbrInputs); - - float G = geometricOcclusion(pbrInputs); - float D = microfacetDistribution(pbrInputs); - - // Calculation of analytical lighting contribution - float3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); - float3 specContrib = F * G * D / (4.0 * NdotL * NdotV); - float3 color = NdotL * lightColour * (diffuseContrib + specContrib); - - - // Calculate lighting contribution from image based lighting source (IBL) -#ifdef USE_IBL - color += getIBLContribution(pbrInputs, n, reflection); -#endif - - // Apply optional PBR terms for additional (optional) shading -#ifdef HAS_OCCLUSIONMAP - float ao = SAMPLE_TEXTURE(occlusionTexture, input.texcoord).r; - color = lerp(color, color * ao, occlusionStrength); -#endif - -#ifdef HAS_EMISSIVEMAP - float3 emissive = SRGBtoLINEAR(SAMPLE_TEXTURE(emissionTexture, input.texcoord)).rgb * emissiveFactor; - color += emissive; -#endif - - // This section uses lerp to override final color for reference app visualization - // of various parameters in the lighting equation. - color = lerp(color, F, scaleFGDSpec.x); - color = lerp(color, float3(G, G, G), scaleFGDSpec.y); - color = lerp(color, float3(D, D, D), scaleFGDSpec.z); - color = lerp(color, specContrib, scaleFGDSpec.w); - color = lerp(color, diffuseContrib, scaleDiffBaseMR.x); - color = lerp(color, baseColor.rgb, scaleDiffBaseMR.y); - color = lerp(color, float3(metallic, metallic, metallic), scaleDiffBaseMR.z); - color = lerp(color, float3(perceptualRoughness, perceptualRoughness, perceptualRoughness), scaleDiffBaseMR.w); - - //return float4(baseColor.xyz, 1.0); - return float4(color, 1.0); -} - -Technique PBR -{ - Pass pass1 - { - VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 main_ps(); - } -} From 9aabffa8d76ffe36eec0a71410ee19f7a6cbea02 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 17:48:02 -0700 Subject: [PATCH 12/16] remove debug logs --- Effects/PBREffect.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 0d477b3..025d05c 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -294,7 +294,6 @@ namespace Smuggler if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) { - System.Console.WriteLine("all enabled"); shaderIndex = 7; } else if (metallicRoughnessMapEnabled && normalMapEnabled) @@ -322,7 +321,6 @@ namespace Smuggler shaderIndex = 1; } - System.Console.WriteLine(shaderIndex); shaderIndexParam.SetValue(shaderIndex); } From 4a5f0d44619663070de02787ac4f0545439d7e2c Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 3 Aug 2020 18:30:55 -0700 Subject: [PATCH 13/16] add intermediate array to fix shader index select --- Effects/PBREffect.fx | 7 ++++++- Effects/PBREffect.fxb | Bin 37732 -> 38008 bytes 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index 08fabd7..ee5ecb7 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -296,6 +296,11 @@ PixelShader PSArray[8] = compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS() }; +int PSIndices[8] = +{ + 0, 1, 2, 3, 4, 5, 6, 7 +}; + int ShaderIndex = 0; Technique PBR @@ -303,6 +308,6 @@ Technique PBR Pass { VertexShader = compile vs_3_0 main_vs(); - PixelShader = (PSArray[ShaderIndex]); + PixelShader = (PSArray[PSIndices[ShaderIndex]]); } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index a4ca2d7cf6fe43feeab8564aee8983a09a57cc8c..97637627ab81ffc08b726b0604530721a4ea9bec 100644 GIT binary patch delta 464 zcmaE|jOoV;CRRqy|NkmBvL0vm`@zlt1{^?=5sEaGXpUT5VHa?8xVt(a{+Nc zuxDOMW^!sVkPT7?0va5X&#|X5%5FC0IL|1{0W?wtWGoaEK-nOZGbRgi35(hQMJ#}L zGE_wfkR7nul52ZQ{T!ewkotgN$D*RdN}wGPZvX!KGdPDhI>`XV`N8gsa06Kl;)C4F z1H>*sCP)md7f2@n@dF@c0*ZjNyaD1rK#Xwy>eV1wMj!;~fr81|to-#2_AoA#c0lDj zpz#~f_zTeZ2hjKrQ24 Date: Tue, 4 Aug 2020 01:14:45 -0700 Subject: [PATCH 14/16] optimize PBR effect setters --- Effects/EffectHelpers.cs | 14 +++++ Effects/PBREffect.cs | 121 ++++++++++++++++++++++----------------- 2 files changed, 84 insertions(+), 51 deletions(-) create mode 100644 Effects/EffectHelpers.cs diff --git a/Effects/EffectHelpers.cs b/Effects/EffectHelpers.cs new file mode 100644 index 0000000..e2618cb --- /dev/null +++ b/Effects/EffectHelpers.cs @@ -0,0 +1,14 @@ +using System; + +namespace Smuggler +{ + [Flags] + internal enum EffectDirtyFlags + { + WorldViewProj = 1, + World = 2, + EyePosition = 4, + ShaderIndex = 8, + All = -1 + } +} \ No newline at end of file diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 025d05c..eec2796 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -83,6 +83,8 @@ namespace Smuggler bool metallicRoughnessMapEnabled = false; bool normalMapEnabled = false; + EffectDirtyFlags dirtyFlags= EffectDirtyFlags.All; + // FIXME: lazily set properties for performance public Matrix World @@ -91,15 +93,7 @@ namespace Smuggler set { world = value; - worldParam.SetValue(world); - - Matrix.Multiply(ref world, ref view, out Matrix worldView); - Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); - worldViewProjectionParam.SetValue(worldViewProj); - - Matrix.Invert(ref world, out Matrix worldInverse); - Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose); - worldInverseTransposeParam.SetValue(worldInverseTranspose); + dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj; } } @@ -109,13 +103,7 @@ namespace Smuggler set { view = value; - - Matrix.Multiply(ref world, ref view, out Matrix worldView); - Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); - worldViewProjectionParam.SetValue(worldViewProj); - - Matrix.Invert(ref view, out Matrix inverseView); - eyePositionParam.SetValue(inverseView.Translation); + dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition; } } @@ -125,10 +113,7 @@ namespace Smuggler set { projection = value; - - Matrix.Multiply(ref world, ref view, out Matrix worldView); - Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); - worldViewProjectionParam.SetValue(worldViewProj); + dirtyFlags |= EffectDirtyFlags.WorldViewProj; } } @@ -185,7 +170,7 @@ namespace Smuggler { albedoTextureParam.SetValue(value); albedoTextureEnabled = value != null; - System.Console.WriteLine(albedoTextureEnabled); + dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } @@ -196,6 +181,7 @@ namespace Smuggler { normalTextureParam.SetValue(value); normalMapEnabled = value != null; + dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } @@ -218,6 +204,7 @@ namespace Smuggler { metallicRoughnessTextureParam.SetValue(value); metallicRoughnessMapEnabled = value != null; + dirtyFlags |= EffectDirtyFlags.ShaderIndex; } } @@ -287,41 +274,73 @@ namespace Smuggler return new PBREffect(this); } - // FIXME: do param applications here for performance protected override void OnApply() { - int shaderIndex = 0; + if ((dirtyFlags & EffectDirtyFlags.World) != 0) + { + worldParam.SetValue(world); - if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) - { - shaderIndex = 7; - } - else if (metallicRoughnessMapEnabled && normalMapEnabled) - { - shaderIndex = 6; - } - else if (albedoTextureEnabled && normalMapEnabled) - { - shaderIndex = 5; - } - else if (albedoTextureEnabled && metallicRoughnessMapEnabled) - { - shaderIndex = 4; - } - else if (normalMapEnabled) - { - shaderIndex = 3; - } - else if (metallicRoughnessMapEnabled) - { - shaderIndex = 2; - } - else if (albedoTextureEnabled) - { - shaderIndex = 1; + Matrix.Invert(ref world, out Matrix worldInverse); + Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose); + worldInverseTransposeParam.SetValue(worldInverseTranspose); + + dirtyFlags &= ~EffectDirtyFlags.World; } - shaderIndexParam.SetValue(shaderIndex); + if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) + { + Matrix.Multiply(ref world, ref view, out Matrix worldView); + Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); + worldViewProjectionParam.SetValue(worldViewProj); + + dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; + } + + if ((dirtyFlags & EffectDirtyFlags.EyePosition) != 0) + { + Matrix.Invert(ref view, out Matrix inverseView); + eyePositionParam.SetValue(inverseView.Translation); + + dirtyFlags &= ~EffectDirtyFlags.EyePosition; + } + + if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) + { + int shaderIndex = 0; + + if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) + { + shaderIndex = 7; + } + else if (metallicRoughnessMapEnabled && normalMapEnabled) + { + shaderIndex = 6; + } + else if (albedoTextureEnabled && normalMapEnabled) + { + shaderIndex = 5; + } + else if (albedoTextureEnabled && metallicRoughnessMapEnabled) + { + shaderIndex = 4; + } + else if (normalMapEnabled) + { + shaderIndex = 3; + } + else if (metallicRoughnessMapEnabled) + { + shaderIndex = 2; + } + else if (albedoTextureEnabled) + { + shaderIndex = 1; + } + + shaderIndexParam.SetValue(shaderIndex); + + dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; + } } void CacheEffectParameters(PBREffect cloneSource) From d670a0ecbd9c3ebb5e8f0b8ae7645c492e405e67 Mon Sep 17 00:00:00 2001 From: Evan Hemsley Date: Wed, 5 Aug 2020 12:15:02 -0700 Subject: [PATCH 15/16] removed all references to effect processing etc --- Effects/EffectHelpers.cs | 14 -- Effects/Macros.fxh | 57 ------ Effects/PBREffect.cs | 374 --------------------------------------- Effects/PBREffect.fx | 313 -------------------------------- Effects/PBREffect.fxb | Bin 38008 -> 0 bytes Importer.cs | 148 +++++----------- Mesh.cs | 23 --- MeshData.cs | 12 ++ MeshPart.cs | 47 ----- MeshPartData.cs | 34 ++++ Model.cs | 24 --- ModelData.cs | 15 ++ Resources.cs | 33 ---- Smuggler.csproj | 6 - 14 files changed, 101 insertions(+), 999 deletions(-) delete mode 100644 Effects/EffectHelpers.cs delete mode 100644 Effects/Macros.fxh delete mode 100644 Effects/PBREffect.cs delete mode 100644 Effects/PBREffect.fx delete mode 100644 Effects/PBREffect.fxb delete mode 100644 Mesh.cs create mode 100644 MeshData.cs delete mode 100644 MeshPart.cs create mode 100644 MeshPartData.cs delete mode 100644 Model.cs create mode 100644 ModelData.cs delete mode 100644 Resources.cs diff --git a/Effects/EffectHelpers.cs b/Effects/EffectHelpers.cs deleted file mode 100644 index e2618cb..0000000 --- a/Effects/EffectHelpers.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Smuggler -{ - [Flags] - internal enum EffectDirtyFlags - { - WorldViewProj = 1, - World = 2, - EyePosition = 4, - ShaderIndex = 8, - All = -1 - } -} \ No newline at end of file diff --git a/Effects/Macros.fxh b/Effects/Macros.fxh deleted file mode 100644 index 91d1702..0000000 --- a/Effects/Macros.fxh +++ /dev/null @@ -1,57 +0,0 @@ -//----------------------------------------------------------------------------- -// Macros.fxh -// -// Microsoft XNA Community Game Platform -// Copyright (C) Microsoft Corporation. All rights reserved. -//----------------------------------------------------------------------------- - -#ifdef SM4 - - -// Macros for targetting shader model 4.0 (DX11) - -#define BEGIN_CONSTANTS cbuffer Parameters : register(b0) { -#define MATRIX_CONSTANTS }; cbuffer ProjectionMatrix : register(b1) { -#define END_CONSTANTS }; - -#define _vs(r) -#define _ps(r) -#define _cb(r) : packoffset(r) - -#define DECLARE_TEXTURE(Name, index) \ - Texture2D Name : register(t##index); \ - sampler Name##Sampler : register(s##index) - -#define DECLARE_CUBEMAP(Name, index) \ - TextureCube Name : register(t##index); \ - sampler Name##Sampler : register(s##index) - -#define SAMPLE_TEXTURE(Name, texCoord) Name.Sample(Name##Sampler, texCoord) -#define SAMPLE_CUBEMAP(Name, texCoord) Name.Sample(Name##Sampler, texCoord) -#define SAMPLE_CUBEMAP_LOD(Name, texCoord) Name.SampleLevel(Name##Sampler, texCoord.xyz, texCoord.w) - -#else - - -// Macros for targetting shader model 2.0 (DX9) - -#define BEGIN_CONSTANTS -#define MATRIX_CONSTANTS -#define END_CONSTANTS - -#define _vs(r) : register(vs, r) -#define _ps(r) : register(ps, r) -#define _cb(r) - -#define DECLARE_TEXTURE(Name, index) \ - texture2D Name; \ - sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); }; - -#define DECLARE_CUBEMAP(Name, index) \ - textureCUBE Name; \ - sampler Name##Sampler : register(s##index) = sampler_state { Texture = (Name); }; - -#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord) -#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord) -#define SAMPLE_CUBEMAP_LOD(Name, texCoord) texCUBElod(Name##Sampler, texCoord) -#endif diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs deleted file mode 100644 index eec2796..0000000 --- a/Effects/PBREffect.cs +++ /dev/null @@ -1,374 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Smuggler -{ - public struct PBRLight - { - public Vector3 position; - public Vector3 color; - - public PBRLight(Vector3 position, Vector3 colour) - { - this.position = position; - this.color = colour; - } - } - - public class PBRLightCollection - { - private readonly Vector3[] positions = new Vector3[4]; - private readonly Vector3[] colors = new Vector3[4]; - - readonly EffectParameter lightPositionsParam; - readonly EffectParameter lightColorsParam; - - public PBRLightCollection(EffectParameter lightPositionsParam, EffectParameter lightColorsParam) - { - this.lightPositionsParam = lightPositionsParam; - this.lightColorsParam = lightColorsParam; - } - - public PBRLight this[int i] - { - get { return new PBRLight(positions[i], colors[i]); } - set - { - positions[i] = value.position; - colors[i] = value.color; - lightPositionsParam.SetValue(positions); - lightColorsParam.SetValue(colors); - } - } - } - - public class PBREffect : Effect - { - EffectParameter worldParam; - EffectParameter worldViewProjectionParam; - EffectParameter worldInverseTransposeParam; - - EffectParameter albedoTextureParam; - EffectParameter normalTextureParam; - EffectParameter emissionTextureParam; - EffectParameter occlusionTextureParam; - EffectParameter metallicRoughnessTextureParam; - EffectParameter envDiffuseTextureParam; - EffectParameter brdfLutTextureParam; - EffectParameter envSpecularTextureParam; - - EffectParameter lightPositionsParam; - EffectParameter lightColorsParam; - - EffectParameter albedoParam; - EffectParameter metallicParam; - EffectParameter roughnessParam; - EffectParameter aoParam; - - EffectParameter eyePositionParam; - - EffectParameter shaderIndexParam; - - Matrix world = Matrix.Identity; - Matrix view = Matrix.Identity; - Matrix projection = Matrix.Identity; - PBRLightCollection pbrLightCollection; - - Vector3 albedo; - float metallic; - float roughness; - float ao; - - bool albedoTextureEnabled = false; - bool metallicRoughnessMapEnabled = false; - bool normalMapEnabled = false; - - EffectDirtyFlags dirtyFlags= EffectDirtyFlags.All; - - // FIXME: lazily set properties for performance - - public Matrix World - { - get { return world; } - set - { - world = value; - dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj; - } - } - - public Matrix View - { - get { return view; } - set - { - view = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition; - } - } - - public Matrix Projection - { - get { return projection; } - set - { - projection = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj; - } - } - - public PBRLightCollection Lights - { - get { return pbrLightCollection; } - internal set { pbrLightCollection = value; } - } - - public Vector3 Albedo - { - get { return albedo; } - set - { - albedo = value; - albedoParam.SetValue(albedo); - } - } - - public float Metallic - { - get { return metallic; } - set - { - metallic = value; - metallicParam.SetValue(metallic); - } - } - - public float Roughness - { - get { return roughness; } - set - { - roughness = value; - roughnessParam.SetValue(roughness); - } - } - - public float AO - { - get { return ao; } - set - { - ao = value; - aoParam.SetValue(ao); - } - } - - public Texture2D AlbedoTexture - { - get { return albedoTextureParam.GetValueTexture2D(); } - set - { - albedoTextureParam.SetValue(value); - albedoTextureEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; - } - } - - public Texture2D NormalTexture - { - get { return normalTextureParam.GetValueTexture2D(); } - set - { - normalTextureParam.SetValue(value); - normalMapEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; - } - } - - public Texture2D EmissionTexture - { - get { return emissionTextureParam.GetValueTexture2D(); } - set { emissionTextureParam.SetValue(value); } - } - - public Texture2D OcclusionTexture - { - get { return occlusionTextureParam.GetValueTexture2D(); } - set { occlusionTextureParam.SetValue(value); } - } - - public Texture2D MetallicRoughnessTexture - { - get { return metallicRoughnessTextureParam.GetValueTexture2D(); } - set - { - metallicRoughnessTextureParam.SetValue(value); - metallicRoughnessMapEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; - } - } - - public TextureCube EnvDiffuseTexture - { - get { return envDiffuseTextureParam.GetValueTextureCube(); } - set { envDiffuseTextureParam.SetValue(value); } - } - - public Texture2D BRDFLutTexture - { - get { return brdfLutTextureParam.GetValueTexture2D(); } - set { brdfLutTextureParam.SetValue(value); } - } - - public TextureCube EnvSpecularTexture - { - get { return envSpecularTextureParam.GetValueTextureCube(); } - set { envSpecularTextureParam.SetValue(value); } - } - - public PBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.PBREffect) - { - CacheEffectParameters(null); - - pbrLightCollection = new PBRLightCollection( - Parameters["LightPositions"], - Parameters["LightColors"] - ); - } - - protected PBREffect(PBREffect cloneSource) : base(cloneSource) - { - CacheEffectParameters(cloneSource); - - World = cloneSource.World; - View = cloneSource.View; - Projection = cloneSource.Projection; - - Lights = new PBRLightCollection( - Parameters["LightPositions"], - Parameters["LightColors"] - ); - - for (int i = 0; i < 4; i++) - { - Lights[i] = cloneSource.Lights[i]; - } - - AlbedoTexture = cloneSource.AlbedoTexture; - NormalTexture = cloneSource.NormalTexture; - EmissionTexture = cloneSource.EmissionTexture; - OcclusionTexture = cloneSource.OcclusionTexture; - MetallicRoughnessTexture = cloneSource.MetallicRoughnessTexture; - EnvDiffuseTexture = cloneSource.EnvDiffuseTexture; - BRDFLutTexture = cloneSource.BRDFLutTexture; - EnvSpecularTexture = cloneSource.EnvSpecularTexture; - - Albedo = cloneSource.Albedo; - Metallic = cloneSource.Metallic; - Roughness = cloneSource.Roughness; - AO = cloneSource.AO; - } - - public override Effect Clone() - { - return new PBREffect(this); - } - - protected override void OnApply() - { - if ((dirtyFlags & EffectDirtyFlags.World) != 0) - { - worldParam.SetValue(world); - - Matrix.Invert(ref world, out Matrix worldInverse); - Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose); - worldInverseTransposeParam.SetValue(worldInverseTranspose); - - dirtyFlags &= ~EffectDirtyFlags.World; - } - - if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) - { - Matrix.Multiply(ref world, ref view, out Matrix worldView); - Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); - worldViewProjectionParam.SetValue(worldViewProj); - - dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; - } - - if ((dirtyFlags & EffectDirtyFlags.EyePosition) != 0) - { - Matrix.Invert(ref view, out Matrix inverseView); - eyePositionParam.SetValue(inverseView.Translation); - - dirtyFlags &= ~EffectDirtyFlags.EyePosition; - } - - if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) - { - int shaderIndex = 0; - - if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) - { - shaderIndex = 7; - } - else if (metallicRoughnessMapEnabled && normalMapEnabled) - { - shaderIndex = 6; - } - else if (albedoTextureEnabled && normalMapEnabled) - { - shaderIndex = 5; - } - else if (albedoTextureEnabled && metallicRoughnessMapEnabled) - { - shaderIndex = 4; - } - else if (normalMapEnabled) - { - shaderIndex = 3; - } - else if (metallicRoughnessMapEnabled) - { - shaderIndex = 2; - } - else if (albedoTextureEnabled) - { - shaderIndex = 1; - } - - shaderIndexParam.SetValue(shaderIndex); - - dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; - } - } - - void CacheEffectParameters(PBREffect cloneSource) - { - worldParam = Parameters["World"]; - worldViewProjectionParam = Parameters["WorldViewProjection"]; - worldInverseTransposeParam = Parameters["WorldInverseTranspose"]; - - albedoTextureParam = Parameters["AlbedoTexture"]; - normalTextureParam = Parameters["NormalTexture"]; - emissionTextureParam = Parameters["EmissionTexture"]; - occlusionTextureParam = Parameters["OcclusionTexture"]; - metallicRoughnessTextureParam = Parameters["MetallicRoughnessTexture"]; - envDiffuseTextureParam = Parameters["EnvDiffuseTexture"]; - brdfLutTextureParam = Parameters["BrdfLutTexture"]; - envSpecularTextureParam = Parameters["EnvSpecularTexture"]; - - lightPositionsParam = Parameters["LightPositions"]; - lightColorsParam = Parameters["LightColors"]; - - albedoParam = Parameters["AlbedoValue"]; - metallicParam = Parameters["MetallicValue"]; - roughnessParam = Parameters["RoughnessValue"]; - aoParam = Parameters["AO"]; - - eyePositionParam = Parameters["EyePosition"]; - - shaderIndexParam = Parameters["ShaderIndex"]; - } - } -} diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx deleted file mode 100644 index ee5ecb7..0000000 --- a/Effects/PBREffect.fx +++ /dev/null @@ -1,313 +0,0 @@ -#include "Macros.fxh" //from FNA - -static const float PI = 3.141592653589793; - -// Samplers - -DECLARE_TEXTURE(AlbedoTexture, 0); -DECLARE_TEXTURE(NormalTexture, 1); -DECLARE_TEXTURE(EmissionTexture, 2); -DECLARE_TEXTURE(OcclusionTexture, 3); -DECLARE_TEXTURE(MetallicRoughnessTexture, 4); -DECLARE_CUBEMAP(EnvDiffuseTexture, 8); -DECLARE_TEXTURE(BrdfLutTexture, 9); -DECLARE_CUBEMAP(EnvSpecularTexture, 10); - -BEGIN_CONSTANTS - - // PBR Values - float3 AlbedoValue _ps(c0) _cb(c0); - float MetallicValue _ps(c1) _cb(c1); - float RoughnessValue _ps(c2) _cb(c2); - float AO _ps(c3) _cb(c3); - - // Light Info - float3 LightPositions[4] _ps(c4) _cb(c4); - float3 LightColors[4] _ps(c8) _cb(c8); - - float3 EyePosition _ps(c12) _cb(c12); - - float4x4 World _vs(c0) _cb(c16); - float4x4 WorldInverseTranspose _vs(c4) _cb(c20); - -MATRIX_CONSTANTS - - float4x4 WorldViewProjection _vs(c8) _cb(c0); - -END_CONSTANTS - -struct VertexShaderInput -{ - float4 Position : POSITION; - float3 Normal : NORMAL; - float2 TexCoord : TEXCOORD0; -}; - -struct PixelShaderInput -{ - float4 Position : SV_Position; - float2 TexCoord : TEXCOORD0; - float3 PositionWS : TEXCOORD1; - float3 NormalWS : TEXCOORD2; -}; - -PixelShaderInput main_vs(VertexShaderInput input) -{ - PixelShaderInput output; - - output.TexCoord = input.TexCoord; - output.PositionWS = mul(input.Position, World).xyz; - output.NormalWS = mul(input.Normal, (float3x3)WorldInverseTranspose).xyz; - output.Position = mul(input.Position, WorldViewProjection); - - return output; -} - -float3 FresnelSchlick(float cosTheta, float3 F0) -{ - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -float DistributionGGX(float3 N, float3 H, float roughness) -{ - float a = roughness * roughness; - float a2 = a * a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH * NdotH; - - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; - - return num / denom; -} - -float GeometrySchlickGGX(float NdotV, float roughness) -{ - float r = (roughness + 1.0); - float k = (r * r) / 8.0; - - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; - - return num / denom; -} - -float GeometrySmith(float3 N, float3 V, float3 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; -} - -// Easy trick to get tangent-normals to world-space to keep PBR code simplified. -float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal) -{ - float3 tangentNormal = SAMPLE_TEXTURE(NormalTexture, texCoords).xyz * 2.0 - 1.0; - - float3 Q1 = ddx(worldPos); - float3 Q2 = ddy(worldPos); - float2 st1 = ddx(texCoords); - float2 st2 = ddy(texCoords); - - float3 N = normalize(normal); - float3 T = normalize(Q1*st2.y - Q2*st1.y); - float3 B = -normalize(cross(N, T)); - float3x3 TBN = float3x3(T, B, N); - - return normalize(mul(tangentNormal, TBN)); -} - -float4 ComputeColor( - float3 worldPosition, - float3 worldNormal, - float3 albedo, - float metallic, - float roughness -) { - float3 V = normalize(EyePosition - worldPosition); - float3 N = worldNormal; - - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); - - float3 Lo = float3(0.0, 0.0, 0.0); - - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - worldPosition; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); - - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - float NDF = DistributionGGX(N, H, roughness); - float G = GeometrySmith(N, V, L, roughness); - float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0); - - float3 numerator = NDF * G * F; - float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0); - float3 specular = numerator / max(denominator, 0.001); - - float3 kS = F; - float3 kD = float3(1.0, 1.0, 1.0) - kS; - - kD *= 1.0 - metallic; - - float NdotL = max(dot(N, L), 0.0); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO; - float3 color = ambient + Lo; - - color = color / (color + float3(1.0, 1.0, 1.0)); - float exposureConstant = 1.0 / 2.2; - color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant)); - - return float4(color, 1.0); -} - -// The case where we have no texture maps for any PBR data -float4 None(PixelShaderInput input) : SV_TARGET0 -{ - return ComputeColor( - input.PositionWS, - input.NormalWS, - AlbedoValue, - MetallicValue, - RoughnessValue - ); -} - -float4 AlbedoMapPS(PixelShaderInput input) : SV_TARGET -{ - float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; - - return ComputeColor( - input.PositionWS, - input.NormalWS, - albedo, - MetallicValue, - RoughnessValue - ); -} - -float4 MetallicRoughnessPS(PixelShaderInput input) : SV_TARGET -{ - float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - - return ComputeColor( - input.PositionWS, - input.NormalWS, - AlbedoValue, - metallicRoughness.r, - metallicRoughness.g - ); -} - -float4 NormalPS(PixelShaderInput input) : SV_TARGET -{ - float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - - return ComputeColor( - input.PositionWS, - normal, - AlbedoValue, - MetallicValue, - RoughnessValue - ); -} - -float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET -{ - float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; - float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - - return ComputeColor( - input.PositionWS, - input.NormalWS, - albedo, - metallicRoughness.r, - metallicRoughness.g - ); -} - -float4 AlbedoNormalPS(PixelShaderInput input) : SV_TARGET -{ - float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; - float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - - return ComputeColor( - input.PositionWS, - normal, - albedo, - MetallicValue, - RoughnessValue - ); -} - -float4 MetallicRoughnessNormalPS(PixelShaderInput input) : SV_TARGET -{ - float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - - return ComputeColor( - input.PositionWS, - normal, - AlbedoValue, - metallicRoughness.r, - metallicRoughness.g - ); -} - -float4 AlbedoMetallicRoughnessNormalMapPS(PixelShaderInput input) : SV_TARGET -{ - float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; - float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - - return ComputeColor( - input.PositionWS, - normal, - albedo, - metallicRoughness.r, - metallicRoughness.g - ); -} - -PixelShader PSArray[8] = -{ - compile ps_3_0 None(), - - compile ps_3_0 AlbedoMapPS(), - compile ps_3_0 MetallicRoughnessPS(), - compile ps_3_0 NormalPS(), - - compile ps_3_0 AlbedoMetallicRoughnessMapPS(), - compile ps_3_0 AlbedoNormalPS(), - compile ps_3_0 MetallicRoughnessNormalPS(), - - compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS() -}; - -int PSIndices[8] = -{ - 0, 1, 2, 3, 4, 5, 6, 7 -}; - -int ShaderIndex = 0; - -Technique PBR -{ - Pass - { - VertexShader = compile vs_3_0 main_vs(); - PixelShader = (PSArray[PSIndices[ShaderIndex]]); - } -} diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb deleted file mode 100644 index 97637627ab81ffc08b726b0604530721a4ea9bec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38008 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 + var meshes = new List(); foreach (var mesh in sharpModel.LogicalMeshes) { - var meshParts = new List(); + var meshParts = new List(); foreach (var primitive in mesh.Primitives) { @@ -27,10 +27,10 @@ namespace Smuggler ); } - meshes.Add(new Mesh(meshParts.ToArray())); + meshes.Add(new MeshData(meshParts.ToArray())); } - var model = new Model(meshes.ToArray()); + var model = new ModelData(meshes.ToArray()); return model; } @@ -98,7 +98,7 @@ namespace Smuggler return null; } - private static MeshPart ImportMeshPart(GraphicsDevice graphicsDevice, System.Type vertexType, SharpGLTF.Schema2.MeshPrimitive primitive) + private static MeshPartData ImportMeshPart(GraphicsDevice graphicsDevice, System.Type vertexType, SharpGLTF.Schema2.MeshPrimitive primitive) { var indices = Indices(primitive); var positions = Positions(primitive); @@ -137,70 +137,41 @@ namespace Smuggler ImportVertexPositionTexture(primitive, vertexBuffer, indices, positions); } - var effect = new PBREffect(graphicsDevice); + var meshPartData = new MeshPartData( + vertexBuffer, + indexBuffer, + positions, + triangles + ); if (primitive.Material != null) { var normalChannel = primitive.Material.FindChannel("Normal"); if (normalChannel.HasValue) { - if (normalChannel.Value.Texture != null) - { - effect.NormalTexture = Texture2D.FromStream( - graphicsDevice, - normalChannel.Value.Texture.PrimaryImage.Content.Open() - ); - } + if (normalChannel.Value.Texture != null) + { + meshPartData.NormalTexture = Texture2D.FromStream( + graphicsDevice, + normalChannel.Value.Texture.PrimaryImage.Content.Open() + ); + } } - //var occlusionChannel = primitive.Material.FindChannel("Occlusion"); - //if (occlusionChannel.HasValue) - //{ - // if (occlusionChannel.Value.Texture != null) - // { - // effect.OcclusionTexture = Texture2D.FromStream( - // graphicsDevice, - // occlusionChannel.Value.Texture.PrimaryImage.Content.Open() - // ); - // } - - // effect.OcclusionStrength = occlusionChannel.Value.Parameter.X; - //} - - //var emissiveChannel = primitive.Material.FindChannel("Emissive"); - //if (emissiveChannel.HasValue) - //{ - // if (emissiveChannel.Value.Texture != null) - // { - // effect.EmissionTexture = Texture2D.FromStream( - // graphicsDevice, - // emissiveChannel.Value.Texture.PrimaryImage.Content.Open() - // ); - // } - - // var parameter = emissiveChannel.Value.Parameter; - - // effect.EmissiveFactor = new Vector3( - // parameter.X, - // parameter.Y, - // parameter.Z - // ); - //} - var albedoChannel = primitive.Material.FindChannel("BaseColor"); if (albedoChannel.HasValue) { if (albedoChannel.Value.Texture != null) { - effect.AlbedoTexture = Texture2D.FromStream( - graphicsDevice, - albedoChannel.Value.Texture.PrimaryImage.Content.Open() - ); + meshPartData.AlbedoTexture = Texture2D.FromStream( + graphicsDevice, + albedoChannel.Value.Texture.PrimaryImage.Content.Open() + ); } var parameter = albedoChannel.Value.Parameter; - effect.Albedo = new Vector3( + meshPartData.Albedo = new Vector3( parameter.X, parameter.Y, parameter.Z @@ -212,63 +183,20 @@ namespace Smuggler { if (metallicRoughnessChannel.Value.Texture != null) { - effect.MetallicRoughnessTexture = Texture2D.FromStream( - graphicsDevice, - metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() - ); + meshPartData.MetallicRoughnessTexture = Texture2D.FromStream( + graphicsDevice, + metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open() + ); } var parameter = metallicRoughnessChannel.Value.Parameter; - effect.Metallic = parameter.X; - effect.Roughness = parameter.Y; + meshPartData.Metallic = parameter.X; + meshPartData.Roughness = parameter.Y; } } - effect.Albedo = new Vector3(0.5f, 0, 0); - effect.AO = 1f; - - effect.Lights[0] = new PBRLight( - new Vector3(-10f, 10f, -5f), - new Vector3(300f, 300f, 300f) - ); - - effect.Lights[1] = new PBRLight( - new Vector3(10f, 10f, 5f), - new Vector3(300f, 300f, 300f) - ); - - effect.Lights[2] = new PBRLight( - new Vector3(-10f, -10f, 5f), - new Vector3(300f, 300f, 300f) - ); - - effect.Lights[3] = new PBRLight( - new Vector3(10f, -10f, 5f), - new Vector3(300f, 300f, 300f) - ); - - /* FIXME: how to load cube maps from GLTF? */ - /* - var diffuseChannel = primitive.Material.FindChannel("Diffuse"); - if (diffuseChannel.HasValue) - { - } - - var specularChannel = primitive.Material.FindChannel("SpecularGlossiness"); - if (specularChannel.HasValue) - { - } - */ - - - return new MeshPart( - vertexBuffer, - indexBuffer, - positions, - triangles, - effect - ); + return meshPartData; } /* Attribute Getters */ @@ -332,7 +260,7 @@ namespace Smuggler private static Triangle[] Triangles(SharpGLTF.Schema2.MeshPrimitive primitive) { var triangles = new List(); - + foreach (var (a, b, c) in primitive.GetTriangleIndices()) { triangles.Add(new Triangle(a, b, c)); @@ -361,7 +289,8 @@ namespace Smuggler VertexBuffer vertexBuffer, uint[] indices, Vector3[] positions - ) { + ) + { var colors = Colors(primitive); var vertices = new VertexPositionColor[positions.Length]; @@ -385,7 +314,8 @@ namespace Smuggler VertexBuffer vertexBuffer, uint[] indices, Vector3[] positions - ) { + ) + { var colors = Colors(primitive); var texcoords = TexCoords(primitive); @@ -412,7 +342,8 @@ namespace Smuggler VertexBuffer vertexBuffer, uint[] indices, Vector3[] positions - ) { + ) + { var normals = Normals(primitive); var texcoords = TexCoords(primitive); @@ -439,7 +370,8 @@ namespace Smuggler VertexBuffer vertexBuffer, uint[] indices, Vector3[] positions - ) { + ) + { var texcoords = TexCoords(primitive); var vertices = new VertexPositionTexture[positions.Length]; diff --git a/Mesh.cs b/Mesh.cs deleted file mode 100644 index f8bd217..0000000 --- a/Mesh.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Smuggler -{ - public class Mesh - { - public MeshPart[] MeshParts { get; } - - public Mesh(MeshPart[] meshParts) - { - MeshParts = meshParts; - } - - public void Draw(GraphicsDevice graphicsDevice, Matrix world, Matrix view, Matrix projection) - { - foreach (var meshPart in MeshParts) - { - meshPart.Draw(graphicsDevice, world, view, projection); - } - } - } -} diff --git a/MeshData.cs b/MeshData.cs new file mode 100644 index 0000000..3c80670 --- /dev/null +++ b/MeshData.cs @@ -0,0 +1,12 @@ +namespace Smuggler +{ + public class MeshData + { + public MeshPartData[] MeshParts { get; } + + public MeshData(MeshPartData[] meshParts) + { + MeshParts = meshParts; + } + } +} diff --git a/MeshPart.cs b/MeshPart.cs deleted file mode 100644 index bc019ea..0000000 --- a/MeshPart.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Smuggler -{ - public class MeshPart - { - public IndexBuffer IndexBuffer { get; } - public VertexBuffer VertexBuffer { get; } - public Triangle[] Triangles { get; } - public PBREffect Effect { get; } - public Vector3[] Positions { get; } - - public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, PBREffect effect) - { - VertexBuffer = vertexBuffer; - IndexBuffer = indexBuffer; - Positions = positions; - Triangles = triangles; - Effect = effect; - } - - public void Draw(GraphicsDevice graphicsDevice, Matrix world, Matrix view, Matrix projection) - { - graphicsDevice.SetVertexBuffer(VertexBuffer); - graphicsDevice.Indices = IndexBuffer; - - Effect.World = world; - Effect.View = view; - Effect.Projection = projection; - - foreach (var pass in Effect.CurrentTechnique.Passes) - { - pass.Apply(); - - graphicsDevice.DrawIndexedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - VertexBuffer.VertexCount, - 0, - Triangles.Length - ); - } - } - } -} diff --git a/MeshPartData.cs b/MeshPartData.cs new file mode 100644 index 0000000..2f935d3 --- /dev/null +++ b/MeshPartData.cs @@ -0,0 +1,34 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Smuggler +{ + public class MeshPartData + { + public IndexBuffer IndexBuffer { get; } + public VertexBuffer VertexBuffer { get; } + public Triangle[] Triangles { get; } + public Vector3[] Positions { get; } + + public Texture2D AlbedoTexture { get; set; } = null; + public Texture2D NormalTexture { get; set; } = null; + public Texture2D MetallicRoughnessTexture { get; set; } = null; + + public Vector3 Albedo { get; set; } = Vector3.One; + public float Metallic { get; set; } = 0.5f; + public float Roughness { get; set; } = 0.5f; + + public MeshPartData( + VertexBuffer vertexBuffer, + IndexBuffer indexBuffer, + Vector3[] positions, + Triangle[] triangles + ) + { + VertexBuffer = vertexBuffer; + IndexBuffer = indexBuffer; + Positions = positions; + Triangles = triangles; + } + } +} diff --git a/Model.cs b/Model.cs deleted file mode 100644 index eeba250..0000000 --- a/Model.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Smuggler -{ - public class Model - { - public Mesh[] Meshes { get; } - public Texture2D[] Textures { get; } - - public Model(Mesh[] meshes) - { - Meshes = meshes; - } - - public void Draw(GraphicsDevice graphicsDevice, Matrix world, Matrix view, Matrix projection) - { - foreach (var mesh in Meshes) - { - mesh.Draw(graphicsDevice, world, view, projection); - } - } - } -} diff --git a/ModelData.cs b/ModelData.cs new file mode 100644 index 0000000..3d1a03a --- /dev/null +++ b/ModelData.cs @@ -0,0 +1,15 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Smuggler +{ + public class ModelData + { + public MeshData[] Meshes { get; } + + public ModelData(MeshData[] meshes) + { + Meshes = meshes; + } + } +} diff --git a/Resources.cs b/Resources.cs deleted file mode 100644 index 53fc5ea..0000000 --- a/Resources.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.IO; - -namespace Smuggler -{ - internal class Resources - { - public static byte[] PBREffect - { - get - { - if (pbrEffect == null) - { - pbrEffect = GetResource("PBREffect"); - } - return pbrEffect; - } - } - - private static byte[] pbrEffect; - - private static byte[] GetResource(string name) - { - Stream stream = typeof(Resources).Assembly.GetManifestResourceStream( - "Smuggler.Resources." + name + ".fxb" - ); - using (MemoryStream ms = new MemoryStream()) - { - stream.CopyTo(ms); - return ms.ToArray(); - } - } - } -} diff --git a/Smuggler.csproj b/Smuggler.csproj index e5628ef..c9385e5 100644 --- a/Smuggler.csproj +++ b/Smuggler.csproj @@ -19,10 +19,4 @@ - - - Smuggler.Resources.PBREffect.fxb - - - From ba97759191a7f770ae6b80889ca04601e15ee65b Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Fri, 21 Aug 2020 21:22:46 -0700 Subject: [PATCH 16/16] add a core and framework csproj --- Smuggler.csproj => Smuggler.Core.csproj | 0 Smuggler.Framework.csproj | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+) rename Smuggler.csproj => Smuggler.Core.csproj (100%) create mode 100644 Smuggler.Framework.csproj diff --git a/Smuggler.csproj b/Smuggler.Core.csproj similarity index 100% rename from Smuggler.csproj rename to Smuggler.Core.csproj diff --git a/Smuggler.Framework.csproj b/Smuggler.Framework.csproj new file mode 100644 index 0000000..a659c97 --- /dev/null +++ b/Smuggler.Framework.csproj @@ -0,0 +1,22 @@ + + + + netstandard2.0 + Smuggler + 0.1.0 + Cassandra Lugo; Evan Hemsley + Cassandra Lugo and Evan Hemsley 2020 + true + Smuggler + AnyCPU;x86 + + + + + + + + + + +