Иногда при портировании проектов XNA 3.1 в XNA 4.0 возникают странные ошибки (NaN and infinity literals not allowed by shader model) при компиляции шейдеров. В этой статье я опишу простой способ избежать ошибки.
Я взяла свой старый проект, который реализуется освещение трехмерных объектов по моделям Гуро и Фонга (то есть освещенность в вычисляется в вершинном и пиксельном шейдере соответственно).
Вот такой шейдер я использую:
float4x4 World;
float4x4 View;
float4x4 Projection;
float4 AmbientColor = float4(0.1, 0.1, 0.1, 1);
float ka = 1;
float4 DiffuseColor = float4(1,1,1,1);
float kd = 0.5;
float4 SpecularColor = float4(1,1,1,1);
float ks = 1;
float SpecularPower = 4;
float3 LightPosition = float3(0,1,1);
float3 Eye;
// TODO: add effect parameters here.
struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Light : COLOR0;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
float4 Ambient = ka * AmbientColor;
float3 worldNormal = normalize(mul(input.Normal, World));
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
output.Light = Ambient + Diffuse + Specular;
// TODO: add your vertex shader code here.
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// TODO: add your pixel shader code here.
return float4(1, 0, 1, 1) * input.Light;
}
technique Gourand
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_1_1 PixelShaderFunction();
}
}
struct VertexShaderInputPhong
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutputPhong
{
float4 Position : POSITION0;
float3 WorldPosition : TEXCOORD0;
float3 Normal : TEXCOORD1;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
VertexShaderOutputPhong VertexShaderFunctionPhong(VertexShaderInputPhong input)
{
VertexShaderOutputPhong output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
float3 worldNormal = normalize(mul(input.Normal, World));
output.Position = mul(viewPosition, Projection);
output.WorldPosition = worldPosition;
output.Normal = worldNormal;
// TODO: add your vertex shader code here.
return output;
}
float4 PixelShaderFunctionPhong(VertexShaderOutputPhong input) : COLOR0
{
// TODO: add your pixel shader code here.
float3 worldPosition = input.WorldPosition;
float3 worldNormal = normalize(input.Normal);
float4 Ambient = ka * AmbientColor;
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
return float4(1, 0, 1, 1) * (Ambient + Diffuse + Specular);
}
technique Phong
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunctionPhong();
PixelShader = compile ps_2_0 PixelShaderFunctionPhong();
}
}
float4x4 View;
float4x4 Projection;
float4 AmbientColor = float4(0.1, 0.1, 0.1, 1);
float ka = 1;
float4 DiffuseColor = float4(1,1,1,1);
float kd = 0.5;
float4 SpecularColor = float4(1,1,1,1);
float ks = 1;
float SpecularPower = 4;
float3 LightPosition = float3(0,1,1);
float3 Eye;
// TODO: add effect parameters here.
struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Light : COLOR0;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
float4 Ambient = ka * AmbientColor;
float3 worldNormal = normalize(mul(input.Normal, World));
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
output.Light = Ambient + Diffuse + Specular;
// TODO: add your vertex shader code here.
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
// TODO: add your pixel shader code here.
return float4(1, 0, 1, 1) * input.Light;
}
technique Gourand
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_1_1 PixelShaderFunction();
}
}
struct VertexShaderInputPhong
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutputPhong
{
float4 Position : POSITION0;
float3 WorldPosition : TEXCOORD0;
float3 Normal : TEXCOORD1;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
VertexShaderOutputPhong VertexShaderFunctionPhong(VertexShaderInputPhong input)
{
VertexShaderOutputPhong output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
float3 worldNormal = normalize(mul(input.Normal, World));
output.Position = mul(viewPosition, Projection);
output.WorldPosition = worldPosition;
output.Normal = worldNormal;
// TODO: add your vertex shader code here.
return output;
}
float4 PixelShaderFunctionPhong(VertexShaderOutputPhong input) : COLOR0
{
// TODO: add your pixel shader code here.
float3 worldPosition = input.WorldPosition;
float3 worldNormal = normalize(input.Normal);
float4 Ambient = ka * AmbientColor;
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
return float4(1, 0, 1, 1) * (Ambient + Diffuse + Specular);
}
technique Phong
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunctionPhong();
PixelShader = compile ps_2_0 PixelShaderFunctionPhong();
}
}
При компиляции получаю следующие ошибки:
Error 1 Errors compiling C: \LightGame\LightGame\Content\light.fx:
C: \LightGame\LightGame\Content\light.fx(132,12): error X4579: NaN and infinity literals not allowed by shader model
error X3539: ps_1_x is no longer supported
C: \LightGame\LightGame\Content\light.fx(77,23): ID3DXEffectCompiler::CompileEffect: There was an error compiling expression
ID3DXEffectCompiler: Compilation failed C: \LightGame\LightGame\Content\light.fx 132 12 LightGame
Ну, с ошибкой «X3539 ps_1_x is no longer supported» все понятно. Дело в том, что XNA 4.0 больше не поддерживается шейдерные профили 1_x. Нужно просто изменить описание техники следующим образом:
technique Gourand
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
А вот со второй ошибкой все сложнее, иногда пропадает сама (бывает и такое), иногда она уходит если поменять местами параметры в указанной строке.
На самом деле сообщение об ошибке указывает на строку в пиксельном шейдере:
float4 PixelShaderFunctionPhong(VertexShaderOutputPhong input) : COLOR0
{
// TODO: add your pixel shader code here.
float3 worldPosition = input.WorldPosition;
float3 worldNormal = normalize(input.Normal);
float4 Ambient = ka * AmbientColor;
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
return float4(1, 0, 1, 1) * (Ambient + Diffuse + Specular);
}
Так вот, самый простой способ избавиться от этой ошибки – это заменить 0 на какое-нибудь очень маленькое число. Например, вот так:
float4 PixelShaderFunctionPhong(VertexShaderOutputPhong input) : COLOR0
{
// TODO: add your pixel shader code here.
float3 worldPosition = input.WorldPosition;
float3 worldNormal = normalize(input.Normal);
float4 Ambient = ka * AmbientColor;
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0.000001, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
return float4(1, 0, 1, 1) * (Ambient + Diffuse + Specular);
}
Комментариев нет:
Отправить комментарий