WebGL - Hướng dẫn nhanh
Một vài năm trở lại đây, các ứng dụng Java - là sự kết hợp của các applet và JOGL - được sử dụng để xử lý đồ họa 3D trên Web bằng cách xử lý GPU (Bộ xử lý đồ họa). Vì các applet yêu cầu JVM để chạy, nên việc dựa vào các applet Java trở nên khó khăn. Một vài năm sau, mọi người ngừng sử dụng các ứng dụng Java.
API Stage3D do Adobe cung cấp (Flash, AIR) cung cấp kiến trúc tăng tốc phần cứng GPU. Sử dụng những công nghệ này, các lập trình viên có thể phát triển các ứng dụng với khả năng 2D và 3D trên trình duyệt web cũng như trên nền tảng IOS và Android. Vì Flash là một phần mềm độc quyền nên nó không được sử dụng làm tiêu chuẩn web.
Vào tháng 3 năm 2011, WebGL đã được phát hành. Nó là một phần mềm mở có thể chạy mà không cần JVM. Nó hoàn toàn được kiểm soát bởi trình duyệt web.
Bản phát hành mới của HTML 5 có một số tính năng hỗ trợ đồ họa 3D như 2D Canvas, WebGL, SVG, chuyển đổi 3D CSS và SMIL. Trong hướng dẫn này, chúng tôi sẽ trình bày những kiến thức cơ bản về WebGL.
OpenGL là gì?
OpenGL (Thư viện đồ họa mở) là một API đa ngôn ngữ, đa nền tảng cho đồ họa 2D và 3D. Nó là một tập hợp các lệnh. OpenGL4.5 là phiên bản mới nhất của OpenGL. Bảng sau liệt kê một tập hợp các công nghệ liên quan đến OpenGL.
API | Công nghệ được sử dụng |
---|---|
OpenGL ES | Đây là thư viện dành cho đồ họa 2D và 3D trên các hệ thống nhúng - bao gồm bảng điều khiển, điện thoại, thiết bị gia dụng và xe cộ. OpenGL ES 3.1 là phiên bản mới nhất của nó. Nó được duy trì bởi Khronos Group www.khronos.org |
JOGL | Nó là liên kết Java cho OpenGL. JOGL 4.5 là phiên bản mới nhất của nó và nó được duy trì bởi jogamp.org. |
WebGL | Nó là ràng buộc JavaScript cho OpenGL. WebGL 1.0 là phiên bản mới nhất và nó được duy trì bởi nhóm khronos . |
OpenGLSL | OpenGL Shading Language. Nó là một ngôn ngữ lập trình đồng hành với OpenGL 2.0 và cao hơn. Nó là một phần của đặc tả OpenGL 4.4 cốt lõi. Nó là một API được thiết kế riêng cho các hệ thống nhúng, chẳng hạn như các hệ thống có trên điện thoại di động và máy tính bảng. |
Note - Trong WebGL, chúng tôi sử dụng GLSL để viết shader.
WebGL là gì?
WebGL (Thư viện đồ họa web) là tiêu chuẩn mới cho đồ họa 3D trên web, Nó được thiết kế cho mục đích kết xuất đồ họa 2D và đồ họa 3D tương tác. Nó có nguồn gốc từ thư viện ES 2.0 của OpenGL, là một API 3D cấp thấp cho điện thoại và các thiết bị di động khác. WebGL cung cấp chức năng tương tự của ES 2.0 (Hệ thống nhúng) và hoạt động tốt trên phần cứng đồ họa 3D hiện đại.
Nó là một API JavaScript có thể được sử dụng với HTML5. Mã WebGL được viết trong thẻ <canvas> của HTML5. Đây là một thông số kỹ thuật cho phép trình duyệt Internet truy cập vào Đơn vị xử lý đồ họa (GPU) trên những máy tính mà chúng được sử dụng.
Ai đã phát triển WebGL
Một kỹ sư phần mềm người Mỹ gốc Serbia tên là Vladimir Vukicevic nền tảng đã hoạt động và dẫn đầu việc tạo ra WebGL
Năm 2007, Vladimir bắt đầu làm việc trên một OpenGL nguyên mẫu cho phần tử Canvas của tài liệu HTML.
Vào tháng 3 năm 2011, Tập đoàn Kronos đã tạo ra WebGL.
Kết xuất
Kết xuất là quá trình tạo ra một hình ảnh từ một mô hình bằng các chương trình máy tính. Trong đồ họa, một cảnh ảo được mô tả bằng cách sử dụng thông tin như hình học, điểm nhìn, kết cấu, ánh sáng và bóng đổ, được chuyển qua một chương trình kết xuất. Đầu ra của chương trình kết xuất này sẽ là một hình ảnh kỹ thuật số.
Có hai kiểu kết xuất -
Software Rendering - Tất cả các tính toán kết xuất được thực hiện với sự trợ giúp của CPU.
Hardware Rendering - Tất cả các tính toán đồ họa được thực hiện bởi GPU (Đơn vị xử lý đồ họa).
Kết xuất có thể được thực hiện cục bộ hoặc từ xa. Nếu hình ảnh được kết xuất quá phức tạp, thì việc kết xuất được thực hiện từ xa trên một máy chủ chuyên dụng có đủ tài nguyên phần cứng cần thiết để kết xuất các cảnh phức tạp. Nó còn được gọi làserver-based rendering. Việc kết xuất cũng có thể được thực hiện cục bộ bởi CPU. Nó được gọi làclient-based rendering.
WebGL tuân theo phương pháp kết xuất dựa trên máy khách để kết xuất cảnh 3D. Tất cả quá trình xử lý cần thiết để có được hình ảnh được thực hiện cục bộ bằng phần cứng đồ họa của máy khách.
GPU
Theo NVIDIA, GPU là "một bộ xử lý chip đơn có tích hợp các công cụ biến đổi, chiếu sáng, thiết lập / cắt hình tam giác và kết xuất có khả năng xử lý tối thiểu 10 triệu đa giác mỗi giây." Không giống như bộ xử lý đa lõi với một vài lõi được tối ưu hóa để xử lý tuần tự, GPU bao gồm hàng nghìn lõi nhỏ hơn xử lý các khối lượng công việc song song một cách hiệu quả. Do đó, GPU tăng tốc độ tạo hình ảnh trong bộ đệm khung hình (một phần ram chứa dữ liệu khung hình hoàn chỉnh) dành cho xuất ra màn hình.
Máy tính tăng tốc GPU
Trong tính toán tăng tốc GPU, ứng dụng được tải vào CPU. Bất cứ khi nào nó gặp phảicompute-intensivephần mã, sau đó phần mã đó sẽ được tải và chạy trên GPU. Nó cung cấp cho hệ thống khả năng xử lý đồ họa một cách hiệu quả.
GPU sẽ có một bộ nhớ riêng biệt và nó chạy nhiều bản sao của một phần nhỏ mã cùng một lúc. GPU xử lý tất cả dữ liệu trong bộ nhớ cục bộ của nó, không phải bộ nhớ trung tâm. Do đó, dữ liệu cần được xử lý bởi GPU nên được tải / sao chép vào bộ nhớ GPU và sau đó được xử lý.
Trong các hệ thống có kiến trúc trên, chi phí giao tiếp giữa CPU và GPU nên được giảm bớt để đạt được tốc độ xử lý các chương trình 3D nhanh hơn. Đối với điều này, chúng tôi phải sao chép tất cả dữ liệu và giữ nó trên GPU, thay vì giao tiếp với GPU nhiều lần.
Các trình duyệt được hỗ trợ
Các bảng sau đây hiển thị danh sách các trình duyệt hỗ trợ WebGL:
Trình duyệt web
Tên trình duyệt | Phiên bản | Ủng hộ |
---|---|---|
Internet Explorer | 11 trở lên | Hoàn thành hỗ trợ |
Google Chrome | 39 trở lên | Hoàn thành hỗ trợ |
Safari | số 8 | Hoàn thành hỗ trợ |
Firefox | 36 trở lên | Hỗ trợ một phần |
Opera | 27 trở lên | Hỗ trợ một phần |
Trình duyệt Di động
Tên trình duyệt | Phiên bản | Ủng hộ |
---|---|---|
Chrome dành cho Android | 42 | Hỗ trợ một phần |
Trình duyệt Android | 40 | Hỗ trợ một phần |
Safari iOS | 8,3 | Hoàn thành hỗ trợ |
Opera Mini | số 8 | Không hỗ trợ |
Trình duyệt Blackberry | 10 | Hoàn thành hỗ trợ |
IE di động | 10 | Hỗ trợ một phần |
Ưu điểm của WebGL
Dưới đây là những lợi thế của việc sử dụng WebGL -
JavaScript programming- Các ứng dụng WebGL được viết bằng JavaScript. Sử dụng các ứng dụng này, bạn có thể tương tác trực tiếp với các phần tử khác của Tài liệu HTML. Bạn cũng có thể sử dụng các thư viện JavaScript khác (ví dụ: JQuery) và các công nghệ HTML để làm phong phú ứng dụng WebGL.
Increasing support with mobile browsers - WebGL cũng hỗ trợ các trình duyệt dành cho thiết bị di động như iOS safari, Trình duyệt Android và Chrome dành cho Android.
Open source- WebGL là một mã nguồn mở. Bạn có thể truy cập mã nguồn của thư viện và hiểu cách thức hoạt động cũng như cách nó được phát triển.
No need for compilation- JavaScript là một thành phần nửa lập trình và nửa HTML. Để thực thi tập lệnh này, không cần phải biên dịch tệp. Thay vào đó, bạn có thể trực tiếp mở tệp bằng bất kỳ trình duyệt nào và kiểm tra kết quả. Vì các ứng dụng WebGL được phát triển bằng JavaScript, nên không cần biên dịch các ứng dụng WebGL.
Automatic memory management- JavaScript hỗ trợ quản lý bộ nhớ tự động. Không cần cấp phát thủ công bộ nhớ. WebGL kế thừa tính năng này của JavaScript.
Easy to set up- Vì WebGL được tích hợp trong HTML 5 nên không cần thiết lập thêm. Để viết một ứng dụng WebGL, tất cả những gì bạn cần là một trình soạn thảo văn bản và một trình duyệt web.
Thiết lập môi trường
Không cần thiết lập một môi trường khác cho WebGL. Các trình duyệt hỗ trợ WebGL có thiết lập tích hợp riêng cho WebGL.
Để tạo các ứng dụng đồ họa trên web, HTML-5 cung cấp một tập hợp phong phú các tính năng như 2D Canvas, WebGL, SVG, chuyển đổi 3D CSS và SMIL. Để viết các ứng dụng WebGL, chúng tôi sử dụng phần tử canvas hiện có của HTML-5. Chương này cung cấp tổng quan về phần tử canvas HTML-5 2D.
HTML5 Canvas
HTML-5 <canvas>cung cấp một tùy chọn dễ dàng và mạnh mẽ để vẽ đồ họa bằng JavaScript. Nó có thể được sử dụng để vẽ đồ thị, tạo bố cục ảnh hoặc tạo các hoạt ảnh đơn giản (và không đơn giản như vậy).
Đây là một đơn giản <canvas> phần tử chỉ có hai thuộc tính cụ thể width và height cộng với tất cả các thuộc tính HTML-5 cốt lõi như id, tên và lớp.
Cú pháp
Cú pháp của thẻ canvas HTML được đưa ra bên dưới. Bạn phải đề cập đến tên của canvas bên trong dấu ngoặc kép (“”).
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
Thuộc tính Canvas
Thẻ canvas có ba thuộc tính là id, width và height.
Id- Id đại diện cho định danh của phần tử canvas trong Mô hình đối tượng tài liệu (DOM) .
Width - Chiều rộng thể hiện chiều rộng của canvas.
Height - Chiều cao thể hiện chiều cao của canvas.
Các thuộc tính này xác định kích thước của canvas. Nếu một lập trình viên không chỉ định chúng trong thẻ canvas, thì theo mặc định, các trình duyệt như Firefox, Chrome và Web Kit sẽ cung cấp phần tử canvas có kích thước 300 × 150.
Ví dụ - Tạo Canvas
Đoạn mã sau đây cho thấy cách tạo canvas. Chúng tôi đã sử dụng CSS để tạo đường viền màu cho canvas.
<html>
<head>
<style>
#mycanvas{border:1px solid red;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
</body>
</html>
Khi thực thi, đoạn mã trên sẽ tạo ra kết quả sau:
Bối cảnh kết xuất
<canvas> ban đầu trống. Để hiển thị thứ gì đó trên phần tử canvas, chúng ta phải sử dụng ngôn ngữ kịch bản. Ngôn ngữ kịch bản này nên truy cập vào ngữ cảnh kết xuất và vẽ trên đó.
Phần tử canvas có một phương thức DOM được gọi là getContext(), được sử dụng để lấy bối cảnh kết xuất và các chức năng vẽ của nó. Phương thức này nhận một tham số, loại ngữ cảnh2d.
Đoạn mã sau sẽ được viết để có được ngữ cảnh cần thiết. Bạn có thể viết script này bên trong thẻ body như hình dưới đây.
<!DOCTYPE HTML>
<html>
<body>
<canvas id = "mycanvas" width = "600" height = "200"></canvas>
<script>
var canvas = document.getElementById('mycanvas');
var context = canvas.getContext('2d');
context.font = '20pt Calibri';
context.fillStyle = 'green';
context.fillText('Welcome to Tutorialspoint', 70, 70);
</script>
</body>
</html>
Khi thực thi, đoạn mã trên sẽ tạo ra kết quả sau:
Để biết thêm ví dụ về HTML-5 2D Canvas, hãy xem liên kết sau HTML-5 Canvas .
Ngữ cảnh WebGL
HTML5 Canvas cũng được sử dụng để viết các ứng dụng WebGL. Để tạo ngữ cảnh kết xuất WebGL trên phần tử canvas, bạn nên chuyển chuỗiexperimental-webgl, thay vì 2d đến canvas.getContext()phương pháp. Một số trình duyệt chỉ hỗ trợ 'webgl'.
<!DOCTYPE html>
<html>
<canvas id = 'my_canvas'></canvas>
<script>
var canvas = document.getElementById('my_canvas');
var gl = canvas.getContext('experimental-webgl');
gl.clearColor(0.9,0.9,0.8,1);
gl.clear(gl.COLOR_BUFFER_BIT);
</script>
</html>
Khi thực thi, đoạn mã trên sẽ tạo ra kết quả sau:
WebGL chủ yếu là một API rasterization cấp thấp hơn là một API 3D. Để vẽ một hình ảnh bằng cách sử dụng WebGL, bạn phải truyền một vectơ đại diện cho hình ảnh. Sau đó, nó chuyển đổi vector đã cho thành định dạng pixel bằng OpenGL SL và hiển thị hình ảnh trên màn hình. Viết một ứng dụng WebGL bao gồm một loạt các bước mà chúng tôi sẽ giải thích trong chương này.
WebGL - Hệ tọa độ
Cũng giống như bất kỳ hệ thống 3D nào khác, bạn sẽ có các trục x, y và z trong WebGL, nơi z trục biểu thị depth. Các tọa độ trong WebGL được giới hạn ở (1, 1, 1) và (-1, -1, - 1). Nó có nghĩa là - nếu bạn coi màn hình chiếu đồ họa WebGL như một khối lập phương, thì một góc của khối đó sẽ là (1, 1, 1) và góc đối diện sẽ là (-1, -1, -1). WebGL sẽ không hiển thị bất kỳ thứ gì được vẽ ra ngoài các ranh giới này.
Sơ đồ sau mô tả hệ tọa độ WebGL. Trục z biểu thị độ sâu. Giá trị dương của z cho biết đối tượng đang ở gần màn hình / người xem, trong khi giá trị âm của z cho biết đối tượng đang ở xa màn hình. Tương tự như vậy, giá trị dương của x cho biết đối tượng ở bên phải màn hình và giá trị âm cho biết đối tượng ở bên trái. Tương tự, các giá trị âm và dương của y cho biết đối tượng đang ở trên cùng hay ở phần dưới cùng của màn hình.
Đồ họa WebGL
Sau khi nhận được ngữ cảnh WebGL của đối tượng canvas, bạn có thể bắt đầu vẽ các phần tử đồ họa bằng cách sử dụng API WebGL trong JavaScript.
Dưới đây là một số thuật ngữ cơ bản bạn cần biết trước khi bắt đầu với WebGL.
Dọc
Nói chung, để vẽ các đối tượng như một đa giác, chúng ta đánh dấu các điểm trên mặt phẳng và nối chúng để tạo thành một đa giác mong muốn. Avertexlà một điểm xác định sự kết hợp của các cạnh của vật thể 3D. Nó được biểu diễn bằng ba giá trị dấu phẩy động, mỗi giá trị đại diện cho các trục x, y, z tương ứng.
Thí dụ
Trong ví dụ sau, chúng ta đang vẽ một tam giác với các đỉnh sau - (0,5, 0,5), (-0,5, 0,5), (-0,5, -0,5).
Note - Chúng ta phải lưu trữ các đỉnh này theo cách thủ công bằng cách sử dụng các mảng JavaScript và chuyển chúng vào đường dẫn kết xuất WebGL bằng cách sử dụng bộ đệm đỉnh.
Chỉ số
Trong WebGL, các giá trị số được sử dụng để xác định các đỉnh. Các giá trị số này được gọi là chỉ số. Các chỉ số này được sử dụng để vẽ các mắt lưới trong WebGL.
Note - Cũng giống như các đỉnh, chúng tôi lưu trữ các chỉ mục bằng cách sử dụng mảng JavaScript và chuyển chúng vào đường dẫn kết xuất WebGL bằng cách sử dụng bộ đệm chỉ mục.
Mảng
Không giống như OpenGL và JoGL, không có phương thức nào được xác định trước trong WebGL để hiển thị trực tiếp các đỉnh. Chúng tôi phải lưu trữ chúng theo cách thủ công bằng cách sử dụng các mảng JavaScript.
Thí dụ
var vertices = [ 0.5, 0.5, 0.1,-0.5, 0.5,-0.5]
Bộ đệm
Bộ đệm là vùng nhớ của WebGL chứa dữ liệu. Có nhiều bộ đệm khác nhau cụ thể là bộ đệm vẽ, bộ đệm khung, bộ đệm kỳ cựu và bộ đệm chỉ mục. Cácvertex buffer và index buffer được sử dụng để mô tả và xử lý hình học của mô hình.
Các đối tượng bộ đệm đỉnh lưu trữ dữ liệu về các đỉnh, trong khi các đối tượng bộ đệm Chỉ mục lưu trữ dữ liệu về các chỉ số. Sau khi lưu trữ các đỉnh thành mảng, chúng tôi chuyển chúng đến đường ống đồ họa WegGL bằng cách sử dụng các đối tượng Buffer này.
Frame bufferlà một phần của bộ nhớ đồ họa chứa dữ liệu cảnh. Bộ đệm này chứa các chi tiết như chiều rộng và chiều cao của bề mặt (tính bằng pixel), màu sắc của từng pixel, độ sâu và bộ đệm stencil.
Lưới thép
Để vẽ các đối tượng 2D hoặc 3D, API WebGL cung cấp hai phương pháp, drawArrays() và drawElements(). Hai phương thức này chấp nhận một tham số được gọi làmodebằng cách sử dụng mà bạn có thể chọn đối tượng bạn muốn vẽ. Các tùy chọn do trường này cung cấp bị hạn chế đối với các điểm, đường thẳng và hình tam giác.
Để vẽ một đối tượng 3D bằng hai phương pháp này, chúng ta phải dựng một hoặc nhiều đa giác nguyên thủy bằng cách sử dụng các điểm, đường thẳng hoặc hình tam giác. Sau đó, sử dụng các đa giác nguyên thủy đó, chúng ta có thể tạo thành một lưới.
Đối tượng 3D được vẽ bằng cách sử dụng đa giác nguyên thủy được gọi là mesh. WebGL cung cấp một số cách để vẽ các đối tượng đồ họa 3D, tuy nhiên người dùng thường thích vẽ lưới hơn.
Thí dụ
Trong ví dụ sau, bạn có thể thấy rằng chúng tôi đã vẽ một hình vuông bằng cách sử dụng hai hình tam giác → {1, 2, 3} và {4, 1, 3}.
Chương trình Shader
Chúng tôi thường sử dụng hình tam giác để tạo lưới. Vì WebGL sử dụng tính toán tăng tốc GPU, thông tin về các hình tam giác này sẽ được chuyển từ CPU sang GPU, vốn tốn rất nhiều chi phí giao tiếp.
WebGL cung cấp một giải pháp để giảm chi phí giao tiếp. Vì nó sử dụng ES SL (Embedded System Shader Language) chạy trên GPU, chúng tôi viết tất cả các chương trình cần thiết để vẽ các phần tử đồ họa trên hệ thống máy khách bằng cách sử dụngshader programs (các chương trình mà chúng tôi viết bằng OpenGL ES Shading Language / GLSL).
Các trình tạo bóng này là các chương trình dành cho GPU và ngôn ngữ được sử dụng để viết các chương trình tạo bóng là GLSL. Trong các bộ đổ bóng này, chúng tôi xác định chính xác cách các đỉnh, phép biến đổi, vật liệu, ánh sáng và máy ảnh tương tác với nhau để tạo ra một hình ảnh cụ thể.
Nói một cách ngắn gọn, nó là một đoạn mã thực hiện các thuật toán để lấy pixel cho một mắt lưới. Chúng ta sẽ thảo luận thêm về shader trong các chương sau. Có hai loại shader - Vertex Shader và Fragment Shader.
Vertex Shader
Vertext shader là mã chương trình được gọi trên mọi đỉnh. Nó được sử dụng để biến đổi (di chuyển) hình học (ví dụ: tam giác) từ nơi này sang nơi khác. Nó xử lý dữ liệu của mỗi đỉnh (dữ liệu mỗi đỉnh) như tọa độ đỉnh, chuẩn, màu và tọa độ kết cấu.
bên trong ES GLmã của vertex shader, lập trình viên phải xác định các thuộc tính để xử lý dữ liệu. Các thuộc tính này trỏ đến mộtVertex Buffer Object được viết bằng JavaScript.
Các tác vụ sau có thể được thực hiện bằng cách sử dụng bộ đổ bóng đỉnh:
- Chuyển đổi đỉnh
- Chuyển đổi bình thường và bình thường hóa
- Tạo tọa độ kết cấu
- Chuyển đổi tọa độ kết cấu
- Lighting
- Ứng dụng vật liệu màu
Fragment Shader (Pixel Shader)
Một lưới được tạo thành bởi nhiều hình tam giác và bề mặt của mỗi hình tam giác được gọi là fragment. Trình đổ bóng phân mảnh là mã chạy trên tất cả các pixel của mọi phân mảnh. Nó được viết để tính toán và tô màu trên các pixel riêng lẻ .
Các tác vụ sau có thể được thực hiện bằng cách sử dụng Trình tạo bóng phân mảnh:
- Các phép toán trên các giá trị nội suy
- Quyền truy cập kết cấu
- Ứng dụng kết cấu
- Fog
- Tổng màu
Biến OpenGL ES SL
Hình thức đầy đủ của OpenGL ES SLlà Ngôn ngữ tô bóng hệ thống nhúng OpenGL. Để xử lý dữ liệu trong các chương trình đổ bóng, ES SL cung cấp ba loại biến. Chúng như sau:
Attributes- Các biến này giữ các giá trị đầu vào của chương trình đổ bóng đỉnh. Các thuộc tính trỏ đến các đối tượng bộ đệm đỉnh có chứa dữ liệu mỗi đỉnh. Mỗi khi trình đổ bóng đỉnh được gọi, các thuộc tính trỏ đến VBO của các đỉnh khác nhau.
Uniforms - Các biến này giữ dữ liệu đầu vào chung cho cả bộ đổ bóng đỉnh và phân mảnh, chẳng hạn như vị trí ánh sáng, tọa độ kết cấu và màu sắc.
Varyings - Các biến này được sử dụng để truyền dữ liệu từ bộ đổ bóng đỉnh sang bộ đổ bóng phân mảnh.
Với nhiều điều cơ bản này, bây giờ chúng ta sẽ chuyển sang thảo luận về Đường ống đồ họa.
Để kết xuất đồ họa 3D, chúng ta phải làm theo một trình tự các bước. Các bước này được gọi làgraphics pipeline hoặc là rendering pipeline. Sơ đồ sau đây mô tả đường ống đồ họa WebGL.
Trong các phần sau, chúng ta sẽ thảo luận lần lượt về vai trò của từng bước trong quy trình.
JavaScript
Trong khi phát triển các ứng dụng WebGL, chúng tôi viết mã ngôn ngữ Shader để giao tiếp với GPU. JavaScript được sử dụng để viết mã điều khiển của chương trình, mã này bao gồm các hành động sau:
Initialize WebGL - JavaScript được sử dụng để khởi tạo ngữ cảnh WebGL.
Create arrays - Chúng tôi tạo các mảng JavaScript để chứa dữ liệu của hình học.
Buffer objects - Chúng ta tạo các đối tượng đệm (đỉnh và chỉ số) bằng cách truyền các mảng dưới dạng tham số.
Shaders - Chúng tôi tạo, biên dịch và liên kết các trình tạo bóng bằng JavaScript.
Attributes - Chúng ta có thể tạo các thuộc tính, kích hoạt chúng và liên kết chúng với các đối tượng đệm bằng JavaScript.
Uniforms - Chúng tôi cũng có thể liên kết đồng phục bằng JavaScript.
Transformation matrix - Sử dụng JavaScript, chúng ta có thể tạo ma trận chuyển đổi.
Ban đầu, chúng tôi tạo dữ liệu cho hình học cần thiết và chuyển chúng đến các bộ đổ bóng dưới dạng bộ đệm. Biến thuộc tính của ngôn ngữ đổ bóng trỏ đến các đối tượng đệm, được chuyển làm đầu vào cho trình đổ bóng đỉnh.
Vertex Shader
Khi chúng tôi bắt đầu quá trình kết xuất bằng cách gọi các phương thức drawElements() và drawArray(), bộ đổ bóng đỉnh được thực thi cho mỗi đỉnh được cung cấp trong đối tượng bộ đệm đỉnh. Nó tính toán vị trí của mỗi đỉnh của một đa giác nguyên thủy và lưu trữ nó trong cácgl_position. Nó cũng tính toán các thuộc tính khác nhưcolor, texture coordinatesvà vertices thường được liên kết với một đỉnh.
Hội nguyên thủy
Sau khi tính toán vị trí và các chi tiết khác của mỗi đỉnh, giai đoạn tiếp theo là primitive assembly stage. Tại đây, các hình tam giác được lắp ráp và chuyển đến máy tách.
Rasterization
Trong bước rasterization, các pixel trong hình ảnh cuối cùng của nguyên thủy được xác định. Nó có hai bước -
Culling- Bước đầu xác định được hướng (hướng ra trước hay ra sau?) Của đa giác. Tất cả những hình tam giác có hướng không phù hợp không hiển thị trong vùng xem sẽ bị loại bỏ. Quá trình này được gọi là tiêu hủy.
Clipping- Nếu một hình tam giác nằm một phần bên ngoài vùng xem thì phần bên ngoài vùng xem sẽ bị loại bỏ. Quá trình này được gọi là clipping.
Fragment Shader
Trình đổ bóng mảnh được
- dữ liệu từ bộ đổ bóng đỉnh trong các biến khác nhau,
- nguyên thủy từ giai đoạn rasterization, và sau đó
- tính toán các giá trị màu cho mỗi pixel giữa các đỉnh.
Trình đổ bóng phân mảnh lưu trữ các giá trị màu của mọi pixel trong mỗi phân mảnh. Các giá trị màu này có thể được truy cập trong các hoạt động phân mảnh mà chúng ta sẽ thảo luận tiếp theo.
Hoạt động phân mảnh
Các hoạt động phân mảnh được thực hiện sau khi xác định màu của từng pixel trong nguyên thủy. Các hoạt động phân mảnh này có thể bao gồm:
- Depth
- Hỗn hợp đệm màu
- Dithering
Khi tất cả các mảnh được xử lý, một hình ảnh 2D sẽ được hình thành và hiển thị trên màn hình. Cácframe buffer là điểm đến cuối cùng của đường dẫn kết xuất.
Khung đệm
Bộ đệm khung là một phần của bộ nhớ đồ họa chứa dữ liệu cảnh. Bộ đệm này chứa các chi tiết như chiều rộng và chiều cao của bề mặt (tính bằng pixel), màu sắc của mỗi pixel, độ sâu và bộ đệm stencil.
Chúng ta đã thảo luận về những điều cơ bản của WebGL và đường dẫn WebGL (một quy trình sau để hiển thị các ứng dụng Đồ họa). Trong chương này, chúng ta sẽ sử dụng một ứng dụng mẫu để tạo một hình tam giác bằng cách sử dụng WebGL và quan sát các bước tiếp theo trong ứng dụng.
Cấu trúc của ứng dụng WebGL
Mã ứng dụng WebGL là sự kết hợp của JavaScript và OpenGL Shader Language.
- Cần có JavaScript để giao tiếp với CPU
- Ngôn ngữ OpenGL Shader là bắt buộc để giao tiếp với GPU.
Ứng dụng mẫu
Bây giờ chúng ta hãy lấy một ví dụ đơn giản để tìm hiểu cách sử dụng WebGL để vẽ một tam giác đơn giản với tọa độ 2D.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/* Step1: Prepare the canvas and get WebGL context */
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
/* Step2: Define the geometry and store it in buffer objects */
var vertices = [-0.5, 0.5, -0.5, -0.5, 0.0, -0.5,];
// Create a new buffer object
var vertex_buffer = gl.createBuffer();
// Bind an empty array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertices data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/* Step3: Create and compile Shader programs */
// Vertex shader source code
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' + ' gl_Position = vec4(coordinates,0.0, 1.0);' + '}';
//Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
//Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
//Compile the vertex shader
gl.compileShader(vertShader);
//Fragment shader source code
var fragCode = 'void main(void) {' + 'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' + '}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragment shader
gl.compileShader(fragShader);
// Create a shader program object to store combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* Step 4: Associate the shader programs to buffer objects */
//Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
//point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 2, gl.FLOAT, false, 0, 0);
//Enable the attribute
gl.enableVertexAttribArray(coord);
/* Step5: Drawing the required object (triangle) */
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Nó sẽ tạo ra kết quả sau:
Nếu bạn quan sát kỹ chương trình trên, chúng ta đã làm theo năm bước tuần tự để vẽ một hình tam giác đơn giản bằng cách sử dụng WebGL. Các bước như sau:
Step 1 − Prepare the canvas and get WebGL rendering context
Chúng tôi lấy đối tượng canvas HTML hiện tại và lấy ngữ cảnh kết xuất WebGL của nó.
Step 2 − Define the geometry and store it in buffer objects
Chúng tôi xác định các thuộc tính của hình học như đỉnh, chỉ số, màu, v.v. và lưu trữ chúng trong các mảng JavaScript. Sau đó, chúng ta tạo một hoặc nhiều đối tượng đệm và chuyển các mảng chứa dữ liệu vào đối tượng đệm tương ứng. Trong ví dụ này, chúng tôi lưu trữ các đỉnh của tam giác trong một mảng JavaScript và chuyển mảng này vào một đối tượng bộ đệm đỉnh.
Step 3 − Create and compile Shader programs
Chúng tôi viết các chương trình đổ bóng đỉnh và đổ bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Step 4 − Associate the shader programs with buffer objects
Chúng tôi liên kết các đối tượng đệm và chương trình đổ bóng kết hợp.
Step 5 − Drawing the required object (triangle)
Bước này bao gồm các thao tác như xóa màu, xóa bit đệm, bật kiểm tra độ sâu, thiết lập cổng xem, v.v. Cuối cùng, bạn cần vẽ các nguyên thủy cần thiết bằng một trong các phương pháp sau: drawArrays() hoặc là drawElements().
Tất cả các bước này được giải thích thêm trong hướng dẫn này.
Để viết một ứng dụng WebGL, bước đầu tiên là lấy đối tượng ngữ cảnh kết xuất WebGL. Đối tượng này tương tác với bộ đệm bản vẽ WebGL và có thể gọi tất cả các phương thức WebGL. Các hoạt động sau được thực hiện để lấy ngữ cảnh WebGL:
- Tạo canvas HTML-5
- Nhận ID canvas
- Nhận WebGL
Tạo phần tử canvas HTML-5
Trong Chương 5, chúng ta đã thảo luận về cách tạo một phần tử canvas HTML-5. Trong phần nội dung của tài liệu HTML-5, hãy viết canvas, đặt tên cho nó và chuyển nó dưới dạng tham số cho id thuộc tính. Bạn có thể xác định kích thước của canvas bằng cách sử dụng thuộc tính chiều rộng và chiều cao (tùy chọn).
Thí dụ
Ví dụ sau đây cho thấy cách tạo phần tử canvas với kích thước 500 × 500. Chúng tôi đã tạo đường viền cho canvas bằng cách sử dụng CSS để hiển thị. Sao chép và dán mã sau vào một tệp có tênmy_canvas.html.
<!DOCTYPE HTML>
<html>
<head>
<style>
#mycanvas{border:1px solid blue;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "300" height = "300"></canvas>
</body>
</html>
Nó sẽ tạo ra kết quả sau:
Nhận ID Canvas
Sau khi tạo canvas, bạn phải lấy ngữ cảnh WebGL. Điều đầu tiên cần làm để lấy bối cảnh bản vẽ WebGL là lấy id của phần tử canvas hiện tại.
Canvas ID có được bằng cách gọi phương thức DOM (Mô hình đối tượng tài liệu) getElementById(). Phương thức này chấp nhận một giá trị chuỗi làm tham số, vì vậy chúng tôi chuyển tên của canvas hiện tại cho nó.
Ví dụ: nếu tên canvas là my_canvas, sau đó ID canvas thu được như hình dưới đây−
var canvas = document.getElementById('my_Canvas');
Nhận bối cảnh vẽ WebGL
Để lấy đối tượng WebGLRenderingContext (hoặc đối tượng ngữ cảnh Bản vẽ WebGL hoặc đơn giản là ngữ cảnh WebGL), hãy gọi getContext() phương pháp của hiện tại HTMLCanvasElement. Cú pháp của getContext () như sau:
canvas.getContext(contextType, contextAttributes);
Vượt qua các chuỗi webgl hoặc là experimental-webgl như là contentType. CáccontextAttributestham số là tùy chọn. (Trong khi tiếp tục với bước này, hãy đảm bảo rằng trình duyệt của bạn triển khai WebGL phiên bản 1 (OpenGL ES 2.0)).
Đoạn mã sau đây cho thấy cách lấy ngữ cảnh kết xuất WebGL. Đâygl là biến tham chiếu đến đối tượng ngữ cảnh thu được.
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
WebGLContextAttributes
Thông số WebGLContextAttributesđó không phải mệnh lệnh. Tham số này cung cấp các tùy chọn khác nhau chấp nhận các giá trị Boolean như được liệt kê bên dưới:
Sr.No. | Thuộc tính & Mô tả |
---|---|
1 | Alpha Nếu giá trị của nó là true, nó sẽ cung cấp một bộ đệm alpha cho canvas. Theo mặc định, giá trị của nó là true. |
2 | depth Nếu giá trị của nó là true, bạn sẽ nhận được bộ đệm bản vẽ chứa bộ đệm độ sâu ít nhất là 16 bit. Theo mặc định, giá trị của nó là true. |
3 | stencil Nếu giá trị của nó là true, bạn sẽ nhận được một bộ đệm vẽ trong đó có một bộ đệm stencil ít nhất 8 bit. Theo mặc định, giá trị của nó là false. |
4 | antialias Nếu giá trị của nó là true, bạn sẽ nhận được bộ đệm bản vẽ thực hiện khử răng cưa. Theo mặc định, giá trị của nó là true. |
5 | premultipliedAlpha Nếu giá trị của nó là true, bạn sẽ nhận được một bộ đệm bản vẽ chứa các màu với alpha được nhân trước. Theo mặc định, giá trị của nó là true. |
6 | preserveDrawingBuffer Nếu giá trị của nó là true, các bộ đệm sẽ không bị xóa và sẽ giữ nguyên các giá trị của chúng cho đến khi bị tác giả xóa hoặc ghi đè. Theo mặc định, giá trị của nó là false. |
Đoạn mã sau cho biết cách tạo ngữ cảnh WebGL với bộ đệm stencil, bộ đệm này sẽ không hoạt động anti-aliasing.
var canvas = document.getElementById('canvas1');
var context = canvas.getContext('webgl', { antialias: false, stencil: true });
Tại thời điểm tạo WebGLRenderingContext, một vùng đệm bản vẽ được tạo. Đối tượng Context quản lý trạng thái OpenGL và hiển thị vào bộ đệm bản vẽ.
WebGLRenderingContext
Nó là giao diện chính trong WebGL. Nó đại diện cho bối cảnh vẽ WebGL. Giao diện này chứa tất cả các phương thức được sử dụng để thực hiện các tác vụ khác nhau trên bộ đệm Vẽ. Các thuộc tính của giao diện này được đưa ra trong bảng sau.
Sr.No. | Thuộc tính & Mô tả |
---|---|
1 | Canvas Đây là một tham chiếu đến phần tử canvas đã tạo ra ngữ cảnh này. |
2 | drawingBufferWidth Thuộc tính này đại diện cho chiều rộng thực của vùng đệm bản vẽ. Nó có thể khác với thuộc tính width của HTMLCanvasElement. |
3 | drawingBufferHeight Thuộc tính này đại diện cho chiều cao thực của vùng đệm bản vẽ. Nó có thể khác với thuộc tính chiều cao của HTMLCanvasElement. |
Sau khi có được ngữ cảnh WebGL, bạn phải xác định hình học cho nguyên thủy (đối tượng bạn muốn vẽ) và lưu trữ nó. Trong WebGL, chúng tôi xác định các chi tiết của một hình học - ví dụ, các đỉnh, chỉ số, màu của hình nguyên thủy - bằng cách sử dụng các mảng JavaScript. Để chuyển các chi tiết này đến các chương trình đổ bóng, chúng ta phải tạo các đối tượng đệm và lưu trữ (đính kèm) các mảng JavaScript chứa dữ liệu trong các bộ đệm tương ứng.
Note: Sau đó, các đối tượng đệm này sẽ được liên kết với các thuộc tính của chương trình đổ bóng (vertex shader).
Xác định Hình học Bắt buộc
Mô hình 2D hoặc 3D được vẽ bằng cách sử dụng các đỉnh được gọi là mesh. Mỗi khía cạnh trong lưới được gọi làpolygon và một đa giác được tạo từ 3 đỉnh trở lên.
Để vẽ các mô hình trong ngữ cảnh kết xuất WebGL, bạn phải xác định các đỉnh và chỉ số bằng cách sử dụng mảng JavaScript. Ví dụ: nếu chúng ta muốn tạo một tam giác nằm trên các tọa độ {(5,5), (-5,5), (-5, -5)} như được hiển thị trong sơ đồ, thì bạn có thể tạo một mảng cho các đỉnh là -
var vertices = [
0.5,0.5, //Vertex 1
0.5,-0.5, //Vertex 2
-0.5,-0.5, //Vertex 3
];
Tương tự, bạn có thể tạo một mảng cho các chỉ số. Các chỉ số cho các chỉ số tam giác trên sẽ là [0, 1, 2] và có thể được định nghĩa là -
var indices = [ 0,1,2 ]
Để hiểu rõ hơn về các chỉ số, hãy xem xét các mô hình phức tạp hơn như hình vuông. Chúng ta có thể biểu diễn một hình vuông dưới dạng một tập hợp hai hình tam giác. Nếu (0,3,1) và (3,1,2) là hai hình tam giác mà chúng ta dự định vẽ một hình vuông, thì các chỉ số sẽ được định nghĩa là -
var indices = [0,3,1,3,1,2];
Note -
Để vẽ nguyên bản, WebGL cung cấp hai phương pháp sau:
drawArrays() - Trong khi sử dụng phương pháp này, chúng ta truyền các đỉnh của nguyên thủy bằng cách sử dụng các mảng JavaScript.
drawElements() - Trong khi sử dụng phương pháp này, chúng ta truyền cả đỉnh và chỉ số của nguyên thủy bằng mảng JavaScript.
Đối tượng đệm
Đối tượng đệm là một cơ chế được cung cấp bởi WebGL chỉ ra một vùng bộ nhớ được cấp phát trong hệ thống. Trong các đối tượng đệm này, bạn có thể lưu trữ dữ liệu của mô hình bạn muốn vẽ, tương ứng với các đỉnh, chỉ số, màu sắc, v.v.
Sử dụng các đối tượng đệm này, bạn có thể truyền nhiều dữ liệu vào chương trình đổ bóng (vertex shader) thông qua một trong các biến thuộc tính của nó. Vì các đối tượng đệm này nằm trong bộ nhớ GPU, chúng có thể được hiển thị trực tiếp, do đó cải thiện hiệu suất.
Để xử lý hình học, có hai loại đối tượng đệm. Họ là -
Vertex buffer object (VBO)- Nó chứa dữ liệu mỗi đỉnh của mô hình đồ họa sẽ được hiển thị. Chúng tôi sử dụng các đối tượng bộ đệm đỉnh trong WebGL để lưu trữ và xử lý dữ liệu liên quan đến các đỉnh như tọa độ đỉnh, chuẩn, màu và tọa độ kết cấu.
Index buffer objects (IBO) - Nó chứa các chỉ số (dữ liệu chỉ mục) của mô hình đồ họa sẽ được hiển thị.
Sau khi xác định hình học cần thiết và lưu trữ chúng trong các mảng JavaScript, bạn cần chuyển các mảng này đến các đối tượng đệm, từ đó dữ liệu sẽ được chuyển đến các chương trình đổ bóng. Các bước sau phải được thực hiện để lưu trữ dữ liệu trong bộ đệm.
Tạo bộ đệm trống.
Liên kết một đối tượng mảng thích hợp với bộ đệm trống.
Chuyển dữ liệu (đỉnh / chỉ số) vào bộ đệm bằng cách sử dụng một trong các typed arrays.
Bỏ liên kết bộ đệm (Tùy chọn).
Tạo vùng đệm
Để tạo một đối tượng bộ đệm trống, WebGL cung cấp một phương thức được gọi là createBuffer(). Phương thức này trả về một đối tượng đệm mới được tạo, nếu việc tạo thành công; nếu không nó trả về giá trị null trong trường hợp không thành công.
WebGL hoạt động như một máy trạng thái. Khi một bộ đệm được tạo, bất kỳ thao tác đệm tiếp theo nào sẽ được thực hiện trên bộ đệm hiện tại cho đến khi chúng tôi hủy liên kết nó. Sử dụng mã sau để tạo bộ đệm:
var vertex_buffer = gl.createBuffer();
Note - gl là biến tham chiếu đến ngữ cảnh WebGL hiện tại.
Ràng buộc đệm
Sau khi tạo một đối tượng bộ đệm trống, bạn cần liên kết một bộ đệm mảng thích hợp (đích) với nó. WebGL cung cấp một phương thức được gọi làbindBuffer() vì mục đích này.
Cú pháp
Cú pháp của bindBuffer() phương pháp như sau:
void bindBuffer (enum target, Object buffer)
Phương thức này chấp nhận hai tham số và chúng được thảo luận bên dưới.
target- Biến đầu tiên là một giá trị enum đại diện cho loại bộ đệm mà chúng ta muốn liên kết với bộ đệm trống. Bạn có hai giá trị enum được xác định trước làm tùy chọn cho tham số này. Họ là -
ARRAY_BUFFER đại diện cho dữ liệu đỉnh.
ELEMENT_ARRAY_BUFFER đại diện cho dữ liệu chỉ mục.
Object buffer- Biến thứ hai là biến tham chiếu đến đối tượng đệm được tạo ở bước trước. Biến tham chiếu có thể là đối tượng đệm đỉnh hoặc đối tượng đệm chỉ mục.
Thí dụ
Đoạn mã sau đây cho biết cách sử dụng phương thức bindBuffer ().
//vertex buffer
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//Index buffer
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
Truyền dữ liệu vào bộ đệm
Bước tiếp theo là truyền dữ liệu (đỉnh / chỉ số) vào bộ đệm. Cho đến bây giờ dữ liệu ở dạng mảng và trước khi chuyển nó vào bộ đệm, chúng ta cần bọc nó vào một trong các mảng đã định kiểu WebGL. WebGL cung cấp một phương thức có tênbufferData() vì mục đích này.
Cú pháp
Cú pháp của phương thức bufferData () như sau:
void bufferData (enum target, Object data, enum usage)
Phương thức này chấp nhận ba tham số và chúng được thảo luận bên dưới:
target - Tham số đầu tiên là một giá trị enum đại diện cho kiểu của bộ đệm mảng mà chúng tôi đã sử dụng. Các tùy chọn cho tham số này là:
ARRAY_BUFFER đại diện vertex data.
ELEMENT_ARRAY_BUFFER đại diện index data.
Object data- Tham số thứ hai là giá trị đối tượng chứa dữ liệu cần ghi vào đối tượng đệm. Ở đây chúng ta phải chuyển dữ liệu bằng cách sử dụngtyped arrays.
Usage- Tham số thứ ba của phương thức này là một biến enum chỉ định cách sử dụng dữ liệu đối tượng đệm (dữ liệu được lưu trữ) để vẽ hình. Có ba tùy chọn cho tham số này như được liệt kê bên dưới.
gl.STATIC_DRAW - Dữ liệu sẽ được chỉ định một lần và sử dụng nhiều lần.
gl.STREAM_DRAW - Dữ liệu sẽ được chỉ định một lần và sử dụng một vài lần.
gl.DYNAMIC_DRAW - Dữ liệu sẽ được chỉ định lặp lại và sử dụng nhiều lần.
Thí dụ
Đoạn mã sau cho biết cách sử dụng bufferData()phương pháp. Giả sử đỉnh và chỉ số là mảng chứa dữ liệu đỉnh và chỉ số tương ứng.
//vertex buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//Index buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
Mảng đã nhập
WebGL cung cấp một loại mảng đặc biệt được gọi là typed arraysđể chuyển các phần tử dữ liệu như đỉnh chỉ mục và kết cấu. Các mảng đã nhập này lưu trữ số lượng lớn dữ liệu và xử lý chúng ở định dạng nhị phân nguyên bản, mang lại hiệu suất tốt hơn. Các mảng đã nhập được WebGL sử dụng là Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, UInt32Array, Float32Array và Float64Array.
Note
Nói chung, để lưu trữ dữ liệu đỉnh, chúng tôi sử dụng Float32Array; và để lưu trữ dữ liệu chỉ mục, chúng tôi sử dụngUint16Array.
Bạn có thể tạo mảng đã nhập giống như mảng JavaScript bằng cách sử dụng new từ khóa.
Bỏ liên kết bộ đệm
Bạn nên hủy liên kết các bộ đệm sau khi sử dụng chúng. Nó có thể được thực hiện bằng cách chuyển một giá trị null vào vị trí của đối tượng đệm, như được hiển thị bên dưới.
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
WebGL cung cấp các phương pháp sau để thực hiện các thao tác đệm:
Sr.No. | Phương pháp và Mô tả |
---|---|
1 | vô hiệu bindBuffer( đích enum , bộ đệm đối tượng ) mục tiêu - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
2 | vô hiệu bufferData( mục tiêu enum , kích thước dài , sử dụng enum ) mục tiêu - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER sử dụng - STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW |
3 | vô hiệu bufferData( đích enum , dữ liệu đối tượng , sử dụng enum ) mục tiêu và cách sử dụng - Tương tự như đối vớibufferData ở trên |
4 | vô hiệu bufferSubData( mục tiêu enum , độ lệch dài , dữ liệu đối tượng ) mục tiêu - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
5 | Vật createBuffer() |
6 | vô hiệu deleteBuffer(Bộ đệm đối tượng ) |
7 | bất kì getBufferParameter(enum target , enum pname ) mục tiêu - ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER pname - BUFFER_SIZE, BUFFER_USAGE |
số 8 | bool isBuffer(Bộ đệm đối tượng ) |
Shader là các chương trình chạy trên GPU. Shader được viết bằng OpenGL ES Shader Language (được gọi là ES SL). ES SL có các biến riêng, kiểu dữ liệu, định tính, đầu vào và đầu ra tích hợp sẵn.
Loại dữ liệu
Bảng sau liệt kê các kiểu dữ liệu cơ bản được cung cấp bởi OpenGL ES SL.
Sr.No. | Loại & Mô tả |
---|---|
1 | void Đại diện cho một giá trị trống. |
2 | bool Chấp nhận đúng hoặc sai. |
3 | int Đây là kiểu dữ liệu số nguyên có dấu. |
4 | float Đây là một kiểu dữ liệu vô hướng nổi. |
5 | vec2, vec3, vec4 vectơ dấu phẩy động n thành phần |
6 | bvec2, bvec3, bvec4 Boolean vector |
7 | ivec2, ivec3, ivec4 vector số nguyên có dấu |
số 8 | mat2, mat3, mat4 Ma trận float 2x2, 3x3, 4x4 |
9 | sampler2D Truy cập kết cấu 2D |
10 | samplerCube Truy cập kết cấu được ánh xạ hình khối |
Vòng loại
Có ba vòng loại chính trong OpenGL ES SL -
Sr.No. | Vòng loại & Mô tả |
---|---|
1 | attribute Bộ định tính này hoạt động như một liên kết giữa bộ đổ bóng đỉnh và OpenGL ES cho dữ liệu mỗi đỉnh. Giá trị của thuộc tính này thay đổi cho mỗi lần thực thi bộ đổ bóng đỉnh. |
2 | uniform Bộ định lượng này liên kết các chương trình đổ bóng và ứng dụng WebGL. Không giống như định tính thuộc tính, giá trị của đồng phục không thay đổi. Đồng phục ở chế độ chỉ đọc; bạn có thể sử dụng chúng với bất kỳ kiểu dữ liệu cơ bản nào để khai báo một biến. Example - đồng phục vec4 ánh sáng; |
3 | varying Bộ định tính này tạo thành một liên kết giữa bộ đổ bóng đỉnh và bộ đổ bóng phân đoạn cho dữ liệu nội suy. Nó có thể được sử dụng với các kiểu dữ liệu sau - float, vec2, vec3, vec4, mat2, mat3, mat4 hoặc mảng. Example - thay đổi vec3 bình thường; |
Vertex Shader
Vertex shader là một mã chương trình, được gọi trên mọi đỉnh. Nó biến đổi (di chuyển) hình học (ví dụ: tam giác) từ nơi này sang nơi khác. Nó xử lý dữ liệu của mỗi đỉnh (dữ liệu mỗi đỉnh) như tọa độ đỉnh, chuẩn, màu và tọa độ kết cấu.
Trong mã ES GL của vertex shader, người lập trình phải xác định các thuộc tính để xử lý dữ liệu. Các thuộc tính này trỏ đến một Đối tượng đệm Vertex được viết bằng JavaScript. Các tác vụ sau có thể được thực hiện bằng cách sử dụng bộ đổ bóng đỉnh cùng với phép biến đổi đỉnh:
- Chuyển đổi đỉnh
- Chuyển đổi bình thường và bình thường hóa
- Tạo tọa độ kết cấu
- Chuyển đổi tọa độ kết cấu
- Lighting
- Ứng dụng vật liệu màu
Các biến được xác định trước
OpenGL ES SL cung cấp các biến được xác định trước sau đây cho trình đổ bóng đỉnh:
Sr.No. | Biến & Mô tả |
---|---|
1 | highp vec4 gl_Position; Giữ vị trí của đỉnh. |
2 | mediump float gl_PointSize; Giữ kích thước điểm đã biến đổi. Các đơn vị cho biến này là pixel. |
Mã mẫu
Hãy xem đoạn mã mẫu sau của công cụ đổ bóng đỉnh. Nó xử lý các đỉnh của một tam giác.
attribute vec2 coordinates;
void main(void) {
gl_Position = vec4(coordinates, 0.0, 1.0);
};
Nếu bạn quan sát kỹ đoạn mã trên, chúng ta đã khai báo một biến thuộc tính với tên coordinates. (Biến này sẽ được liên kết với Đối tượng đệm Vertex bằng phương thứcgetAttribLocation(). Thuộc tínhcoordinates được truyền dưới dạng một tham số cho phương thức này cùng với đối tượng chương trình đổ bóng.)
Trong bước thứ hai của chương trình đổ bóng đỉnh đã cho, gl_position biến được xác định.
gl_Position
gl_Position là biến được xác định trước chỉ có trong chương trình tô bóng đỉnh. Nó chứa vị trí đỉnh. Trong đoạn mã trên,coordinatesthuộc tính được chuyển dưới dạng một vector. Vì vertex shader là một hoạt động trên mỗi đỉnh, nên giá trị gl_position được tính cho mỗi đỉnh.
Sau đó, giá trị gl_position được sử dụng bởi lắp ráp nguyên thủy, cắt, chọn và các hoạt động chức năng cố định khác hoạt động trên nguyên thủy sau khi quá trình xử lý đỉnh kết thúc.
Chúng ta có thể viết các chương trình đổ bóng đỉnh cho tất cả các hoạt động có thể có của trình đổ bóng đỉnh, mà chúng ta sẽ thảo luận riêng trong hướng dẫn này.
Fragment Shader
A mesh được tạo thành bởi nhiều hình tam giác và bề mặt của mỗi hình tam giác được gọi là fragment. Trình đổ bóng phân mảnh là mã chạy trên mỗi pixel trên mỗi phân mảnh. Điều này được viết để tính toán và tô màu trên các pixel riêng lẻ. Các tác vụ sau có thể được thực hiện bằng cách sử dụng trình tạo bóng phân đoạn:
- Các phép toán trên các giá trị nội suy
- Quyền truy cập kết cấu
- Ứng dụng kết cấu
- Fog
- Tổng màu
Các biến được xác định trước
OpenGL ES SL cung cấp các biến được xác định trước sau đây cho trình tạo bóng phân đoạn:
Sr.No. | Biến & Mô tả |
---|---|
1 | trung gian vec4 gl_FragCoord; Giữ vị trí phân mảnh trong bộ đệm khung. |
2 | bool gl_FrontFacing; Giữ phân mảnh thuộc về nguyên thủy mặt trước. |
3 | mediump vec2 gl_PointCoord; Giữ vị trí phân mảnh trong một điểm (chỉ rasterization điểm). |
4 | mediump vec4 gl_FragColor; Giữ giá trị màu của mảnh đầu ra của bộ đổ bóng |
5 | mediump vec4 gl_FragData[n] Giữ màu phân mảnh để đính kèm màu n. |
Mã mẫu
Mã mẫu sau đây của trình tạo bóng phân mảnh cho thấy cách áp dụng màu cho mọi pixel trong một hình tam giác.
void main(void) {
gl_FragColor = vec4(0, 0.8, 0, 1);
}
Trong đoạn mã trên, colorgiá trị được lưu trữ trong biến gl.FragColor
. Chương trình đổ bóng phân mảnh chuyển đầu ra đến đường ống bằng cách sử dụng các biến hàm cố định; FragColor là một trong số đó. Biến này giữ giá trị màu của các pixel của mô hình.
Lưu trữ và biên dịch các chương trình Shader
Vì shader là những chương trình độc lập, chúng ta có thể viết chúng dưới dạng một script riêng biệt và sử dụng trong ứng dụng. Hoặc, bạn có thể lưu trữ chúng trực tiếp trongstring định dạng, như được hiển thị bên dưới.
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 0.0, 1.0);' +
'}';
Biên dịch Shader
Biên dịch bao gồm ba bước sau:
- Tạo đối tượng đổ bóng
- Đính kèm mã nguồn vào đối tượng đổ bóng đã tạo
- Biên soạn chương trình
Tạo Vertex Shader
Để tạo một bộ đổ bóng trống, WebGL cung cấp một phương thức được gọi là createShader(). Nó tạo và trả về đối tượng đổ bóng. Cú pháp của nó như sau:
Object createShader (enum type)
Như đã quan sát trong cú pháp, phương thức này chấp nhận một giá trị enum được xác định trước làm tham số. Chúng tôi có hai lựa chọn cho việc này -
gl.VERTEX_SHADER để tạo bóng đổ đỉnh
gl.FRAGMENT_SHADER để tạo bộ đổ bóng phân mảnh.
Gắn nguồn vào Shader
Bạn có thể đính kèm mã nguồn vào đối tượng đổ bóng đã tạo bằng phương pháp shaderSource(). Cú pháp của nó như sau:
void shaderSource(Object shader, string source)
Phương thức này chấp nhận hai tham số -
shader - Bạn phải truyền đối tượng đổ bóng đã tạo dưới dạng một tham số.
Source - Bạn phải truyền mã chương trình đổ bóng ở định dạng chuỗi.
Biên soạn chương trình
Để biên dịch chương trình, bạn phải sử dụng phương pháp compileShader(). Cú pháp của nó như sau:
compileShader(Object shader)
Phương thức này chấp nhận đối tượng chương trình đổ bóng như một tham số. Sau khi tạo một đối tượng chương trình đổ bóng, hãy đính kèm mã nguồn vào nó và chuyển đối tượng đó vào phương thức này.
Đoạn mã sau đây cho biết cách tạo và biên dịch bộ đổ bóng đỉnh cũng như bộ đổ bóng phân đoạn để tạo một hình tam giác.
// Vertex Shader
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
// Fragment Shader
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0, 0.8, 0, 1);' +
'}';
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
Chương trình kết hợp
Sau khi tạo và biên dịch cả hai chương trình đổ bóng, bạn cần tạo một chương trình kết hợp có chứa cả hai trình đổ bóng (đỉnh & đoạn). Các bước sau cần được thực hiện:
- Tạo một đối tượng chương trình
- Đính kèm cả hai bộ đổ bóng
- Liên kết cả hai bộ đổ bóng
- Sử dụng chương trình
Tạo một đối tượng chương trình
Tạo một đối tượng chương trình bằng phương pháp createProgram(). Nó sẽ trả về một đối tượng chương trình trống. Đây là cú pháp của nó -
createProgram();
Đính kèm Shader
Đính kèm các bộ đổ bóng vào đối tượng chương trình đã tạo bằng phương thức attachShader(). Cú pháp của nó như sau:
attachShader(Object program, Object shader);
Phương thức này chấp nhận hai tham số -
Program - Truyền đối tượng chương trình rỗng đã tạo dưới dạng một tham số.
Shader - Vượt qua một trong các chương trình đổ bóng đã biên dịch (trình đổ bóng đỉnh, trình đổ bóng phân mảnh)
Note - Bạn cần gắn cả hai shader bằng phương pháp này.
Liên kết các Shader
Liên kết các bộ đổ bóng bằng phương pháp này linkProgram(), bằng cách chuyển đối tượng chương trình mà bạn đã đính kèm các bộ đổ bóng. Cú pháp của nó như sau:
linkProgram(shaderProgram);
Sử dụng chương trình
WebGL cung cấp một phương thức được gọi là useProgram(). Bạn cần chuyển chương trình được liên kết tới nó. Cú pháp của nó như sau:
useProgram(shaderProgram);
Đoạn mã sau cho biết cách tạo, liên kết và sử dụng chương trình đổ bóng kết hợp.
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
Mỗi thuộc tính trong chương trình tô bóng đỉnh trỏ đến một đối tượng bộ đệm đỉnh. Sau khi tạo các đối tượng bộ đệm đỉnh, người lập trình phải liên kết chúng với các thuộc tính của chương trình đổ bóng đỉnh. Mỗi thuộc tính chỉ đến một đối tượng bộ đệm đỉnh mà từ đó chúng trích xuất các giá trị dữ liệu, sau đó các thuộc tính này được chuyển đến chương trình đổ bóng.
Để liên kết các đối tượng bộ đệm đỉnh với các thuộc tính của chương trình bộ tạo bóng đỉnh, bạn phải làm theo các bước dưới đây:
- Nhận vị trí thuộc tính
- Trỏ thuộc tính vào một đối tượng bộ đệm đỉnh
- Bật thuộc tính
Nhận vị trí thuộc tính
WebGL cung cấp một phương thức được gọi là getAttribLocation()trả về vị trí thuộc tính. Cú pháp của nó như sau:
ulong getAttribLocation(Object program, string name)
Phương thức này chấp nhận đối tượng chương trình tô bóng đỉnh và các giá trị thuộc tính của chương trình tô bóng đỉnh.
Đoạn mã sau đây cho biết cách sử dụng phương pháp này.
var coordinatesVar = gl.getAttribLocation(shader_program, "coordinates");
Đây, shader_program là đối tượng của chương trình đổ bóng và coordinates là thuộc tính của chương trình tô bóng đỉnh.
Trỏ thuộc tính vào VBO
Để gán đối tượng đệm cho biến thuộc tính, WebGL cung cấp một phương thức được gọi là vertexAttribPointer(). Đây là cú pháp của phương thức này:
void vertexAttribPointer(location, int size, enum type, bool normalized, long stride, long offset)
Phương thức này chấp nhận sáu tham số và chúng được thảo luận bên dưới.
Location- Nó chỉ định vị trí lưu trữ của một biến thuộc tính. Theo tùy chọn này, bạn phải chuyển giá trị được trả về bởigetAttribLocation() phương pháp.
Size - Nó chỉ định số lượng thành phần trên mỗi đỉnh trong đối tượng đệm.
Type - Nó chỉ định kiểu dữ liệu.
Normalized- Đây là một giá trị Boolean. Nếu đúng, dữ liệu không thả nổi được chuẩn hóa thành [0, 1]; khác, nó được chuẩn hóa thành [-1, 1].
Stride - Nó chỉ định số byte giữa các phần tử dữ liệu đỉnh khác nhau, hoặc số không cho sải chân mặc định.
Offset- Nó chỉ định độ lệch (tính bằng byte) trong đối tượng đệm để cho biết dữ liệu đỉnh được lưu trữ từ byte nào. Nếu dữ liệu được lưu trữ từ đầu, offset là 0.
Đoạn mã sau đây cho biết cách sử dụng vertexAttribPointer() trong một chương trình -
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
Bật thuộc tính
Kích hoạt thuộc tính bộ đổ bóng đỉnh để truy cập đối tượng đệm trong bộ đổ bóng đỉnh. Đối với hoạt động này, WebGL cung cấpenableVertexAttribArray()phương pháp. Phương thức này chấp nhận vị trí của thuộc tính như một tham số. Đây là cách sử dụng phương pháp này trong một chương trình -
gl.enableVertexAttribArray(coordinatesVar);
Sau khi liên kết bộ đệm với các bộ đổ bóng, bước cuối cùng là vẽ các nguyên thủy cần thiết. WebGL cung cấp hai phương pháp cụ thể là,drawArrays() và drawElements() để vẽ mô hình.
drawArrays ()
drawArrays()là phương pháp được sử dụng để vẽ mô hình bằng cách sử dụng các đỉnh. Đây là cú pháp của nó -
void drawArrays(enum mode, int first, long count)
Phương thức này có ba tham số sau:
mode- Trong WebGL, các mô hình được vẽ bằng các kiểu nguyên thủy. Chế độ sử dụng, người lập trình phải chọn một trong những kiểu nguyên thủy do WebGL cung cấp. Các giá trị có thể có cho tùy chọn này là - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN và gl.TRIANGLES.
first- Tùy chọn này chỉ định phần tử bắt đầu trong các mảng đã bật. Nó không thể là một giá trị âm.
count - Tùy chọn này chỉ định số lượng phần tử được hiển thị.
Nếu bạn vẽ một mô hình bằng cách sử dụng drawArrays() , sau đó WebGL, trong khi hiển thị các hình dạng, tạo ra hình học theo thứ tự tọa độ đỉnh được xác định.
Thí dụ
Nếu bạn muốn vẽ một hình tam giác bằng cách sử dụng drawArray() , sau đó bạn phải vượt qua ba đỉnh và gọi drawArrays() như hình dưới đây.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 3);
Nó sẽ tạo ra một hình tam giác như hình dưới đây.
Giả sử bạn muốn vẽ các tam giác liền kề, thì bạn phải vượt qua ba đỉnh tiếp theo theo thứ tự trong bộ đệm đỉnh và đề cập đến số phần tử sẽ được hiển thị là 6.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5, 0.0,-0.5, 0.25,0.5, 0.5,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 6);
Nó sẽ tạo ra một tam giác tiếp giáp như hình dưới đây.
drawElements ()
drawElements()là phương pháp được sử dụng để vẽ các mô hình bằng cách sử dụng các đỉnh và chỉ số. Cú pháp của nó như sau:
void drawElements(enum mode, long count, enum type, long offset)
Phương thức này có bốn tham số sau:
mode- Các mô hình WebGL được vẽ bằng các kiểu nguyên thủy. Chế độ sử dụng, người lập trình phải chọn một trong những kiểu nguyên thủy do WebGL cung cấp. Danh sách các giá trị có thể có cho tùy chọn này là - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN và gl.TRIANGLES.
count - Tùy chọn này chỉ định số lượng phần tử được hiển thị.
type - Tùy chọn này chỉ định kiểu dữ liệu của các chỉ số phải là UNSIGNED_BYTE hoặc UNSIGNED_SHORT.
offset- Tùy chọn này chỉ định điểm bắt đầu để kết xuất. Nó thường là phần tử đầu tiên (0).
Nếu bạn vẽ một mô hình bằng cách sử dụng drawElements()thì đối tượng đệm chỉ mục cũng nên được tạo cùng với đối tượng đệm đỉnh. Nếu bạn sử dụng phương pháp này, dữ liệu đỉnh sẽ được xử lý một lần và sử dụng nhiều lần như đã đề cập trong các chỉ số.
Thí dụ
Nếu bạn muốn vẽ một tam giác duy nhất bằng cách sử dụng các chỉ số, bạn cần chuyển các chỉ số cùng với các đỉnh và gọi drawElements() như hình dưới đây.
var vertices = [ -0.5,-0.5,0.0, -0.25,0.5,0.0, 0.0,-0.5,0.0 ];
var indices = [0,1,2];
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Nó sẽ tạo ra kết quả sau:
Nếu bạn muốn vẽ các hình tam giác lây nhiễm bằng cách sử dụng drawElements() , chỉ cần thêm các đỉnh khác và đề cập đến các chỉ số cho các đỉnh còn lại.
var vertices = [
-0.5,-0.5,0.0,
-0.25,0.5,0.0,
0.0,-0.5,0.0,
0.25,0.5,0.0,
0.5,-0.5,0.0
];
var indices = [0,1,2,2,3,4];
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Nó sẽ tạo ra kết quả sau:
Hoạt động bắt buộc
Trước khi vẽ sơ đồ, bạn cần thực hiện một số thao tác, được giải thích dưới đây.
Xóa Canvas
Trước hết, bạn nên xóa canvas, sử dụng clearColor()phương pháp. Bạn có thể chuyển các giá trị RGBA của một màu mong muốn làm tham số cho phương thức này. Sau đó, WebGL xóa canvas và tô nó bằng màu được chỉ định. Do đó, bạn có thể sử dụng phương pháp này để thiết lập màu nền.
Hãy xem ví dụ sau. Ở đây chúng tôi đang chuyển giá trị RGBA của màu xám.
gl.clearColor(0.5, 0.5, .5, 1);
Bật kiểm tra độ sâu
Bật kiểm tra độ sâu bằng cách sử dụng enable() như hình dưới đây.
gl.enable(gl.DEPTH_TEST);
Xóa bit đệm màu
Xóa màu cũng như vùng đệm độ sâu bằng cách sử dụng clear() như hình dưới đây.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Đặt cổng xem
Cổng khung nhìn đại diện cho một vùng có thể xem hình chữ nhật chứa kết quả hiển thị của bộ đệm bản vẽ. Bạn có thể đặt kích thước của cổng xem bằng cách sử dụngviewport()phương pháp. Trong đoạn mã sau, kích thước cổng xem được đặt thành kích thước canvas.
gl.viewport(0,0,canvas.width,canvas.height);
Chúng ta đã thảo luận trước đó (trong Chương 5) cách làm theo quy trình từng bước để vẽ một nguyên thủy. Chúng tôi đã giải thích quy trình trong năm bước. Bạn cần lặp lại các bước này mỗi khi vẽ một hình mới. Chương này giải thích cách vẽ điểm với tọa độ 3D trong WebGL. Trước khi tiến xa hơn, chúng ta hãy xem xét năm bước.
Các bước bắt buộc
Các bước sau là bắt buộc để tạo một ứng dụng WebGL để vẽ điểm.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Trong bước này, chúng ta có được đối tượng ngữ cảnh Kết xuất WebGL bằng phương pháp getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Vì chúng tôi đang vẽ ba điểm, chúng tôi xác định ba đỉnh với tọa độ 3D và lưu trữ chúng trong bộ đệm.
var vertices = [
-0.5,0.5,0.0,
0.0,0.5,0.0,
-0.25,0.25,0.0,
];
Step 3 − Create and Compile the Shader Programs
Trong bước này, bạn cần viết các chương trình đổ bóng đỉnh và đổ bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Vertex Shader - Trong bộ đổ bóng đỉnh của ví dụ đã cho, chúng tôi xác định một thuộc tính vectơ để lưu trữ các tọa độ 3D và gán nó cho gl_position Biến đổi.
gl_pointsizelà biến được sử dụng để gán kích thước cho điểm. Chúng tôi chỉ định kích thước điểm là 10.
var vertCode = 'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
Fragment Shader - Trong trình đổ bóng phân mảnh, chúng ta chỉ cần gán màu phân mảnh cho gl_FragColor Biến đổi
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
Trong bước này, chúng tôi liên kết các đối tượng đệm với chương trình đổ bóng.
Step 5 − Drawing the Required Object
Chúng tôi sử dụng phương pháp drawArrays()để vẽ điểm. Vì số điểm chúng ta muốn vẽ là ba nên giá trị đếm là 3.
gl.drawArrays(gl.POINTS, 0, 3)
Ví dụ - Vẽ ba điểm bằng cách sử dụng WebGL
Đây là chương trình WebGL hoàn chỉnh để rút ra ba điểm -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*================Creating a canvas=================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*==========Defining and storing the geometry=======*/
var vertices = [
-0.5,0.5,0.0,
0.0,0.5,0.0,
-0.25,0.25,0.0,
];
// Create an empty buffer object to store the vertex buffer
var vertex_buffer = gl.createBuffer();
//Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*=========================Shaders========================*/
// vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======== Associating shaders to buffer objects ========*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============= Drawing the primitive ===============*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.POINTS, 0, 3);
</script>
</body>
</html>
Nó sẽ tạo ra kết quả sau:
Trong chương trước (Chương 11), chúng ta đã thảo luận về cách vẽ ba điểm bằng cách sử dụng WebGL. Trong Chương 5, chúng tôi đã lấy ứng dụng mẫu để chứng minh cách vẽ một hình tam giác. Trong cả hai ví dụ, chúng tôi đã vẽ các nguyên thủy chỉ sử dụng các đỉnh.
Để vẽ các hình dạng / lưới phức tạp hơn, chúng tôi cũng chuyển các chỉ số của một hình học, cùng với các đỉnh, cho các bóng đổ. Trong chương này, chúng ta sẽ xem cách vẽ một tam giác bằng cách sử dụng các chỉ số.
Các bước cần thiết để vẽ một tam giác
Các bước sau là bắt buộc để tạo ứng dụng WebGL để vẽ hình tam giác.
Step 1 − Prepare the Canvas and Get WebGL Rendering Context
Trong bước này, chúng ta có được đối tượng ngữ cảnh Kết xuất WebGL bằng cách sử dụng getContext().
Step 2 − Define the Geometry and Store it in Buffer Objects
Vì chúng ta đang vẽ một tam giác bằng cách sử dụng các chỉ số, chúng ta phải vượt qua ba đỉnh của tam giác, bao gồm các chỉ số và lưu trữ chúng trong bộ đệm.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
indices = [0,1,2];
Step 3 − Create and Compile the Shader Programs
Trong bước này, bạn cần viết các chương trình đổ bóng đỉnh và đổ bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Vertex Shader - Trong phần đổ bóng đỉnh của chương trình, chúng tôi xác định thuộc tính vector để lưu trữ tọa độ 3D và gán nó cho gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - Trong trình đổ bóng phân mảnh, chúng ta chỉ cần gán màu phân mảnh cho gl_FragColor Biến đổi.
var fragCode = 'void main(void) {' +
' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +
'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
Trong bước này, chúng tôi kết hợp các đối tượng đệm và chương trình đổ bóng.
Step 5 − Drawing the Required Object
Vì chúng tôi đang vẽ một hình tam giác bằng cách sử dụng các chỉ số, chúng tôi sẽ sử dụng drawElements()
. Đối với phương pháp này, chúng ta phải chuyển số chỉ số. Giá trị củaindices.length biểu thị số lượng chỉ số.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Ví dụ - Vẽ hình tam giác
Đoạn mã chương trình sau đây cho thấy cách vẽ một hình tam giác trong WebGL bằng cách sử dụng các chỉ số:
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============== Creating a canvas ====================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*======== Defining and storing the geometry ===========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
indices = [0,1,2];
// Create an empty buffer object to store vertex buffer
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object to store Index buffer
var Index_Buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
/*================ Shaders ====================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======= Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*=========Drawing the triangle===========*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Trong chương trước (Chương 12), chúng ta đã thảo luận về cách vẽ một tam giác bằng cách sử dụng WebGL. Ngoài hình tam giác, WebGL hỗ trợ nhiều chế độ vẽ khác. Chương này giải thích các chế độ vẽ được hỗ trợ bởi WebGL.
Thông số chế độ
Hãy cùng xem cú pháp của các phương thức: drawElements() và vẽ Arrays().
void drawElements(enum mode, long count, enum type, long offset);
void drawArrays(enum mode, int first, long count);
Nếu bạn quan sát rõ ràng, cả hai phương thức đều chấp nhận một tham số mode. Sử dụng tham số này, người lập trình có thể chọn chế độ vẽ trong WebGL.
Các chế độ vẽ do WebGL cung cấp được liệt kê trong bảng sau.
Sr.No. | Chế độ & Mô tả |
---|---|
1 | gl.POINTS Để vẽ một loạt các điểm. |
2 | gl.LINES Để vẽ một chuỗi các đoạn thẳng không nối (các đoạn riêng lẻ). |
3 | gl.LINE_STRIP Để vẽ một loạt các đoạn thẳng được kết nối. |
4 | gl.LINE_LOOP Để vẽ một loạt các đoạn thẳng được kết nối. Nó cũng nối các đỉnh đầu tiên và cuối cùng để tạo thành một vòng lặp. |
5 | gl.TRIANGLES Để vẽ một loạt các hình tam giác riêng biệt. |
6 | gl.TRIANGLE_STRIP Để vẽ một loạt các hình tam giác được kết nối trong thời trang dải. |
7 | gl.TRIANGLE_FAN Để vẽ một loạt các tam giác được kết nối có chung đỉnh đầu tiên theo kiểu hình quạt. |
Ví dụ - Vẽ ba đường song song
Ví dụ sau đây cho thấy cách vẽ ba đường thẳng song song bằng cách sử dụng gl.LINES.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*======= Creating a canvas =========*/
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
/*======= Defining and storing the geometry ======*/
var vertices = [
-0.7,-0.1,0,
-0.3,0.6,0,
-0.3,-0.3,0,
0.2,0.6,0,
0.3,-0.3,0,
0.7,0.6,0
]
// Create an empty buffer object
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*=================== Shaders ====================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// Fragment shader source code
var fragCode =
'void main(void) {' +
'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======= Associating shaders to buffer objects ======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============ Drawing the triangle =============*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.LINES, 0, 6);
// POINTS, LINE_STRIP, LINE_LOOP, LINES,
// TRIANGLE_STRIP,TRIANGLE_FAN, TRIANGLES
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Chế độ vẽ
Trong chương trình trên, nếu bạn thay thế chế độ của drawArrays() với một trong các chế độ vẽ sau, nó sẽ tạo ra các đầu ra khác nhau mỗi lần.
Chế độ vẽ | Kết quả đầu ra |
---|---|
LINE_STRIP |
|
LINE_LOOP |
|
TRIANGLE_STRIP |
|
TRIANGLE_FAN |
|
HÌNH TAM GIÁC |
|
Trong chương trước, chúng ta đã thảo luận về các chế độ vẽ khác nhau do WebGL cung cấp. Chúng tôi cũng có thể sử dụng các chỉ số để vẽ các nguyên thủy bằng một trong các chế độ này. Để vẽ các mô hình trong WebGL, chúng ta phải chọn một trong những nguyên thủy này và vẽ lưới bắt buộc (tức là, một mô hình được hình thành bằng cách sử dụng một hoặc nhiều nguyên thủy).
Trong chương này, chúng ta sẽ lấy một ví dụ minh họa cách vẽ một tứ giác bằng cách sử dụng WebGL.
Các bước để vẽ một tứ giác
Cần thực hiện các bước sau để tạo ứng dụng WebGL để vẽ một hình tứ giác.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Trong bước này, chúng ta có được đối tượng ngữ cảnh Kết xuất WebGL bằng cách sử dụng getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Một hình vuông có thể được vẽ bằng cách sử dụng hai hình tam giác. Trong ví dụ này, chúng tôi cung cấp các đỉnh cho hai tam giác (có một cạnh chung) và các chỉ số.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
indices = [3,2,1,3,1,0];
Step 3 − Create and Compile the Shader Programs
Trong bước này, bạn cần viết chương trình tô bóng đỉnh và tô bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Vertex Shader - Trong phần đổ bóng đỉnh của chương trình, chúng tôi xác định thuộc tính vector để lưu trữ tọa độ 3D và gán nó cho gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - Trong trình đổ bóng phân mảnh, chúng ta chỉ cần gán màu phân mảnh cho gl_FragColor Biến đổi.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(0.5, 0.3, 0.0, 7.5);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
Trong bước này, chúng tôi liên kết các đối tượng đệm với chương trình đổ bóng.
Step 5 − Drawing the Required Object
Vì chúng ta đang vẽ hai tam giác để tạo thành một tứ giác, sử dụng các chỉ số, chúng ta sẽ sử dụng phương pháp drawElements(). Đối với phương pháp này, chúng ta phải chuyển số chỉ số. Giá trị củaindices.length đưa ra số chỉ số.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Ví dụ - Vẽ một hình tứ giác
Chương trình sau đây trình bày cách tạo một ứng dụng WebGL để vẽ một hình tứ giác.
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============ Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry =========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
indices = [3,2,1,3,1,0];
// Create an empty buffer object to store vertex buffer
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object to store Index buffer
var Index_Buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
/*====================== Shaders =======================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// Fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* ======= Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============= Drawing the Quad ================*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Trong tất cả các ví dụ trước đây, chúng tôi đã áp dụng màu cho đối tượng bằng cách gán giá trị màu mong muốn cho gl_FragColorBiến đổi. Ngoài ra, chúng ta có thể xác định màu sắc cho mỗi đỉnh - giống như tọa độ đỉnh và chỉ số. Chương này lấy một ví dụ minh họa cách áp dụng màu sắc cho một hình tứ giác bằng cách sử dụng WebGL.
Áp dụng màu sắc
Để áp dụng màu, bạn phải xác định màu cho từng đỉnh bằng cách sử dụng các giá trị RGB, trong mảng JavaScript. Bạn có thể gán các giá trị giống nhau cho tất cả các đỉnh để có một màu duy nhất cho đối tượng. Sau khi xác định màu sắc, bạn phải tạo một bộ đệm màu và lưu trữ các giá trị này trong đó, đồng thời liên kết nó với các thuộc tính đổ bóng đỉnh.
Trong trình đổ bóng đỉnh, cùng với thuộc tính tọa độ (giữ vị trí của các đỉnh), chúng tôi xác định một attribute và một varying để xử lý màu sắc.
Các color thuộc tính giữ giá trị màu trên mỗi đỉnh và varyinglà biến được chuyển làm đầu vào cho bộ đổ bóng phân mảnh. Do đó, chúng ta phải chỉ địnhcolor có giá trị đối với varying.
Trong trình đổ bóng mảnh, varying giữ giá trị màu được gán cho gl_FragColor, giữ màu cuối cùng của đối tượng.
Các bước áp dụng màu sắc
Các bước sau là cần thiết để tạo một ứng dụng WebGL để vẽ một Quad và áp dụng màu sắc cho nó.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Trong bước này, chúng ta có được đối tượng ngữ cảnh Kết xuất WebGL bằng cách sử dụng getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Một hình vuông có thể được vẽ bằng cách sử dụng hai hình tam giác. Do đó, trong ví dụ này, chúng tôi cung cấp các đỉnh cho hai tam giác (có một cạnh chung) và các chỉ số. Vì chúng ta muốn áp dụng màu sắc cho nó, một biến chứa các giá trị màu cũng được xác định và các giá trị màu cho mỗi (Đỏ, Xanh lam, Xanh lục và Hồng) được gán cho nó.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [ 0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
Step 3 − Create and Compile the Shader Programs
Trong bước này, bạn cần viết chương trình tô bóng đỉnh và tô bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Vertex Shader- Trong phần đổ bóng đỉnh của chương trình, chúng ta xác định các thuộc tính vector để lưu trữ tọa độ 3D (vị trí), và màu sắc của mỗi đỉnh. Avaringbiến được khai báo để chuyển các giá trị màu từ bộ đổ bóng đỉnh sang bộ đổ bóng phân đoạn. Và cuối cùng, giá trị được lưu trữ trong thuộc tính color được gán chovarying.
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
Fragment Shader - Trong trình đổ bóng phân mảnh, chúng tôi chỉ định varying đến gl_FragColor Biến đổi.
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
Trong bước này, chúng tôi kết hợp các đối tượng đệm và chương trình đổ bóng.
Step 5 − Drawing the Required Object
Vì chúng tôi đang vẽ hai hình tam giác sẽ tạo thành một phần tư, bằng cách sử dụng các chỉ số, chúng tôi sẽ sử dụng phương pháp drawElements(). Đối với phương pháp này, chúng ta phải chuyển số chỉ số. Giá trị củaindices.length cho biết số lượng chỉ số.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Ví dụ - Áp dụng màu
Chương trình sau đây trình bày cách vẽ một quad bằng ứng dụng WebGL và áp dụng màu sắc cho nó.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas ==================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry ==========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
// Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object and store Index data
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// Create an empty buffer object and store color data
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
/*======================= Shaders =======================*/
// vertex shader source code
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* ======== Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
// bind the color buffer
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
// get the attribute location
var color = gl.getAttribLocation(shaderProgram, "color");
// point attribute to the volor buffer object
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// enable the color attribute
gl.enableVertexAttribArray(color);
/*============Drawing the Quad====================*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
//Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Cho đến nay, chúng ta đã thảo luận về cách vẽ các hình dạng khác nhau và áp dụng màu sắc cho chúng bằng cách sử dụng WebGL. Ở đây, trong chương này, chúng tôi sẽ lấy một ví dụ để chỉ ra cách dịch một tam giác.
Dịch
Bản dịch là một trong những affine transformationsdo WebGL cung cấp. Sử dụng phép tịnh tiến, chúng ta có thể di chuyển một tam giác (bất kỳ đối tượng nào) trên mặt phẳng xyz. Giả sử chúng ta có một tam giác [a, b, c] và chúng ta muốn di chuyển tam giác đến một vị trí cách trục X dương 5 đơn vị và 3 đơn vị đối với trục Y dương. Khi đó các đỉnh mới sẽ là [a + 5, b + 3, c + 0]. Điều đó có nghĩa là, để dịch tam giác, chúng ta cần thêm các khoảng cách tịnh tiến, giả sử, tx, ty, tz cho mỗi đỉnh.
Vì nó là một per-vertex operation, chúng ta có thể mang nó trong chương trình đổ bóng đỉnh.
Trong bộ đổ bóng đỉnh, cùng với thuộc tính, coordinates(giữ các vị trí đỉnh), chúng tôi xác định một biến đồng nhất chứa các khoảng cách tịnh tiến (x, y, z). Sau đó, chúng tôi thêm biến thống nhất này vào biến tọa độ và gán kết quả chogl_Position Biến đổi.
Note - Vì vertex shader sẽ được chạy trên mỗi đỉnh, nên tất cả các đỉnh của tam giác sẽ được dịch.
Các bước để dịch một tam giác
Các bước sau là cần thiết để tạo ứng dụng WebGL để vẽ một hình tam giác và sau đó dịch nó sang vị trí mới.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Trong bước này, chúng ta có được đối tượng ngữ cảnh Kết xuất WebGL bằng cách sử dụng getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Vì chúng ta đang vẽ một tam giác, chúng ta phải đi qua ba đỉnh của tam giác và lưu chúng trong bộ đệm.
var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];
Step 3 − Create and Compile the Shader Programs
Trong bước này, bạn cần viết chương trình tô bóng đỉnh và tô bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Vertex Shader- Trong phần đổ bóng đỉnh của chương trình, chúng ta xác định một thuộc tính vector để lưu trữ tọa độ 3D. Cùng với nó, chúng tôi xác định một biến thống nhất để lưu trữ khoảng cách dịch và cuối cùng, chúng tôi thêm hai giá trị này và gán nó chogl_position mà giữ vị trí cuối cùng của các đỉnh.
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
Fragment Shader - Trong bộ đổ bóng phân mảnh, chúng ta chỉ cần gán màu phân mảnh cho biến gl_FragColor.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
Trong bước này, chúng tôi liên kết các đối tượng đệm với chương trình đổ bóng.
Step 5 − Drawing the Required Object
Vì chúng tôi đang vẽ tam giác bằng cách sử dụng các chỉ số, chúng tôi sẽ sử dụng phương pháp drawArrays(). Đối với phương pháp này, chúng ta phải truyền số lượng đỉnh / phần tử được xem xét. Vì chúng ta đang vẽ một tam giác, chúng ta sẽ chuyển 3 làm tham số.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Ví dụ - Dịch một Tam giác
Ví dụ sau đây cho thấy cách tịnh tiến một tam giác trên mặt phẳng xyz.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
//Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
//Create a new buffer
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//bind it to the current buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Pass the buffer data
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*========================Shaders============================*/
//vertex shader source code
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
//Create a vertex shader program object and compile it
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
//Create a fragment shader program object and compile it
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//Create and use combiened shader program
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
/* ===========Associating shaders to buffer objects============*/
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coordinatesVar);
/* ==========translation======================================*/
var Tx = 0.5, Ty = 0.5, Tz = 0.0;
var translation = gl.getUniformLocation(shaderProgram, 'translation');
gl.uniform4f(translation, Tx, Ty, Tz, 0.0);
/*=================Drawing the riangle and transforming it========================*/
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Trong chương này, chúng tôi sẽ lấy một ví dụ để chứng minh cách sửa đổi tỷ lệ của một tam giác bằng cách sử dụng WebGL.
Mở rộng quy mô
Chia tỷ lệ không là gì khác ngoài việc tăng hoặc giảm kích thước của một đối tượng. Ví dụ, nếu một tam giác có các đỉnh có kích thước là [a, b, c], thì tam giác có các đỉnh [2a, 2b, 2c] sẽ có kích thước gấp đôi kích thước của nó. Do đó, để chia tỷ lệ một tam giác, bạn phải nhân mỗi đỉnh với hệ số tỷ lệ. Bạn cũng có thể chia tỷ lệ một đỉnh cụ thể.
Để chia tỷ lệ một tam giác, trong bộ đổ bóng đỉnh của chương trình, chúng ta tạo một ma trận đồng nhất và nhân các giá trị tọa độ với ma trận này. Sau đó, chúng ta chuyển một ma trận đường chéo 4 × 4 có hệ số tỷ lệ của tọa độ x, y, z ở các vị trí đường chéo (vị trí đường chéo cuối cùng 1).
Các bước bắt buộc
Các bước sau là cần thiết để tạo một ứng dụng WebGL để chia tỷ lệ một tam giác.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
Trong bước này, chúng ta có được đối tượng ngữ cảnh Kết xuất WebGL bằng cách sử dụng getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Vì chúng ta đang vẽ một tam giác, chúng ta phải đi qua ba đỉnh của tam giác và lưu chúng trong bộ đệm.
var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];
Step 3 − Create and Compile the Shader Programs
Trong bước này, bạn cần viết chương trình tô bóng đỉnh và tô bóng phân mảnh, biên dịch chúng và tạo một chương trình kết hợp bằng cách liên kết hai chương trình này.
Vertex Shader- Trong phần đổ bóng đỉnh của chương trình, chúng ta xác định một thuộc tính vector để lưu trữ tọa độ 3D. Cùng với nó, chúng tôi xác định một ma trận thống nhất để lưu trữ các hệ số tỷ lệ và cuối cùng, chúng tôi nhân hai giá trị này và gán nó chogl_position mà giữ vị trí cuối cùng của các đỉnh.
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
Fragment Shader - Trong trình đổ bóng phân mảnh, chúng ta chỉ cần gán màu phân mảnh cho gl_FragColor Biến đổi.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
Trong bước này, chúng tôi liên kết các đối tượng đệm với chương trình đổ bóng.
Step 5 − Drawing the Required Object
Vì chúng tôi đang vẽ tam giác bằng cách sử dụng các chỉ số, chúng tôi sử dụng drawArrays()phương pháp. Đối với phương pháp này, chúng ta phải truyền số lượng đỉnh / phần tử được xem xét. Vì chúng ta đang vẽ một tam giác, chúng ta sẽ chuyển 3 làm tham số.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Ví dụ - Quy mô hình tam giác
Ví dụ sau đây cho thấy cách chia tỷ lệ một tam giác:
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
//Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*========================Shaders============================*/
//Vertex shader source code
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
//Create a vertex shader program object and compile it
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
//Create a fragment shader program object and compile it
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//Create and use combiened shader program
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
/*===================scaling==========================*/
var Sx = 1.0, Sy = 1.5, Sz = 1.0;
var xformMatrix = new Float32Array([
Sx, 0.0, 0.0, 0.0,
0.0, Sy, 0.0, 0.0,
0.0, 0.0, Sz, 0.0,
0.0, 0.0, 0.0, 1.0
]);
var u_xformMatrix = gl.getUniformLocation(shaderProgram, 'u_xformMatrix');
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);
/* ===========Associating shaders to buffer objects============*/
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coordinatesVar);
/*=================Drawing the Quad========================*/
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Trong chương này, chúng tôi sẽ lấy một ví dụ để minh họa cách xoay một hình tam giác bằng cách sử dụng WebGL.
Ví dụ - Xoay tam giác
Chương trình sau đây cho thấy cách xoay một hình tam giác bằng cách sử dụng WebGL.
<!doctype html>
<html>
<body>
<canvas width = "400" height = "400" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [ -1,-1,-1, 1,-1,-1, 1, 1,-1 ];
var colors = [ 1,1,1, 1,1,1, 1,1,1 ];
var indices = [ 0,1,2 ];
//Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
//Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*==========================Shaders=========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/*===========associating attributes to vertex shader ============*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ; //position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ; //color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*========================= MATRIX ========================= */
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
//translating z
view_matrix[14] = view_matrix[14]-6; //zoom
/*=======================rotation========================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1] = c*m[1]+s*mv0;
m[5] = c*m[5]+s*mv4;
m[9] = c*m[9]+s*mv8;
}
/*=================Drawing===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.002);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Trong chương này, chúng tôi sẽ lấy một ví dụ để minh họa cách vẽ một khối 3D xoay bằng cách sử dụng WebGL.
Ví dụ - Vẽ một khối 3D xoay
Chương trình sau đây hướng dẫn cách vẽ một khối 3D xoay -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*============ Defining and storing the geometry =========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== Shaders =========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/* ====== Associating attributes to vertex shader =====*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ;
// Position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// Color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*==================== MATRIX =====================*/
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
// translating z
view_matrix[14] = view_matrix[14]-6;//zoom
/*==================== Rotation ====================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1]=c*m[1]+s*mv0;
m[5]=c*m[5]+s*mv4;
m[9]=c*m[9]+s*mv8;
}
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*================= Drawing ===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.005);//time
rotateY(mov_matrix, dt*0.002);
rotateX(mov_matrix, dt*0.003);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau:
Trong chương này, chúng tôi sẽ lấy một ví dụ để minh họa cách vẽ một hình khối 3D có thể xoay bằng cách sử dụng điều khiển chuột.
Ví dụ - Vẽ một khối tương tác
Chương trình sau đây cho thấy cách xoay một khối bằng cách sử dụng các điều khiển chuột:
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas ======================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry ==========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== SHADERS =================== */
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderprogram = gl.createProgram();
gl.attachShader(shaderprogram, vertShader);
gl.attachShader(shaderprogram, fragShader);
gl.linkProgram(shaderprogram);
/*======== Associating attributes to vertex shader =====*/
var _Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
var _Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
var _Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var _position = gl.getAttribLocation(shaderprogram, "position");
gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(_position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var _color = gl.getAttribLocation(shaderprogram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderprogram);
/*==================== MATRIX ====================== */
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mo_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
var view_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
view_matrix[14] = view_matrix[14]-6;
/*================= Mouse events ======================*/
var AMORTIZATION = 0.95;
var drag = false;
var old_x, old_y;
var dX = 0, dY = 0;
var mouseDown = function(e) {
drag = true;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
return false;
};
var mouseUp = function(e){
drag = false;
};
var mouseMove = function(e) {
if (!drag) return false;
dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
THETA+= dX;
PHI+=dY;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
};
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mouseup", mouseUp, false);
canvas.addEventListener("mouseout", mouseUp, false);
canvas.addEventListener("mousemove", mouseMove, false);
/*=========================rotation================*/
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*=================== Drawing =================== */
var THETA = 0,
PHI = 0;
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
if (!drag) {
dX *= AMORTIZATION, dY*=AMORTIZATION;
THETA+=dX, PHI+=dY;
}
//set model matrix to I4
mo_matrix[0] = 1, mo_matrix[1] = 0, mo_matrix[2] = 0,
mo_matrix[3] = 0,
mo_matrix[4] = 0, mo_matrix[5] = 1, mo_matrix[6] = 0,
mo_matrix[7] = 0,
mo_matrix[8] = 0, mo_matrix[9] = 0, mo_matrix[10] = 1,
mo_matrix[11] = 0,
mo_matrix[12] = 0, mo_matrix[13] = 0, mo_matrix[14] = 0,
mo_matrix[15] = 1;
rotateY(mo_matrix, THETA);
rotateX(mo_matrix, PHI);
time_old = time;
gl.enable(gl.DEPTH_TEST);
// gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Nếu bạn chạy ví dụ này, nó sẽ tạo ra kết quả sau: