В четвёртой версии XNA Microsoft предлагает создание шейдеров только на стадии компиляции, путём помещения fx-файлов в директорию ресурсов и последующей загрузки уже скомпилированного шейдера в эффекте из ресурсов.
Если есть потребность создания шейдеров в рантайме придётся прибегнуть к громоздкой и медленной процедуре. Поэтому лучше использовать обычный способ загрузки шейдеров из ресурсов.
Далее описание динамического создания шейдера.
Для получения эффекта с шейдером его конструктору надо передать код компилированного эффекта.
Компилированный эффект получается в результате работы эффект процессора, которому нужно передать исходник эффекта и контекст процессора.
Эффект процессор получить легко - это просто экземпляр класса EffectProcessor.
var processor = new EffectProcessor();
Исходник эффекта уже несколько сложнее. Именно тут нужно смоделировать загрузку исходного кода шейдера из ресурса.
myshader.fx - можно использовать любое имя, наличие этого файла не требуется. Видимо не стоит использовать имя уже существующего файла, последствия не проверял.
effectBody - собственно HLSL-код шейдера.
Например конвертация изображения в оттенки серого:
И самый громоздкий этап создание контекста эффект-процессора.
Для этого создаём свой класс наследованный от ContentProcessorContext.
И для него понадобится ещё один класс, логгер компилятора наследованный от ContentBuildLogger.
Использование полученного эффекта такое же как и обычного эффекта из ресурсов.
Например при старте отображения спрайтов:
Источник.
var effect = Content.Load<Effect>( Path.Combine(Directories.ContentDirectory, "ShaderFileName"));
Если есть потребность создания шейдеров в рантайме придётся прибегнуть к громоздкой и медленной процедуре. Поэтому лучше использовать обычный способ загрузки шейдеров из ресурсов.
Далее описание динамического создания шейдера.
Для получения эффекта с шейдером его конструктору надо передать код компилированного эффекта.
var effect = new Effect( graphicsDevice, compiledEffect.GetEffectCode() );
Компилированный эффект получается в результате работы эффект процессора, которому нужно передать исходник эффекта и контекст процессора.
var compiledEffect = processor.Process( effectSource, new EffectCompilerProcessorContext() );
Эффект процессор получить легко - это просто экземпляр класса EffectProcessor.
var processor = new EffectProcessor();
Исходник эффекта уже несколько сложнее. Именно тут нужно смоделировать загрузку исходного кода шейдера из ресурса.
var effectSource = new EffectContent {
Identity = new ContentIdentity { SourceFilename = "myshader.fx" },
EffectCode = effectBody
};
myshader.fx - можно использовать любое имя, наличие этого файла не требуется. Видимо не стоит использовать имя уже существующего файла, последствия не проверял.
effectBody - собственно HLSL-код шейдера.
Например конвертация изображения в оттенки серого:
effectBody = @"
uniform extern texture ScreenTexture;
sampler screen = sampler_state {
Texture = <ScreenTexture>;
};
float4 PixelShaderFunction(float2 inCoord: TEXCOORD0) : COLOR {
float4 color = tex2D(screen, inCoord);
color.rgb = (color.r+color.g+color.b)/3.0f;
return color;
}
technique {
pass P0 {
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}";
И самый громоздкий этап создание контекста эффект-процессора.
Для этого создаём свой класс наследованный от ContentProcessorContext.
class EffectCompilerProcessorContext : ContentProcessorContext {
public override TargetPlatform TargetPlatform { get { return TargetPlatform.Windows; } }
public override GraphicsProfile TargetProfile { get { return GraphicsProfile.HiDef; } }
public override string BuildConfiguration { get { return string.Empty; } }
public override string IntermediateDirectory { get { return string.Empty; } }
public override string OutputDirectory { get { return string.Empty; } }
public override string OutputFilename { get { return string.Empty; } }
public override OpaqueDataDictionary Parameters { get { return parameters; } }
readonly OpaqueDataDictionary parameters = new OpaqueDataDictionary();
public override ContentBuildLogger Logger { get { return logger; } }
readonly ContentBuildLogger logger = new EffectCompilerLogger();
public override void AddDependency( string filename ) { }
public override void AddOutputFile( string filename ) { }
public override T_OUTPUT Convert<T_INPUT, T_OUTPUT>( T_INPUT input, string processor_name, OpaqueDataDictionary processor_parameters ) { throw new NotImplementedException(); }
public override T_OUTPUT BuildAndLoadAsset<T_INPUT, T_OUTPUT>( ExternalReference<T_INPUT> source_asset, string processor_name, OpaqueDataDictionary processor_parameters, string importer_name ) { throw new NotImplementedException(); }
public override ExternalReference<T_OUTPUT> BuildAsset<T_INPUT, T_OUTPUT>( ExternalReference<T_INPUT> source_asset, string processor_name, OpaqueDataDictionary processor_parameters, string importer_name, string asset_name ) { throw new NotImplementedException(); }
}
И для него понадобится ещё один класс, логгер компилятора наследованный от ContentBuildLogger.
class EffectCompilerLogger : ContentBuildLogger {
public override void LogMessage( string message, params object[] message_args ) { }
public override void LogImportantMessage( string message, params object[] message_args ) { }
public override void LogWarning( string help_link, ContentIdentity content_identity, string message, params object[] message_args ) { }
}
Использование полученного эффекта такое же как и обычного эффекта из ресурсов.
Например при старте отображения спрайтов:
spriteBatch.Begin( 0, null, null, null, null, effect );
Источник.
Комментариев нет:
Отправить комментарий