normal map) Trước khi đi chi tiết vào thuật toán ta cần xem qua 1 số khái niệm mới dùng trong phần này Không gian tiếp tuyến của vật thể (tangent space). Tọa độ texture tại mỗi đỉnh (vertex) hình thành một hệ trục tọa độ 3 chiều với trục U (tiếp tuyến), trục W (pháp tuyến) và trục V (binormal = U x W). Hệ trục tọa độ này gọi là không gian tiếp tuyến hay không gian texture của vật thể tại các đỉnh (vertex).
Không gian tiếp tuyến
• Normal map, Normal map là một texture nhưng có đặc tính khá đặc biệt, thay vì chứa thông tin về điểm màu như texture thông thường, normal map lai chứa thông tin về không gian tiếp tuyến (tangent space) hay không gian texture (texture space) của vật thể, hay nói cách khác nếu các điểm ảnh của texture biểu diễn màu sắc của vật thể tại 1 điểm thì normal map sẽ biểu diễn không gian tiếp tuyến của vật thể tại điểm đó. Mỗi điểm ảnh của normal map có định dạng là RGBA trong đó 3 thành phần RGB có giá trị [0..1] được ánh xạ từ 3 trục U, V, W có giá trị trong khoảng [-1, 1]. Normal map có thể tạo ra bằng 2 cách, dùng height map (texture dạng graycale chứa thông tin độ sâu về bề mặt của vật thể trong đó màu sáng hơn biểu thị độ cao lớn hơn). Cách thứ 2 phức tạp hơn do phải tạo thêm 1 vật thể khác có độ chi tiết cao
hơn, sau đó ta so sánh sự khác nhau giữa 2 vật thể để tạo ra normal map (quá trình này có thể được thực hiện bằng tool Melody của NVidia).
Có thể bạn quan tâm!
- Môi Trường Và Ngôn Ngữ Lập Trình Cho Đồ Họa 3D
- Chiếu Sáng Chính Diện (Front Lighting)
- Bóng Cung Cấp Thông Tin Về Vị Trí Tương Đối Của Vật Thể.
- Một Số Thuật Toán Chiếu Sáng Toàn Cục
- Các Nút Chức Năng Cho Cửa Sổ Scene.
- Mô phỏng sự tạo bóng của vật thể từ một nguồn sáng trong thực tại ảo - 9
Xem toàn bộ 81 trang tài liệu này.
Hình 2.14 Tạo normal map từ hight map
• Bump bề mặt sử dụng normal map, Bump bề mặt chủ yếu được thực hiện trên Pixel Shader cho từng điểm ảnh. Thuật toán này sử dụng giá trị normal trong normal map để xác định mức độ của ánh sáng tác động vào điểm ảnh đó bằng cách nhân tích vô hướng giá trị normal trên với vector hướng ánh sáng trong không gian tiếp tuyến. Sau đó giá trị này được nhân với màu sắc của vertex và màu lấy mẫu từ texture để tính ra màu diffuse (màu của vertex được tính trong Vertex Shader) Trong đó:
+ Normal. Vector pháp tuyến (normal vector) tại điểm đó, normal vector có được do lấy mẫu từ normal map.
+ Light vector. Vector hướng ánh sáng trong không gian tiếp tuyến (tangent space), vector này được tính trong Vertex Shader và được truyền vào Pixel Shader để sử dụng. vertex color. Màu của vertex sau khi thực hiện chiếu sáng trên vertex (pervertex lighting) trong Vertex Shader. texture color. Màu của texture chính, có được do lấy mẫu texture.
+ Tính toán màu specular (sử dụng specular map), specular map là texture dạng grayscale, specular map có tác dụng cho biết vùng nào của vật thể phản chiếu nhiều ánh sáng vùng nào phản chiếu ít ánh sáng (tương ứng với màu trong specular map từ sáng tới tối).
+ Tính độ phản chiếu của ánh sánh, Độ phản chiếu (phản xạ) của ánh sáng trên vật thể thì phụ thuộc vị trí của mắt (hay camera). Khi mắt nằm ngay trên đường phản xạ của ánh sáng thì mắt sẽ nhìn thấy một vùng ánh sáng chói do toàn bộ năng lượng của ánh sáng được truyền thẳng vào mắt. Muốn tính màu specular của điểm ảnh ta phải xác định được mức độ ánh sáng phản chiếu tại điểm đó. Công thức tính vector phản chiếu (phản xạ) như sau:
Trong đó:
Sự phản xạ của tia sáng trên bề mặt
R = 2(L dot N)N - L
L. Light vector R.
Reflection vector
N. Norma
l Mức độ phản chiếu của ánh sáng phụ thuộc rất nhiều vào chất liệu bề mặt của vật thể, các bề mặt nhẵn bóng có độ phản chiếu lớn trong khi các bề mặt gồ ghề lại có độ phản chiếu thấp. Để tránh công việc phải phân rã vật thể ra thành nhiều thành phần để dựng hình với các mức phản chiếu khác nhau người ta dùng specular map như một lookup table để xác định mức độ phản chiếu của ánh sánh trên từng điểm ảnh.
reflection vector = 2 * dotproduct (normal, light vector) * normal - light vector specular factor = dotproduct (reflection vector, view vector)
specular color = (specular factor ^ specular constant) * specular lookup Trong đó
• normal. Vector pháp tuyến (normal vector) tại điểm đó, normal vector có được do lấy mẫu từ normal map.
• light vector. Vector hướng ánh sáng trong không gian tiếp tuyến (tangent space), vector này được tính trong Vertex Shader và được truyền vào Pixel Shader để sử dụng.
• view vector. Vector tính từ mắt đến điểm nhìn (tọa độ trong không gian tiếp tuyến), vector này được tính trong Vertex Shader và truyền vào Pixel Shader để sử dụng specular constant. Hằng phản chiếu, giá trị càng lớn thì vùng phản chiếu càng nhỏ.
• specular lookup. Cho biết mức độ phản chiếu của điểm đó, giá trị này có được do lấy mẫu từ specular map.
2.4. Kỹ thuật biểu diễn bóng đổ
Kỹ thuật ánh xạ bóng phụ thuộc vào thực tế là bóng đổ của mỗi pixel chỉ thể hiện các đỉnh gần máy ảnh nhất. Do đó, chỉ những phần vật thể gần nhất với "nguồn sáng" mới được vẽ vào vùng bóng và lưu vào bộ đệm khi thể hiện bóng đổ của ảnh. Khi chúng ta đang vẽ các đối tượng của mình từ điểm quan sát, chúng ta có thể xác định khoảng cách thực tế của mỗi đỉnh từ nguồn sáng, sau đó chúng ta có thể so sánh với giá trị được lưu trữ trong bộ đệm sâu. Nếu giá trị được lưu trong bộ đệm độ sâu nhỏ hơn khoảng cách thực tế của đỉnh từ nguồn sáng, thì nó phải có một vật thể nằm giữa nó và máy ảnh và điểm đó cần thể hiện bóng đổ
Khoảng cách từ
nguồn
Khoảng cách từ
nguồn
tâm Học liệu và Công nghệ thông tin – ĐHTN http://lr
Số hóa bởi Trung
Khoảng cách từ nguồn sáng đến mặt phẳng >Khoảng cách từ nguồn sáng đến vật thì mới có bóng đổ
c.tnu.edu.vn
Để nhận được giá trị lưu trữ trong bộ nhớ cho các điểm đã vẽ, chúng ta phải ánh xạ hình ảnh chính xác cho từng điểm, sau đó thêm vào bóng của điểm bằng cách gọi thủ tục PPModel.fx effect nghĩa là copy hiệu ứng bóng thêm vào các tham số tọa độ và độ dài của bóng
bool DoShadowMapping = true; float4x4 ShadowView; float4x4 ShadowProjection; texture2D ShadowMap;
sampler2D shadowSampler = sampler_state
{
texture = <ShadowMap>; minfilter = point; magfilter = point; mipfilter = point;
}
Thủ tục VertexShaderOutput struct sẽ thêm giá trị vị trí không gian của đỉnh, của nguồn sáng
float4 ShadowScreenPosition : TEXCOORD2; Bóng đổ của đỉnh cần tính toán các giá trị sau:
output.ShadowScreenPosition = mul(mul(input.Position, World), mul(ShadowView, ShadowProjection));
Sau đó chúng ta cần lấy mẫu của bề mặt vật, để tạo biên của bóng cho phù hợp với hình ảnh thực tế chúng ta quan sát bằng mắt thường. Vấn đề là lấy đủ số mẫu cần thiết để bóng được trơn nhưng cũng không quá nhiều mẫu làm giảm tốc độ xử lý
float sampleShadowMap(float2 UV)
{
if (UV.x < 0 || UV.x > 1 || UV.y < 0 || UV.y > 1) return 1;
return tex2D(shadowSampler, UV).r;
}
Cuối cùng chúng ta dùng hàm để xác định kích thước từ độ sâu bề mặt vật ứng với bóng đổ của điểm
float2 shadowTexCoord = postProjToScreen(input.ShadowScreenPosition)
+ halfPixel();
float mapDepth = sampleShadowMap(shadowTexCoord);
Nếu chúng ta nhận giá trị trả về giá trị 1 nghiã là sẽ tạo bóng đổ cho điểm xét trên bề mặt vật thể
return float4(mapDepth, mapDepth, mapDepth, 1);
Trước khi sử dụng hàm này để lấy giá trị trả về để sinh ra bóng đổ, ta cần chắc chắn rằng ta đã thiết lập các tham số ngưỡng để xác định độ sâu bề mặt vật
prepareMainPass() function of PrelightingRenderer:
if (part.Effect.Parameters["DoShadowMapping"] != null) part.Effect.Parameters["DoShadowMapping"].SetValue(DoShadowMappi ng);
if (!DoShadowMapping) continue;
if (part.Effect.Parameters["ShadowMap"] != null) part.Effect.Parameters["ShadowMap"].SetValue(shadowDepthTarg); if (part.Effect.Parameters["ShadowView"] != null) part.Effect.Parameters["ShadowView"].SetValue(shadowView);
if (part.Effect.Parameters["ShadowProjection"] != null) part.Effect.Parameters["ShadowProjection"].
SetValue(shadowProjection);
Bóng đổ mờ
Khi tạo bóng như thuật toán trên, bóng tạo ra rất chuẩn nhưng đôi khi chưa phản ánh đúng thực tế của thể giới thực mà thực tế có sự giao thoa ánh sáng, nhiễu nên bóng thường có độ nhòe thậm chí hai bóng riêng biệt khi có hai nguồn sáng chói phân biệt. Tác dụng của xử lý mờ bóng (soft shadow), khi biểu diễn các vật thể trên bề mặt có nền phức tạp đảm bảo biểu diễn chính xác
Hình 2.15 Bóng đổ mờ
Như vậy, bề mặt vật có hai giá trị, giá trị bao phủ bề mặt bằng một vật liệu nào đó, và giá trị bóng. Quá trình làm mờ là tính toán giá trị trung bình các pixel và các điểm láng giếng. Hàm Gausian được sử dụng để tính toán như sau:
// The texture to blur texture ScreenTexture;
sampler2D tex = sampler_state {
texture = ; minfilter = point; magfilter = point; mipfilter = point;
};
// Precalculated weights and offsets
float weights[15] = { 0.1061154, 0.1028506, 0.1028506, 0.09364651,
0.09364651, 0.0801001, 0.0801001, 0.06436224, 0.06436224,
0.04858317, 0.04858317, 0.03445063, 0.03445063, 0.02294906,
0.02294906 };
float offsets[15] = { 0, 0.00125, -0.00125, 0.002916667, -0.002916667,
0.004583334, -0.004583334, 0.00625, -0.00625, 0.007916667, -
0.007916667, 0.009583334, -0.009583334, 0.01125, -0.01125 };
// Blurs the input image horizontally float4 BlurHorizontal(float4 Position : POSITION0, float2 UV : TEXCOORD0) : COLOR0 {
float4 output = float4(0, 0, 0, 1);
// Sample from the surrounding pixels using the precalculated
// pixel offsets and color weights for (int i = 0; i < 15; i++) output += tex2D(tex, UV + float2(offsets[i], 0)) * weights[i]; return output; } // Blurs the input image vertically float4 BlurVertical(float4 Position : POSITION0, float2 UV : TEXCOORD0) : COLOR0 { float4 output = float4(0, 0, 0, 1); for (int i = 0; i < 15; i++) output += tex2D(tex, UV + float2(0, offsets[i])) * weights[i]; return output; }
technique Technique1
{
pass Horizontal
{
PixelShader = compile ps_2_0 BlurHorizontal();
}
pass Vertical
{
PixelShader = compile ps_2_0 BlurVertical();
}
}