静态反射
//计算反射
float3 ReflectionColor = GetReflectionColor(MatConstBuffer, ModelNormal, MVOut.WorldPosition.xyz);
float3 FresnelSchlickMethod(float3 InF0,float3 InObjectPointNormal,float3 InDirection,int InPowM)
{
return InF0 + (1.f - InF0) * pow(1.f - saturate(dot(InObjectPointNormal, InDirection)),InPowM);
}
float4 GetMaterialBaseColor(MaterialConstBuffer MatConstBuffer,float2 InTexCoord)
{
if (MatConstBuffer.BaseColorIndex != -1)
{
return SimpleTexture2DMap[MatConstBuffer.BaseColorIndex].Sample(TextureSampler, InTexCoord);
}
return MatConstBuffer.BaseColor;
}
float3 GetMaterialNormals(
MaterialConstBuffer MatConstBuffer,
float2 InTexCoord,
float3 InUnitWorldNormal,
float3 InWorldTangent)
{
if (MatConstBuffer.NormalIndex != -1)
{
float4 SampleNormal = SimpleTexture2DMap[MatConstBuffer.NormalIndex].Sample(AnisotropicSampler, InTexCoord);
//[0,1]->[-1,1] => [0,1] * 2.f = [0,2] => [0-2]-1.f = [-1,1];
float3 NormalsInTangentSpace = 2.0f * SampleNormal.rgb - 1.f;
//拿到世界TBN
float3x3 TBN = GetBuildTBNMatrix(InUnitWorldNormal, InWorldTangent);
//把切线空间下的采样法线转为世界的法线
return mul(NormalsInTangentSpace,TBN);
}
return InUnitWorldNormal;
}
float4 GetMaterialSpecular(MaterialConstBuffer MatConstBuffer, float2 InTexCoord)
{
if (MatConstBuffer.SpecularIndex != -1)
{
return SimpleTexture2DMap[MatConstBuffer.SpecularIndex].Sample(TextureSampler, InTexCoord);
}
return float4(MatConstBuffer.SpecularColor,1.f);
}
float3 GetReflect(float3 InUnitWorldNormal,float3 WorldPosition)
{
float3 ViewDirection = normalize(ViewportPosition.xyz - WorldPosition);
return reflect(-ViewDirection, InUnitWorldNormal);
}
float3 GetRefract(float3 InUnitWorldNormal, float3 WorldPosition,float InRefractiveValue)
{
float3 ViewDirection = normalize(ViewportPosition.xyz - WorldPosition);
return refract(-ViewDirection,InUnitWorldNormal,InRefractiveValue);
}
float3 GetReflectionSampleColor(float3 InUnitWorldNormal,float3 NewReflect)
{
return SimpleCubeMap.Sample(TextureSampler, NewReflect);
}
float GetShininess(MaterialConstBuffer MatConstBuffer)
{
return 1.f - MatConstBuffer.MaterialRoughness;
}
float3 FresnelSchlickFactor(MaterialConstBuffer MatConstBuffer, float3 InUnitWorldNormal, float3 InReflect)
{
return FresnelSchlickMethod(MatConstBuffer.FresnelF0, InUnitWorldNormal, InReflect,5);
}
float3 FresnelSchlickRoughness(float NV, float3 F0, float Roughness)
{
return F0 + (max(float3(1.0 - Roughness, 1.0 - Roughness, 1.0 - Roughness), F0) - F0) * pow(1.0 - NV, 5.0);
}
//获取反射的颜色
float3 GetReflectionColor(MaterialConstBuffer MatConstBuffer, float3 InUnitWorldNormal, float3 WorldPosition)
{
float3 NewReflect = GetReflect(InUnitWorldNormal, WorldPosition);
float3 SampleReflectionColor = GetReflectionSampleColor(InUnitWorldNormal, NewReflect);
float Shininess = GetShininess(MatConstBuffer);
float3 FresnelFactor = FresnelSchlickFactor(MatConstBuffer, InUnitWorldNormal, NewReflect);
return SampleReflectionColor * FresnelFactor * Shininess;
}
动态反射
在Obj周围架设六个摄像机(六个方向)进行采样,因此将摄像机层分层给管线使用。
离屏渲染
应用:截屏、AO、阴影、反射
相当于GPU绘制了多个看不到的RTV——上述的六个相机每个渲染成一个RTV。
六个RTV组成CubeMap(在Shader中)给反射和折射进行采样
代码上的变化:摄像机层分离、RT层分离
折射
采样方法如上。
但要注意的是:开启折射的物体不是透明物体,它在折射不透明物体渲染层。
{
//先计算折射
float3 NewRefract = GetRefract(ModelNormal, MVOut.WorldPosition.xyz, MatConstBuffer.Refraction);
float3 SampleRefractColor = GetReflectionSampleColor(ModelNormal, NewRefract);//采样
//计算反射
float3 NewReflect = GetReflect(ModelNormal, MVOut.WorldPosition.xyz);
float3 SampleReflectionColor = GetReflectionSampleColor(ModelNormal, NewReflect);//采样
//算A通道
float3 V = normalize(ViewportPosition.xyz - MVOut.WorldPosition.xyz);
float Shininess = GetShininess(MatConstBuffer);
float3 FresnelFactor = FresnelSchlickFactor(MatConstBuffer, ModelNormal, V);
float3 Color = lerp(SampleRefractColor , SampleReflectionColor, pow(Shininess * FresnelFactor,2));
MVOut.Color.xyz += Color;
break;
}
//折射
float3 GetRefract(float3 InUnitWorldNormal, float3 WorldPosition,float InRefractiveValue)
{
float3 ViewDirection = normalize(ViewportPosition.xyz - WorldPosition);
return refract(-ViewDirection,InUnitWorldNormal,InRefractiveValue);
}
//反射
float3 GetReflect(float3 InUnitWorldNormal,float3 WorldPosition)
{
float3 ViewDirection = normalize(ViewportPosition.xyz - WorldPosition);
return reflect(-ViewDirection, InUnitWorldNormal);
}
阴影
代码上的变化:PSO层分离。
1.偏移补偿(DX12支持) BY 斜率
解决粉刺——产生原因:摄像机屏幕上的相邻两个像素同时看向一个文素,分别对应同一个文素的暗面和亮面。但在计算中一个文素对应一个值,所有亮面变暗了(反之亦然),就形成了粉刺。
偏移一下让整个文素在阴影内或外即可。
ShaderViewMatrix:灯光位置
平行光:正交矩阵(DepthBias=100000)
聚光灯:透视矩阵(DepthBias=1000--平衡粉刺和阴影飞出去之间的效果)
百分比渐进算法(PCF)
4采样
九采样