Перейти к контенту

Об этом клубе

Реализуем. Кипятим мозги.

Устав клуба

struct чаво_не_желательно_оставлять_здеся {

"Зделаити" за меня                 :  вообще_нежелательно0;
"Акак" сделать всё мега прекрасно  :  вообще_нежелательно1;
любой "кык акак"                   :  вообще_нежелательно2;

};

half4   main   (  чаво_не_желательно_оставлять_здеся   I  ):НАДЕЕМСЯ_НА_РЕЗУЛЬТАТ
{
 Окей, поехали. Здесь рассуждаем о графике в стулкире, реализуем те или иные эффекты, просим помощи, переносим из других игр;
}

  1. Что нового в этом клубе
  2. Привет всем, недавно задался вопросом реализации бликов like battlefield, наткнулся на статью: John Chapman Pseudo Lens Flares Демонстрационное видео мне понравилось, посему взялся за реализацию прямо по статье. Вот что вышло у меня: клик Собтсвенно, а как оно делается на сталкере, весь код приведу ниже с пояснением. Шейдер Treshold/Downsample, так как реализация в статье не подходит для сталкера, пришлось делать совсем иначе, на выходе почти идентичный результат. А что он делает? Говоря "поруски", отбрасывает пиксели с низкой яркостью оставляя только светлые участки, т.е. те участки которые и будут учавствовать в создании призраков и гало эффекта. Шейдер можно сказать необходимый, его можно использовать и для эффекта Dirty Lens, похожим способом и блум пилится и ещё много чего. Из входных данных, это люминанс вектор и rt_Generic_0(сцена до фазы combine). Пишется всё это дело в новый рендер таргет, который мы дальше будем использовать для генерирования бликов. Скрытый текст #include "common.h" uniform sampler2D samplerScene;//rt_Generic_0 uniform half4 uLuminance;//luminance vector ////////////////////////////////////////////////////////////////////////////////////////// // half4 main ( AntiAliasingStruct INStruct ) : COLOR { half3 color =tex2D(samplerScene,INStruct.texCoord0.xy).rgb; half3 brightColor =max(color -uLuminance.xyz, 0); half bright =dot(brightColor, 1); bright =smoothstep(0, .5, bright); half3 outColor =lerp(0, color, bright); return half4 (outColor, 1); } Терь сам шейдер генерирующий блики. Входные данные: -ранее созданный рендер таргет downsample, "обозванный" samplerTreshold -1D текстура, в нашем случае фейковая, т.к. нельзя в dds сохранить текстуру с высотой в один пиксель, у меня она 256x4. Используется она для окрашивания бликов. Всё это тоже пишется в новый РТшник. Скрытый текст #include "common.h" half3 tex2Ddistorted(sampler2D inputSampler, float2 texCoord, float2 direction, float3 distortion) { return half3 ( tex2D(inputSampler, texCoord +direction *distortion.r).r, tex2D(inputSampler, texCoord +direction *distortion.g).g, tex2D(inputSampler, texCoord +direction *distortion.b).b ); } #define GHOSTS int(5)//num of ghosts uniform sampler2D samplerTreshold;//treshold sampler uniform sampler2D samplerLensColor;//fake1D texture uniform half4 uGhostDispersal; uniform half4 uHaloWidth; uniform half4 uDistortion; ////////////////////////////////////////////////////////////////////////////////////////// // half4 main ( AntiAliasingStruct INStruct ) : COLOR { float2 texCoord =-INStruct.texCoord0.xy +float2(1,1); float3 distortion =float3(-screen_res.z *uDistortion.x, 0, screen_res.z *uDistortion.x); float2 ghostVector =(float2(.5,.5) -texCoord) *uGhostDispersal.x; float2 direction =normalize(ghostVector); half3 outColor=half3(0,0,0); // half4 outColor=half4(0,0,0,0); for ( int i=0; i<GHOSTS; i++ ) { float2 offset =frac(texCoord +ghostVector *float(i)); float weight =length(float2(.5,.5) -offset)/length(float2(.5,.5)); weight =pow(1-weight,10); //outColor +=tex2D(samplerTreshold,offset) *weight;//.rgb *weight; outColor +=tex2Ddistorted(samplerTreshold,offset,direction,distortion).rgb *weight; } //outColor*=tex2D(samplerLensColor,length(float2(.5,.5) -texCoord)/length(float2(.5,.5)));//.rgb; outColor*=tex2Ddistorted(samplerLensColor,length(float2(.5,.5) -texCoord)/length(float2(.5,.5)),direction,distortion).rgb; float2 haloVector =normalize(ghostVector) *uHaloWidth.x; float haloWeight =length(float2(.5,.5) -frac(texCoord +haloVector))/length(float2(.5,.5)); haloWeight =pow(1-haloWeight,5); //outColor +=tex2D(samplerTreshold,texCoord +haloVector) *haloWeight;//.rgb *haloWeight; outColor +=tex2Ddistorted(samplerTreshold,texCoord +haloVector,direction,distortion).rgb *haloWeight; return half4(outColor, 1); //return outColor; } Терь нужно "пустить под блюр" сгенерированные блики, обычно я это делаю незамысловатым Gauss блюром, но в сей раз хотел испробовать что-нибудь новенькое. На самом деле я не ручаюсь за правильность работы этого шейдера , так как не выводил его на результ для проверки. Чтобы перестраховаться можно использовать проверенный блюр, код будет прямо под этим. Скрытый текст #include "common.h" uniform sampler2D samplerBlur; ////////////////////////////////////////////////////////////////////////////////////////// // half4 main ( AntiAliasingStruct INStruct ) : COLOR { float offset[3] = { 0, 1.3846153846, 3.2307692308 }; float weight[3] = { 0.2270270270, 0.3162162162, 0.0702702703 }; half4 outColor =tex2D(samplerBlur,(INStruct.texCoord0.xy)) *weight[0];///1024 ); // float offset[3] = // { // 0, // 1.3846153846, // 3.2307692308 // }; // float weight[3] = // { // 0.2270270270, // 0.3162162162, // 0.0702702703 // }; //for ( int i=0; i<2; i++) for ( int i=1; i<3; i++) { outColor +=tex2D(samplerBlur,(INStruct.texCoord0.xy +float2(0,offset) ))*weight;///1024 ) *weight; outColor +=tex2D(samplerBlur,(INStruct.texCoord0.xy -float2(0,offset) ))*weight;///1024 ) *weight; } return outColor; } Тут Gauss. Входные параметры: -семплер обречённый на блюр -текстурные координаты -сила блюра (почему в int? потомучто я всегда его использую только в цикле и как сила блюра у меня выступает кол-во оборотов цикла, к тому же значение динамическое) for ( int i=0; i<BLUR_SAMPLES; i++ ) { outColor =Gauss(samplerBlur,texCoord,i,false); } -бул значение для юза оптимизированного блюра Примечание: по сути, юниформ screen_res здесь не так важен и можно заменить универсальной константой 1024.f Скрытый текст #ifndef GAUSSBLUR_H_INCLUDED #define GAUSSBLUR_H_INCLUDED half4 Gauss(sampler2D inputSampler, float2 texCoord, int factor, bool optimize) { half4 outColor; if(!optimize) { float dx = factor*.5f/screen_res.x; float dy = factor*.5f/screen_res.y; outColor = ( //1.f * tex2Dlod(inputSampler,float4(texCoord,0,0)).rgba + 1.f * tex2Dlod(inputSampler,float4(texCoord+float2(dx,0),0,0)).rgba + 1.f * tex2Dlod(inputSampler,float4(texCoord+float2(dy,0),0,0)).rgba + 1.f * tex2Dlod(inputSampler,float4(texCoord+float2(-dx,0),0,0)).rgba + 1.f * tex2Dlod(inputSampler,float4(texCoord+float2(-dx,-dy),0,0)).rgba + 1.f * tex2Dlod(inputSampler,float4(texCoord+float2(dx,-dy),0,0)).rgba )/5.f; } else { const float delta = factor * (.5f/screen_res.x); outColor = ( tex2Dlod(inputSampler,float4(texCoord+delta,0,0)).rgba + tex2Dlod(inputSampler,float4(texCoord-delta,0,0)).rgba )*(1.f/2.f); } return outColor; } #endif//GAUSSBLUR_H_INCLUDED В идеале, конечно, я бы и Dawnsample обрёк на блюр, но переделывать было уже лень. Ну и последняя фаза комбайн с основным изображением. Не стал парится с SturBurst эффектом, оставил статичным, оно и так прилично выглядит, DirtyLens Тоже не стал делать, так как у меня это отдельная история, хотя смешивать его тоже в этом шейдере буду. Скрытый текст #include "common.h" uniform sampler2D samplerFlares;//lens flares sampler //uniform sampler2D samplerDirt;//dirty texture uniform sampler2D samplerScene;//rt_Generic_0 uniform sampler2D samplerStarbust;// ////////////////////////////////////////////////////////////////////////////////////////// // half4 main ( AntiAliasingStruct INStruct ) : COLOR { // half4 lensDirt =tex2D(samplerDirt,INStruct.texCoord0.xy); // half4 lensMod =tex2D(samplerFlares,INStruct.texCoord0.xy) *lensDirt; half4 starbust =tex2D(samplerStarbust,INStruct.texCoord0.xy); half4 lensMod =tex2D(samplerFlares,INStruct.texCoord0.xy) *starbust; half4 scene =tex2D(samplerScene,INStruct.texCoord0.xy) +lensMod; return scene; } Ну вроде всё. Надеюсь кому-нибудь пригодится.
  3.  
×