Trang chủ > Phát triển di động > Nội dung chính

OpenGL ES và biến đổi tọa độ (hai)


Phân tích cấu trúc dữ liệu bên trong Redis OpenGL ES và biến đổi tọa độ Phần thứ hai trong loạt bài viết này. Trong bài viết nàybầu cua, chúng ta sẽ tập trung thảo luận về các nội dung sau:

  1. Đầu tiênbầu cua, chúng ta hãy lấy ví dụ từ mã nguồn của một ứng dụng Demo để giải thích cách thức mà model, view và projection được biểu diễn bằng code trong môi trườ Ba phép biến đổi này đóng vai trò quan trọng trong việc định hình không gian đồ họa và giúp chúng ta kiểm soát cách các đối tượng được hiển thị trên màn hình. Thông qua mã nguồn, chúng ta có thể thấy rõ cách từng phép biến đổi ảnh hưởng đến kết quả cuối cùng mà người dùng nhìn thấy.
  2. Trong phần giới thiệu lý thuyết này789 Club, chúng ta sẽ cùng tìm hiểu cách diễn giải chi tiết hai phép biến đổi quan trọng trong quá trình chuyển đổi mô hình: đó là phép thu nhỏ (scaling) và phép dịch chuyển (translation). Hai phép biến đổi này thường được sử dụng để điều chỉnh kích thước và vị trí của đối tượng trong không gian. Tuy nhiên, việc xử lý phép xoay (rotation) lại phức tạp hơn nhiều, do đó chúng ta sẽ dành thời gian thảo luận về chủ đề này trong bài viết tiếp theo. Đầu tiên, hãy bắt đầu với phép thu nhỏ. Khi thực hiện phép thu nhỏ, chúng ta thay đổi kích thước của đối tượng bằng cách nhân tọa độ của nó với một hệ số nhất định. Giả sử chúng ta có một điểm P(x, y) và muốn thu nhỏ nó với hệ số k trên cả trục x và y. Quá trình tính toán đơn giản như sau: - Đối với trục x: \(x' = x \cdot k\) - Đối với trục y: \(y' = y \cdot k\) Kết quả cuối cùng là điểm P'(x', y') sau khi đã được thu nhỏ. Tiếp theo là phép dịch chuyển. Trong trường hợp này, thay vì thay đổi kích thước, chúng ta chỉ cần di chuyển đối tượng đến một vị trí mới trong không gian. Để làm điều này, chúng ta thêm hoặc trừ một giá trị cố định vào tọa độ x và y ban đầu của điểm. Giả sử điểm P(x, y) cần được dịch chuyển bằng vectơ dịch chuyển (dx, dy), công thức tính toán sẽ là: - \(x' = x + dx\) - \(y' = y + dy\) Với kết quả cuối cùng là điểm P'(x', y') sau khi đã được dịch chuyển. Hai phép biến đổi này tuy đơn giản nhưng rất hữu ích trong việc kiểm soát và điều chỉnh hình học của các đối tượng. Tuy nhiên, như đã đề cập trước đó, phép xoay đòi hỏi sự phân tích sâu hơn, do đó chúng ta sẽ tiếp tục bàn luận về nó ở phần sau.
  3. Chúng ta hãy cùng phân tích cụ thể cách thức thực hiện các phép biến đổi thu phóng (scaling) và dịch chuyển (translation) trong Androidbầu cua, đồng thời đối chiếu lý thuyết đã được suy diễn trước đó với việc triển khai mã nguồn để làm rõ hơn về chủ đề này. Điều này sẽ giúp chúng ta hiểu sâu hơn về cơ chế hoạt động bên trong và nắm vững các khái niệm cơ bản.

Khi một công trình hoàn thành789 Club, cần phải dọn sạch tất cả khung giá đỡ.

Bài viết này nhằm làm cho cuộc thảo luận về chi tiết trở nên rõ ràng hơn789 Club, chắc chắn sẽ không đi theo phong cách của Gauss. Thay vào đó, trong phần tiếp theo của bài viết, chúng tôi sẽ cố gắng trình bày từng bước suy luận một cách chi tiết nhất và nỗ lực hết sức để giải thích rõ ràng tư duy đằng sau quá trình suy diễn này.

Giới thiệu chương trình demo

Bài trước Địa chỉ của chương trình Demo đã được cung cấp trước đóbacarat, nhưng để đảm bảo rõ ràng, xin vui lòng tìm thấy địa chỉ dưới đây một lần nữa. Tất cả mã nguồn được đề cập trong bài viết này đều đến từ tệp tin được liệt kê bên dưới:

Đầu tiênbầu cua, trong vertex shader liên quan đến biến đổi tọa độ là dòng mã này:

								
									
										gl_Position
									 =
									 projection
									 *
									 view
									 *
									 model
									 *
									 vec4
									(
									position
									.
									xyz
									,
									 1
									);
									

								

Nó cho thấy rằng789 Club, để xử lý một tọa độ đỉnh, bạn cần áp dụng tuần tự ba loại biến đổi: model (mô hình), view (xem) và projection (dự án). Mỗi loại biến đổi này đều được thực hiện bằng cách nhân trái (left-multiply) với một ma trận tương ứng. Trong dòng mã trên, có vẻ thứ tự của các phép biến đổi không giống như mong đợi, nhưng điều đó là do đặc tính của việc nhân trái ma trận gây ra. Khi nhân trái, thứ tự thực sự đóng vai trò quan trọng, và thứ tự ngược lại trong đoạn mã chính xác phản ánh cách hoạt động của phép toán ma trận.

Đoạn mã bên trong vec4(position.xyzbacarat, 1)Bạn có thể biểu diễn tọa độ của đỉnh trong hệ tọa độ cục bộ (sử dụng một tọa độ đồng nhất bốn chiềubầu cua, chúng ta sẽ đề cập đến điều này sau). Khi nhân tọa độ của đỉnh đó với ma trận model từ bên trái, bạn sẽ thu được tọa độ của đỉnh trong hệ tọa độ thế giới. Bài trước Chúng ta đã biết rằngbacarat, quá trình biến đổi của model có thể bao gồm ba loại thay đổi chính: thu nhỏ (scaling), xoay (rotation) và dịch chuyển (translation). Sau khi tọa độ trong hệ tọa độ thế giới được nhân trái với ma trận view, nó sẽ được chuyển đổi sang hệ tọa độ của máy ảnh. Cuối cùng, khi nhân trái thêm một lần với ma trận projection, quá trình biến đổi chiếu (projection transformation) sẽ được hoàn tất. Trong thực tế, việc kết hợp các phép toán này không chỉ đơn giản là để định hình lại không gian mà còn giúp tạo ra những hiệu ứng trực quan sinh động, cho phép người dùng cảm nhận rõ hơn về khung cảnh 3D mà chúng ta đang xây dựng. Mỗi loại biến đổi đều đóng vai trò quan trọng, từ việc điều chỉnh kích thước của đối tượng đến việc thay đổi góc nhìn hoặc vị trí của nó trong không gian. Tất cả những yếu tố này kết hợp lại tạo nên một bức tranh tổng thể hoàn hảo trong lĩnh vực đồ họa máy tính.

Vậy thì trong đoạn mã nàybacarat, ma trận model, view và projection, chúng có giá trị là gì? Hãy cùng xem trong chương trình Demo, các giá trị của chúng được tính toán như thế nào. Lấy ví dụ về hình lập phương thứ hai, mã để tính toán ma trận model như sau:

								
									
										Matrix
									.
									setIdentityM
									(
									modelMatrix2
									,
									 0
									);
									
Matrix
									.
									translateM
									(
									modelMatrix2
									,
									 0
									,
									 0.5f
									,
									 1.0f
									,
									 -
									1.5f
									);
									
Matrix
									.
									rotateM
									(
									modelMatrix2
									,
									 0
									,
									 angle
									,
									 0.0f
									,
									 1.0f
									,
									 0.0f
									);
									
Matrix
									.
									scaleM
									(
									modelMatrix2
									,
									 0
									,
									 1.5f
									,
									 1.5f
									,
									 1.5f
									);
									

								

Đoạn mã này modelMatrix2 Bạn cần tính toán ma trận modelbacarat, một ma trận 4x4 được lưu trữ trong một mảng float có độ dài 16. Ma trận này đóng vai trò quan trọng trong việc xác định vị trí, hướng và các thông số liên quan đến đối tượng trong không gian 3D. Ngoài ra, nó cũng thường được sử dụng để thực hiện các phép biến đổi như xoay, dịch chuyển hay thu nhỏ đối tượng theo ý muốn. float[16] Tại sao không phải là ma trận 3x3 nhỉ? Điều này liên quan đến tọa độ thuần nhấtbacarat, nhưng chúng ta sẽ đề cập đến điều đó sau. Hiện tại, hãy cùng tìm hiểu về việc chúng ta đã sử dụng SDK của Android để... Matrix Phương pháp của lớp công cụ đã gán giá trị cho nó. setIdentityM Thể hiện việc thiết lập ma trận đơn vị ban đầu789 Club, và translateM , rotateM Một quá trình đọc: Quá trình thứ scaleM Bạn có thể bắt đầu từ ma trận đơn vị ban đầu và lần lượt điều chỉnh ma trận theo các bước khác nhau789 Club, cụ thể là dịch chuyển, xoay, và thay đổi kích thước. Tuy nhiên, cần lưu ý rằng thứ tự gọi hàm trong đoạn mã này là dịch chuyển trước, sau đó xoay, cuối cùng mới thay đổi kích thước. Nhưng về mặt ý nghĩa, thứ tự này lại cần được hiểu ngược lại: tức là trước tiên đã thực hiện thay đổi kích thước, tiếp đến là xoay, và cuối cùng mới tiến hành dịch chuyển. Lý do cho sự khác biệt này liên quan đến ý nghĩa của phép nhân trái (left multiplication) trong ma trận, và chúng ta sẽ giải thích kỹ hơn về vấn đề này ở phần cuối bài viết. Hiện tại, hãy ghi nhớ thứ tự giải thích trên, thì đoạn mã trên chính xác có nghĩa là:

  1. Thu nhỏ : Trước hết789 Club, phóng to 1,5 lần trên ba trục tọa độ x, y, z;
  2. Quay : Sau đó xoay quanh vectơ [0.0bacarat, 1.0, 0.0] T (tức là trục y) với góc độ angle
  3. Dịch chuyển Bạn có thể di chuyển 0bacarat,5 đơn vị theo hướng dương của trục x, tiếp đó dịch chuyển 1,0 đơn vị theo hướng dương của trục y và cuối cùng di chuyển 1,5 đơn vị theo hướng âm của trục z.

Nếu bạn đã chạy chương trình demo và quan sát kỹ theo những gì được mô tả ở trênbầu cua, bạn sẽ nhận ra rằng hình lập phương này chính là khối lập phương lớn nhất nằm ở phần trên cùng của màn hình. Nó đang xoay liên tục quanh một trục nhất định. Nguyên nhân khiến nó xoay là do bước thứ hai mà chúng ta đã thiết lập trước đó – cụ thể là góc quay đã được cấu hình trong bước đó. Chính điều này đã tạo nên chuyển động xoay không ngừng cho khối lập phương, mang lại cảm giác sống động và thú vị cho người xem. angle Là một giá trị độngbacarat, giá trị của nó thay đổi mỗi khung hình, do đó trông như đang xoay không ngừng.

Ảnh chụp màn hình đầu ra của chương trình ví dụ

Lúc nàybacarat, có lẽ một số bạn sẽ không khỏi thắc mắc: Trong mô tả trên, trục y có phải là hướng lên trên màn hình hay không? Còn trục z có phải là vuông góc với màn hình hay không? Thực tế thì không hẳn vậy. Khi nói về tọa độ và các trục tọa độ, điều đầu tiên chúng ta cần làm rõ chính là hệ tọa độ mà chúng ta đang đề cập đến là hệ nào. Trong quá trình tính toán, chúng ta thường xuyên chuyển đổi giữa các hệ tọa độ khác nhau. Tùy thuộc vào... Bài trước Trong phần giới thiệu nàybacarat, chúng ta đang nói về việc chuyển đổi model từ hệ tọa độ cục bộ sang hệ tọa độ thế giới. Vì vậy, các trục x, y, z ở đây thực sự đại diện cho hệ tọa độ thế giới. Tuy nhiên, vị trí và góc của hệ tọa độ thế giới so với màn hình không liên quan trực tiếp đến nhau. Điều này phụ thuộc vào bước biến đổi view tiếp theo (từ góc nhìn nào để quan sát). Cụ thể hơn, hệ tọa độ thế giới là một khung tham chiếu cố định, trong khi cách chúng ta nhìn nhận nó trên màn hình sẽ thay đổi dựa trên cách mà camera hoặc người quan sát được định vị trong không gian.

Tiếp theobacarat, chúng ta hãy xem xét cách tính ma trận view trong chương trình demo.

								
									
										Matrix
									.
									setLookAtM
									(
									viewMatrix
									,
									 0
									,
									 3.0f
									,
									 3.0f
									,
									 10.0f
									,
									 0.0f
									,
									 0.0f
									,
									 0.0f
									,
									 0.0f
									,
									 1.0f
									,
									 0.0f
									);
									

								

Dòng mã này viewMatrix Là ma trận view cần tính toánbacarat, nó cũng là một ma trận 4x4. Chúng ta vẫn gọi Matrix Phương pháp của lớp công cụ đã thực hiện việc gán giá trị này. Ý nghĩa ở đây là chúng ta đặt mắt (hoặc máy ảnh) tại điểm (3.0bacarat, 3.0, 10.0) trong hệ tọa độ thế giới và hướng quan sát của nó đang nhắm thẳng vào điểm gốc của hệ tọa độ thế giới, cụ thể là điểm (0.0, 0.0, 0.0). Bên cạnh đó, chúng ta cũng cần xác định rõ hướng "đầu hướng lên" (up vector), mà trong mã nguồn được chỉ định là vectơ (0.0, 1.0, 0.0), tức là hướng thẳng đứng. Điều này đảm bảo rằng mọi thao tác quan sát sẽ diễn ra một cách chính xác và có trật tự trong không gian 3D.

Cuối cùngbầu cua, hãy nhìn vào cách tính toán ma trận projection:

								
									
										Matrix
									.
									perspectiveM
									(
									projectionMatrix
									,
									 0
									,
									 45.0f
									,
									 width
									 /
									 (
									float
									)
									 height
									,
									 0.1f
									,
									 100.0f
									);
									

								

Dòng mã này projectionMatrix Đây là ma trận projection cần tính toánbầu cua, nó cũng là một ma trận 4x4. Matrix.perspectiveM Đã gán giá trị cho ma trận nàybầu cua, cuộc gọi này cần một số tham số đầu vào như sau:

  • Góc quan sát được đặt thành 45789 Club,0 độ. Giá trị này thường được gọi là trường nhìn, viết tắt là fov. Ý nghĩa của nó đã được đánh dấu rõ ràng trong hình dưới đây. Trong lĩnh vực đồ họa máy tính, góc nhìn fov đóng vai trò quan trọng khi mô phỏng cách mắt người nhìn nhận khô Khi giá trị fov tăng lên, góc nhìn sẽ rộng hơn, tạo cảm giác như bạn đang đứng giữa một thế giới mở rộng. Ngược lại, nếu giảm giá trị này xuống, mọi thứ sẽ trở nên hẹp và sâu hơn, giống như nhìn qua một ống nhòm. Chính vì vậy, việc điều chỉnh góc nhìn fov sao cho phù hợp rất cần thiết để tạo ra trải nghiệm thị giác chân thực nhất cho người dùng.

Biểu đồ thể hiện FOV của phép biến đổi chiếu

  • Tham số thứ hai là tỷ lệ chiều rộng so với chiều caobacarat, chỉ số tỷ lệ chiều rộng so với chiều cao của mặt phẳng gần (N).
  • Tham số thứ ba và thứ tư lần lượt biểu thị khoảng cách từ mặt phẳng gần (N) và mặt phẳng xa (F) đến máy ảnh.

Hiện tạibầu cua, chúng ta đã xem qua tất cả các đoạn mã liên quan đến việc tính toán ba ma trận model, view và projection, và đã có cái nhìn tổng quát về quy trình tính toán. Trong phần tiếp theo, chúng ta sẽ đi sâu hơn để phân tích định lượng một số bước tính toán cụ thể của các ma trận này. Điều này sẽ giúp hiểu rõ hơn về cách hoạt động cũng như vai trò của từng ma trận trong hệ thống đồ họa.

Sự suy diễn của ma trận thu nhỏ và dịch chuyển

Về cơ sở lý thuyết đại số tuyến tính

Trước đây (bao gồm cả Bài trước Khi chúng ta nhắc đến việc biến đổi tọa độbầu cua, chúng ta thường nói về việc biến đổi các đỉnh. Tuy nhiên, chúng ta cũng biết rằng trong đại số tuyến tính, các khái niệm mà chúng ta nghiên cứu đều dựa trên vector và không có khái niệm điểm. Khái niệm gốc của vector là một đối tượng có nguồn gốc từ... Một vector thực sự là một đại lượng có cả độ lớn lẫn hướng, nó có thể được biểu diễn như một mũi tên trong không gian. Những vector này có thể được cộng vào nhau hoặc nhân với một số vô hướng để tạo ra các kết quả mới. Tuy nhiên, khi nói đến các điểm (points), chúng ta đang đề cập đến những vị trí cụ thể trong không gian, và để mô tả chúng, chúng ta cần sử dụng thêm một công cụ đặc biệt - đó là phép thêm vector. Trong thực tế, khi làm việc với các điểm trong không gian, chúng ta thường thêm một vector vào một điểm khác để di chuyển điểm đó đến một vị trí mới. Điều này cho phép chúng ta hiểu rõ hơn cách thức hoạt động của hệ tọa độ và cách mà các phép biến đổi ảnh hưởng đến các đối tượng trong không gian. Vì vậy, mặc dù trong đại số tuyến tính, chúng ta tập trung vào việc nghiên cứu vector, nhưng các khái niệm liên quan đến điểm vẫn đóng vai trò quan trọng trong việc hiểu sâu hơn về cách hoạt động của các hệ tọa độ và phép biến đổi trong không gian. n Được tạo thành bởi n Mảng nguyên. Khi ánh xạ vectơ sang không gian hình họcbầu cua, chúng ta mới có khái niệm về điểm và mối quan hệ giữa điểm và vectơ.

Biểu đồ khái niệm điểm và vectơ

Như hình trên789 Club, chúng tôi đã thiết lập một hệ tọa độ vuông góc,Đây là một vectơbầu cua, biểu thị một lượng có độ lớn và hướng. Khi biểu diễn nó trong hệ tọa độ, điểm bắt đầu tại gốc tọa độ O bầu cua, điểm kết thúc hướng tới điểm P . Tọa độ của vectơ này và điểm P Tọa độ của một điểm bất kỳ sẽ trùng với tọa độ của vectơ dẫn từ gốc tọa độ đến điểm đóbacarat, chẳng hạn như (1, 2). Điều này có nghĩa là mỗi điểm và vectơ dẫn đến điểm đó có thể được ánh xạ tương ứng một cách duy nhất. Trong OpenGL ES, khi chúng ta thực hiện thay đổi tọa độ đỉnh (vertex), điều này có thể liên hệ trực tiếp với các phép biến đổi tuyến tính và thay đổi tọa độ mà chúng ta học trong đại số tuyến tính. Qua đó, lý thuyết toán học về không gian vectơ và phép biến đổi tuyến tính trở thành nền tảng quan trọng cho việc xử lý đồ họa trong lập trình đồ họa 3D.

Trong phần mô tả tiếp theobầu cua, đôi khi chúng ta sẽ nói về việc biến đổi một vectơ, và có lúc lại nói về việc biến đổi một điểm (hoặc đỉnh). Hai cách diễn đạt này thực chất là tương đương nhau, vì một điểm và một vectơ có gốc tại điểm xuất phát ban đầu và điểm kết thúc nằm chính xác tại điểm đó hoàn toàn có thể được coi là tương ứng với nhau. Điều này giúp chúng ta dễ dàng chuyển đổi giữa khái niệm điểm và vectơ trong nhiều trường hợp cụ thể mà không làm thay đổi bản chất của vấn đề đang xét.

Trong hệ tọa độ Descartesbầu cua, một vector còn có một tính chất đặc biệt là nó không phụ thuộc vào vị trí của điểm gốc (điểm đầu). Nói cách khác, một vector sẽ vẫn giữ nguyên giá trị và hướng ngay cả khi nó được dịch chuyển theo bất kỳ hướng nào. Ví dụ như trong hình trên, vector **AB** và vector **CD**, mặc dù chúng nằm ở các vị trí khác nhau trên mặt phẳng, nhưng nếu xét về độ dài và hướng thì chúng hoàn toàn tương đương với nhau. Điều này cho phép chúng ta dễ dàng so sánh hoặc thực hiện các phép toán giữa các vector mà không cần quan tâm đến nơi chúng xuất phát. Được biểu diễn bởi vectơ Sau khi thực hiện phép tịnh tiếnbầu cua, vectơ thu được sẽ có cùng độ dài và hướng như vectơ ban đầu. Chính vì vậy, chúng biểu diễn cùng một vectơ. Do đó, vectơ sau khi bị tịnh tiến vẫn giữ nguyên giá trị và ý nghĩa đại diện cho chính nó trước khi dịch chuyển.Vẫn được biểu diễn bằng tọa độ (1789 Club,2).

Vì khi dịch chuyển một vectơbầu cua, tọa độ của nó vẫn không đổi, nên để thực hiện phép biến đổi tọa độ của đỉnh, chúng ta không thể đạt được mục đích chỉ bằng cách di chuyển một vectơ đơn thuần. Thay vào đó, trong trường hợp này, chúng ta cần sử dụng phép cộng giữa hai vectơ (ở phần tiếp theo, bạn sẽ hiểu rõ hơn về điều này).

Trong đại số tuyến tínhbầu cua, khái niệm biến đổi tuyến tính là một phần quan trọng với nền tảng lý thuyết vô cùng phong phú và hoàn chỉnh. Tuy nhiên, các quy trình biến đổi trong OpenGL ES mà chúng ta sẽ thảo luận không thể hoàn toàn được diễn tả bằng biến đổi tuyến tính. Ví dụ như việc thu nhỏ (scale) và xoay (rotate) có thể được biểu thị dưới dạng biến đổi tuyến tính, nhưng việc dịch chuyển (translate) thì không. Các loại biến đổi mà chúng ta sẽ nghiên cứu sau này, chẳng hạn như biến đổi quan sát (view transform) và biến đổi chiếu (projection transform), cũng không thuộc phạm vi của biến đổi tuyến tính. Thực tế, chúng thuộc về nhóm biến đổi ánh xạ (affine transformation). Biến đổi ánh xạ mở rộng hơn so với biến đổi tuyến tính, cho phép bao gồm cả các phép dịch chuyển, điều mà biến đổi tuyến tính không thể làm được một cách trực tiếp. Affine Transformation Chúng ta hãy tạm thời không vội vàng đi sâu vào những khái niệm trừu tượng đó mà thay vào đó tập trung phân tích từng phép biến đổi cụ thểbacarat, tìm hiểu cách chúng được suy ra. Có lẽ đến cuối cùng, khi quay lại nhìn nhận những khái niệm trừu tượng ấy, chúng ta sẽ hiểu rõ hơn và có cái nhìn toàn diện hơn về vấn đề.

Quá trình suy diễn ma trận dịch chuyển

Đầu tiênbacarat, chúng ta hãy cùng xem xét việc dịch chuyển (translation) của đỉnh. Điều này có thể được thực hiện thông qua phép cộng vectơ. Hãy quan sát hình dưới đây để hiểu rõ hơn: [Thêm một đoạn mô tả hình ảnh giả định] Trong hình minh họa, chúng ta thấy rằng khi áp dụng phép dịch chuyển, vị trí ban đầu của đỉnh sẽ di chuyển theo hướng và độ dài mà vectơ chỉ định, tạo ra một điểm mới trên mặt phẳng tọa độ. Đây là cách trực quan để hiểu rõ hơn về khái niệm dịch chuyển trong không gian hai chiều.

Biểu đồ cộng vectơ

Trong hình A Điểm di chuyển đến B Điểm789 Club, tương đương với thực hiện một phép cộng vectơ:

Chúng ta thấy rằng trong hệ tọa độ vuông góc789 Club, phép cộng vectơ tuân theo quy tắc tam giác. Trong đó vectơĐại diện cho độ lớn và hướng của sự dịch chuyển được gọi là vectơ dịch (translation vector). Để có thể dễ dàng xác định tọa độ của vectơ dịch nàybầu cua, chúng ta sẽ di chuyển nó về điểm gốc (nguyên điểm). Khi đó, vectơ dịch sẽ trùng với một vectơ khác, từ đó giúp ta dễ dàng quan sát và phân tích các thông số liên quan. Vectơ dịch không chỉ đơn thuần là một công cụ toán học mà còn đóng vai trò quan trọng trong việc giải thích nhiều hiện tượng vật lý hoặc ứng dụng trong đồ họa máy tính, nơi mà việc di chuyển các đối tượng trong không gian 3D cần được thực hiện chính xác và hiệu quả.Bằng nhaubầu cua, có thể thấy tọa độ của nó là (0,5,1). VectơCộng thêm một vectơ dịch chuyển như vậybacarat, tương đương với việc di chuyển điểm A Dọc theo trục x 0bacarat,5 đơn vị và dọc theo trục y 1 đơn vị, như vậy sẽ di chuyển đến vị trí của điểm B Trong hình trước đây là ví dụ về vectơ hai chiềubacarat, bây giờ chúng ta mở rộng sang ba chiều, biểu diễn phép biến đổi dịch chuyển bằng tọa độ vectơ, như sau:

Trong biểu thức trên

Đại diện cho giá trị của vectơ dịch chuyển (translation vector) được đề cập trước đó.

bầu cua, nhân nó với tọa độ ba chiều của đỉnh:

Trong đại số tuyến tínhbacarat, một biến đổi thường được biểu diễn thông qua phép nhân ma trận. Thêm vào đó, OpenGL ES tận dụng sức mạnh của GPU để thực hiện các phép tính, và GPU có các thuật toán cực kỳ hiệu quả cho phép nhân ma trận. Chúng ta cũng mong muốn biến đổi tịnh tiến (translation) ở đây có thể được trình bày dưới dạng phép nhân ma trận (cụ thể là nhân trái). Vì vậy, chúng ta hãy tưởng tượng một ma trận 3x3 để đạt được điều này. Ma trận 3x3 mà chúng ta đang nghĩ đến sẽ có cấu trúc đặc biệt, với các phần tử được sắp xếp sao cho nó có thể duy trì tính chất của hệ tọa độ sau khi thực hiện phép biến đổi tịnh tiến. Điều này sẽ giúp chúng ta dễ dàng xử lý các phép tính trong không gian hai chiều mà vẫn giữ nguyên được tính chính xác và hiệu suất cao của GPU. Ví dụ, nếu chúng ta có một điểm (x, y), thì bằng cách nhân điểm đó với ma trận 3x3, chúng ta có thể thêm một giá trị dịch chuyển (dx, dy) vào tọa độ gốc một cách dễ dàng. Điều này không chỉ làm cho việc quản lý các đối tượng đồ họa trở nên đơn giản hơn mà còn tạo ra hiệu quả đáng kể trong quá trình xử lý đồ họa thực tế. A Chúng tôi nhận ra rằng bất kể ma trận

Chuyển đổi thành tọa độ đồng nhất chính là: A Bạn có thể tự hỏi giá trị của các thành phần khác nhau trong phương trình sẽ cho ra kết quả nàobầu cua, nhưng bạn chỉ có thể nhận được các tổ hợp tuyến tính giữa x, y và z. Bạn không bao giờ có thể đạt được kết quả giống như phép cộng vector trước đó (nơi x, y và z được cộng thêm một hằng số). Để giải quyết vấn đề này, chúng ta sẽ chuyển từ tọa độ ba chiều sang hệ tọa độ đồng nhất (homogeneous coordinates). Hệ tọa độ đồng nhất nghĩa là bạn sẽ thêm một chiều thứ tư vào tọa độ ba chiều cơ bản và đặt giá trị của nó là 1. Nói cách khác, với tọa độ ba chiều, bạn...

bacarat, đây là một tọa độ đồng nhất.

Bạn có thể nghĩ rằng thành phần thứ 4 trong tọa độ thuần nhất không nhất thiết phải là 1789 Club, nhưng trong phạm vi hiện tại của chúng ta, ta chưa cần đến trường hợp này. Chúng ta sẽ nghiên cứu kỹ hơn về vấn đề này khi bàn về phép biến đổi chiếu (projection transformation) và phép chia theo góc nhìn (perspective division). Hiện tại, hãy tạm thời coi tọa độ thuần nhất như một cách mở rộng thêm một chiều mới, với giá trị cố định là 1. Có thể tưởng tượng rằng việc thêm vào giá trị này không gây ra bất kỳ tác động tiêu cực nào đối với chúng ta, miễn là khi cần thiết, ta chỉ việc loại bỏ nó để quay lại hệ tọa độ ba chiều ban đầu. Thực tế, trong OpenGL ES, chúng ta luôn sử dụng tọa độ thuần nhất bốn chiều để biểu diễn tọa độ đỉnh. Hãy nhớ lại đoạn mã trong chương trình vertex shader mà chúng ta đã thảo luận trước đây:vec4(position.xyz789 Club, 1) Ma trận trong biểu thức trên:

Bạn có thể tưởng tượng rằng một tọa độ đỉnh trong không gian bốn chiềubacarat, sau khi được nhân trái với một ma trận, sẽ cho ra một kết quả cũng là một tọa độ đỉnh trong không gian bốn chiều (vẫn là một tọa độ thuần nhất). Ma trận này phải có kích thước 4x4. Dựa trên định nghĩa của phép nhân ma trận, việc xây dựng một ma trận có khả năng biểu diễn phép dịch chuyển trở nên khá đơn giản: --- Hãy nghĩ đến việc bạn đang làm việc với một hệ trục tọa độ bốn chiều, nơi mỗi điểm có thể được mô tả bởi bốn thành phần (x, y, z, w), trong đó w thường là 1 để đại diện cho các điểm trong khô Khi muốn dịch chuyển một điểm từ vị trí này sang vị trí khác mà không thay đổi hướng hoặc tỷ lệ, chúng ta cần thêm một thành phần đặc biệt vào ma trận – chính là thông tin về khoảng cách và hướng dịch chuyển. Điều này có thể được thực hiện bằng cách tạo ra một ma trận 4x4 với các giá trị không đồng đều, trong đó hàng cuối cùng chứa thông số dịch chuyển. Ma trận như vậy sẽ có dạng: \[ \begin{bmatrix} 1 & 0 & 0 & dx \\ 0 & 1 & 0 & dy \\ 0 & 0 & 1 & dz \\ 0 & 0 & 0 & 1 \end{bmatrix} \] Trong đó, \(dx\), \(dy\), và \(dz\) là các giá trị dịch chuyển theo các trục x, y, và z tương ứng. Khi bạn nhân ma trận này với tọa độ của một điểm, kết quả sẽ là tọa độ đã được dịch chuyển đúng theo yêu cầu!

Quá trình suy diễn ma trận thu nhỏ

Đúng như vậy789 Club, đây chính là ma trận dịch chuyển mà chúng ta cần suy ra. Ma trận này có kích thước 4x4. Chúng ta nhận thấy rằng phần góc trên bên trái của nó là một ma trận đơn vị 3x3, trong khi ba phần tử đầu tiên của cột thứ tư chính là vector dịch chuyển. Có thể thấy rằng, nhờ việc sử dụng hệ tọa độ thuần nhất (homogeneous coordinates), thêm vào một chiều thứ tư bằng 1, sau khi thực hiện phép nhân ma trận, chúng ta đã đạt được kết quả giống với phép cộng vectơ (x, y, z cộng với vector dịch chuyển). Điều này làm nổi bật sự tiện lợi và linh hoạt của hệ tọa độ thuần nhất trong việc xử lý các phép biến đổi không gian.

Biểu đồ thể hiện quá trình thu nhỏ vectơ

Hình trên thể hiện quá trình thu nhỏ vectơ hai chiều. Vectơ

Khi được phóng to 1bầu cua,5 lần trên cả hai trục x và y sẽ tạo ra vectơKhi thu nhỏ 0bầu cua,5 lần trên trục x và phóng to 2 lần trên trục y, sẽ tạo ra vectơBạn có thể quan sát sự thay đổi tọa độ từ (2789 Club,1) thành (3,1.5). Cách biến đổi này phù hợp với khái niệm "phóng to" hoặc " thu nhỏ" trong suy nghĩ thông thường của chúng ta, tức là tất cả các chiều đều được "phóng to" hoặc "thu nhỏ" theo cùng một tỷ lệ. Nếu trong không gian 3 chiều, mỗi đỉnh của một đối tượng đều được "phóng to" hoặc "thu nhỏ" theo cùng một tỷ lệ, thì toàn bộ đối tượng đó sẽ tự động "phóng to" hoặc "thu nhỏ" theo tỷ lệ tương ứng. Điều này cho thấy sự nhất quán giữa các chiều và cách mà hình học có thể mô tả sự thay đổi kích thước một cách logic và có hệ thống.

Tuy nhiênbacarat, phép biến đổi tỷ lệ trong OpenGL ES có thể biểu diễn tình huống chung hơn, tức là các tỷ lệ thu nhỏ trên mỗi trục có thể khác nhau. Hãy tiếp tục lấy ví dụ về vector hai chiều từ hình ảnh phía trên, khi áp dụng phép biến đổi này, vector sẽ...bầu cua, tọa độ từ (2,1) thay đổi thành (1,2), đây cũng là một phép biến đổi thu nhỏ.Câu trên có nghĩa làbacarat, tọa độ x, y, z của một vectơ sau khi trải qua phép biến đổi thu nhỏ, lần lượt trở thành S

Từ các ví dụ trên có thể thấybacarat, phép biến đổi tỷ lệ là việc "phóng to" hoặc "co lại" tọa độ của từng chiều theo một hệ số nhất định. Khi mở rộng sang không gian 3 chiều, chúng ta vẫn sử dụng tọa độ đồng nhất 4 chiều, và phép biến đổi tỷ lệ có thể được biểu diễn bằng phép nhân ma trận như sau:

Lần. Và ma trận 4x4 ở bên trái biểu thức nàybacarat, chính là ma trận thu nhỏ mà chúng ta cần suy diễn: x ,S y ,S z Thực hiện thu nhỏ và dịch chuyển trong Android

(Lưu ý tên gói)bầu cua, dùng để tính toán các ma trận biến đổi thông thường.

Cuối cùngbầu cua, chúng ta hãy cùng tìm hiểu cách ma trận dịch chuyển và ma trận thu phóng được tính toán trong phần trước được thực hiện như thế nà Trong hệ thống Android, có một lớp công cụ được gọi là **MatrixUtils**, đây là nơi mà các phép toán liên quan đến việc xử lý ma trận được thực hiện một cách chính xác và hiệu quả. **MatrixUtils** không chỉ đơn giản là một tập hợp các phương thức để tính toán ma trận dịch chuyển và thu phóng mà còn bao gồm cả các chức năng hỗ trợ để tối ưu hóa hiệu suất khi thao tác với đồ họa trên màn hình. Các phương thức trong lớp này sử dụng thuật toán riêng dựa trên cấu trúc dữ liệu của Android để đảm bảo rằng mọi phép biến đổi đều diễn ra nhanh chóng và chính xác. Điều thú vị là, lớp **MatrixUtils** cũng cung cấp khả năng tùy chỉnh đối với các yếu tố như tỷ lệ thu phóng và góc quay, giúp các nhà phát triển dễ dàng tạo ra các hiệu ứng đồ họa phức tạp mà vẫn giữ được sự mượt mà trong trải nghiệm người dùng. android.opengl.Matrix Ba phương pháp công cụ). Đoạn mã này chúng tôi sẽ dán lại789 Club, như sau:

Theo như những gì chúng ta đã chứng minh trước đó789 Club, công thức của ma trận dịch chuyển và ma trận thu nhỏ đều được biểu diễn dưới dạng ma trận 4x4, và cấu trúc của chúng cũng không quá phức tạp. Việc viết mã để thực hiện hai loại ma trận này có lẽ sẽ không khiến bạn phải đắn đo lâu. Tuy nhiên, nếu so sánh kỹ lưỡng đoạn mã trong phần đầu tiên của bài viết này với công thức ma trận mà chúng ta vừa suy ra, bạn sẽ nhận ra rằng vấn đề không hề đơn giản như ban đầu nghĩ. Trong thực tế, việc lập trình không chỉ là áp dụng công thức một cách máy móc; nó đòi hỏi bạn phải hiểu rõ từng yếu tố chi tiết và cách các thành phần tương tác với nhau. Điều này đặc biệt đúng khi làm việc với ma trận hình học vì sự chính xác là yếu tố then chốt để đảm bảo tính đúng đắn của kết quả cuối cùng.

Theo lý thuyếtbầu cua, quá trình biến đổi đỉnh có thể được biểu diễn như sau: một tọa độ đỉnh dạng đồng nhất (homogeneous) trong không gian 4 chiều sẽ được nhân trái với một ma trận biến đổi 4x4 để thu được tọa độ đỉnh dạng đồng nhất sau khi đã thực hiện biến đổi. Nếu một đỉnh cần phải thực hiện nhiều loại biến đổi, chẳng hạn như trước tiên thực hiện biến đổi tỷ lệ (scale), sau đó là biến đổi dịch chuyển (translation), thì bạn cần nhân trái ma trận trước tiên với ma trận tỷ lệ, rồi tiếp tục nhân trái với ma trận dịch chuyển. Tuy nhiên, trong đoạn mã mà chúng ta đã giới thiệu ở phần đầu tiên, thay vì thực hiện các phép biến đổi theo thứ tự trên, ma trận ban đầu được thiết lập dưới dạng ma trận đơn vị (identity matrix), sau đó lần lượt điều chỉnh ma trận này theo thứ tự: dịch chuyển (translation), xoay (rotation), và cuối cùng là tỷ lệ (scaling). Điều này tương đương với việc gọi tuần tự các hàm liên quan đến từng loại biến đổi cụ thể (như dịch chuyển, xoay, và tỷ lệ). Matrix Tất nhiên phải tuân theo thứ tự sau trong chuỗi sắp xếp hoàn chỉnh cuối cùng: translateM , rotateM , scaleM Ma trận cuối cùng đạt được

								
									
										Matrix
									.
									setIdentityM
									(
									modelMatrix2
									,
									 0
									);
									
Matrix
									.
									translateM
									(
									modelMatrix2
									,
									 0
									,
									 0.5f
									,
									 1.0f
									,
									 -
									1.5f
									);
									
Matrix
									.
									rotateM
									(
									modelMatrix2
									,
									 0
									,
									 angle
									,
									 0.0f
									,
									 1.0f
									,
									 0.0f
									);
									
Matrix
									.
									scaleM
									(
									modelMatrix2
									,
									 0
									,
									 1.5f
									,
									 1.5f
									,
									 1.5f
									);
									

								

Chúng ta hãy quan sát riêng modelMatrix2 Khi dữ liệu được truyền vào vertex shaderbầu cua, nó sẽ thực hiện các phép toán ma trận theo thứ tự trái ngược với cách bạn gọi trong mã nguồn: trước tiên là nhân trái với ma trận quy mô (scale matrix), sau đó là ma trận xoay (rotation matrix), và cuối cùng là ma trận dịch chuyển (translation matrix). Điều này có thể khiến nhiều người thắc mắc: tại sao lại có sự khác biệt này? Thực tế, thứ tự này được quyết định bởi bản chất của không gian tọa độ trong đồ họa máy tính. Khi một đối tượng di chuyển trong không gian 3D, các phép biến đổi ma trận thường được áp dụng từ "nội tại" ra "ngoài", nghĩa là chúng bắt đầu từ việc thay đổi kích thước trước, sau đó xoay xung quanh tâm mới đã được điều chỉnh kích thước, và cuối cùng dịch chuyển đến vị trí mong muốn. Chính thứ tự này giúp đảm bảo rằng các phép biến đổi diễn ra một cách chính xác và tự nhiên hơn, phù hợp với cách hoạt động của hệ thống đồ họa. Vì vậy, dù thứ tự trong mã có thể khác, nhưng khi kết hợp với cách hoạt động của vertex shader, nó sẽ vẫn tạo ra kết quả đúng như mong đợi. Đây là một trong những yếu tố quan trọng giúp các nhà phát triển hiểu rõ hơn về cách hoạt động của hệ thống đồ họa.

Cuộc gọi nàybầu cua, phân tích một chút. Chữ ký của phương pháp này như sau: Matrix.scaleM Nó thể hiện rằng đầu vào

								
									
										public
									 static
									 void
									 scaleM
									(
									float
									[]
									 m
									,
									 int
									 mOffset
									,
									
            float
									 x
									,
									 float
									 y
									,
									 float
									 z
									);
									

								

Mảng float Đã lưu trữ sẵn một ma trận biến đổi tại vị trí dịch chuyển m (là ma trận 4x4)789 Club, ký hiệu ma trận này là mOffset . Sau khi M . Ma trận mới cuối cùng này scaleM Sau khi thực hiện lệnh này789 Club, ma trận biến đổi được nhập vào sẽ được điều chỉnh trực tiếp tại chỗ, tích hợp thêm thao tác phóng to (scale), tạo ra một ma trận biến đổi mới, được ký hiệu là M’ Nhân trái với tọa độ đỉnhbầu cua, hiệu quả cuối cùng là trước tiên co rút ba chiều của tọa độ đỉnh xuống M’ Lần789 Club, sau đó thực hiện phép biến đổi ban đầu x , y , z . Lưu ý: ở đây M Ba tham số này tương đương với S x , y , z Ghi nhớ ma trận thu nhỏ được suy diễn trước đó là x ,S y ,S z

, tức là: S Tất nhiên phải có điều này:

Chỉ có như vậybầu cua, khi nhân trái với một tọa độ đỉnh nào đó, mới có thể giải thích là: trước tiên thu nhỏ, sau đó thực hiện phép biến đổi

M’ = M S

Lưu ý: công thức này thể hiện rằng sau khi xử lýbầu cua, tương đương với việc thêm vào ma trận biến đổi ban đầu M’ Nhân phải M

Một ma trận thu nhỏ. scaleM Để rõ ràng hơn về thao tác "nhân phải" này789 Club, chúng ta đặt bất kỳ ma trận biến đổi nào Nhân phải với Sau đó, nhận được:

Biểu thức trên này thể hiện M Phải thực hiện thao tác: nhân từng phần tử của ba cột đầu tiên của ma trận biến đổi ban đầu

Với S S ; cột thứ tư giữ nguyên.

Bây giờ chúng ta hãy xem scaleM Mã nguồn thực hiện: M Đoạn mã này chính xác là những gì biểu thức trước đó thể hiện. Điều cần chú ý ở đây là: x ,S y ,S z Ma trận789 Club, mỗi cột thực tế chứa một hàng của ma trận. Cụ thể, thứ tự lưu trữ dữ liệu như sau:

Do đó đoạn mã này dễ hiểu hơn. scaleM Dựa trên cùng một ý tưởngbầu cua, chúng ta cũng có thể suy diễn

								
									public
									 static
									 void
									 scaleM
									(
									float
									[]
									 m
									,
									 int
									 mOffset
									,
									
            float
									 x
									,
									 float
									 y
									,
									 float
									 z
									)
									 {
									
        for
									 (
									int
									 i
									=
									0
									 ;
									 i
									<
									4
									 ;
									 i
									++)
									 {
									
            int
									 mi
									 =
									 mOffset
									 +
									 i
									;
									
            m
									[
									     mi
									]
									 *=
									 x
									;
									
            m
									[
									 4
									 +
									 mi
									]
									 *=
									 y
									;
									
            m
									[
									 8
									 +
									 mi
									]
									 *=
									 z
									;
									
        }
									
    }
									

								

Quá trình tính toán. Nó tương đương với việc nhân phải ma trận biến đổi bất kỳ android.opengl.Matrix Trong tài liệu nàybầu cua, ma trận được lưu trữ theo thứ tự cột (column-major order), do đó trong mã code, chúng ta sẽ thấy cách xử lý đặc biệt dành cho việc truy xuất và thao tác theo từng cột. Điều này giúp tối ưu hóa hiệu suất khi làm việc với các phép tính ma trận lớn, vì dữ liệu liên tục trong bộ nhớ sẽ giảm thiểu thời gian truy cập đệm. Vì vậy, trong phần mã nguồn phía dưới, bạn sẽ nhận thấy sự khác biệt rõ rệt khi triển khai thuật toán dựa trên thứ tự lưu trữ này. m Với ma trận dịch chuyển

  m[offset +  0] m[offset +  4] m[offset +  8] m[offset + 12]
  m[offset +  1] m[offset +  5] m[offset +  9] m[offset + 13]
  m[offset +  2] m[offset +  6] m[offset + 10] m[offset + 14]
  m[offset +  3] m[offset +  7] m[offset + 11] m[offset + 15]

789 Club, tạo ra một ma trận biến đổi mới scaleM Theo lý thuyết suy diễn ở phần trướcbacarat, chúng ta biết rằng giá trị của ma trận dịch chuyển là:

Tính toán Matrix.translateM Biểu thức này thể hiện M Phải thực hiện thao tác. Có thể thấy rằng ba cột đầu tiên của ma trận biến đổi ban đầu T Không thay đổibacarat, chỉ có cột thứ tư thay đổi. M’

Chúng ta hãy xem mã nguồn thực hiện

Nó thực sự thực hiện tính toán biểu thức này trước đây: M’ Phải thực hiện thao tác: nhân từng phần tử của ba cột đầu tiên của ma trận biến đổi ban đầu

Do bài viết này chưa thảo luận sâu về phép biến đổi xoay789 Club, nên translateM Đây không được thảo luậnbầu cua, chúng tôi sẽ để lại cho bài tiếp theo. M Trong bài tiếp theobacarat, chúng tôi sẽ thảo luận về một phép biến đổi rất quan trọng trong biến đổi tọa độ - phép biến đổi xoay.

Đây không được thảo luậnbacarat, chúng tôi sẽ để lại cho bài tiếp theo. translateM Trong bài tiếp theobacarat, chúng tôi sẽ thảo luận về một phép biến đổi rất quan trọng trong biến đổi tọa độ - phép biến đổi xoay.

								
									public
									 static
									 void
									 translateM
									(
									
            float
									[]
									 m
									,
									 int
									 mOffset
									,
									
            float
									 x
									,
									 float
									 y
									,
									 float
									 z
									)
									 {
									
        for
									 (
									int
									 i
									=
									0
									 ;
									 i
									<
									4
									 ;
									 i
									++)
									 {
									
            int
									 mi
									 =
									 mOffset
									 +
									 i
									;
									
            m
									[
									12
									 +
									 mi
									]
									 +=
									 m
									[
									mi
									]
									 *
									 x
									 +
									 m
									[
									4
									 +
									 mi
									]
									 *
									 y
									 +
									 m
									[
									8
									 +
									 mi
									]
									 *
									 z
									;
									
        }
									
    }
									

								

Matrix.rotateM


Tóm lạibầu cua, bài viết này tập trung phân tích cách tính toán ma trận dịch chuyển và ma trận tỷ lệ trong quá trình biến đổi model cũng như thực hiện mã nguồn tương ứng. Mặc dù phần còn lại về việc biến đổi tọa độ đỉnh chưa được đề cập chi tiết, nhưng đã cung cấp một hướng tiếp cận tổng quan cho toàn bộ quy trình. Các bài viết tiếp theo trong loạt bài này sẽ vẫn duy trì cách tiếp cận này. Vì vậy, những độc giả nóng lòng có thể bắt đầu hành trình khám phá của mình bằng cách áp dụng phương pháp tương tự ngay từ bây giờ.

——

(Kết thúc)

Các bài viết được chọn lọc khác


Bài viết gốcbầu cua, xin vui lòng trích dẫn nguồn và bao gồm mã QR bên dưới! Nếu không, từ chối tái bản!
Liên kết bài viết: /ehh7t2ct.html
Hãy theo dõi tài khoản Weibo cá nhân của tôi: Tìm kiếm tên tôi "Trương Thiết Lệ" trên Weibo.
Tài khoản WeChat của tôi: tielei-blog (Trương Thiết Lệ)
Bài trước: Tại sao một số cuốn sách về công nghệ lại khó đọc?
Bài sau: Thiên phú có phải là giả thuyết không?