trying stuff but the shading still seems to be model-relative
parent
37b45caea2
commit
4b36860b62
|
@ -5,48 +5,81 @@ namespace Smuggler
|
||||||
{
|
{
|
||||||
public struct PBRLight
|
public struct PBRLight
|
||||||
{
|
{
|
||||||
public Vector3 direction;
|
public Vector3 position;
|
||||||
public Vector3 colour;
|
public Vector3 color;
|
||||||
|
|
||||||
public PBRLight(Vector3 direction, Vector3 colour)
|
public PBRLight(Vector3 position, Vector3 colour)
|
||||||
{
|
{
|
||||||
this.direction = direction;
|
this.position = position;
|
||||||
this.colour = colour;
|
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
|
public class PBREffect : Effect
|
||||||
{
|
{
|
||||||
readonly EffectParameter modelParam;
|
EffectParameter worldParam;
|
||||||
readonly EffectParameter viewParam;
|
EffectParameter viewParam;
|
||||||
readonly EffectParameter projectionParam;
|
EffectParameter projectionParam;
|
||||||
readonly EffectParameter lightDirParam;
|
EffectParameter worldViewProjectionParam;
|
||||||
readonly EffectParameter lightColourParam;
|
EffectParameter worldInverseTransposeParam;
|
||||||
readonly EffectParameter normalScaleParam;
|
|
||||||
readonly EffectParameter emissiveFactorParam;
|
|
||||||
readonly EffectParameter occlusionStrengthParam;
|
|
||||||
readonly EffectParameter metallicRoughnessValuesParam;
|
|
||||||
readonly EffectParameter baseColorFactorParam;
|
|
||||||
readonly EffectParameter cameraLookParam;
|
|
||||||
|
|
||||||
readonly EffectParameter baseColourTextureParam;
|
EffectParameter baseColorTextureParam;
|
||||||
readonly EffectParameter normalTextureParam;
|
EffectParameter normalTextureParam;
|
||||||
readonly EffectParameter emissionTextureParam;
|
EffectParameter emissionTextureParam;
|
||||||
readonly EffectParameter occlusionTextureParam;
|
EffectParameter occlusionTextureParam;
|
||||||
readonly EffectParameter metallicRoughnessTextureParam;
|
EffectParameter metallicRoughnessTextureParam;
|
||||||
readonly EffectParameter envDiffuseTextureParam;
|
EffectParameter envDiffuseTextureParam;
|
||||||
readonly EffectParameter brdfLutTextureParam;
|
EffectParameter brdfLutTextureParam;
|
||||||
readonly EffectParameter envSpecularTextureParam;
|
EffectParameter envSpecularTextureParam;
|
||||||
|
|
||||||
|
EffectParameter lightPositionsParam;
|
||||||
|
EffectParameter lightColorsParam;
|
||||||
|
|
||||||
|
EffectParameter albedoParam;
|
||||||
|
EffectParameter metallicParam;
|
||||||
|
EffectParameter roughnessParam;
|
||||||
|
EffectParameter aoParam;
|
||||||
|
|
||||||
|
EffectParameter eyePositionParam;
|
||||||
|
|
||||||
Matrix world = Matrix.Identity;
|
Matrix world = Matrix.Identity;
|
||||||
Matrix view = Matrix.Identity;
|
Matrix view = Matrix.Identity;
|
||||||
Matrix projection = Matrix.Identity;
|
Matrix projection = Matrix.Identity;
|
||||||
PBRLight light = new PBRLight();
|
PBRLightCollection pbrLightCollection;
|
||||||
float normalScale = 1;
|
|
||||||
Vector3 emissiveFactor;
|
Vector3 albedo;
|
||||||
float occlusionStrength;
|
float metallic;
|
||||||
Vector2 metallicRoughnessValue;
|
float roughness;
|
||||||
Vector4 baseColorFactor;
|
float ao;
|
||||||
|
|
||||||
|
// FIXME: lazily set properties for performance
|
||||||
|
|
||||||
public Matrix World
|
public Matrix World
|
||||||
{
|
{
|
||||||
|
@ -54,7 +87,9 @@ namespace Smuggler
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
world = value;
|
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;
|
view = value;
|
||||||
viewParam.SetValue(view);
|
viewParam.SetValue(view);
|
||||||
cameraLookParam.SetValue(-new Vector3(
|
worldViewProjectionParam.SetValue(world * view * projection);
|
||||||
view.M13,
|
eyePositionParam.SetValue(Matrix.Invert(view).Translation);
|
||||||
view.M23,
|
|
||||||
view.M33
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,75 +111,61 @@ namespace Smuggler
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
projection = value;
|
projection = value;
|
||||||
projectionParam.SetValue(value);
|
projectionParam.SetValue(projection);
|
||||||
|
worldViewProjectionParam.SetValue(world * view * projection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PBRLight Light
|
public PBRLightCollection Lights
|
||||||
{
|
{
|
||||||
get { return light; }
|
get { return pbrLightCollection; }
|
||||||
set
|
internal set { pbrLightCollection = value; }
|
||||||
{
|
|
||||||
light = value;
|
|
||||||
lightDirParam.SetValue(light.direction);
|
|
||||||
lightColourParam.SetValue(light.colour);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float NormalScale
|
public Vector3 Albedo
|
||||||
{
|
{
|
||||||
get { return normalScale; }
|
get { return albedo; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
normalScale = value;
|
albedo = value;
|
||||||
normalScaleParam.SetValue(normalScale);
|
albedoParam.SetValue(albedo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 EmissiveFactor
|
public float Metallic
|
||||||
{
|
{
|
||||||
get { return emissiveFactor; }
|
get { return metallic; }
|
||||||
set
|
|
||||||
{
|
|
||||||
emissiveFactor = value;
|
|
||||||
emissiveFactorParam.SetValue(emissiveFactor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float OcclusionStrength
|
|
||||||
{
|
|
||||||
get { return occlusionStrength; }
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
occlusionStrength = value;
|
metallic = value;
|
||||||
occlusionStrengthParam.SetValue(occlusionStrength);
|
metallicParam.SetValue(metallic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 MetallicRoughnessValue
|
public float Roughness
|
||||||
{
|
{
|
||||||
get { return metallicRoughnessValue; }
|
get { return roughness; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
metallicRoughnessValue = value;
|
roughness = value;
|
||||||
metallicRoughnessValuesParam.SetValue(metallicRoughnessValue);
|
roughnessParam.SetValue(roughness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector4 BaseColorFactor
|
public float AO
|
||||||
{
|
{
|
||||||
get { return baseColorFactor; }
|
get { return ao; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
baseColorFactor = value;
|
ao = value;
|
||||||
baseColorFactorParam.SetValue(baseColorFactor);
|
aoParam.SetValue(ao);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Texture2D BaseColourTexture
|
public Texture2D BaseColourTexture
|
||||||
{
|
{
|
||||||
get { return baseColourTextureParam.GetValueTexture2D(); }
|
get { return baseColorTextureParam.GetValueTexture2D(); }
|
||||||
set { baseColourTextureParam.SetValue(value); }
|
set { baseColorTextureParam.SetValue(value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Texture2D NormalTexture
|
public Texture2D NormalTexture
|
||||||
|
@ -194,66 +212,31 @@ namespace Smuggler
|
||||||
|
|
||||||
public PBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.PBREffect)
|
public PBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.PBREffect)
|
||||||
{
|
{
|
||||||
modelParam = Parameters["model"];
|
CacheEffectParameters(null);
|
||||||
viewParam = Parameters["view"];
|
|
||||||
projectionParam = Parameters["projection"];
|
|
||||||
|
|
||||||
lightDirParam = Parameters["lightDir"];
|
pbrLightCollection = new PBRLightCollection(
|
||||||
lightColourParam = Parameters["lightColour"];
|
Parameters["LightPositions"],
|
||||||
|
Parameters["LightColors"]
|
||||||
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)
|
protected PBREffect(PBREffect cloneSource) : base(cloneSource)
|
||||||
{
|
{
|
||||||
modelParam = Parameters["model"];
|
CacheEffectParameters(cloneSource);
|
||||||
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"];
|
|
||||||
|
|
||||||
World = cloneSource.World;
|
World = cloneSource.World;
|
||||||
View = cloneSource.View;
|
View = cloneSource.View;
|
||||||
Projection = cloneSource.Projection;
|
Projection = cloneSource.Projection;
|
||||||
|
|
||||||
Light = cloneSource.Light;
|
Lights = new PBRLightCollection(
|
||||||
|
Parameters["LightPositions"],
|
||||||
|
Parameters["LightColors"]
|
||||||
|
);
|
||||||
|
|
||||||
NormalScale = cloneSource.normalScale;
|
for (int i = 0; i < 4; i++)
|
||||||
EmissiveFactor = cloneSource.EmissiveFactor;
|
{
|
||||||
OcclusionStrength = cloneSource.OcclusionStrength;
|
Lights[i] = cloneSource.Lights[i];
|
||||||
MetallicRoughnessValue = cloneSource.MetallicRoughnessValue;
|
}
|
||||||
BaseColorFactor = cloneSource.BaseColorFactor;
|
|
||||||
|
|
||||||
BaseColourTexture = cloneSource.BaseColourTexture;
|
BaseColourTexture = cloneSource.BaseColourTexture;
|
||||||
NormalTexture = cloneSource.NormalTexture;
|
NormalTexture = cloneSource.NormalTexture;
|
||||||
|
@ -263,6 +246,11 @@ namespace Smuggler
|
||||||
EnvDiffuseTexture = cloneSource.EnvDiffuseTexture;
|
EnvDiffuseTexture = cloneSource.EnvDiffuseTexture;
|
||||||
BRDFLutTexture = cloneSource.BRDFLutTexture;
|
BRDFLutTexture = cloneSource.BRDFLutTexture;
|
||||||
EnvSpecularTexture = cloneSource.EnvSpecularTexture;
|
EnvSpecularTexture = cloneSource.EnvSpecularTexture;
|
||||||
|
|
||||||
|
Albedo = cloneSource.Albedo;
|
||||||
|
Metallic = cloneSource.Metallic;
|
||||||
|
Roughness = cloneSource.Roughness;
|
||||||
|
AO = cloneSource.AO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Effect Clone()
|
public override Effect Clone()
|
||||||
|
@ -275,5 +263,33 @@ namespace Smuggler
|
||||||
{
|
{
|
||||||
base.OnApply();
|
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"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,408 +1,159 @@
|
||||||
|
#include "Macros.fxh" //from FNA
|
||||||
|
|
||||||
#include "Macros.fxh"
|
static const float PI = 3.141592653589793;
|
||||||
|
|
||||||
#define NORMALS
|
// Transformation Matrices
|
||||||
#define UV
|
|
||||||
|
|
||||||
// A constant buffer that stores the three basic column-major matrices for composing geometry.
|
float4x4 World;
|
||||||
cbuffer ModelViewProjectionConstantBuffer : register(b0)
|
float4x4 View;
|
||||||
{
|
float4x4 Projection;
|
||||||
matrix model;
|
|
||||||
matrix view;
|
float4x4 WorldViewProjection;
|
||||||
matrix projection;
|
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
|
struct VertexShaderInput
|
||||||
{
|
{
|
||||||
float4 position : POSITION;
|
float4 Position : POSITION;
|
||||||
#ifdef NORMALS
|
float3 Normal : NORMAL;
|
||||||
float3 normal : NORMAL;
|
float2 TexCoord : TEXCOORD0;
|
||||||
#endif
|
|
||||||
#ifdef UV
|
|
||||||
float2 texcoord : TEXCOORD0;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Per-pixel color data passed through the pixel shader.
|
|
||||||
struct PixelShaderInput
|
struct PixelShaderInput
|
||||||
{
|
{
|
||||||
float4 position : SV_POSITION;
|
float4 Position : SV_POSITION;
|
||||||
float3 poswithoutw : POSITION1;
|
float2 TexCoord : TEXCOORD0;
|
||||||
|
float3 PositionWS : TEXCOORD1;
|
||||||
#ifdef NORMALS
|
float3 NormalWS : TEXCOORD2;
|
||||||
float3 normal : NORMAL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float2 texcoord : TEXCOORD0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PixelShaderInput main_vs(VertexShaderInput input)
|
PixelShaderInput main_vs(VertexShaderInput input)
|
||||||
{
|
{
|
||||||
PixelShaderInput output;
|
PixelShaderInput output;
|
||||||
|
|
||||||
// Transform the vertex position into projected space.
|
output.PositionWS = mul(input.Position, World).xyz;
|
||||||
float4 pos = mul(input.position, model);
|
output.TexCoord = input.TexCoord;
|
||||||
output.poswithoutw = float3(pos.xyz) / pos.w;
|
output.NormalWS = normalize(mul(WorldInverseTranspose, input.Normal));
|
||||||
|
|
||||||
#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.Position = mul(input.Position, WorldViewProjection);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
float3 FresnelSchlick(float cosTheta, float3 F0)
|
||||||
// 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;
|
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||||
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
|
float DistributionGGX(float3 N, float3 H, float roughness)
|
||||||
// or from the interpolated mesh normal and tangent attributes.
|
|
||||||
float3 getNormal(float3 position, float3 normal, float2 uv)
|
|
||||||
{
|
{
|
||||||
// Retrieve the tangent space matrix
|
float a = roughness * roughness;
|
||||||
#ifndef HAS_TANGENTS
|
float a2 = a * a;
|
||||||
float3 pos_dx = ddx(position);
|
float NdotH = max(dot(N, H), 0.0);
|
||||||
float3 pos_dy = ddy(position);
|
float NdotH2 = NdotH * NdotH;
|
||||||
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
|
float num = a2;
|
||||||
float3 ng = normalize(normal);
|
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||||
#else
|
denom = PI * denom * denom;
|
||||||
float3 ng = cross(pos_dx, pos_dy);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
t = normalize(t - ng * dot(ng, t));
|
return num / denom;
|
||||||
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
|
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||||
// 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 r = (roughness + 1.0);
|
||||||
float lod = (pbrInputs.perceptualRoughness * mipCount);
|
float k = (r * r) / 8.0;
|
||||||
|
|
||||||
// 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;
|
float num = NdotV;
|
||||||
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
|
||||||
#ifdef USE_TEX_LOD
|
return num / denom;
|
||||||
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())
|
float GeometrySmith(float3 N, float3 V, float3 L, float roughness)
|
||||||
// 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);
|
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()),
|
// The case where we have no texture maps for any PBR data
|
||||||
// where rougher material will reflect less light back to the viewer.
|
float4 None(PixelShaderInput input) : SV_TARGET
|
||||||
// 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;
|
float3 N = normalize(input.NormalWS);
|
||||||
float NdotV = pbrInputs.NdotV;
|
float3 V = normalize(EyePosition - input.PositionWS);
|
||||||
float r = pbrInputs.alphaRoughness;
|
|
||||||
|
|
||||||
float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
|
float3 Lo = float3(0.0, 0.0, 0.0);
|
||||||
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())
|
for (int i = 0; i < 4; i++)
|
||||||
// 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.
|
float3 lightDir = LightPositions[i] - input.PositionWS;
|
||||||
float microfacetDistribution(PBRInfo pbrInputs)
|
float3 L = normalize(lightDir);
|
||||||
{
|
float3 H = normalize(V + L);
|
||||||
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
|
float distance = length(lightDir);
|
||||||
{
|
float attenuation = 1.0 / (distance * distance);
|
||||||
// Metallic and Roughness material properties are packed together
|
float3 radiance = LightColors[i] * attenuation;
|
||||||
// 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
|
float3 F0 = float3(0.04, 0.04, 0.04);
|
||||||
// Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
|
F0 = lerp(F0, Albedo, Metallic);
|
||||||
// This layout intentionally reserves the 'r' channel for (optional) occlusion map data
|
float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||||
float4 mrSample = SAMPLE_TEXTURE(metallicRoughnessTexture, input.texcoord);
|
|
||||||
|
|
||||||
// Had to reverse the order of the channels here - TODO: investigate..
|
float NDF = DistributionGGX(N, H, Roughness);
|
||||||
perceptualRoughness = mrSample.g * perceptualRoughness;
|
float G = GeometrySmith(N, V, L, Roughness);
|
||||||
metallic = mrSample.b * metallic;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
|
float3 numerator = NDF * G * F;
|
||||||
metallic = clamp(metallic, 0.0, 1.0);
|
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,
|
float3 kS = F;
|
||||||
// convert to material roughness by squaring the perceptual roughness [2].
|
float3 kD = float3(1.0, 1.0, 1.0) - kS;
|
||||||
float alphaRoughness = perceptualRoughness * perceptualRoughness;
|
|
||||||
|
|
||||||
// The albedo may be defined from a base texture or a flat color
|
kD *= 1.0 - Metallic;
|
||||||
|
|
||||||
#ifdef HAS_BASECOLORMAP
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
float4 baseColor = SRGBtoLINEAR(SAMPLE_TEXTURE(baseColourTexture, input.texcoord)) * baseColorFactor;
|
Lo += (kD * Albedo / PI + specular) * radiance * NdotL;
|
||||||
#else
|
}
|
||||||
float4 baseColor = baseColorFactor;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float3 f0 = float3(0.04, 0.04, 0.04);
|
float3 ambient = float3(0.03, 0.03, 0.03) * Albedo * AO;
|
||||||
float3 diffuseColor = baseColor.rgb * (float3(1.0, 1.0, 1.0) - f0);
|
float3 color = ambient + Lo;
|
||||||
|
|
||||||
diffuseColor *= 1.0 - metallic;
|
color = color / (color + float3(1.0, 1.0, 1.0));
|
||||||
|
float exposureConstant = 1.0 / 2.2;
|
||||||
float3 specularColor = lerp(f0, baseColor.rgb, metallic);
|
color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant));
|
||||||
|
|
||||||
// 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(color, 1.0);
|
return float4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Technique PBR
|
Technique PBR
|
||||||
{
|
{
|
||||||
Pass pass1
|
Pass Pass1
|
||||||
{
|
{
|
||||||
VertexShader = compile vs_3_0 main_vs();
|
VertexShader = compile vs_3_0 main_vs();
|
||||||
PixelShader = compile ps_3_0 main_ps();
|
PixelShader = compile ps_3_0 None();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,410 @@
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
163
Importer.cs
163
Importer.cs
|
@ -141,98 +141,113 @@ namespace Smuggler
|
||||||
|
|
||||||
if (primitive.Material != null)
|
if (primitive.Material != null)
|
||||||
{
|
{
|
||||||
var normalChannel = primitive.Material.FindChannel("Normal");
|
//var normalChannel = primitive.Material.FindChannel("Normal");
|
||||||
if (normalChannel.HasValue)
|
//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 albedoChannel = primitive.Material.FindChannel("BaseColor");
|
||||||
|
if (albedoChannel.HasValue)
|
||||||
{
|
{
|
||||||
if (normalChannel.Value.Texture != null)
|
//if (albedoChannel.Value.Texture != null)
|
||||||
{
|
//{
|
||||||
effect.NormalTexture = Texture2D.FromStream(
|
// effect.BaseColourTexture = Texture2D.FromStream(
|
||||||
graphicsDevice,
|
// graphicsDevice,
|
||||||
normalChannel.Value.Texture.PrimaryImage.Content.Open()
|
// albedoChannel.Value.Texture.PrimaryImage.Content.Open()
|
||||||
);
|
// );
|
||||||
}
|
//}
|
||||||
|
|
||||||
effect.NormalScale = normalChannel.Value.Parameter.X;
|
var parameter = albedoChannel.Value.Parameter;
|
||||||
}
|
|
||||||
|
|
||||||
var occlusionChannel = primitive.Material.FindChannel("Occlusion");
|
effect.Albedo = new Vector3(
|
||||||
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.X,
|
||||||
parameter.Y,
|
parameter.Y,
|
||||||
parameter.Z
|
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 = baseColorChannel.Value.Parameter;
|
|
||||||
|
|
||||||
effect.BaseColorFactor = new Vector4(
|
|
||||||
parameter.X,
|
|
||||||
parameter.Y,
|
|
||||||
parameter.Z,
|
|
||||||
parameter.W
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var metallicRoughnessChannel = primitive.Material.FindChannel("MetallicRoughness");
|
var metallicRoughnessChannel = primitive.Material.FindChannel("MetallicRoughness");
|
||||||
if (metallicRoughnessChannel.HasValue)
|
if (metallicRoughnessChannel.HasValue)
|
||||||
{
|
{
|
||||||
if (metallicRoughnessChannel.Value.Texture != null)
|
//if (metallicRoughnessChannel.Value.Texture != null)
|
||||||
{
|
//{
|
||||||
effect.MetallicRoughnessTexture = Texture2D.FromStream(
|
// effect.MetallicRoughnessTexture = Texture2D.FromStream(
|
||||||
graphicsDevice,
|
// graphicsDevice,
|
||||||
metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open()
|
// metallicRoughnessChannel.Value.Texture.PrimaryImage.Content.Open()
|
||||||
);
|
// );
|
||||||
}
|
//}
|
||||||
|
|
||||||
var parameter = metallicRoughnessChannel.Value.Parameter;
|
var parameter = metallicRoughnessChannel.Value.Parameter;
|
||||||
|
|
||||||
effect.MetallicRoughnessValue = new Vector2(
|
effect.Metallic = parameter.X;
|
||||||
parameter.X,
|
effect.Roughness = parameter.Y;
|
||||||
parameter.Y
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
effect.Light = new PBRLight(
|
effect.Albedo = new Vector3(0.5f, 0, 0);
|
||||||
new Vector3(0.5f, 0.5f, -0.5f),
|
effect.AO = 1f;
|
||||||
new Vector3(10f, 10f, 10f)
|
|
||||||
|
effect.Lights[0] = new PBRLight(
|
||||||
|
new Vector3(-10f, 10f, 10f),
|
||||||
|
new Vector3(300f, 300f, 300f)
|
||||||
|
);
|
||||||
|
|
||||||
|
effect.Lights[1] = new PBRLight(
|
||||||
|
new Vector3(10f, 10f, 10f),
|
||||||
|
new Vector3(300f, 300f, 300f)
|
||||||
|
);
|
||||||
|
|
||||||
|
effect.Lights[2] = new PBRLight(
|
||||||
|
new Vector3(-10f, -10f, 10f),
|
||||||
|
new Vector3(300f, 300f, 300f)
|
||||||
|
);
|
||||||
|
|
||||||
|
effect.Lights[3] = new PBRLight(
|
||||||
|
new Vector3(10f, -10f, 10f),
|
||||||
|
new Vector3(300f, 300f, 300f)
|
||||||
);
|
);
|
||||||
|
|
||||||
/* FIXME: how to load cube maps from GLTF? */
|
/* FIXME: how to load cube maps from GLTF? */
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<Copyright>Cassandra Lugo and Evan Hemsley 2020</Copyright>
|
<Copyright>Cassandra Lugo and Evan Hemsley 2020</Copyright>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<AssemblyName>Smuggler</AssemblyName>
|
<AssemblyName>Smuggler</AssemblyName>
|
||||||
|
<Platforms>AnyCPU;x86</Platforms>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FNA\FNA.Core.csproj"/>
|
<ProjectReference Include="..\FNA\FNA.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in New Issue