It seems to be going a little off-topic in the Jaguar thread so I'm pulling this out here.
I don't have the Aronde mapped yet so a 3d random noise seemed relevant to me. Because actual random number generators take a while I'm just using a random noise texture map here.
The white spot is the reflection of the sun, not part of specular lighting.
specCol is then fairly random 3d noise, assuming specMap is a noisy texture. Multiply it onto specular as with the metallic shader.
I'm using IN.Position and N here because it's more compatible with existing shaders, really it is better to rewrite _v to pass model coordinates/normal, and use those (which is what the Aronde has). They'll look the same in screenshots, but when you drive around, the speckles move if it's using world coordinates.
This is probably not going to fit into the 64 operations some people are limited to unfortunately. More of the math ends up in _f.
I haven't had a chance to look at Tiberius' metallic flake shader yet (my connection is not good enough to download a 30MB car), I just applied this by multiplying the specular.
These go in carfolder\cg\ to work properly.
speckle_v.cg
speckle_f.cg
In car.shd,
One minor flaw I saw is that this method is symmetric, left and right side of the car have the exact same mapping and it's somewhat visible along the centerline. Also, if you have a flat surface the texture tends to visibly repeat.
Mr. Whippy said:Either way, I think your shader is great. On my track with a few tweaks as discussed it works intuitively and nicely. I even added the metallic flake to my TVR colour cars (cascadey type look), and it worked fine! From a reading and making sense of it point of view it is implemented as realistically as we could, to copy real life, so I don't think it could be done better with what we have either
I'd like to see a version of it as a default in the global shaders folder, but just have some kind of maths noise rather than the texture perhaps, and have it applied in 3d space rather than 2d mapped, with a scale factor, so then you don't even have to have nice texture mapping coords of a constant scale to make it look right...
I don't have the Aronde mapped yet so a 3d random noise seemed relevant to me. Because actual random number generators take a while I'm just using a random noise texture map here.
The white spot is the reflection of the sun, not part of specular lighting.
Code:
dyn_reflect_spec_f.cg
uniform sampler2D specMap : TEXUNIT2,
[...]
float3 p=IN.Position;
float4 spCol1=tex2D(specMap,(p.xy)*5.0f);
float4 spCol2=tex2D(specMap,(p.yz)*5.0f);
float4 spCol3=tex2D(specMap,(p.zx)*5.0f);
float4 specCol=spCol1*N.z+ spCol2*N.x+ spCol3*N.y;
I'm using IN.Position and N here because it's more compatible with existing shaders, really it is better to rewrite _v to pass model coordinates/normal, and use those (which is what the Aronde has). They'll look the same in screenshots, but when you drive around, the speckles move if it's using world coordinates.
This is probably not going to fit into the 64 operations some people are limited to unfortunately. More of the math ends up in _f.
I haven't had a chance to look at Tiberius' metallic flake shader yet (my connection is not good enough to download a 30MB car), I just applied this by multiplying the specular.
These go in carfolder\cg\ to work properly.
speckle_v.cg
Code:
//
// Standard lighting with reflection - dynamic models (modelMatrix)
// RvG, 16-3-09
//
#include "../../../renderer/shaders_hdr/atmosphere.cg"
#include "../../../renderer/shaders_hdr/lighting.cg"
// App to vertex
struct a2v
{
float4 Position : POSITION;
float3 normal : NORMAL;
float2 tc0 : TEXCOORD0;
};
// Vertex to pixel shader structure
struct v2p
{
float4 Position : POSITION;
float2 tc0 : TEXCOORD0; // zw is pos.xy
float3 Direction : TEXCOORD1; // w is pos.z
float4 RayleighColor : TEXCOORD2;
float4 MieColor : TEXCOORD3;
float4 FPosition : TEXCOORD4; // For fragment shader
float3 normal : TEXCOORD5;
// Interpolate fresnel in PS
float3 I : TEXCOORD6;
//float fresnel : TEXCOORD6;
float3 R : TEXCOORD7; // Reflection vector
float extinction : COLOR; // 0..1
};
void main(
// a2v
in a2v IN,
out v2p OUT,
// Constants
uniform float4x4 modelViewProj,
uniform float4x4 modelMatrix,
uniform float3 lightDirection,
uniform float3 eyePosW,
uniform float3 lightColor,
// Atmosphere
uniform float sunIntensity,
uniform float atmosRayleigh,
uniform float atmosMie,
uniform float extinctionFactor
)
{
// Transform to clipspace
OUT.Position=mul(modelViewProj,IN.Position);
float3 posW=mul(modelMatrix,IN.Position).xyz;
// Atmosphere
CalculateAtmosphere(atmosRayleigh,atmosMie,sunIntensity,eyePosW,IN.Position,lightDirection,
OUT.RayleighColor,OUT.MieColor,OUT.Direction.xyz);
// Extinction factor of regular color
OUT.extinction=CalculateAtmosphereExtinction(OUT.Position,atmosRayleigh,atmosMie,extinctionFactor);
// Pass texcoords and such
OUT.tc0=IN.tc0;
// put position in
OUT.normal=IN.normal; //mul((float3x3)modelMatrix, IN.normal);
//OUT.normal=N;
OUT.FPosition=IN.Position; //mul(modelMatrix,IN.Position).xyz;
float3 N=mul((float3x3)modelMatrix,IN.normal);
// Reflection
float3 I=posW-eyePosW;
OUT.R=reflect(I,N);
/*
// Fresnel
const float fresnelBias=0; //0.2;
const float fresnelScale=1.0; //0.9
const float fresnelPower=2.0; //4.0;
I=normalize(I);
float dotIN=dot(I,N);
// Avoid sharp edges
// dotIN=min(dotIN,0.2);
// dotIN=max(dotIN,-0.2);
OUT.fresnel=fresnelBias+fresnelScale*pow(1.0+dotIN,fresnelPower);
//OUT.fresnel=pow(1+dotIN,fresnelPower);
//OUT.fresnel=N; //dotIN;
*/
// Fresnel in pixel shader (pixely effects when done in VS)
OUT.I=I;
/*
// Reflection (dynamic)
float3 posW=mul(modelMatrix,IN.Position).xyz;
float3 I=posW-eyePosW;
float3 Nwc=mul((float3x3)modelMatrix,IN.normal);
R=reflect(I,Nwc);
*/
}
speckle_f.cg
Code:
//
// Standard with reflection cubemap
//
#include "../../../renderer/shaders_hdr/atmosphere.cg"
#include "../../../renderer/shaders_hdr/lighting.cg"
#include "../../../renderer/shaders_hdr/fresnel.cg"
// Vertex to pixel shader structure
struct v2p
{
float extinction : COLOR;
float2 tc0 : TEXCOORD0; // tc0.zw is pos.xy
float3 Direction : TEXCOORD1; // Direction.w is pos.z
float4 RayleighColor : TEXCOORD2;
float4 MieColor : TEXCOORD3;
float4 Position : TEXCOORD4; // For fragment shader
float3 normal : TEXCOORD5;
// Fresnel in pixel shader
float3 I : TEXCOORD6;
//float fresnel : TEXCOORD6;
float3 R : TEXCOORD7; // Reflection vector
};
void main(
// In
in v2p IN,
// Out
out float4 outColor : COLOR,
// Constants
uniform sampler2D baseMap : TEXUNIT0,
uniform samplerCUBE envMap : TEXUNIT1,
uniform sampler2D specMap : TEXUNIT2,
uniform float4x4 modelMatrix,
uniform float3 lightDirection,
uniform float3 lightColor,
uniform float3 lightAmbient,
uniform float3 eyePosW,
uniform float atmosRayleigh,
uniform float atmosMie,
uniform float3 Ke,
uniform float3 Ka,
uniform float3 Kd,
uniform float3 Ks,
uniform float Kr,
uniform float3 shininess,
uniform float exposure
)
{
float3 skyColor;
float3 posW=mul(modelMatrix,IN.Position).xyz;
float3 N=normalize(mul((float3x3)modelMatrix,IN.normal));
float3 N2=normalize(IN.normal);
// Get sky gradient color
skyColor.rgb=GetSkyColor(lightDirection,IN.Direction,IN.RayleighColor,IN.MieColor,atmosRayleigh,atmosMie,lightColor,lightAmbient);
// Get base texture color
float3 p=IN.Position.xyz;
float4 spCol1=tex2D(specMap,(p.xy)*5.0f);
float4 spCol2=tex2D(specMap,(p.yz)*5.0f);
float4 spCol3=tex2D(specMap,(p.zx)*5.0f);
float4 specCol=spCol1*N2.z+ spCol2*N2.x+ spCol3*N2.y;
float4 baseCol=tex2D(baseMap,IN.tc0);
// Reflection
//const float Kr=0.5f;
float4 envColor=texCUBE(envMap,IN.R);
// Lighting
float3 ambient,diffuse,specular;
LightingSun(Ke,Ka,Kd,Ks,shininess,lightDirection,lightColor,lightAmbient,posW,N,eyePosW,
ambient,diffuse,specular);
baseCol.rgb=baseCol*(ambient+Ke)+baseCol*diffuse*lightColor+specular*specCol;
// Add reflection with fresnel
float fresnel=Fresnel(0.15,0.85,2.0,normalize(IN.I),normalize(N));
baseCol.rgb=FresnelMix(baseCol.rgb,envColor.rgb,(Kr<0?baseCol.a:Kr),fresnel);
// HDR toning of sky
//skyColor.rgb=1.0-exp(-exposure*skyColor.rgb);
// Mix sky with texture color based on atmospheric influence
outColor.rgb=lerp(skyColor,baseCol,IN.extinction);
// Blending
outColor.a=baseCol.a;
}
In car.shd,
Code:
vf_speckle
{
vertex_shader
{
file=cg\speckle_v.cg
}
fragment_shader
{
file=cg\speckle_f.cg
}
}
shader_body~vf_speckle
{
compression=0
reflect=0.6
specular=.62 .45 .66 ; purple specular
shininess=15
tangents=1
layer0
{
map=stereo_ar_purple.tga ; plain purple image
}
layer1
{
map=$trackenvmap
}
layer2
{
map=volumespec.tga ; random noise
}
}