Bạn có thể làm điều này hoàn toàn trong một shader đỉnh. Bạn muốn áp dụng trình đổ bóng này cho mọi thứ bạn kết xuất.
Một mẹo nhỏ mà bạn có thể làm là cân nó sao cho các vật thể gần đó nằm thẳng ra để nói 100 mét. Tôi khuyên bạn nên điều này bởi vì trong một trò chơi FPS, sự biến dạng trên các vật thể đòi hỏi bạn phải thay đổi mọi thứ. (Người chơi sẽ nhắm vào những thứ sai). Nếu bạn giữ cho các vùng lân cận bằng phẳng thì bắt đầu đường cong ở khoảng cách nó sẽ trông giống nhau mà không gặp vấn đề tương tác.
Đây là một hình ảnh để hiểu. (Tôi không có mã tại thời điểm này trên máy này, nhưng đó chỉ là một vài dòng nếu tôi nhớ chính xác).
Vì bạn đã yêu cầu mã. Tôi không thể kiểm tra mã này 100%, nhưng tôi đã thấy hình ảnh của nó hoạt động. (Tôi đã viết mã giả cho một người bạn đã chuyển đổi nó thành HLSL và các hình ảnh cho thấy nó hoạt động).
cbuffer matrix_buffer
{
matrix world;
matrix view;
matrix projection;
};
struct vertex_input_type
{
float4 position : POSITION;
float3 normal : NORMAL;
};
struct pixel_input_type
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
};
pixel_input_type vertex_shader(vertex_input_type input)
{
pixel_input_type output;
input.position.w = 1.0f;
#if 0
output.position = mul(world, input.position);
output.position = mul(view, output.position);
output.position = mul(projection, output.position);
#else
float4 viewPosition = float4(0, 20.0, 0, 1);
float seaLevel = 0.0;
float4 vertex = input.position;
matrix model = world;
float radius = 900.0;
vertex = mul(model, vertex);
float2 diff = vertex.xz - viewPosition.xz;
float angleX = -length(diff) / radius;
float angleY = atan2(diff.x, diff.y);
float3x3 rotateX =
{
1, 0, 0,
0, cos(angleX), -sin(angleX),
0, sin(angleX), cos(angleX)
};
float3x3 rotateY =
{
cos(angleY), 0, sin(angleY),
0, 1, 0,
-sin(angleY), 0, cos(angleY)
};
vertex = float4(mul(rotateY, mul(rotateX, float3(0, radius + vertex.y - seaLevel, 0))) + float3(0, -radius, 0), 1);
vertex = mul(projection, mul(view, vertex));
output.position = vertex;
#endif
output.normal = input.normal;
return output;
}