Paste will expire never. Expiration is locked.
- #define LIGHT_SPACE "Object"
- #include "bindings.h"
- struct VS_IN
- {
- float4 position: POSITION;
- float2 texcoord: TEXCOORD;
- float3 tangent: TANGENT;
- float3 bitangent: BINORMAL;
- float3 normal: NORMAL;
- };
- struct VS_OUT
- {
- float2 texcoord: TEXCOORD0;
- // view vector, tangent space
- float3 view: TEXCOORD1;
- // light vectors, unnormalized, tangent space
- // l0.x l1.x l2.x l3.x
- // l0.y l1.y l2.y l3.y
- // l0.z l1.z l2.z l3.z
- // twice.
- float4 lights[6]: TEXCOORD2;
- };
- uniform float4x4 world_view_inverse: WorldViewInverse;
- uniform float4x4 world_view_projection: WorldViewProjection;
- // light position, object space
- static float3 light_positions[8] =
- {
- Lamp1Pos, Lamp2Pos, Lamp3Pos, Lamp4Pos,
- Lamp5Pos, Lamp6Pos, Lamp7Pos, Lamp8Pos
- };
- VS_OUT vs_main(VS_IN I, out float4 clippos: POSITION)
- {
- clippos = mul(I.position, world_view_projection);
- VS_OUT O;
- O.texcoord = I.texcoord;
- // view vector
- float3 eye_pos = mul(float4(0, 0, 0, 1), world_view_inverse);
- float3 view = normalize(I.position - eye_pos);
- // transform to tangent space
- O.view.x = dot(view, I.tangent);
- O.view.y = dot(view, I.bitangent);
- O.view.z = dot(view, I.normal);
- // note: this loop can be optimized if application feeds light data in SoA
- // order, we can do SoA-style calculation here also. It's not quite easy to
- // do in FX Composer, I guess, and anyway this is left as is for clarity.
- for (int i = 0; i < 2; ++i)
- {
- // compute light vectors in tangent space
- float3 light_vectors[4];
- for (int j = 0; j < 4; ++j)
- {
- float3 l = light_positions[i*4 + j] - I.position;
- light_vectors[j].x = dot(l, I.tangent);
- light_vectors[j].y = dot(l, I.bitangent);
- light_vectors[j].z = dot(l, I.normal);
- }
- // splat in SoA order
- O.lights[i*3 + 0] = float4(light_vectors[0].x, light_vectors[1].x, light_vectors[2].x, light_vectors[3].x);
- O.lights[i*3 + 1] = float4(light_vectors[0].y, light_vectors[1].y, light_vectors[2].y, light_vectors[3].y);
- O.lights[i*3 + 2] = float4(light_vectors[0].z, light_vectors[1].z, light_vectors[2].z, light_vectors[3].z);
- }
- return O;
- }
- // light colors
- static float3 light_colors[8] =
- {
- Lamp1Col, Lamp2Col, Lamp3Col, Lamp4Col,
- Lamp5Col, Lamp6Col, Lamp7Col, Lamp8Col
- };
- // 1 / light radius^2
- uniform float4 light_radius_inv[2] =
- {
- (1 / 0.25).xxxx,
- (1 / 0.25).xxxx
- };
- // specular power A, B constant
- // http://www.gamasutra.com/features/20020801/beaudoin_01.htm
- // m = 2, n = 18 => A = 6.645, B = -5.645
- uniform const float2 specular_ab = float2(6.645, -5.645);
- texture diffuse_texture;
- uniform sampler2D diffuse_map = TRILINEAR_SAMPLER(diffuse_texture);
- texture normal_texture;
- uniform sampler2D normal_map = TRILINEAR_SAMPLER(normal_texture);
- texture specular_texture;
- uniform sampler2D specular_map = TRILINEAR_SAMPLER(specular_texture);
- float4 compute_specular_power(float4 v)
- {
- // originally: pow(v, N)
- // x^N is roughly equal to (max(Ax+B, 0))^2
- // A,B depend on N
- float4 t = saturate(specular_ab.x * v + specular_ab.y);
- return t * t;
- }
- struct LightingData
- {
- float4 diffuse;
- float4 specular;
- };
- LightingData computeLighting4(VS_OUT I, int light_bucket_index, float3 normal)
- {
- // compute squared lengths in parallel
- float4 squared_lengths = 0;
- for (int i = 0; i < 3; ++i)
- {
- squared_lengths += pow(I.lights[light_bucket_index * 3 + i], 2);
- }
- // compute NdotL in parallel
- float4 NdotL = 0;
- for (int i = 0; i < 3; ++i)
- {
- NdotL += I.lights[light_bucket_index * 3 + i] * normal[i];
- }
- // compute RdotL in parallel
- float3 reflected = reflect(I.view, normal);
- float4 RdotL = 0;
- for (int i = 0; i < 3; ++i)
- {
- RdotL += I.lights[light_bucket_index * 3 + i] * reflected[i];
- }
- // correct NdotL and RdotL
- float4 correction = 1 / sqrt(squared_lengths);
- NdotL = saturate(NdotL * correction);
- RdotL = saturate(RdotL * correction);
- // attenuation
- // 1 - d^2 / r^2 for diffuse
- float4 atten = squared_lengths * light_radius_inv[light_bucket_index];
- // modulate diffuse by attenuation
- NdotL = saturate(NdotL - NdotL * atten);
- // specular
- float4 spec = compute_specular_power(RdotL);
- LightingData data;
- data.diffuse = NdotL;
- data.specular = spec;
- return data;
- }
- float4 ps_main(VS_OUT I): COLOR
- {
- float3 normal = tex2D(normal_map, I.texcoord).xyz * 2 - 1;
- LightingData lights[] =
- {
- computeLighting4(I, 0, normal),
- computeLighting4(I, 1, normal)
- };
- // final diffuse color
- float3 diffuse = 0;
- for (int i = 0; i < 8; ++i)
- {
- diffuse += lights[i/4].diffuse[i%4] * light_colors[i];
- }
- // final specular color
- float4 specular_color = tex2D(specular_map, I.texcoord);
- float3 specular = specular_color.rgb * saturate(dot(lights[0].specular + lights[1].specular, 1));
- // final color
- float4 albedo = tex2D(diffuse_map, I.texcoord);
- return float4(albedo.rgb * diffuse + specular, albedo.a);
- }
- technique t0
- {
- pass p0
- {
- VertexShader = compile vs_1_1 vs_main();
- PixelShader = compile ps_2_0 ps_main();
- }
- }
Editing is locked.