В четвёртой версии 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 );
Источник.
Комментариев нет:
Отправить комментарий