Bài đăng phổ biến

Thứ Hai, 22 tháng 10, 2012

OpenGL ES 2.x – (Phần 2/3)


  • TỔNG QUAN
Như trong phần một chúng ta đã nghiên cứu qua 3 phần chính

  • Logic của Opengl chỉ chứa bởi 3 khái niệm cơ bản: Primitives, Buffer, và Rasterize
  • Opengl làm việc với Fixed và programable pipeline
  • Programable pipeline thì đồng nghĩa với Shaders: Vertex Shader, fragment Shader
Ở đây tôi hiển thị đoạn mã bởi C hoặc Objective - C. Ở một số phần sau tôi sẽ nói về iPhone và IOS. Nhưng nói chung đoạn mã sẽ chung cho tất cả các ngôn ngữ. NHư Opengles là chính xác nhất về các API của OPENGL. Tôi sẽ tập chung trên Opengles.

Đoạn mã trong bài này chỉ minh chứng cho các hàm hoặc khái niệm, không phải code thực sự. Trong link cuối bài bạn sẽ có 1 Project của Android và của Iphone để minh họa tìm hiểu thêm, sử dụng ngôn ngữ C++, Objective - C, Java for android kết hợp với Opengles 2.0. Ngay cả những ai mới tìm hiểu tôi hy vọng cũng sẽ hiểu được chương trình.

Trước tiên đi tìm hiểu có điều quan trọng tôi nói đến là để tránh xung đột giữa các ngôn ngữ. Opengl đưa ra cách xử lý riêng cho các câu lệnh với tiền tố đầu tiên là "GL" như GLfloat, GLint, dưới đây là đầy đủ các kiểu dữ liệu của opengles.
OPENGL’S DATA TYPESAME AS CDESCRIPTION
GLboolean (1 bits)unsigned char0 to 1
GLbyte (8 bits)char-128 to 127
GLubyte (8 bits)unsigned char0 to 255
GLchar (8 bits)char-128 to 127
GLshort (16 bits)short-32,768 to 32,767
GLushort (16 bits)unsigned short0 to 65,353
GLint (32 bits)int-2,147,483,648 to 2,147,483,647
GLuint (32 bits)unsigned int0 to 4,294,967,295
GLfixed (32 bits)int-2,147,483,648 to 2,147,483,647
GLsizei (32 bits)int-2,147,483,648 to 2,147,483,647
GLenum (32 bits)unsigned int0 to 4,294,967,295
GLdouble (64 bits)double−9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
GLbitfield (32 bits)unsigned int0 to 4,294,967,295
GLfloat (32 bits)float-2,147,483,648 to 2,147,483,647
GLclampx (32 bits)intInteger clamped to the range 0 to 1
GLclampf (32 bits)floatFloating-point clamped to the range 0 to 1
GLclampd (64 bits)doubleDouble clamped to the range 0 to 1
GLintptrintpointer *
GLsizeiptrintpointer *
GLvoidvoidCan represent any data type

Một điều rất quan trọng về kiểu dữ liệu của opengl là Opengl ES không hỗ trợ kiểu dữ liệu 64 bits. Vì là hệ thống nhúng nên ta cần xử lý tốc độ hiệu suất và một số thiết bị cũng không hỗ trợ xử lý 64 bits. Bằng cách sử dụng dữ liệu của Opengl bạn có thể an toàn chuyển đổi ứng dụng của bàn từ C++ tới JavaScript....với thay đổi là ít nhất.

Một điều cuối cùng để giới thiệu là Graphics pipeline. Chúng ta sẽ sử dụng và nói về Programable pipeline rất nhiều. Đây là hình ảnh minh họa trực quan:


                                                       The OpenGL programmable pipeline.                                                       



  • TEXTURE

Texture là 1 chủ đề lớn trong Opengl. Chúng ta hãy xem texture ở đây, phần nâng cao sẽ chuyển sang phần 3 hoặc một bài viết riêng. Điều đầu tiên tôi cần để nói cho bạn biết về sức mạnh của Two (POT). OpengGL ONLY accept POT Textures. Điều đó có nghĩa là tất cả các texture phải có cả 2 chiều rộng và chiều cao một sức mạnh của 2 giá trị này: Giống như  2, 4, 8, 16, 32, 64, 128, 256, 512 or 1024 pixels. Để 2 texture 1024 là kích thước rất lớn,  và thường cho biết kích thước tối đa có thể có của một texture. Vì vậy tất cả các texture sử dụng trong Opengl phải có kích thước là 64 x 128 or 256 x 32 or 512 x 512 VD: Bạn không thể sử dụng  200 x 200 or 256 x 100. Đây là một quy tắt để tối ưu hóa việc xử lý Opengl nội bộ trong GPU.

Một điều quan trọng khác cần biết về textures trong Opengl là đọc thứ tự Pixel.  Thông thường hình ảnh định dạng tập tin lưu trữ các thông tin điểm ảnh bắt đầu từ góc trên bên trái và di chuyển thông qua từng dòng, từng dòng rồi tới góc dưới bên phải. Tập tin định dạng như JPG, PNG, BMP, GIF, TIFF và những người khác sử dụng thứ tự Pixel này. Nhưng trong Opengl thứ tự này lại bị lộn ngược lại. Texture trong Opengl đọc pixels bắt đầu từ góc dưới bên trái và đi dần lên góc phải bên trên. 


                                     Image data must be flipped vertically to right fit into OpenGL.

Bây giờ đoạn ngắn về logic của Textures. Texture trong Opengl làm việc theo cách này, Bạn có 1 file ảnh, vì vậy bạn phải trích xuất các thông tin màu nhị phân (binary) từ nó, giá trị thập lục phân. Bạn cũng có thể trích xuất thông tin alpha. Opengl hỗ trợ định dạng RGB, GRBA. Trong trường hợp này, bạn sẽ cần phải trích xuất các giá trị thập lục phân + alpha từ hình ảnh của bạn. Lưu trữ tất cả mọi thứ vào một mảng của các Pixels.
Với mảng này của điểm ảnh (còn gọi là texels, vì sẽ được sử dụng trong một Texture), bạn có thể xây dựng đối tượng texture của OpenGL. OpenGL sẽ sao chép mảng của bạn và lưu trữ nó trong một định dạng tối ưu hóa để sử dụng trong các GPU và FrameBuffer, nếu cần thiết.

Bây giờ là phần phức tạp, một số người đã chỉ trích OpenGL rất nhiều bởi cách tiếp cận này. Cá nhân tôi nghĩ rằng điều này có thể là tốt hơn, nhưng là những gì chúng ta có ngày hôm nay. OpenGL có một cái gì đó được gọi là "Texture Units", theo mặc định bất kỳ việc thực hiện OpenGL bởi nhà cung cấp phải hỗ trợ lên đến 32 Texture Units. Những đơn vị này miêu tả một liên kết tạm thời giữa các mảng lưu trữ của các điểm ảnh (Pixels) và  thực tế xử lý việc dựng hình. Bạn sẽ sử dụng các Texture Units bên trong shaders, cụ thể hơn bên trong fragment Shader. Theo mặc định, mỗi shader có thể sử dụng lên đến 8 Textures, một số nhà cung cấp hỗ trợ lên đến 16 Texture mỗi shader. Hơn nữa, OpenGL có một giới hạn cặp Shaders, mặc dù mỗi shader có thể sử dụng lên đến 8 đơn vị kết cấu, các cặp shader (đỉnh và đoạn) được giới hạn sử dụng lên đến 8 Texture Units với nhau. Nhầm lẫn? Hãy nhìn xem, nếu bạn đang sử dụng các Texture Units trong một Shader, bạn có thể sử dụng lên đến 8. Tuy nhiên, nếu bạn đang sử dụng các đơn vị kết cấu trong cả hai Shader (Texture Units khác nhau), bạn không thể sử dụng nhiều hơn 8 đơn vị Texture kết hợp cả 2.

Opengl có thể dữ tối đa lên đến 32 texture Units. Mà chúng ta sẽ sử dụng bên trong shader, nhưng shader của chúng ta chỉ hỗ trơ tối đa 8 texture units. Điều này không có ý nghĩa đúng không?? Vâng điểm mà bạn có thể sử dụng tối đa lên tới 32 Texture Units và sử dụng nó trong suốt nhiều shader, Nhưng nếu bạn cần 1 texture Units thứ 33 bạn phải cần sử dụng lại 1 slot từ 32 cái đầu tiên.

Thực sự rất khó hiểu đúng không??
Hãy xem ảnh sau:
              Bạn có thể định nghĩa >32 texture units, nhưng chỉ 8 texture units trên mỗi cặp Shader.

Như bạn đã nhìn thấy trong hình ảnh bên trên. Một texture Unit có thể được sử dụng rất nhiều lần bởi nhiều cặp Shaders. Cách tiếp cận này thì thực sự bối rối, Nhưng hãy hiểu nó bằng con mắt Khronos, "Shader thực sự tuyệt vời". Một nhà phát triển Khronos nói với người khác "Chúng được xử lý rất nhanh bởi GPU. Đúng tuy nhiên đối với Textures .....hmmm. Dữ liệu textures vẫn ở trên GPU, chúng rất lớn và nặng vì vậy chúng ta cần 1 cách nhanh hơn để cho Shader truy cập và tới Textures.  giống như một cây cầu, hoặc một cái gì đó tạm thời. Hmmm .....Chúng ta có thể tạo ra 1 đơn vị của Textures và có thể được xử lý trực tiếp trên GPU. Một bộ nhớ cache trong GPU, Nó rất nhanh, và tốt hơn thế, Để làm điều này người xử dụng phải rằng buộc 1 dữ liệu texture tới 1 texture Unit và hướng dẫn Shader của mình sử dụng đơn vị đó. Rất đơn giản đúng không. Hãy thực hiện theo cách tiếp cận này.

Bình thường Texture Unit được sử dụng trong fragment Shader. Nhưng vertex Shader cũng có thể tìm kiếm vào trong 1 texture. Điều này không phổ biến nhưng nó có ích trong một số TH.

Hai điều rất quan trọng cần nhớ là: Đầu tiên bạn phải Active the Texture Unit bằng sử dụng lệnh glActiveTexture(). Và sau đó Bind tên texture/ id Sử dụng glBindTexture().
ĐIều quan trọng thứ 2 là ngay cả khi mặc định Opengles cũng hỗ trợ lên tới 32 Texture Unit. Bạn không thể sử dụng một số slot cao hơn so với texture unit trong cài đặt của nhà cung cấp của bạn. Vì vậy nếu Opengl cài đặt không hỗ trợ quá 16 texture Unit. Bạn chỉ có thể sử dụng Texture Units trong khoảng 0->15.

Và sau đây là mã:

TEXTURE CREATION
GLvoid glGenTextures(GLsizei n, GLuint* textures)

  • n: The number representing how many textures’ names/ids will be generated at once.
  • textures: A pointer to a variable to store the generated names/ids. If more than one name/id was generated, this pointer will point to the start of an array.
GLvoid glBindTexture(GLenum target, GLuint texture)

  • target: The target will define what kind of texture will be, a 2D texture or a 3D texture. The values can be:
    • GL_TEXTURE_2D: This will set a 2D texture.
    • GL_TEXTURE_CUBE_MAP: This will set a 3D texture.
  • texture: The name/id of the texture to be bound.

Kỳ lạ nhất "3D texture"? Lần đầu tiên tôi nghe "texture 3D" Tôi nghĩ: "WTF!". Vâng, bởi vì của sự khó hiểu này, OpenGL gọi một texture 3D của một Cube map.Nghe như tốt hơn! Dù sao, chỉ là mô tả cho một khối lập phương với Texture 2D trong từng  mặt, do đó, các Texture 3D hoặc Cube map mô tả cho một bộ sưu tập của 6 TExture 2D. Và làm thế nào chúng ta có thể lấy texels các Với một vector 3D được đặt ở trung tâm của khối lập phương. Chủ đề này cần được quan tâm nhiều hơn nữa, vì vậy tôi sẽ bỏ qua các kết cấu 3D ở đây và sẽ cho phép thảo luận này để phần thứ ba của hướng dẫn này. Hãy tập trung vào texture 2D. Sử dụng chỉ GL_TEXTURE_2D.

Vì vậy, sau khi chúng tôi đã tạo ra một Texture 2D chúng ta cần phải thiết lập các thuộc tính của nó. Nhóm Khronos gọi cốt lõi của OpenGL là "Server", do đó, khi chúng ta định nghĩa một dữ liệu texture  họ nói đây là một "upload". Để upload các dữ liệu texture và thiết lập một số thuộc tính, chúng ta sử dụng:

TEXTURE PROPERTIES
GLvoid glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)

  • target: To a 2D texture this always will be GL_TEXTURE_2D.
  • level: This parameter represents the mip map level. The base level is 0, for now let’s use only 0.
  • internalformat: This represents the color format of the pixels. This parameter can be:
    • GL_RGBA: For RGB + Alpha.
    • GL_RGB: For RGB only.
    • GL_LUMINANCE_ALPHA: For Red + Alpha only. In this case the red channel will represent the luminosity.
    • GL_LUMINANCE: For Red only. In this case the red channel will represent the luminosity.
    • GL_ALPHA: For Alpha only.
  • width: The width of the image in pixels.
  • height: The height of the image in pixels.
  • border: This parameter is ignored in OpenGL ES. Always use the value 0. This is just an internal constant to conserve the compatibly with the desktop versions.
  • format: The format must to have the same value of internalformat. Again, this is just an internal OpenGL convention.
  • type: This represent the data format of the pixels. This parameter can be:
    • GL_UNSIGNED_BYTE: This format represent 4 Bytes per pixel, so you can use 8 bits for red, 8 bits for green, 8 bits for blue and 8 bits for alpha channels, for example. This definition is used with all color formats.
    • GL_UNSIGNED_SHORT_4_4_4_4: This format represents 2 bytes per pixel, so you can use 4 bits for red, 4 bits for green, 4 bits for blue and 4 bits for alpha channels, for example. This definition is used with RGBA only.
    • GL_UNSIGNED_SHORT_5_5_5_1: This format represents 2 bytes per pixel, so you can use 5 bits for red, 5 bits for green, 5 bits for blue and 1 bit for alpha channels, for example. This definition is used with RGBA only.
    • GL_UNSIGNED_SHORT_5_6_5: This format represents 2 bytes per pixel, so you can use 5 bits for red, 6 bits for green and 5 bits for blue, for example. This definition is used with RGB only.
  • pixels: The pointer to your array of pixels.
Rất nhiều tham số nhưng khoog phải là khó hiểu đúng không? Trước hết, cùng một hành vi của những thứ khác "Hooks", một lời gọi đến glTexImage2D sẽ thiết lập các thuộc tính cho các texture cuối cùng được ràng buộc.



TO BE CONTINUE..................................









































Không có nhận xét nào:

Đăng nhận xét