Восстановление нормального после вращения модели экземпляра в HLSL
Я начинаю использовать технику "инстанцированной модели", чтобы нарисовать мою сцену, и у меня проблема с вершиной нормали
Я даю HLSL МАТРИЦУ (вращение / масштабирование / положение) для рисования каждого экземпляра модели, но я не могу получить нормальный результат после их поворота.
3D-моделирование моей модели работает нормально после применения MATRIX, но свет действительно странный в зависимости от нормальной ориентации.
struct InstancingVSinput
{
float4 Position : SV_POSITION0;
float4 Norm : NORMAL0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSoutput
{
float4 Position : POSITION0;
float3 Norm : NORMAL0;
float2 TexCoord : TEXCOORD0;
};
InstancingVSoutput InstancingVS(InstancingVSinput input,
float4 InstPos : POSITION1, float4 InstTexCoord : TEXCOORD1,
float4 Mat1 : POSITION2, float4 Mat2 : POSITION3, float4 Mat3 : POSITION4, float4 Mat4 : POSITION5)
{
InstancingVSoutput output;
float4x4 O = float4x4(Mat1, Mat2, Mat3, Mat4);
float4 pos = mul(input.Position,xWorld);
pos = mul(input.Position, O);
pos = InstPos + pos;
O = transpose(O);
float3 norm = normalize((float3)input.Norm);
norm = mul(norm, (float3x3)O);
pos = mul(pos, WVP);
output.Position = pos;
output.Norm = norm;
output.TexCoord = float2((input.TexCoord.x / 2.0f) + (1.0f / 2.0f * InstTexCoord.x),
(input.TexCoord.y / 2.0f) + (1.0f / 2.0f * InstTexCoord.y));
return output;
}
float4 InstancingPS(InstancingVSoutput input) : COLOR0
{
float4 C = tex2D(TextureSampler, input.TexCoord);
float3 N = input.Norm;
C.rgb *= dot(float3(0, -1, -1), N);
return C;
}
Должны ли вы предложить мне правильный способ получения моего нормального после вращения?
Thanx
Крис
4 ответа
Если ваша матрица экземпляров содержит какое-либо масштабирование, вам нужно нормализовать нормали после умножения. Кроме того, если масштабирование не является равномерным, вы должны умножить входные нормали на обратную транспонированность матрицы. В настоящее время вы применяете только транспонирование, но не наоборот.
Однако вычисление обратной матрицы - дорогостоящая операция, поэтому подумайте о том, чтобы предварительно вычислить ее вне шейдера.
Проблема решена, все нормально. На самом деле, код HLSL был хорош... но проблема сохранялась из-за плохого вычисления нормалей вершин. Теперь у меня хорошие лица с хорошим направлением света.
Вот следующие строки, которые я изменил, чтобы выразить ваше решение:
1 - Подготовьте свойства экземпляров, просто добавьте новое для Inverse Transpose Matrix (предварительно вычислено)
Matrix MatRot = Matrix.CreateRotationX(3 - rnd.Next(6)) *
Matrix.CreateRotationY(3 - rnd.Next(6)) *
Matrix.CreateRotationZ(3 - rnd.Next(6));
instances[i].Geometry = Matrix.CreateScale(0.5f + rnd.Next(2)) * MatRot;
instances[i].Inverse = Matrix.Transpose(Matrix.Invert(MatRot));
2 - шейдер воспринимает эту новую матрицу и использует ее для каждой модели
float4x4 WVP;
float4x4 WV;
float4x4 xLightView;
float4x4 xLightProj;
float4x4 xWorld;
texture cubeTexture;
sampler TextureSampler = sampler_state
{
texture = <cubeTexture>;
mipfilter = LINEAR;
minfilter = LINEAR;
magfilter = LINEAR;
};
struct InstancingVSinput
{
float4 Position : SV_POSITION;
float4 Norm : NORMAL0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSoutput
{
float4 Position : POSITION0;
float4 Norm : NORMAL0;
float2 TexCoord : TEXCOORD0;
};
InstancingVSoutput InstancingVS(InstancingVSinput input,
float4 InstPos : POSITION1, float4 InstTexCoord : TEXCOORD1,
float4 Mat1 : POSITION2, float4 Mat2 : POSITION3, float4 Mat3 : POSITION4, float4 Mat4 : POSITION5,
float4 Mat5 : POSITION6, float4 Mat6 : POSITION7, float4 Mat7 : POSITION8, float4 Mat8 : POSITION9)
{
InstancingVSoutput output;
float4x4 O = float4x4(Mat1, Mat2, Mat3, Mat4);
float4x4 I = float4x4(Mat5, Mat6, Mat7, Mat8);
float4 pos = mul(input.Position,xWorld);
pos = mul(input.Position, O);
pos = InstPos + pos;
pos = mul(pos, WVP);
output.Position = pos;
output.Norm = normalize(mul(input.Norm,I));
output.TexCoord = float2((input.TexCoord.x / 2.0f) + (1.0f / 2.0f * InstTexCoord.x),
(input.TexCoord.y / 2.0f) + (1.0f / 2.0f * InstTexCoord.y));
return output;
}
float4 InstancingPS(InstancingVSoutput input) : COLOR0
{
float4 C = tex2D(TextureSampler, input.TexCoord);
C.rgb *= dot(input.Norm , normalize(float3(0, -1, -1)));
return C;
}
technique Instancing
{
pass Pass0
{
VertexShader = compile vs_5_0 InstancingVS();
PixelShader = compile ps_5_0 InstancingPS();
}
}
Идея?
Как вы можете видеть, мои лица плохо освещены в зависимости от нормы