Cheaton - chams для цінителів

Привіт чітера і чітмейкери. У цій темі я хочу показати, як зробити чамс, але вся родзинка не в тому, яким чином вони створюються, а як його зробити "нестандартним". + З коду, який я приведу можна буде почерпнути знання у створенні д3д аімбот і тріггербота, а якщо фантазією ви не обділені, то і щось більшого.

Природно, я буду вважати, що ви колись уже робили простий валлхак + чамс. Завдання полягає в перехопленні функції DrawIndexedPrimitive бібліотеки d3dx9.dll і визначенні даних для потрібної вам модельки, з цим усім ви вже знайомі, тому описувати весь процес не буду.

У чому ж полягатиме незвичайність нашого чамса? А в тому, що за допомогою можливостей d3dx, ми будемо малювати наші модельки не просто зафарбованими дефолтних кольором, а ще й з деяким ефектом.

Саме в моєму прикладі буде чамс вигляді силуету. Для цього нам буде потрібно використовувати шейдери, якщо ви не в курсі що це таке, то знайдіть інформацію в інтернеті. Далі маючи деяку базу, яку я приведу в вигляді коду, можна робити вогненні чамси, що світяться, glow, все що вам спаде на думку, змінюючи лише код самого шейдера, благо, що вони пишуться на мові HLSL, дуже схожий з вашим улюбленим сі + +. Однак використання самого шейдера я приведу на дельфи, але не турбуйтеся, переписати на сі ++ все це справа буде дуже просто, так як використовувати я буду тільки бібліотеку діректікс, а на сі ++ всі функції описані також.

Тепер опишу алгоритм.
1) Створюємо необхідні нам об'єкти d3dx: шейдери, текстура, вертексний буфер. Текстура нам буде потрібно для рендеринга в неї тільки потрібних нам модельок. У конкретному прикладі, рендерить будемо модельки гравців. Вертексний буфер нам буде потрібно щоб накласти на нього текстуру і вивести на екран результат. Текстура ж повинна на чомусь сидіти. І два шейдера, перший стандартний, який просто заливає модель кольором, 2-ий наш з ефектом силуету.
2) В DrawIndexedPrimitive, потрібні нам моделі Рендер в текстуру (модель визначаєте своїм способом, класичний це - numvertices і primcount (к-ть вершин, кількість примітивів)).

3) В EndScene застосовуємо шейдер до текстури, в якому намальовані наші модельки. Шейдер зробить свою справу і виріже середини з модельок.

Cheaton - chams для цінителів

4) Після цього малюємо тексуру поверх екрану. Після відтворення необхідно очистити текстуру, інакше на екрані буде невідома нісенітниця.
Cheaton - chams для цінителів

Створюємо необхідні об'єкти.

d3ddev. GetDeviceCaps (caps);
VERSPX1: = (inttostr (D3DSHADER_VERSION_MAJOR (caps. PixelShaderVersion)));
VERSPX2: = (inttostr (D3DSHADER_VERSION_MINOR (caps. PixelShaderVersion)));
STRASM: = 'ps_' + VERSPX1 + '_' + VERSPX2 + # 13 + 'mov oC0, c0' + # 13; // це код першого шейдер для заливки модельок кольором, якщо ви жахає від цих символів нічого страшного, другий шейдер ми будемо писати на HLSL
pixelshader: = nil;
if D3DXASSEMBLESHADER (PCHAR (STRASM), length (strasm), nil. nil. 0, @ pshader. nil) = d3d_ok then begin
d3ddev. CreatePixelShader (pshader. GetBufferPointer. Pixelshader);
end;
pshader: = nil;
d3ddev. GetRenderTarget (0. backbuffer);
if backbuffer <> nil then backbuffer. GetDesc (desc);
D3DDEV. CreateTexture (DESC. Width. DESC. Height. 1. D3DUSAGE_RENDERTARGET. D3DFMT_A8R8G8B8. D3DPOOL_DEFAULT. Sil_texture. NIL);
sil_texture. GetSurfaceLevel (0. rendersurface);

// шейдер силуету, код знаходиться в файлі t.fx
if D3DXCompileShaderFromFile (pchar (str + '\ t.fx'), nil. nil. 'main'. pchar ( 'ps_' + VERSpx1 + '_' + VERSpx2), 0, @ pshader. nil. nil) = d3d_ok then
d3ddev. CreatePixelShader (pshader. GetBufferPointer. Sil_ps);

d3ddev. CreateVertexBuffer (sizeof (TVertex2) * 4. 0. fvf2. D3DPOOL_MANAGED. Sil_vertex. Nil);

fl: = 0;
// визначаємо модель
if check_model1 (numvertices. promcount) then fl: = 1
if check_model2 (numvertices. promcount) then fl: = 2

if (fl> 0) then begin
d3ddev. CreateStateBlock (D3DSBT_ALL. PStateBlock); // зберігаємо поточні настройки renderstate. а то після перемикання виведення рендеру в інше місце, трапляється всяку маячню.


if fl = 1 then begin
r: = 1; g: = 1; b: = 0;
end;
if fl = 2 then begin
r: = 0; g: = 1; b: = 1;
end;

d3ddev. getrenderstate (d3drs_zenable. old_zenable);
d3ddev. SetRenderTarget (0. rendersurface); // встановлюємо рендер в текстуру
d3ddev. setrenderstate (d3drs_zenable. ifalse); //

pixelvalue # 91; 0 # 93;: = r; pixelvalue # 91; 1 # 93;: = g; pixelvalue # 91; 2 # 93;: = b; pixelvalue # 91; 3 # 93;: = 1;
d3ddev. SetPixelShader (pixelshader);
d3ddev. SetPixelShaderConstantF (0, @ pixelvalue. 1); // застосовуємо перший шейдер, для заливки кольором. У нас в текстурі будуть зберігатися зафарбовані модельки, а на екрані звичайні, ось цей спосіб можна використовувати для аімбот за кольором, без чамса.
result: = or_drawindexedprimitive (self. _Type. BasevertexIndex. Minvertexindex. Numvertices. Startindex. Primcount);

/////
if fl = 1 then begin
r: = 1; g: = 0; b: = 0;
end;
if fl = 2 then begin
r: = 0; g: = 1; b: = 0;
end;
d3ddev. setrenderstate (d3drs_zenable. old_zenable);
pixelvalue # 91; 0 # 93;: = r; pixelvalue # 91; 1 # 93;: = g; pixelvalue # 91; 2 # 93;: = b; pixelvalue # 91; 3 # 93;: = 1;
d3ddev. SetPixelShader (pixelshader);
d3ddev. SetPixelShaderConstantF (0, @ pixelvalue. 1);
result: = or_drawindexedprimitive (self. _Type. BasevertexIndex. Minvertexindex. Numvertices. Startindex. Primcount);


d3ddev. SetRenderTarget (0. oldrendersurface); // відновлюємо колишній рендер
d3ddev. SetPixelShader (oldpixelshader);
d3ddev. SetPixelShaderConstantF (0, @ oldpixelvalue. 1);

pStateBlock. apply; // настройки рендеру ставимо як було.
pStateBlock: = nil;
end;
result: = or_drawindexedprimitive (self. _Type. BasevertexIndex. Minvertexindex. Numvertices. Startindex. Primcount);

Написав таку процидурку для виведення текстури з шейдером.

procedure draw_texture (x1. y1. x2. y2. single; texture. idirect3dtexture9; ps. idirect3dpixelshader9);
var
Vertices. array # 91; 0..3 # 93; of TVertex2;
pVertices. Pointer;
begin
// структура вертексов
// fvf2 = D3DFVF_XYZRHW or D3DFVF_TEX1;
// TVertex2 = record
// x, y, z, rhw: single;
// tu, tv: single;
// end;


if d3ddev = nil then exit;
if sil_vertex = nil then exit;
// задаємо координати вертексов і текстурних координат
Vertices # 91; 0 # 93 ;. x: = x1; Vertices # 91; 0 # 93 ;. y: = y1; Vertices # 91; 0 # 93 ;. z: = 0; Vertices # 91; 0 # 93 ;. rhw: = 1;
Vertices # 91; 0 # 93 ;. tu: = 0; Vertices # 91; 0 # 93 ;. tv: = 0;

Vertices # 91; 1 # 93 ;. x: = x2; Vertices # 91; 1 # 93 ;. y: = y1; Vertices # 91; 1 # 93 ;. z: = 0; Vertices # 91; 1 # 93 ;. rhw: = 1;
Vertices # 91; 1 # 93 ;. tu: = 1; Vertices # 91; 1 # 93 ;. tv: = 0;

Vertices # 91; 2 # 93 ;. x: = x1; Vertices # 91; 2 # 93 ;. y: = y2; Vertices # 91; 2 # 93 ;. z: = 0; Vertices # 91; 2 # 93 ;. rhw: = 1;
Vertices # 91; 2 # 93 ;. tu: = 0; Vertices # 91; 2 # 93 ;. tv: = 1;

Vertices # 91; 3 # 93 ;. x: = x2; Vertices # 91; 3 # 93 ;. y: = y2; Vertices # 91; 3 # 93 ;. z: = 0; Vertices # 91; 3 # 93 ;. rhw: = 1;
Vertices # 91; 3 # 93 ;. tu: = 1; Vertices # 91; 3 # 93 ;. tv: = 1;


Result: = sil_vertex. Lock (0. sizeof (TVertex2) * 4. pVertices. 0);
if FAILED (Result) then Exit;
Move (Vertices # 91; 0 # 93 ;, pVertices ^, sizeof (TVertex2) * 4);
sil_vertex. Unlock;


d3ddev. CreateStateBlock (D3DSBT_ALL. PStateBlock);
d3ddev. SetPixelShader (NIL);

d3ddev. SetPixelShader (ps); // ліпимо на наш прямокутник текстуру і використовуємо шейдер
d3ddev. SetTexture (0. texture);
d3ddev. SetStreamSource (0. sil_vertex. 0. sizeof (TVertex2));
d3ddev. SetFVF (FVF2);

d3ddev. DrawPrimitive (D3DPT_trianglestrip. 0. 2);

pStateBlock. apply;
pStateBlock: = nil;

// малюємо квадратик, це нам потрібно для очищення текстури

procedure DrawRect (x1. y1. x2. y2. integer; r. g. b. byte);
var BarRect. D3DRECT; Cor. D3DCOLOR;
begin
cor: = ((b) + ((g) shl 8) + ((r) shl 16));
BarRect. x1: = x1; BarRect. y1: = y1; BarRect. x2: = x2; BarRect. y2: = y2;
if d3ddev <> nil then d3ddev. Clear (1. @ BarRect. D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER. Cor. 0. 0);
end;

draw_texture (0. 0. desc. Width. desc. Height. sil_texture. sil_ps); // малюємо текстуру

result: = or_endscene (self);
// Чистимо текстурки
if d3ddev <> nil then begin
d3ddev. GetRenderTarget (0. oldrendersurface);
d3ddev. SetRenderTarget (0. rendersurface);
drawrect (0. 0. desc. Width. desc. Height. 0. 0. 0);
d3ddev. SetRenderTarget (0. oldrendersurface);
end;

Ось сам код шейдера силуету, пішітся в звичайному блокноті, в даному прикладі ім'я файлу t.fx

// shader silhouette by Baunti
sampler TextureSampler;

struct PixelInput
<
float2 TexCoord. TEXCOORD0;
>;


float sum (float4 a)
return (a # 91; 0 # 93; + a # 91; 1 # 93; + a # 91; 2 # 93; + a # 91; 3 # 93;);
>;

float4 main (PixelInput input). COLOR0

float xx = 0.003; // ширина силуету
float4 colorout;
float4 color = tex2D (TextureSampler. float2 (input. TexCoord. x. input. TexCoord. y));
float4 color1 = tex2D (TextureSampler. float2 (input. TexCoord. x + xx. input. TexCoord. y));
float4 color2 = tex2D (TextureSampler. float2 (input. TexCoord. x - xx. ​​input. TexCoord. y));
float4 color3 = tex2D (TextureSampler. float2 (input. TexCoord. x. input. TexCoord. y + xx));
float4 color4 = tex2D (TextureSampler. float2 (input. TexCoord. x. input. TexCoord. y - xx));
colorout = color;

if ((sum (color1)> 0) (sum (color) == 0))
colorout = color1;
>;

if ((sum (color2)> 0) (sum (color) == 0))
colorout = color2;
>;

if ((sum (color3)> 0) (sum (color) == 0))
colorout = color3;
>;

if ((sum (color4)> 0) (sum (color) == 0))
colorout = color4;
>;

Якщо хто освоїв всі, що я написав, пропоную в цій тим викладати свої шейдери і скріншоти, я ще робив міні шейдер, "скляний" ефект, кому цікаво буде могу скинуть.