mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-09-12 18:50:22 -07:00
demos/teapot: Add specular lighting.
This commit is contained in:
Notes:
Henri Verbeet
2025-07-28 16:38:42 +02:00
Approved-by: Henri Verbeet (@hverbeet) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1650
@@ -38,6 +38,7 @@ struct teapot_fence
|
|||||||
struct teapot_cb_data
|
struct teapot_cb_data
|
||||||
{
|
{
|
||||||
struct demo_matrix mvp_matrix;
|
struct demo_matrix mvp_matrix;
|
||||||
|
struct demo_vec3 eye;
|
||||||
float level;
|
float level;
|
||||||
unsigned int wireframe, flat;
|
unsigned int wireframe, flat;
|
||||||
};
|
};
|
||||||
@@ -521,6 +522,7 @@ static void teapot_update_mvp(struct teapot *teapot)
|
|||||||
demo_matrix_perspective_rh(&projection, 2.0f, 2.0f * teapot->height / teapot->width, 5.0f, 160.0f);
|
demo_matrix_perspective_rh(&projection, 2.0f, 2.0f * teapot->height / teapot->width, 5.0f, 160.0f);
|
||||||
demo_matrix_look_at_rh(&world, &eye, &ref, &up);
|
demo_matrix_look_at_rh(&world, &eye, &ref, &up);
|
||||||
demo_matrix_multiply(&teapot->cb_data->mvp_matrix, &world, &projection);
|
demo_matrix_multiply(&teapot->cb_data->mvp_matrix, &world, &projection);
|
||||||
|
teapot->cb_data->eye = eye;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void teapot_update_text(struct teapot *teapot, double fps)
|
static void teapot_update_text(struct teapot *teapot, double fps)
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
cbuffer teapot_cb : register(b0)
|
cbuffer teapot_cb : register(b0)
|
||||||
{
|
{
|
||||||
float4x4 mvp_matrix;
|
float4x4 mvp_matrix;
|
||||||
|
float3 eye;
|
||||||
float level;
|
float level;
|
||||||
uint wireframe, flat;
|
uint wireframe, flat;
|
||||||
};
|
};
|
||||||
@@ -185,21 +186,75 @@ float3 brdf_lambert(float3 diffuse)
|
|||||||
return diffuse / M_PI;
|
return diffuse / M_PI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The Schlick Fresnel approximation:
|
||||||
|
*
|
||||||
|
* R(θ) ≈ R₀ + (1 - R₀)(1 - c̅o̅s̅ θ)⁵
|
||||||
|
*/
|
||||||
|
float3 fresnel_schlick(float3 r0, float cos_theta)
|
||||||
|
{
|
||||||
|
return lerp(r0, 1.0, pow(1.0 - cos_theta, 5.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float g1(float cos_theta, float alpha_sq)
|
||||||
|
{
|
||||||
|
return cos_theta + sqrt(alpha_sq + (cos_theta - alpha_sq * cos_theta) * cos_theta);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trowbridge-Reitz, "Average irregularity representation of a rough surface for ray reflection".
|
||||||
|
* Also known as "GGX".
|
||||||
|
*
|
||||||
|
* G1(θ) = 2 / (1 + sqrt(α² + (1 - α²)c̅o̅s̅² θ))
|
||||||
|
* G(θᵢ, θₒ) = G1(θᵢ) * G1(θₒ)
|
||||||
|
*
|
||||||
|
* This returns G / (4 c̅o̅s̅ θᵢ c̅o̅s̅ θₒ)
|
||||||
|
*/
|
||||||
|
float geometric_att_trowbridge_reitz(float cos_theta_i, float cos_theta_o, float alpha_sq)
|
||||||
|
{
|
||||||
|
return 1.0 / (g1(cos_theta_i, alpha_sq) * g1(cos_theta_o, alpha_sq));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trowbridge-Reitz, "Average irregularity representation of a rough surface for ray reflection".
|
||||||
|
* Also known as "GGX".
|
||||||
|
*
|
||||||
|
* D(θ) = α² / π((cos² θ)(α² - 1) + 1)²
|
||||||
|
*/
|
||||||
|
float ndf_trowbridge_reitz(float cos_theta_h, float alpha_sq)
|
||||||
|
{
|
||||||
|
float f = (cos_theta_h * alpha_sq - cos_theta_h) * cos_theta_h + 1.0;
|
||||||
|
return alpha_sq / (M_PI * f * f);
|
||||||
|
}
|
||||||
|
|
||||||
float4 ps_main(struct ps_in i) : SV_TARGET
|
float4 ps_main(struct ps_in i) : SV_TARGET
|
||||||
{
|
{
|
||||||
|
float3 barycentric, diffuse, diffuse_colour, radiance, specular, f, h, n, v;
|
||||||
|
float alpha, alpha_sq, cos_theta_h, cos_theta_i, cos_theta_o, d, g, wire;
|
||||||
float3 light_dir = normalize(float3(5.0, 5.0, 10.0));
|
float3 light_dir = normalize(float3(5.0, 5.0, 10.0));
|
||||||
float3 light_colour = float3(1.0, 0.95, 0.88);
|
float3 light_colour = float3(1.0, 0.95, 0.88);
|
||||||
float3 light_irradiance = 5.0 * light_colour;
|
float3 light_irradiance = 5.0 * light_colour;
|
||||||
float3 barycentric, diffuse_colour, radiance;
|
|
||||||
float3 base_colour = float3(0.8, 0.8, 0.8);
|
float3 base_colour = float3(0.8, 0.8, 0.8);
|
||||||
|
float3 f0 = float3(0.04, 0.04, 0.04);
|
||||||
float3 ambient = 0.3 * light_colour;
|
float3 ambient = 0.3 * light_colour;
|
||||||
float cos_theta_i, wire;
|
float roughness = 0.2;
|
||||||
float metallic = 0.3;
|
float metallic = 0.3;
|
||||||
|
|
||||||
diffuse_colour = base_colour * (1.0 - metallic);
|
n = normalize(i.normal);
|
||||||
cos_theta_i = saturate(dot(normalize(i.normal), light_dir));
|
v = normalize(eye - i.pos);
|
||||||
/* Cook-Torrance. */
|
h = normalize(light_dir + v);
|
||||||
radiance = brdf_lambert(diffuse_colour) * light_irradiance * cos_theta_i;
|
cos_theta_h = dot(n, h);
|
||||||
|
cos_theta_i = saturate(dot(n, light_dir));
|
||||||
|
cos_theta_o = saturate(dot(n, v));
|
||||||
|
|
||||||
|
diffuse_colour = base_colour * (float3(1.0, 1.0, 1.0) - f0) * (1.0 - metallic);
|
||||||
|
alpha = roughness * roughness;
|
||||||
|
alpha_sq = alpha * alpha;
|
||||||
|
|
||||||
|
/* Cook-Torrance. The division by (4 c̅o̅s̅ θᵢ c̅o̅s̅ θₒ) is folded into G. */
|
||||||
|
f = fresnel_schlick(lerp(f0, base_colour, metallic), dot(v, h));
|
||||||
|
g = geometric_att_trowbridge_reitz(cos_theta_i, cos_theta_o, alpha_sq);
|
||||||
|
d = ndf_trowbridge_reitz(cos_theta_h, alpha_sq);
|
||||||
|
diffuse = (1.0 - f) * brdf_lambert(diffuse_colour);
|
||||||
|
specular = f * g * d;
|
||||||
|
radiance = (diffuse + specular) * light_irradiance * cos_theta_i;
|
||||||
radiance += ambient * base_colour;
|
radiance += ambient * base_colour;
|
||||||
|
|
||||||
barycentric = float3(i.barycentric, 1.0 - (i.barycentric.x + i.barycentric.y));
|
barycentric = float3(i.barycentric, 1.0 - (i.barycentric.x + i.barycentric.y));
|
||||||
|
Reference in New Issue
Block a user