7/23/16

Lâp trình OpenGLES - Phần 6

Phần trước mình đã hướng dẩn các bạn cách load nhân vật từ file .nfg(định dạng .got chúng ta sẽ tìm hiểu sau) nhưng nhân vật load lên còn chưa có "da", trông trắng bệch còn hơn bạch tạng. Bài này và bài tiếp theo sẽ hướng dẩn cách "đắp da" cho nhân vật.
Mình cũng xin nói luôn, loạt bài viết này sẽ không phù hợp với những bạn thiếu kiên nhẫn. Có thể đến phần 10, 11, 12 hoặc xa hơn nữa mà bạn vẩn chưa thấy "game" đâu cả. Vì đây không phải là fast food đây là chicken stew. Bạn có thể chọn đồ ăn nhanh nếu bạn không có thời gian như Unity hay Cocos2d. Còn loạt bài viết này là món gà hầm bổ dưỡng nhưng bạn thật sự phải xăng tay áo lên và vào bếp đấy, sẽ tốn chút nhiều thời gian nhưng cũng đáng để đầu tư lắm :)).
Hơi bị dài dòng rồi, let's go!

Texture Là gì?

Texture đơn giản là một ảnh 2D được "đắp" lên một vật thể 3D.

Kích thước của texture

Texture nên có kích thước(chiều rộng và chiều cao) là một giá trị POT(power of two), nghĩa là nó nên có giá trị 1, 2, 4, 8, 16, 32...Một số card màng hình đời mới với với phiên bản OpenGL ES 2.0 trở lên hổ trợ các loại texture có kích thước bất kỳ. Vì lý do tương thích và hiệu năng ta nên sử dụng kích thước POT.

Tọa độ và texel

Texture coordinate(textcoord) hay UV là một thuộc tính mô tả vị trí của vertex trên ảnh. Một pixel trên texture gọi là texel.
Texture bên trên cho ta biết một số thông tin như sau:

  • Điểm T trong hình chính là texel.
  • Tọa độ điểm T được xác định bằng 2 giá trị u và v.
  • Giá trị UV nằm trong khoản [0..1].
Theo quy ước thì tọa độ (0, 0) chính là góc trái trên cùng và tọa độ (1, 1) sẽ là góc phải dưới cùng. 

Wrapping

Quá trình xử lý sử dụng các tọa độ của texture để lấy về thông tin màu sắt được gọi là quá trình lấy mẫu(sampling). OpenGL cung cấp khá nhiều tùy chọn để điều khiển quá trình lấy mẫu, một số tùy chỉnh thông dụng sẽ được mô tả bên dưới.
Khi giá trị UV vược ra ngoài khoản [0..1], lúc này bạn có 4 lựa chọn để điều khiển quá trình lấy mẫu này.
  • GL_REPEAT: Texture sẽ được lặp đi lặp lại.
  • GL_MIRROED_REPEAT: Texture cũng sẽ được lặp đi lặp lại nhưng các hình ảnh được "lát" theo kiểu phản chiếu.
  • GL_CLAMP_TO_EDGE: Tọa độ sẽ bị "kẹp" giữa 0 và 1.
  • GL_CLAMP_TO_BORDER: Tọa độ bên ngoài khoản [0..1] sẽ được vẽ bằng một màu đã được định nghĩa.
Đây là ví dụ về việc sử dụng các tùy chỉnh này.
Một ví dụ khác.
Để thay đổi tùy chỉnh trên cho quá trình sampling, bạn sử dụng hàm glTexParameter*. Ví dụ như sau:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
Trong đó i xác định loại giá trị bạn muốn định nghĩa. Nếu bạn sử dụng GL_CLAMP_BORDER và bạn muốn thay đổi màu của border bên ngoài, lúc này bạn cần thay đổi giá trị GL_TEXTURE_BORDER_COLOR và truyền một màu RGBA như sau:
float color[] = { 1.0f, 0.0f, 0.0f, 1.0f };// set border color to red
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);

Filtering

Khi ảnh của một texture bị co giản quá lớn hoặc quá nhỏ vược quá kích thước gốc của nó. Giống như khi bạn tải một tẩm ảnh 240x320 từ internet và đặt nó làm hình nền cho máy tính ở chế độ stretch. Lúc này ảnh sẽ cần phải được kéo giản ra để vừa với kích thước màng hình desktop. Dĩ nhiên ảnh sẽ bị mờ đi, như khi bạn phóng to quá cỡ một bức ảnh vậy. Khi đắp texture lên bề mặt vật thể trong OpenGL cũng sẽ gặp trường hợp tương tự. OpenGL cung cấp cho bạn bộ lọc(filter) và một số hàm kèm theo để giải quyết vấn đề này khi phóng to hoặc thu nhỏ ảnh.
Ở đây bạn có thể tùy chỉnh cho 2 trường hợp hình ảnh bị phóng to(hơn kích thước gốc) gọi là Magnification và trường hợp ảnh bị thu nhỏ(hơn kích thước gốc) gọi là Minification. Magnification và Minification có thể nhận các tùy chỉnh như sau:
  • GL_NEAREST: Lấy màu của pixel gần nhất trên ảnh của texture.
  • GL_LINEAR: Nó sẽ lấy 4 pixels liền kề xung quanh tọa độ UV và tính toán giá trị trung bình để cho ra màu sắt.
  • GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR: Sử dụng cho mipmap, ta sẽ tìm hiểu sau.
Dưới đây là ví dụ về sự khác biệt giữa 2 tùy chọn GL_NEAREST và GL_LINEAR khi phóng to(zoom in) từ ảnh gốc.
Tùy chỉnh GL_NEAREST sẽ cho hình sắt nét hơn nhưng lại bị vỡ hình và xuất hiện răng cưa. Với tùy chọn GL_LINEAR thì ngược lại, hình ảnh trông mịn và không bị vỡ nhưng lại mờ và không sắt nét.

Để thiết đặt cũng như thay đổi các tùy chỉnh này bạn sử dụng đoạn code bên dưới.
// apply GL_LINEAR for both
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

Mipmap

Đây là những bản copy nhỏ hơn của texture, nó được tính toán trước và tối ưu cho một tập(collection) các ảnh của texture chính. Thay vì bạn sử dụng 1 texture như trước thì bây giờ bạn sử dụng nhiều "textures" giống nhau nhưng khác kích thước.

Lợi ích:
  • Nâng cao tốc độ vẽ(render),
  • Chất lượng hình ảnh cao hơn.
  • Giảm tải quá trình tính toán(phép nội suy).
Mặt hại của nó là ta cần sử dụng nhiều ảnh hơn thay vì một ảnh như trước, do đó ta sẽ tốn nhiều bộ nhớ hơn bình thường.
Để sử dụng mipmap bạn cần chọn một trong bốn bộ lọc mipmap bên dưới, chú ý rằng ở đây chỉ khác với cách thông thường ở chổ là bạn cần lựa chọn mipmip rồi sau đó áp dụng 2 bộ lọc đã đề cập ở trên.
  • GL_NEAREST_MIPMAP_NEAREST: Lấy màu của pixel gần nhất trên mipmap gần nhất.
  • GL_LINEAR_MIPMAP_NEAREST: Chọn mipmap gần nhất và sử dụng bộ lọc GL_LINEAR trên mipmap đó.
  • GL_NEAREST_MIPMAP_LINEAR: Chọn 2 mipmap gần nhất sau đó tính giá trị trung bình.
  • GL_LINEAR_MIPMAP_LINEAR: Lấy mẫu 2 mipmap gần nhất bằng phép nội suy tuyến tính.
Như thế là bạn đã tìm hiểu sơ lượt một số khái niệm về texture cũng như cách giải quyết các vấn đề khi zoom in/out hình ảnh bằng việc sử dụng các bộ lọc. Phần kế tiếp mình sẽ hướng dẩn cách sử dụng texture(coding). Từng bước một chúng ta đang tiến gần đến việc xây dựng một thế giới 3D mà không cần sử dụng bất kỳ một engine của bên thứ 3. Chỉ sử dụng các "viên gạch" từ thư viện OpenGL chúng ta đang xây dựng nên môt engine "make by me" và dựa vào đó xây dựng nên mọi thứ ta cần.

Source code cho phần này tại đây: https://github.com/sontx/opengles/tree/day6

References

https://open.gl/textures

0 nhận xét :

Post a Comment