HLSL中的镜面反射
Specular reflection in HLSL
我正在尝试理解HLSL和DirectX11 中的镜面反射
cbuffer ConstantBuffer : register( b0 )
{
matrix World; // Матрица мира
matrix View; // Матрица вида
matrix Projection; // Матрица проекции
float4 vLightDir[3]; // Dir of light
float4 vLightColor[3]; // color of light
float4 vOutputColor; // Active color
//float3 Eye;
}
struct VS_INPUT // Входящие данные вершинного шейдера
{
float4 Pos : POSITION; // Позиция по X, Y, Z
float3 Norm : NORMAL; // Нормаль по X, Y, Z
};
struct PS_INPUT // Входящие данные пиксельного шейдера
{
float4 Pos : SV_POSITION; // Позиция пикселя в проекции (экранная)
float3 Norm : TEXCOORD0; // Относительная нормаль пикселя по tu, tv
};
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Norm = mul( input.Norm, World );
return output;
}
float4 Diffuse( PS_INPUT input) : SV_Target
{
float4 diffuse = float4(1.0, 1.0, 1.0, 1.0);
float4 finalColor = diffuse *0.1;
// Adding all light colours
for(int i=0; i<3; i++)
{
finalColor += saturate( dot( (float3)vLightDir[i], input.Norm) * vLightColor[i] );
}
finalColor.a = 1;
return finalColor;
}
float4 Specular(PS_INPUT input) : SV_Target
{
float4 diffuse = float4(1.0, 0.0, 0.0, 1.0);
float4 finalColor = diffuse *0.1;
float3 Eye = float3(0.0f, 4.0f, -20.0f);
float4 intensity = 0.1;
float power = 4;
float3 R = reflect(-normalize(Eye), input.Norm);
for (int i = 0; i < 3; i++)
{
finalColor += saturate(intensity * vLightColor[i] * pow(dot(R, Eye), power));
}
return finalColor;
}
float4 PSSolid( PS_INPUT input) : SV_Target
{
return vOutputColor;
}
现在我只有漫反射,镜面反射只显示白色立方体(我在哪里可以得到关于镜面反射的例子或导师?
您试图实现的称为Phong反射模型,该模型通过计算法线向量和光方向向量之间的反射向量来生成镜面高光。然后使用点积来计算反射矢量和从表面到眼睛位置的矢量之间的角度的余弦。
Specular
着色器存在一些问题。
首先,您的Eye
矢量不正确。它需要是从表面到眼睛位置的矢量。目前,您只使用一个职位。若要完成此操作,您需要修改顶点着色器,以输出顶点位置的世界空间位置。为此,添加:
float3 WorldPos : TEXCOORD1;
到您的PS_INPUT
。现在计算顶点着色器中的世界空间顶点位置:
output.WorldPos = mul( input.Pos, World );
该值将被发送到像素着色器,并在像素之间进行插值,以便提供像素的世界位置。使用此选项,可以计算像素着色器中从像素到眼睛位置的视图向量V。要做到这一点,请使用:
float3 V = normalize( Eye - input.WorldPos );
现在,反射向量R是通过反射表面法线周围的入射光方向(而不是眼睛位置)来创建的,并且必须为循环中的每一盏灯计算它:
float3 R = reflect( normalize( vLightDir[i] ), normalize( input.Norm ) );
请注意,在这个等式中,光向量是从光指向表面的(所以不要像下面描述的那样否定它)。
现在,您可以使用R和V之间的点积来计算每个光创建的镜面反射分量:
finalColor += intensity * vLightColor[i] * pow( saturate( dot( R, V ) ), power );
我看到的最后一个问题是,在Specular
着色器中没有正确计算漫反射。如果希望不面向灯光的区域更暗,则需要像Diffuse
着色器一样执行此操作。但是,您不需要直接使用vLightDir[i]
,而是需要将其取反,使其从表面指向光:
float3 L = -normalize( vLightDir[i].xyz );
一种比Phong反射模型更便宜的方法称为Blinn Phong反射模式。它不使用R,而是使用以下简单方程计算V和L之间的半矢量:
float3 H = normalize( L + V );
现在,在计算镜面反射时不使用dot( R, V )
,而是使用:
dot( N, H );
- 光线跟踪器灯光反射错误
- 如何有效地计算将单位立方体映射到自身的反射和旋转?
- Direct3D 11 - HLSL - 获取顶点索引 ID
- 使用即将推出的C++反射工具打印类型的全名
- Assimp 无法加载除 FBX 的漫反射纹理之外的其他纹理
- 虚幻引擎使用什么样的反射?
- 反射 + 函数指针与观察者模式
- C++ 17 有静态反射吗?
- 如何在Visual Studio 2017中启动HLSL调试器?
- 在 texture2D 中绘制线条和字符(DirectCompute HLSL 编程)
- Unity 的 HLSL/Cg 预处理器工作方式错误?
- 漫反射材质的奇怪光线跟踪行为
- 光线追踪对象文件漫反射着色问题
- C++:使用反射循环访问结构中的元素
- 像 c++ 的功能一样的侵入式反射?
- 使用结构进行反射,对称或及时的测试集
- 确实被认为是实验性的 - 静态反射功能包括对母类的迭代
- 从Qt3D PickEvent获取漫反射贴图RGB数据
- 如何在 HLSL 中定义具有大维度的数组
- HLSL中的镜面反射