Получение нормали после поворота модели экземпляра в HLSL

Я начинаю использовать технику "Instance Model" для рисования своей сцены, и у меня возникла проблема с вершиной нормали.

Я даю HLSL МАТРИЦУ (поворот/масштаб/положение) для рисования каждого экземпляра модели, но я не могу получить хорошую нормаль после их вращения.

Трехмерное вычисление моей модели работает нормально после применения 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;
    }

Должны ли вы предложить мне правильный способ восстановить мою норму после вращения?

спасибо

Крис


person Chris PIZZ    schedule 02.06.2016    source источник


Ответы (4)


Если ваша матрица экземпляра содержит какое-либо масштабирование, вам необходимо нормализовать нормали после умножения. Кроме того, если масштабирование неравномерно, вы должны умножить входные нормали на обратное транспонирование матрицы. В настоящее время вы применяете только транспонирование, но не обратное.

Однако вычисление обратной матрицы — дорогостоящая операция, поэтому подумайте о предварительном вычислении ее вне шейдера.

person Quinchilion    schedule 03.06.2016
comment
Спасибо за ответ, попробую... а там видно будет - person Chris PIZZ; 03.06.2016
comment
Извините, но после попытки это не работает ... Кажется, что каждый экземпляр хорошо рисует, повернутый геометрией, но лица подсвечиваются, поскольку они не будут вращаться. - person Chris PIZZ; 03.06.2016

Вот следующие строки, которые я изменил, чтобы выразить ваше решение:

1 - Подготовьте свойства экземпляров, просто добавьте новый для матрицы обратного транспонирования (предварительно вычисленный)

        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();
    }
}

Идея ?

person Chris PIZZ    schedule 03.06.2016

Как видите, мои лица имеют не очень хорошую световую экспозицию в зависимости от нормального

Нажмите, чтобы увидеть изображение

person Chris PIZZ    schedule 03.06.2016

Проблема решена, все ок. На самом деле код HLSL был хорош... но проблема сохранялась из-за плохого вычисления нормалей вершин. Теперь у меня хорошие лица с хорошим направлением света.

person Chris PIZZ    schedule 04.06.2016