The adapter records everything the client draws (state, transforms, lights, fog, textures and buffers) as a command stream, sent in chunks through the shared memory channel, while IMVU's Direct3D renderer still draws the whole view. The renderer process draws it with Diligent, with shaders reproducing IMVU's Direct3D 9 fixed-function setup, over the right half of the 3D view to compare. It skips to the newest frame when it falls behind, and logs its errors and frame times. Co-Authored-By: Claude Opus 5.5 <[email protected]>
118 lines
3.9 KiB
HLSL
118 lines
3.9 KiB
HLSL
// IMVU's Direct3D 9 fixed-function look, as its renderer sets it up (docs/interface.md):
|
|
// - per-vertex (Gouraud) lighting, with the vertex color as diffuse and ambient material (white without one): the
|
|
// environment's ambient light, plus each light's color times max(0, N.L); no specular or emissive light;
|
|
// - textures: none (the lit color), one (times the lit color), or two (the second blended over the first by its
|
|
// alpha, then times the lit color), both on the vertex's texture coordinates with their own transforms;
|
|
// - an alpha test passing pixels whose alpha is greater than the reference, then linear fog by view depth.
|
|
//
|
|
// Compiled for each combination of the vertex streams present (HAS_NORMALS, HAS_TEX_COORDS, HAS_COLORS) and the
|
|
// number of textures (TEXTURES).
|
|
|
|
cbuffer Constants
|
|
{
|
|
row_major float4x4 g_World;
|
|
row_major float4x4 g_View;
|
|
row_major float4x4 g_Projection;
|
|
float4 g_TexTransform0[2]; // u' = dot((u, v, 1), [0].xyz), v' = dot((u, v, 1), [1].xyz)
|
|
float4 g_TexTransform1[2];
|
|
float4 g_Ambient; // rgb
|
|
float4 g_LightColor[8]; // rgb, a: enabled
|
|
float4 g_LightVector[8]; // xyz: position, or direction toward the light; w: 1 if directional
|
|
float4 g_FogColor; // rgb
|
|
float4 g_Fog; // x: start, y: end, z: on
|
|
float4 g_Flags; // x: lighting on, y: alpha test on, z: alpha reference (0-255)
|
|
};
|
|
|
|
struct VSInput
|
|
{
|
|
float3 Position : ATTRIB0;
|
|
#if HAS_NORMALS
|
|
float3 Normal : ATTRIB1;
|
|
#endif
|
|
#if HAS_TEX_COORDS
|
|
float2 TexCoord : ATTRIB2;
|
|
#endif
|
|
#if HAS_COLORS
|
|
float4 Color : ATTRIB3; // bytes B, G, R, A
|
|
#endif
|
|
};
|
|
|
|
struct PSInput
|
|
{
|
|
float4 Position : SV_POSITION;
|
|
float4 Color : COLOR0;
|
|
float2 TexCoord0 : TEXCOORD0;
|
|
float2 TexCoord1 : TEXCOORD1;
|
|
float Depth : TEXCOORD2;
|
|
};
|
|
|
|
void vs_main(in VSInput input, out PSInput output)
|
|
{
|
|
float4 world = mul(float4(input.Position, 1.0), g_World);
|
|
float4 view = mul(world, g_View);
|
|
output.Position = mul(view, g_Projection);
|
|
output.Depth = abs(view.z);
|
|
|
|
float4 material = float4(1.0, 1.0, 1.0, 1.0);
|
|
#if HAS_COLORS
|
|
material = input.Color.zyxw;
|
|
#endif
|
|
float4 color = material;
|
|
if (g_Flags.x > 0.5)
|
|
{
|
|
float3 normal = float3(0.0, 0.0, 0.0);
|
|
#if HAS_NORMALS
|
|
normal = normalize(mul(input.Normal, (float3x3)g_World));
|
|
#endif
|
|
float3 lit = g_Ambient.rgb * material.rgb;
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
if (g_LightColor[i].a > 0.5)
|
|
{
|
|
float3 toLight = g_LightVector[i].w > 0.5 ? g_LightVector[i].xyz : g_LightVector[i].xyz - world.xyz;
|
|
lit += g_LightColor[i].rgb * material.rgb * max(0.0, dot(normal, normalize(toLight)));
|
|
}
|
|
}
|
|
color = float4(saturate(lit), material.a);
|
|
}
|
|
output.Color = color;
|
|
|
|
float3 uv = float3(0.0, 0.0, 1.0);
|
|
#if HAS_TEX_COORDS
|
|
uv.xy = input.TexCoord;
|
|
#endif
|
|
output.TexCoord0 = float2(dot(uv, g_TexTransform0[0].xyz), dot(uv, g_TexTransform0[1].xyz));
|
|
output.TexCoord1 = float2(dot(uv, g_TexTransform1[0].xyz), dot(uv, g_TexTransform1[1].xyz));
|
|
}
|
|
|
|
#if TEXTURES >= 1
|
|
Texture2D g_Texture0;
|
|
SamplerState g_Texture0_sampler;
|
|
#endif
|
|
#if TEXTURES >= 2
|
|
Texture2D g_Texture1;
|
|
SamplerState g_Texture1_sampler;
|
|
#endif
|
|
|
|
float4 ps_main(in PSInput input) : SV_Target
|
|
{
|
|
float4 color = input.Color;
|
|
#if TEXTURES == 1
|
|
color *= g_Texture0.Sample(g_Texture0_sampler, input.TexCoord0);
|
|
#elif TEXTURES == 2
|
|
float4 first = g_Texture0.Sample(g_Texture0_sampler, input.TexCoord0);
|
|
float4 second = g_Texture1.Sample(g_Texture1_sampler, input.TexCoord1);
|
|
color *= lerp(first, second, second.a);
|
|
#endif
|
|
if (g_Flags.y > 0.5 && !(color.a * 255.0 > g_Flags.z))
|
|
{
|
|
discard;
|
|
}
|
|
if (g_Fog.z > 0.5)
|
|
{
|
|
float visible = saturate((g_Fog.y - input.Depth) / max(g_Fog.y - g_Fog.x, 1e-6));
|
|
color.rgb = lerp(g_FogColor.rgb, color.rgb, visible);
|
|
}
|
|
return color;
|
|
}
|