But, after 6 hours of figuring many of the techniques a compiler uses to make the most efficient code it can, I finally translated the vertex shader for PAR2000, one-half of the thirty-five shaders responsible for parallax displacement mapping in Oblivion. Now I know the inputs for both the vertex and pixel shader, and what they look like coming out of the vertex shader. After vtastek mentioned cone-relief mapping, I just had to go and read about it... After a couple of days figuring out how to create the custom assets for cone-relief mapping (and doing it in such a way that Oblivion will still mostly work), I set off to replace a single shader with cone relief mapping, and the textures for great forest rocks to see how it looks.
Well, I haven't gotten that far yet, but here is the HLSL for PAR2000.vso:
row_major float4x4 ModelViewProj : register(c0);float3 LightDirection : register(c13);float4 FogParam : register(c23);float3 FogColor : register(c24);float4 EyePosition : register(c25);struct vertexInput{ float4 pos : POSITION; float3 tangent : TANGENT; float3 binormal : BINORMAL; float3 normal : NORMAL; float2 texCoord : TEXCOORD0; float4 color : COLOR0;};struct pixelInput{ float4 pos : POSITION; float4 color : COLOR0; float4 fogcolor : COLOR1; float2 texCoord : TEXCOORD0; float3 lightDir : TEXCOORD1; float3 cameraDir : TEXCOORD6;};pixelInput simple_vs(vertexInput IN){ float temp1; float3 temp3; //Transform light direction to tangent space. float3x3 tangentMatrix = {IN.binormal,IN.tangent,IN.normal}; temp3 = mul(tangentMatrix, LightDirection); //Normalize the light direction and output. OUT.lightDir = normalize(temp3); //Find camera direction and normalize it. temp3 = normalize(EyePosition.xyz - IN.pos.xyz); //Transform the camera vector to tangent space. temp3 = mul(tangentMatrix, temp3); OUT.cameraDir = normalize(temp3); //Transform position of the vertex into clip coordinates float4 posCS = mul(ModelViewProj, IN.pos); //...and output. OUT.pos = posCS; //Next, calculate the fog attenuation. temp1 = (FogParam.x - length(posCS.xyz)) / FogParam.y; temp1 = saturate(temp1); //Encode the attenuation amount into the fog color's alpha channel. OUT.fogcolor.rgb = FogColor; OUT.fogcolor.a = 1.0 - temp1; //And output the rest of our outputs. OUT.texCoord = IN.texCoord; OUT.color = IN.color; return OUT;}
vtastek is right. It is pretty standard, but now I at least know its all in tangent space, and how fog attenuation was programmed. It was a more difficult task to reverse engineer this than I thought, but hopefully it'll be worth it. I haven't attempted to compile it yet, but it looks right and makes sense. Let me know if there is anything off about it.
Brilliant work. :thumbsup:
Does anyone know why the shader packages seem to contain many identical shaders, eg. the nighteye shader, which has a copy in each package? I haven't done anything with the shaders myself yet, but I did notice this when I had a quick look.