#Gromov
Мастер
В этом уроке, мы сделаем разноцветные следы от заноса транспорта!
Для начала давайте создадим папку "shader_skidmarks"!!
Далее делаем...:
1) Создадим файл "meta.xml", и в него вставим следующий код:
PHP:
<meta>
<info name="Skid marks" description="Shader for vehicle tracks" author="ccw" version="0.0.2" type="script" />
<min_mta_version client="1.1.0" server="1.1.0" />
<script src="util.lua" type="server" />
<script src="s_skidmarks.lua" type="server" />
<script src="util.lua" type="client" />
<script src="c_skidmarks.lua" type="client" />
<file src="skidmarks.fx" type="client" />
<file src="mta-helper.fx" type="client" />
<config src="help.xml" type="client" />
<settings>
<!-- *****************************************************
All these settings are adjustable in the Admin Panel:
1. start admin
2. press 'p'
3. select Resources tab
4. double click on resource name
***************************************************** -->
<setting name="*presetID" value="2"
friendlyname="Preset ID"
group="Display"
accept="1-4"
examples="1"
desc="ID of the preset to use, between 1 and 4"
/>
<setting name="*admingroup" value="Admin,SuperModerator"
friendlyname="Admin group list"
group="_Advanced"
accept="*"
examples="Admin,Moderator,SuperModerator"
desc="To issue certain commands, the player must belong to one of the groups listed."
/>
</settings>
</meta>
2) Создаём "help.xml", и в него вставляем код:
PHP:
<help>
Admins
----------
/skidmarks 1 - Thick dark
/skidmarks 2 - Subtle dark colored
/skidmarks 3 - Bright
/skidmarks 4 - Too bright
Change other settings in the Admin panel 'Resources' tab. (Double click on 'skidmarks')
</help>
PHP:
--
-- c_skidmarks.lua
--
g_Settings = {}
local myShader
local Settings = {}
Settings.var = {}
-----------------------------------------------------------------------------
-- Client start
-----------------------------------------------------------------------------
addEventHandler( "onClientResourceStart", resourceRoot,
function()
triggerServerEvent( "onClientReady", resourceRoot )
end
)
-----------------------------------------------------------------------------
-- Client start shader
-----------------------------------------------------------------------------
addEvent( "onClientStartShader", true )
addEventHandler( "onClientStartShader", resourceRoot,
function(verbose)
-- Version check
if getVersion ().sortable < "1.1.0" then
if verbose then outputChatBox( "Resource is not compatible with this client." ) end
return
end
-- Create shader
myShader, tec = dxCreateShader ( "skidmarks.fx" )
if not myShader then
if verbose then outputChatBox( "Could not create shader. Please use debugscript 3" ) end
else
if verbose then outputChatBox( "Using technique " .. tec ) end
engineApplyShaderToWorldTexture ( myShader, "particleskid" )
selectPreset(g_Settings.presetID)
end
end
)
-----------------------------------------------------------------------------
-- Settings from server
-----------------------------------------------------------------------------
addEvent( "onClientUpdateSettings", true )
addEventHandler( "onClientUpdateSettings", resourceRoot,
function(settings)
g_Settings = settings
selectPreset(g_Settings.presetID)
end
)
-----------------------------------------------------------------------------
-- Select preset
-----------------------------------------------------------------------------
function selectPreset(id)
if id==1 then setTypeBlack()
elseif id==2 then setTypeSubtle()
elseif id==3 then setTypeBright()
elseif id==4 then setTypeTooBright()
end
applySettings()
end
-----------------------------------------------------------------------------
-- Presets
-----------------------------------------------------------------------------
function setTypeBlack()
local v = Settings.var
v.hue1=0.00
v.hue2=0.00
v.hue3=0.00
v.hue4=0.00
v.alpha1=1.00
v.alpha2=0.84
v.alpha3=0.71
v.alpha4=0.55
v.saturation=1.00
v.lightness=0.00
v.pos_changes_hue=0.00
v.time_changes_hue=0.00
v.filth=1.00
end
function setTypeSubtle()
local v = Settings.var
v.hue1=0.00
v.hue2=0.00
v.hue3=0.00
v.hue4=0.00
v.alpha1=1.00
v.alpha2=0.83
v.alpha3=0.63
v.alpha4=0.40
v.saturation=1.00
v.lightness=0.070
v.pos_changes_hue=0.21
v.time_changes_hue=0.02
v.filth=1.00
end
function setTypeBright()
local v = Settings.var
v.hue1=0.00
v.hue2=0.00
v.hue3=0.00
v.hue4=0.00
v.alpha1=1.00
v.alpha2=0.84
v.alpha3=0.71
v.alpha4=0.55
v.saturation=1.00
v.lightness=0.66
v.pos_changes_hue=0.06
v.time_changes_hue=0.06
v.filth=1.00
end
function setTypeTooBright()
local v = Settings.var
v.hue1=0.00
v.hue2=0.02
v.hue3=0.06
v.hue4=0.11
v.alpha1=1.00
v.alpha2=0.84
v.alpha3=0.71
v.alpha4=0.55
v.saturation=1.00
v.lightness=0.66
v.pos_changes_hue=0.39
v.time_changes_hue=0.13
v.filth=0.06
end
-----------------------------------------------------------------------------
-- Apply settings
-----------------------------------------------------------------------------
function applySettings()
if not myShader then return end
local v = Settings.var
dxSetShaderValue( myShader, "sHSVa1", v.hue1, v.saturation, v.lightness, v.alpha1 )
dxSetShaderValue( myShader, "sHSVa2", v.hue2, v.saturation, v.lightness, v.alpha2 )
dxSetShaderValue( myShader, "sHSVa3", v.hue3, v.saturation, v.lightness, v.alpha3 )
dxSetShaderValue( myShader, "sHSVa4", v.hue4, v.saturation, v.lightness, v.alpha4 )
dxSetShaderValue( myShader, "sPosAmount", v.pos_changes_hue )
dxSetShaderValue( myShader, "sSpeed", v.time_changes_hue )
dxSetShaderValue( myShader, "sFilth", v.filth )
end
4) Создаём "s_skidmarks.lua", и в него вставляем код:
PHP:
--
-- s_skidmarks.lua
--
g_Settings = {}
-----------------------------------------------------------------------------
-- onClientReady
-----------------------------------------------------------------------------
addEvent( "onClientReady", true )
addEventHandler( "onClientReady", resourceRoot,
function()
-- Send initial settings to player
sendSettings( client )
end
)
-----------------------------------------------------------------------------
-- Command
-----------------------------------------------------------------------------
addCommandHandler( "skidmarks",
function ( player, command, arg1, arg2 )
if isPlayerInACLGroup(player, g_Settings.admingroup ) then
if selectPreset(arg1) then
outputChatBox( "Setting changed to " .. tostring(arg1), player )
else
outputChatBox( "Incorrect input for command", player )
end
else
outputChatBox( "You are not in the correct ACL group", player )
end
end
)
-----------------------------------------------------------------------------
-- Change preset
-----------------------------------------------------------------------------
function selectPreset( id )
local id = tonumber(id)
if id and id >= 1 and id <= 4 then
set('presetID',id)
-- Send updated settings to all players
cacheSettings ()
sendSettings ()
return true
end
return false
end
---------------------------------------------------------------------------
--
-- Settings
--
---------------------------------------------------------------------------
function cacheSettings()
g_Settings = {}
g_Settings.presetID = getNumber('presetID',1)
g_Settings.admingroup = getString('admingroup','Admin')
end
-- Initial cache
addEventHandler('onResourceStart', resourceRoot,
function()
cacheSettings()
resourceStartTime = getTickCount()
end
)
-- Send initial settings to player
addEvent( "onClientReady", true )
addEventHandler( "onClientReady", resourceRoot,
function()
sendSettings( client )
-- Turn shader on at client now
local verbose = getTickCount() - resourceStartTime < 5000
triggerClientEvent ( client, "onClientStartShader", resourceRoot, verbose )
end
)
-- React to admin panel changes
addEventHandler('onSettingChange', resourceRoot,
function(name, oldvalue, value)
cacheSettings()
sendSettings()
end
)
-- Send settings to one client or all of them
function sendSettings( target )
triggerClientEvent ( target or root, "onClientUpdateSettings", resourceRoot, g_Settings )
end
5) Создаём "util.lua", и в него вставляем код:
PHP:
--
-- util.lua
-- client and server file
--
-----------------------------------------------------------------------------
-- Util
-----------------------------------------------------------------------------
function isPlayerInACLGroup(player, groupName)
local account = getPlayerAccount(player)
if not account then
return false
end
local accountName = getAccountName(account)
for _,name in ipairs( split(groupName,string.byte(',')) ) do
local group = aclGetGroup(name)
if group then
for i,obj in ipairs(aclGroupListObjects(group)) do
if obj == 'user.' .. accountName or obj == 'user.*' then
return true
end
end
end
end
return false
end
---------------------------------------------------------------------------
-- gets
---------------------------------------------------------------------------
-- get string or default
function getString(var,default)
local result = get(var)
if not result then
return default
end
return tostring(result)
end
-- get number or default
function getNumber(var,default)
local result = get(var)
if not result then
return default
end
return tonumber(result)
end
-- get true or false or default
function getBool(var,default)
local result = get(var)
if not result then
return default
end
return result == 'true'
end
6) Создаём "mta-helper.fx", отвкрываем любым текстовым редактирором, и вставляем в него код:
PHP:
//
// mta-helper.fx
//
// File version: 0.0.1
// Date updated: 2011-09-26
//
// Big file of doom containg most of the stuff you need to get shaders working with MTA
//
//
// This file has 4 sections:
// 1. Variables
// 2. Renders states (parital - includes only those that are used the most)
// 3. Helper functions
// 4. Normal generation
//
//####################################################################################################################
//####################################################################################################################
//
// Section #1 : Variables
//
//####################################################################################################################
//####################################################################################################################
//---------------------------------------------------------------------
// These parameters are set by MTA whenever a shader is drawn
//---------------------------------------------------------------------
//
// Matrices
//
float4x4 gWorld : WORLD;
float4x4 gView : VIEW;
float4x4 gProjection : PROJECTION;
float4x4 gWorldView : WORLDVIEW;
float4x4 gWorldViewProjection : WORLDVIEWPROJECTION;
float4x4 gViewProjection : VIEWPROJECTION;
float4x4 gViewInverse : VIEWINVERSE;
float4x4 gWorldInverseTranspose : WORLDINVERSETRANSPOSE;
float4x4 gViewInverseTranspose : VIEWINVERSETRANSPOSE;
//
// Camera
//
float3 gCameraPosition : CAMERAPOSITION;
float3 gCameraDirection : CAMERADIRECTION;
//
// Seconds counter
//
float gTime : TIME;
//
// Strongest light influence
//
float4 gLightAmbient : LIGHTAMBIENT;
float4 gLightDiffuse : LIGHTDIFFUSE;
float4 gLightSpecular : LIGHTSPECULAR;
float3 gLightDirection : LIGHTDIRECTION;
//####################################################################################################################
//####################################################################################################################
//
// Section #2 : Renders states
//
//####################################################################################################################
//####################################################################################################################
//---------------------------------------------------------------------
// The parameters below mirror the contents of the D3D registers.
// They are only relevant when using engineApplyShaderToWorldTexture.
//---------------------------------------------------------------------
//------------------------------------------------------------------------------------------
// renderState (partial) - String value should be one of D3DRENDERSTATETYPE without the D3DRS_ http://msdn.microsoft.com/en-us/library/bb172599%28v=vs.85%29.aspx
//------------------------------------------------------------------------------------------
int gLighting < string renderState="LIGHTING"; >; // = 137,
float4 gGlobalAmbient < string renderState="AMBIENT"; >; // = 139,
int gDiffuseMaterialSource < string renderState="DIFFUSEMATERIALSOURCE"; >; // = 145,
int gSpecularMaterialSource < string renderState="SPECULARMATERIALSOURCE"; >; // = 146,
int gAmbientMaterialSource < string renderState="AMBIENTMATERIALSOURCE"; >; // = 147,
int gEmissiveMaterialSource < string renderState="EMISSIVEMATERIALSOURCE"; >; // = 148,
//------------------------------------------------------------------------------------------
// materialState - String value should be one of the members from D3DMATERIAL9 http://msdn.microsoft.com/en-us/library/bb172571%28v=VS.85%29.aspx
//------------------------------------------------------------------------------------------
float4 gMaterialAmbient < string materialState="Ambient"; >;
float4 gMaterialDiffuse < string materialState="Diffuse"; >;
float4 gMaterialSpecular < string materialState="Specular"; >;
float4 gMaterialEmissive < string materialState="Emissive"; >;
float gMaterialSpecPower < string materialState="Power"; >;
//------------------------------------------------------------------------------------------
// textureState (partial) - String value should be a texture number followed by 'Texture'
//------------------------------------------------------------------------------------------
texture gTexture0 < string textureState="0,Texture"; >;
texture gTexture1 < string textureState="1,Texture"; >;
texture gTexture2 < string textureState="2,Texture"; >;
texture gTexture3 < string textureState="3,Texture"; >;
//------------------------------------------------------------------------------------------
// vertexDeclState (partial)
//------------------------------------------------------------------------------------------
int gDeclNormal < string vertexDeclState="Normal"; >; // Set to 1 if vertex stream includes normals
//####################################################################################################################
//####################################################################################################################
//
// Section #3 : Helper functions
//
//####################################################################################################################
//####################################################################################################################
//------------------------------------------------------------------------------------------
// MTAUnlerp
// - Find a the relative position between 2 values
//------------------------------------------------------------------------------------------
float MTAUnlerp( float from, float to, float pos )
{
if ( from == to )
return 1.0;
else
return ( pos - from ) / ( to - from );
}
//------------------------------------------------------------------------------------------
// MTACalcScreenPosition
// - Transform vertex position for the camera
//------------------------------------------------------------------------------------------
float4 MTACalcScreenPosition( float3 InPosition )
{
float4 posWorld = mul(float4(InPosition,1), gWorld);
float4 posWorldView = mul(posWorld, gView);
return mul(posWorldView, gProjection);
}
//------------------------------------------------------------------------------------------
// MTACalcWorldPosition
// - Transform position by current world matix
//------------------------------------------------------------------------------------------
float3 MTACalcWorldPosition( float3 InPosition )
{
return mul(float4(InPosition,1), gWorld).xyz;
}
//------------------------------------------------------------------------------------------
// MTACalcWorldNormal
// - Rotate normal by current world matix
//------------------------------------------------------------------------------------------
float3 MTACalcWorldNormal( float3 InNormal )
{
return mul(InNormal, (float3x3)gWorld);
}
//------------------------------------------------------------------------------------------
// MTACalcGTABuildingDiffuse
// - Calculate GTA lighting for buildings
//------------------------------------------------------------------------------------------
float4 MTACalcGTABuildingDiffuse( float4 InDiffuse )
{
float4 OutDiffuse;
if ( !gLighting )
{
// If lighting render state is off, pass through the vertex color
OutDiffuse = InDiffuse;
}
else
{
// If lighting render state is on, calculate diffuse color by doing what D3D usually does
float4 ambient = gAmbientMaterialSource == 0 ? gMaterialAmbient : InDiffuse;
float4 diffuse = gDiffuseMaterialSource == 0 ? gMaterialDiffuse : InDiffuse;
float4 emissive = gEmissiveMaterialSource == 0 ? gMaterialEmissive : InDiffuse;
OutDiffuse = gGlobalAmbient * saturate( ambient + emissive );
OutDiffuse.a *= diffuse.a;
}
return OutDiffuse;
}
//------------------------------------------------------------------------------------------
// MTACalcGTAVehicleDiffuse
// - Calculate GTA lighting for vehicles
//------------------------------------------------------------------------------------------
float4 MTACalcGTAVehicleDiffuse( float3 WorldNormal, float4 InDiffuse )
{
// Calculate diffuse color by doing what D3D usually does
float4 ambient = gAmbientMaterialSource == 0 ? gMaterialAmbient : InDiffuse;
float4 diffuse = gDiffuseMaterialSource == 0 ? gMaterialDiffuse : InDiffuse;
float4 emissive = gEmissiveMaterialSource == 0 ? gMaterialEmissive : InDiffuse;
float4 TotalAmbient = ambient * ( gGlobalAmbient + gLightAmbient );
// Add the strongest light
float DirectionFactor = max(0,dot(WorldNormal, -gLightDirection ));
float4 TotalDiffuse = ( diffuse * gLightDiffuse * DirectionFactor );
float4 OutDiffuse = saturate(TotalDiffuse + TotalAmbient + emissive);
OutDiffuse.a *= diffuse.a;
return OutDiffuse;
}
//------------------------------------------------------------------------------------------
// MTACalculateCameraDirection
// - Get camera direction to a world point
//------------------------------------------------------------------------------------------
float3 MTACalculateCameraDirection( float3 CamPos, float3 InWorldPos )
{
return normalize( InWorldPos - CamPos );
}
//------------------------------------------------------------------------------------------
// CalcCameraDistance
// - Get camera distance from a world point
//------------------------------------------------------------------------------------------
float MTACalcCameraDistance( float3 CamPos, float3 InWorldPos )
{
return distance( InWorldPos, CamPos );
}
//------------------------------------------------------------------------------------------
// CalculateSpecular
// - Get specular intensity
//------------------------------------------------------------------------------------------
float MTACalculateSpecular( float3 CamDir, float3 LightDir, float3 SurfNormal, float SpecPower )
{
// Using Blinn half angle modification for performance over correctness
LightDir = normalize(LightDir);
SurfNormal = normalize(SurfNormal);
float3 halfAngle = normalize(-CamDir - LightDir);
float r = dot(halfAngle, SurfNormal);
return pow(saturate(r), SpecPower);
}
//####################################################################################################################
//####################################################################################################################
//
// Section #4 : Normal generation
//
//####################################################################################################################
//####################################################################################################################
//
// Declare '#define GENERATE_NORMALS' before this file is included to tell MTA to generate vertex normals if required
//
//---------------------------------------------------------------------
// Flags for MTA to do something about
//---------------------------------------------------------------------
int CUSTOMFLAGS
<
#ifdef GENERATE_NORMALS
string createNormals = "yes"; // Some models do not have normals by default. Setting this to 'yes' will add them to the VertexShaderInput as NORMAL0
#endif
string skipUnusedParameters = "yes"; // This will make the shader a bit faster
>;
//------------------------------------------------------------------------------------------
// MTAFixUpNormal
// - Make sure the normal is valid
//------------------------------------------------------------------------------------------
void MTAFixUpNormal( in out float3 OutNormal )
{
// Incase we have no normal inputted
if ( OutNormal.x == 0 && OutNormal.y == 0 && OutNormal.z == 0 )
OutNormal = float3(0,0,1); // Default to up
}
7) Создаём "skidmarks.fx", отвкрываем любым текстовым редактирором, и вставляем в него код:
PHP:
//
// skidmarks.fx
//
//---------------------------------------------------------------------
// Skidmarks settings
//---------------------------------------------------------------------
float4 sHSVA1 = float4( 0, 1, 1, 1); // HSV + Alpha for each of the 4 layers
float4 sHSVA2 = float4( 0.25, 1, 1, 0.75);
float4 sHSVA3 = float4( 0.5, 1, 1, 0.5);
float4 sHSVA4 = float4( 0.75, 1, 1, 0.25);
float sPosAmount = 0; // How much the position changes the color
float sSpeed = 0; // How much the time changes the color
float sFilth = 0; // Amount of random black patches
//---------------------------------------------------------------------
// Include some common stuff
//---------------------------------------------------------------------
#include "mta-helper.fx"
//---------------------------------------------------------------------
// Sampler for the main texture
//---------------------------------------------------------------------
sampler Sampler0 = sampler_state
{
Texture = (gTexture0);
};
//---------------------------------------------------------------------
// Structure of data sent to the vertex shader
//---------------------------------------------------------------------
struct VSInput
{
float3 Position : POSITION0;
float4 Diffuse : COLOR0;
float2 TexCoord : TEXCOORD0;
};
//---------------------------------------------------------------------
// Structure of data sent to the pixel shader ( from the vertex shader )
//---------------------------------------------------------------------
struct PSInput
{
float4 Position : POSITION0;
float4 Diffuse : COLOR0;
float2 TexCoord : TEXCOORD0;
};
//---------------------------------------------------------------------
// Helper function - Converts HSV to RGB
//---------------------------------------------------------------------
float3 HSVToRGB(float3 HSV)
{
float3 RGB = HSV.z;
float var_h = HSV.x * 6;
float var_i = floor(var_h);
float var_1 = HSV.z * (1.0 - HSV.y);
float var_2 = HSV.z * (1.0 - HSV.y * (var_h-var_i));
float var_3 = HSV.z * (1.0 - HSV.y * (1-(var_h-var_i)));
if (var_i == 0) { RGB = float3(HSV.z, var_3, var_1); }
else if (var_i == 1) { RGB = float3(var_2, HSV.z, var_1); }
else if (var_i == 2) { RGB = float3(var_1, HSV.z, var_3); }
else if (var_i == 3) { RGB = float3(var_1, var_2, HSV.z); }
else if (var_i == 4) { RGB = float3(var_3, var_1, HSV.z); }
else { RGB = float3(HSV.z, var_1, var_2); }
return RGB;
}
//------------------------------------------------------------------------------------------
// VertexShaderFunction
// 1. Read from VS structure
// 2. Process
// 3. Write to PS structure
//------------------------------------------------------------------------------------------
PSInput VertexShaderFunction(VSInput VS, uniform float height, uniform float4 HSVA )
{
PSInput PS = (PSInput)0;
// Adjust z coord upwards for each layer
VS.Position.z += height * 0.025 - 0.05;
// Calculate screen pos of vertex
PS.Position = MTACalcScreenPosition ( VS.Position );
// Pass through tex coord
PS.TexCoord = VS.TexCoord;
//
// Calculate color
//
// Get HSVA components
float hue = HSVA.x;
float saturation = HSVA.y;
float brightness = HSVA.z;
float alpha = HSVA.w;
float3 worldPos = MTACalcWorldPosition( VS.Position );
// Modulate brightness (using position) to give the look of occasional black stripes (controlled by sFilth setting)
brightness *= lerp( fmod( abs(worldPos.x), 2 ) / 2, 1, 1 - sFilth );
// Cycle hue depending upon position (controlled by sPosAmount setting)
hue += fmod( abs(worldPos.x), 20 ) / 20 * sPosAmount;
// Cycle hue depending upon time (controlled by sSpeed setting)
hue += gTime * sSpeed;
// Keep hue inside 0-1
hue = fmod( hue, 1 );
// Apply color
PS.Diffuse.rgb = HSVToRGB( float3(hue,saturation,brightness) );
// Calculate alpha
PS.Diffuse.a = VS.Diffuse.a * alpha / 2;
return PS;
}
//------------------------------------------------------------------------------------------
// PixelShaderFunction
// 1. Read from PS structure
// 2. Process
// 3. Return pixel color
//------------------------------------------------------------------------------------------
float4 PixelShaderFunction(PSInput PS) : COLOR0
{
// Get texture pixel
float4 texel = tex2D(Sampler0, PS.TexCoord);
// Apply diffuse lighting
float4 finalColor = texel * PS.Diffuse * 2;
//finalColor.rgb += PS.Diffuse.rgb;
return finalColor;
}
//------------------------------------------------------------------------------------------
// Techniques
//------------------------------------------------------------------------------------------
technique skidmarks
{
// 4 passes, one for each layer
pass P0
{
AlphaRef = 0;
VertexShader = compile vs_2_0 VertexShaderFunction( 0, sHSVA1 );
PixelShader = compile ps_2_0 PixelShaderFunction();
}
pass P1
{
VertexShader = compile vs_2_0 VertexShaderFunction( 1, sHSVA2 );
PixelShader = compile ps_2_0 PixelShaderFunction();
}
pass P2
{
VertexShader = compile vs_2_0 VertexShaderFunction( 2, sHSVA3 );
PixelShader = compile ps_2_0 PixelShaderFunction();
}
pass P3
{
VertexShader = compile vs_2_0 VertexShaderFunction( 3, sHSVA4 );
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
// Fallback
technique fallback
{
pass P0
{
// Just draw normally
}
}
Ну вот и всё! Теперь осталось его запустить, и пользоваться
