marcelluss Posted September 30 Share Posted September 30 Hello dear forum members, I am deeply interested in a persistent question regarding my shader for the effect of raindrops flowing down the sides of the car, as well as the effect of raindrops (spots) on the surface of the car (roof, bumper). I’ve been struggling with these issues for a long time and still can’t figure out how to solve my two problems. I hope someone can help me and explain to a beginner in HLSL how to properly implement the shader. The first problem is that I don’t understand how to make the raindrops flow down the different sides of the car. Essentially, I have a single texture applied to the car, and I can't figure out how to split it into multiple segments and adapt it to flow around the sides of the car. (I also need to account for the unique features of each car model so that the flow looks realistic on each vehicle.) The second problem is the effect of tiny raindrops on the roof, hood, and bumper of the car (the generation of small droplets that gradually appear and disappear). The issue is that I’m trying to apply both effects in one shader, but the problem is that either only one of them works under certain settings, or nothing works at all. I can't get both effects to work harmoniously together. I’ll also provide an example of the Lua script and the textures used for the shader. I really hope for your help. I've been spending too much time on this, and I can't seem to find a solution. float4x4 gWorld : WORLD; float4x4 gView : VIEW; float4x4 gProjection : PROJECTION; float gTime : TIME; // Rain parameters float gDropSpeed = 0.03; // Speed of droplet flow float2 noiseScale = float2(0.2, 0.8); // Noise texture scale float3 lightDirection = float3(1.0, 1.0, -1.0); // Light direction float gDropSpread = 0.3; // Droplet spread float gDropDepth = 0.3; // Droplet depth texture gTexture; // Main car texture texture texRain; // Raindrop texture texture texNormalRain; // Raindrop normals texture texNoise; // Noise texture // Variables for controlling the effect float gAlpha = 0.01; // Alpha channel for the car float rainAlpha = 1.8; // Alpha channel for raindrops sampler2D gTextureSampler = sampler_state { Texture = ( gTexture ); MinFilter = Linear; MagFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; sampler2D texRainSampler = sampler_state { Texture = ( texRain ); MinFilter = Linear; MagFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; sampler2D texNormalRainSampler = sampler_state { Texture = ( texNormalRain ); MinFilter = Linear; MagFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; sampler2D texNoiseSampler = sampler_state { Texture = ( texNoise ); MinFilter = Linear; MagFilter = Linear; AddressU = Wrap; AddressV = Wrap; }; struct VertexShaderInput { float4 Position : POSITION; // Using standard POSITION semantics for the vertex shader float2 TextureCoordinate : TEXCOORD0; // Passing texture coordinates }; struct PixelShaderInput { float4 Position : POSITION; // Passing position as float4 for proper operation float3 WorldPos : TEXCOORD1; // Passing world coordinates for calculations float2 TextureCoordinate : TEXCOORD0; // Passing texture coordinates }; PixelShaderInput VertexShaderFunction(VertexShaderInput input) { PixelShaderInput output; // Position in world coordinates float4 worldPos = mul(input.Position, gWorld); // Storing position for further projection output.Position = mul(mul(input.Position, gWorld), gView); output.Position = mul(output.Position, gProjection); // Applying projection // Storing world coordinates (for droplet flow) output.WorldPos = worldPos.xyz; // Passing texture coordinates output.TextureCoordinate = input.TextureCoordinate; return output; } float4 PixelShaderFunction(PixelShaderInput output) : COLOR0 { float2 textureCoordinate = output.TextureCoordinate; // Main car texture float4 baseColor = tex2D(gTextureSampler, textureCoordinate); baseColor.rgb = max(baseColor.rgb, 0.1); // Brightening dark areas // Getting noise for random movement float noise = tex2D(texNoiseSampler, textureCoordinate * noiseScale).r; // World coordinates to determine droplet direction float3 worldPos = output.WorldPos; // Using world coordinates // Determining droplet direction based on normals and world position float3 normal = normalize(output.WorldPos); // Normal to the surface // Checking direction by normals to determine which side of the car we're on if (abs(normal.x) > abs(normal.y) && abs(normal.x) > abs(normal.z)) { // Side surfaces textureCoordinate.y += gDropSpeed * gTime; // Flowing down the sides } else if (normal.y > 0.5) { // Top surface (roof) textureCoordinate.y -= gDropSpeed * gTime; // Droplets flow down } else { // Other sides (front and back) textureCoordinate.x -= gDropSpeed * gTime; // Optionally add droplet flow forward/backward } // Reducing random offset for more precise flow float2 offset = gDropSpread * (noise * 4.0 - 0.5) * float2(1.0, 2.5); // Using float2 for offset textureCoordinate -= offset; // Applying deviation in both axes // Raindrop texture float4 rainColor = tex2D(texRainSampler, textureCoordinate); // Adjusting droplets to the car color rainColor.rgb = baseColor.rgb * 0.8 + float3(0.1, 0.1, 0.1); // Adding body tint to droplets rainColor.a = rainAlpha; // Alpha channel of droplets // Normals for droplets float4 tempRainNormal = tex2D(texNormalRainSampler, textureCoordinate); // Explicitly using float4 float3 rainNormal = normalize(tempRainNormal.rgb * 2.5 - 0.75); // Normalizing normals // Lighting on droplets float diffuse = saturate(dot(normalize(rainNormal), normalize(lightDirection))); // Correct lighting // Combining colors float4 finalColor = lerp(baseColor, rainColor, rainAlpha * diffuse); finalColor.a = lerp(gAlpha, rainAlpha, diffuse * 0.9); // Adding droplet depth finalColor.rgb += gDropDepth * 0.9; // Depth effect of droplets float3 v = float3(0.0, 0.0, 0.0); float Tr2 = gTime * 11000.0; float2 n = tex2D(texNoiseSampler, textureCoordinate * 0.5).rg; for (float r = 4.0; r > 0.0; r--) // Reducing the number of iterations { float2 x = 2100.0 * r * 0.015; float2 p = 6.28 * textureCoordinate * x + (n - 0.5) * 2.0; float4 d = tex2D(texNoiseSampler, round(textureCoordinate * x - 0.25) / x); float t = (sin(p.x) + sin(p.y)) * max(0.0, 1.0 - frac(Tr2 * (d.b + 0.1) + d.g) * 2.0); if (d.r < (2.0 - r) * 0.08 && t > 0.5) { v += normalize(float3(-cos(p.x), lerp(1.2, 2.0, t - 0.5), 0.0)); } } finalColor.rgb += v * rainAlpha; return finalColor; } technique Replace { pass P0 { DepthBias = -0.0001; AlphaBlendEnable = TRUE; SrcBlend = SRCALPHA; DestBlend = INVSRCALPHA; VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_3_0 PixelShaderFunction(); } } LUA CODE: local shader = dxCreateShader("fx/shader.fx", 2, 300, true, "vehicle"); local zapylyayushiesyaDetali = { "remap_body", }; local rainTexture = dxCreateTexture("assets/RainCar.png") local normalRainTexture = dxCreateTexture("assets/RainNormal.png") local noiseTexture = dxCreateTexture("assets/enbnoise.png") dxSetShaderValue(shader, "texRain", rainTexture) dxSetShaderValue(shader, "texNormalRain", normalRainTexture) dxSetShaderValue(shader, "texNoise", noiseTexture) -- Применение шейдера к машине local vehicle = getPedOccupiedVehicle(localPlayer) if vehicle then --engineApplyShaderToWorldTexture(shader, "vehiclegrunge256", vehicle) for _, name in ipairs(zapylyayushiesyaDetali) do engineRemoveShaderFromWorldTexture(shader, name, localPlayer.vehicle) engineApplyShaderToWorldTexture(shader, name, localPlayer.vehicle) end end renderTarget = dxCreateRenderTarget(512, 512, true) addEventHandler("onClientRender", root, function() iprint(shader) if shader then if renderTarget then dxSetRenderTarget(renderTarget, true) dxDrawImage(0, 0, 512, 512, shader) dxSetRenderTarget() dxDrawImage(50, 50, 256, 256, renderTarget) end end end) Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now