Phần 1: Các khái niệm cơ bản của thế giới 3D
Phần 2: Đi xâu vào Opengles 2.0
Phần 3: Kỹ năng trong Opengl es2.0 và đồ họa 2D nâng cao
Vì vậy, nếu bạn quan tâm đến các đoạn mã thì nhảy đến phần 2/3, bởi vì trong này đầu tiên tôi sẽ chỉ nói về các khái niệm, không có gì nhiều.
- TỔNG QUAN
Bạn đã bao giờ nghe nói về Opengl chưa? Opengl là Open Graphics Labary và nó được sử dụng rất nhiều trong các ngôn ngữ lập trình. Opengl là điểm gần nhất giữa CPU và GPU (Bộ xử lý đồ họa, nó tồn tại trong tất cả các card đồ họa máy tính). Vì vậy Opengl cần được hỗ trợ bởi các nhà cung cấp card đồ họa (NVIDIA) và được cài đặt bởi các nhà cung cấp hệ điều hành (Như Android - HĐH android, Apple - HĐH IOS...) và cuối cùng Opengl tới chúng ta, các nhà phát triển, 1 API thống nhất để làm việc. Các API này hoàn toàn miễn phí, điều này là rất tuyệt vời. Bởi vì nếu bạn sử dụng C/C++, ObjectiveC,....Java..bất cứ ngôn ngữ nào APIs đều tương thích. Nó đều đem lại các hoạt động tương tự như nhau, cùng chức năng, cùng lệnh, ....
- MỘT CÂU CHUYỆN NHỎ
Khoảng 20 năm trước có 1 người tên là Silicon Graphics (SGI) đã làm 1 loạt các thiết bị. Các thiết bị đó có thể thể hiện 1 ảnh ảo của thực tế trong thế giới hình ảnh 2D. Thiết bị này còn thể hiện hình ảnh 3D, mô phỏng các nhìn và chiều sâu của mắt người. Thiết bị này gọi là IrisGL (Có lẽ thiết bị này bởi vì nó sẽ cố gắng để mô phỏng mống mắt của mắt).
Vâng thiết bị trên là thư viện đồ họa vĩ đại đầu tiên. Nhưng nó biến mất rất nhanh, bởi vì để thực hiện những gì mà nó làm thì cần phải điều khiển nhiều thứ trong CPU như card đồ họa, hệ thống Windows, ngôn ngữ ...Nó là quá nhiều để 1 công ty quản lý. Vì vậy SGI để lại một số thứ như "Tạo ra card đồ họa", "Quản lý windows." ...cho các công ty khác và SGI tập chung vào phần quan trọng nhất của thư viện đồ họa. Trong năm 1992 khởi chạy lần đầu tiên.
Trong năm 1995 Microsoft phát hành Direct3D, đối thủ cạnh tranh của OpenGL
Và năm 1997 Opengl 1.1 ra đời. Nhưng thực sự thú vì là năm 2004 với sự ra đời của OpengL 2.0 với nhiều thay đổi lớn, Shaders, Programable Pipeline.
Vào năm 2007 chúng ta gặp được Opengl es2.0 nó mang đến cho chúng ta sức mạnh thực sự của Shaders, Programable pipeline và hệ thống nhúng(Embedded Systems).
- ĐỐI THỦ LỚN NHẤT CỦA OPENGL
Ta nói về Microsoft Windows. Bạn nhớ lại rằng Opengl ra đời 1992, tại thời điểm đó Microsoft có window 3.1. Vâng MS tin rằng không có gì được tạo ra, mọi thứ được sao chép. MS cố gắng sao chép tất cả của Opengl và họ có Direct3D và giới thiệt nó vào năm 1995 trên Windows 95.
Một năm sau đó 1996. MS giới thiệu Direct3D là 1 bản sao đen của Opengl, ưu điểm lại là MS thống trị thị trường thông tin trong nhiều năm liền, và Direct3D đã có được lợi thế và nó lây lan như là bệnh dịch của máy tính. và sau đố MS cung cấp các hệ điều hành cho Mobile và các trò chơi, tất nhiên là đi cùng với Direct3D.
Ngày nay Direct3D tương tự như Opengl. Có HLSL, cũng có programable pipeline, và fixed pipeline, và thậm chí các tên Hàm cũng tương tự. Nhưng sự khác biệt rất lớn là OpengL là mã nguồn mở, còn Direct3D thì không. Opengl dành cho mọi hệ điều hành, trong khi Direct chỉ WDow.
Bây giờ chúng ta tiếp tục tìm hiểu thế giới 3 D nhé:
- THẾ GIỚI 3D
FIRT POINT - THE EYE
Chúng ta đều say mê thế giới ảo 3D, từ hình tượng con người, nhân vật,... nhưng câu chuyện ly kỳ của thế giới ảo tất cả những thứ đó đều được mô phỏng trong thế giới 3D. Và chúng ta cảm nhận được chính là mắt chúng ta.
Mắt là cơ sở của tất cả mọi thứ trong thế giới 3D. Tất cả những gì mà chúng ta làm là mô phỏng sức mạnh, vẻ đẹp và sự kỳ diệu của mắt con người. Trong bài này tôi không muốn nói về mắt con người nhưng nó sẽ là rất tốt nếu bạn sử dụng các khái niệm như thấu kính, camera,...điều này có thể giúp bạn hiểu thêm 1 số khái niệm.
Mọi thứ chúng ta làm là tái tại lại cảm giác từ mắt con người, như cái nhìn, độ sâu ảnh,....tất cả đều mô tả cảm giác tới từ mắt.
SECOND POINT - THE THIRD DIMENSION
Điều này nghe có vẻ điên rồ nhưng nó lại rất cần thiết khi ta nói đến thế giới 3D bởi vì thế giới 3D là 3 chiều. Điều này rất rõ ràng,
Trong thế giới 2D chúng ta cần xoay 1 hình vuông thì rất đơn giản. nhưng trong thế giới 3D để xoay 1 hình vuông đòi hỏi phải xoay X, Y hoặc Z nữa. Tùy thuộc vào thứ tự mà người xoay xoay, kết quả cuối cùng hoàn toàn khác nhau. Mọi thứ tồi tệ hơn khi chúng ta thực hiện nhiều phép quay. VD: Xoay x=25độ, y=20 là 1 chuyện nhưng xoay x=15, y=20 rồi sau đó xoay x=10 lại là 1 chuyện khác hoàn toàn.
Vâng ở đây muốn nói lên rằng khi bổ xung thêm 1 chiều Z thì khối lượng công việc lớn hơn rất nhiều.
THIRD POINT - IT IS NOT 3D ...IT'S OFTEN 4D
Thêm 1 chiều??
Vâng điểm cuối cùng mà ta phải nói chính là nó. Thường chúng ta không chỉ làm việc trong thế giới 3D. Chúng ta có 1 chiều thứ 4 đó chính là thời gian. Những điều trong thế giới 3D cần để tương tác, cần di chuyển, cần phải đẩy nhanh, cần va chạm...Như chúng ta đã nói trước đây khi thực hiện nhiều công việc thì thực sự khó khăn nâng lên gấp nhiều lân.
OK! Đến đây chúng ta đã hiểu thế giới 3D "Mô phỏng của mắt người và di chuyển mọi thứ"
- OPENGL TRONG THẾ GIỚI 3D
Bây giờ trong phần này sẽ thú vị hơn. Chúng ta hãy nói về Opengl là 1 công cụ thật tuyệt vời, Trước tiên chúng ta cần phải cảm ơn các nhà toán học lớn như EULER, HAMINTON, PYTHAGORAS, DECART...nhờ họ mà ngày nay chúng ta đã vận dụng rất nhiều các công thức vào trong thế giới 3D. OPENGL vận dụng tất cả các kiến thức này để xây dựng thế giới 3D. Ngay trước mắt chúng ta có hàng ngàn thậm chí hàng triệu hoạt động trong 1 giây, cùng với nó là rất nhiều công thức được vận dụng.
Để tưởng tượng Opengl là gì chúng ta hãy tưởng tượng 1 cảng lớn có chứa rất nhiều thùng bên trong. Opengl là toàn bộ những gì trong đó.
- Container là đối tượng của Opengl (Texture, shader, mắt lới và các loại công cụ)
- Những gì bên trong các container là những gì chúng ta đã tạo ra trong các ứng dụng bằng cách sử dụng Opengl .
- Cầu cẳng là APIs của Opengl cho phép chúng ta sử dụng.
Bạn không cần phải truy cập trực tiếp nó. Bạn không thể nhìn thấy và thay đổi nội dung của container. bạn không thể làm bất cứ điều gì trực tiếp các container tại cảng. Tât cả những gì bạn có thể làm là cẩu. Cẩu là công cụ duy nhất giúp bạn quản lý các container.
Có vẻ như API rất hạn chế sử dụng. Nhưng thực sự không phải vậy. Cần cẩu của Opengl là 1 thứ rất mạnh mẽ, Nó có thể lặp lại nhiều sử lý và dữ, thả container hàng triệu thùng...mỗi giây. Một lợi thế lớn của Opengl là sử dụng State machine pattern là chúng ta không cần phải giữ bất kỳ trường hợp nào chúng ta không cần phải tạo ra đối tượng trực tiếp. chúng ta chỉ cần phải dữ trên các ID, hay nói cách khác chúng ta chỉ cần phải nhận dạng Container.
- OPENGL LÀM VIỆC NHƯ THẾ NÀO
Ta đi xâu vào trong lõi Opengl việc tính toán được thực hiện trực tiếp tại GPU sử dụng tăng tốc phần cứng tới các điểm floating.CPU là bộ sử lý của máy tính hoặc thiêt bị. GPU là card đồ họa của máy tính hoặc thiết bị. Card đồ họa đi kèm để làm giảm bớt tính toán của vi xử lý của máy, nó có thể tính toán và đối phó với rất nhiều tính toán hình ảnh và đưa nội dung hình ra bên ngoài.
Vì vậy những gì mà Opengl thực hiện là để khối lượng tính toán cho GPU thay vì tất cả các tính toán đó cho CPU. GPU thực hiện nhanh hơn nhiều so với CPU trong việc tính toán floating point. Điều này giải thích lý do tại sao 1 trò chơi 3D có card đồ họa tốt thì game đó sẽ chạy nhanh hơn. Điều này thậm chí là lý do 1 phần mềm 3D chuyên nghiệp giúp cho bạn tùy chọn làm việc với "Software's Render" (CPU xử lý) hoặc "Graphics card's Render" (CPU xử lý). vài phần mềm cũng cho bạn tùy chọn xử lý của OPENGL như bạn đã biết tùy chọn này là (GPU xử lý).
Vì vậy Opengl làm việc hoàn toàn trong GPU.
Chỉ cần 1 xử lý hình ảnh khó và vài thứ khác, Opengl đưa ra cho chúng ta nhiều tính năng để lưu trữ hình ảnh, dữ liệu thông tin và 1 định dạng được tối ưu. Những dữ liệu tối ưu này sẽ được xử lý sau bởi GPU.
Vì vậy là Opengl phụ thuộc phần cứng???
Thật không may! Nếu phần cứng không hỗ trợ Opengl (Graphics card), chúng ta không thể sử dụng nó.
Phiên bản mới của Opengl cần các tính năng của GPU mới. Điều này là 1 cái gì đó để ta biết nhưng đừng bận tâm với nó. Như Opengl luôn luôn cần sự cài đặt của nhà cung cấp. Chúng ta (Developer) sẽ làm việc trên phiên bản mới của Opengl khi thiết bị đã sẵn sàng cho nó.
Trong thực tế, bây giờ tất cả các máy tính đều hỗ trợ cài đặt Opengl. Vì vậy bạn có thể sử dụng Opengl với nhiều ngôn ngữ và các thiết bị khác nhau. Thậm chí cả MS.
- LOGIC CỦA OPENGL
Opengl là 1 thư viện đồ họa rất ngắn gọn và xúc tích.Những gì mà bạn có thể nhìn thấy trong phần mềm 3D chuyên nghiệp là 1 siêu công việc cực kỳ phức tạp trên Opengl. Bởi vì bên trong logic của Opengl nhận thức 1 số thứ như sau:
- Primitives
- Buffers
- Rasterize
Opengl chỉ làm việc xung quanh 3 khái niệm trên, Bạn hãy xem các khái niệm độc lập và làm thế nào để 3 thứ trên làm việc tạo ra thư viện đồ họa 3D tiên tiến nhất.
- PRIMITIVES
Opengl's Primitives là giới hạn loại nhỏ của các đối tượng:
- Về một điểm 3D trong không gian (X, Y, Z)
- Về 1 đường thẳng trong không gian(Bao gồm bởi 2 điểm 3D)
- Về 1 hình tam giác 3D trong không gian (Bao gồm 3 điểm)
1 Điểm 3D được sử dụng như 1 phần tử trong không gian
1 Đường thẳng 3D được sử dụng giống như 3 Vector 3D
1 Tam giác 3D có thể là 1 mặt, có thể là hàng triệu mặt trong 1 mesh. Một số version Opengl cũng hỗ trợ square mà cũng chỉ đơn thuần là các phần của Triangle tạo thành, Với Opengles thì phải đạt hiệu xuất tối đa nên SQUARE không hỗ trợ.
- BUFFERS
Bây giờ hãy nói về buffers. Trong 1 từ đơn giản, Buffer là một nơi lưu trữ đã tối ưu hóa tạm thời, lưu trữ cho rất nhiều stuffs.
Opengl làm việc với 3 loại Buffers
- Frame Buffers
- Render buffers
- Buffer Objects
RENDER BUFFER là 1 nơi lưu trữ tạm thời của 1 ảnh đơng giản. Bây giờ bạn có thể nhìn thấy rõ hơn 1 FrameBuffer là 1 tập hợp các Renderbuffers. Tồn tại vài loại Render Buffer như Màu, Độ xâu, mẫu tô...
Color Render Buffer được lưu trữ hình ảnh màu cuối cùng được tạo ra bởi Opengl's Render.
Color Render Buffer là 1 hình ảnh có màu RGB.
Depth Render Buffer lưu trữ thông tin độ xâu cuối cùng của Z của các đối tượng. Nếu bạn quen thuộc các phần mền 3D bạn đã biết những gì là hình ảnh độ xâu Z, Nó là 1 hình ảnh màu xám tỉ lệ về vị trí của Z của các Objects trong 3D Space. Trong đó độ trắng hoàn toàn đại diện cho đối tượng gần nhất có thể nhìn thấy. Và màu đen miêu tả các đối tượng ở rất xa (coi như không thấy)
Buffer Render Stencil là nhận thức về phần thấy của đối tượng. GIống như mặt nạ phần có thể nhìn thấy. Stencil Render Buffer là một image màu đen và trắng.
BUFFER OBJECTS: là 1 nơi lưu trữ mà Opengl gọi là: "Server-side" (KHông gian địa chỉ của máy chủ). Buffer objects là 1 nơi lưu trữ tạm thời, nhưng nó không phải tạm thời giống những Buffer khác. Một Buffer Object có thể tồn tại trong suốt quá trình thực thi của ứng dụng. Buffer Object có thể dữ các thông tin về đối tượng 3D trong 1 định dạng tối ưu. Những thông tin này có thể 2 kiểu là : Structures hoặc Indicates
Structures là mảng trong đó mô tả đối tượng 3D, giống như 1 mảng các đỉnh, một mảng các tọa độ texture, hoặc mảng bất cứ gì bạn muốn,
Indicates thì chi tiết cụ thể hơn. Mảng của các chỉ số được sử dụng để cho biết bao mặt của lưới của bạn sẽ được xây dựng dựa trên một mảng của cấu trúc.
OK! Hãy nhìn ví dụ:
HÌnh cube bên dưới, có 6 mặt, bao gồm 8 đỉnh.
Mỗi mặt là 1 hình vuông. Nhưng bạn đã biết Opengles chỉ biết về hình tam giác. Vì vậy chúng ta phải chuyển nó thành hình tam giác để làm việc với Opengl. Khi chúng ta làm điều này thì 6 mặt bây giờ thành 12 mặt.
Hình tam giác trong Opengl là 1 kết hợp của 3 đỉnh 3D. Vì vậy để xây dựng mặt trước của cube thì ta cần hướng dẫn Opengl cách này: {vertex 1, vertex2, vertex 3}, {vertex 1, vertex 3, vertex 4}
Nói cách khác chúng ta cần lặp lại 2 đỉnh tại từng mặt của cube. Điều này rất là tồi tệ nếu MESH của chúng ta ngôi sao 5 cách thì chúng ta lặp lại thông tin 4 đỉnh. Nếu là 1 Hexangle chúng ta cần phải lặp lại thông tin 6 đỉnh. ........rất nhiều.
Vì vậy Opengl cung cấp cho chúng ta một cách làm việc với điều đó dễ dàng hơn bởi MẢNG CÁC CHỈ SỐ.
Trong ví dụ trên chúng ta có 1 mảng 8 đỉnh. (vertex1,....vertex8) và thay vì viết lại thông tin những đỉnh này ở mỗi mặt của cube. chúng ta giới thiệu mảng các chỉ số {0,1,2, 0,2,3, 2,6,3,2,5,6....}sự kết hợp của 3 thành phần trong mảng sẽ tạo nên 1 mặt của hình tam giác. Với tính năng này, chúng ta có thể ghi thông tin đỉnh của một lần và tái sử dụng nó nhiều lần trong các mảng của các chỉ số.
Ưu điểm lớn của Buffer Object là chúng được tối ưu để làm việc trực tiếp trong bộ xử lý GPU, và bạn không cần phải nắm giữ các mảng này trog ứng dụng nữa sau khi tạo xong bufer object.
- RASTERIZE
The Rasterize là quá trình mà Opengl mất tất cả các thông tin về đối tượng 3D. (Các tọa độ, vertices, toán học....). để tạo ra hình ảnh 2D, Hình ảnh này sẽ chịu một số thay đổi và sau đó nó hiển thị trên màn hình thiết bị.Nhưng bước cuối cùng này, là cầu nối giữa các thông tin pixel và màn hình thiết bị, nó là trách nhiệm của nhà cung cấp. Tập đoàn Khronos cung cấp API gọi là EGL, nhưng ở đây nhà cung cấp có thể can thiệp vào. Chúng ta không làm việc trực tiếp với Khronos EGL, nhưng với phiên bản sửa đổi của nhà cung cấp.
Vì vậy khi bạn làm 1 Opengl Render bạn có thể vẽ trực tiếp vào màn hình. Sử dụng cài đặt EGL của nhà cung cấp. hoặc Render tới 1 frame Buffer. Rendering tới frame buffer bạn vẫn trong API của Opengl nhưng nội dung sẽ không thây được trên màn hình thiết bị. Ra trực tiếp đến màn hình của thiết bị, bạn đi ra ngoài API OpenGL và nhập API EGL. Vì vậy, tại thời gian render, bạn có thể chọn một trong cả hai đầu ra.
Nhưng đừng lo lắng về điều này bây giờ, như tôi đã nói, mỗi nhà cung cấp thực hiện của riêng của họ EGL API. Apple, ví dụ, không cho phép bạn render trực tiếp đến màn hình của thiết bị, bạn luôn cần phải trả cho một bộ đệm khung hình và sau đó sử dụng thực hiện EGL của Apple để trình bày các nội dung trên màn hình của thiết bị.
- ĐƯỜNG ỐNG CỦA OPENGL
Như đã nói ở trên "Programable pipeline" và "Fixed Pipeline"Programable Pipeline là các thư viện đồ họa ủy thác cho chúng ta, người phát triển, chịu trách nhiệm tới mọi thứ như CAMERA, ÁNH SÁNG, VẬT LIỆU , CÁC HIỆU ỨNG....và chúng ta có thể thực hiện điều này với Shader Language nổi tiếng. Vì vây bất kỳ lúc nào bạn nghe về Programable Pipeline thì bạn nghĩ ngay đến Shader Language.
Shaders giống như những mẩu code. chỉ giống các chương trình nhỏ, làm việc trực tiếp trong GPU để thực hiện các tính toán phức tạp. phức tạp như màu điểm của 1 bề mặt mà có 1 texture T. Modify bởi 1 TB bump texture. với cách sử dụng 1 màu SC phản chiếu với SL mức độ phản xạ dưới một ánh sáng L với LP sức mạnh của ánh sáng.....................Và tất cả những điều này, nhìn thấy bởi con mắt của CAMERA nằm ở vị trí P. với ống kính chiếu T.
Dù điều này có nghĩa là gì, nó rất phức tạp xử lý bởi CPU, và rất phức tạp tới thư viện đồ họa vì vậy mà Programable pipeline chỉ là chúng ta quả lý vấn đề này.
Nó là nghịch đảo! The FIxed Pipeline là Thư viện đồ họa chăm sóc về loại mà tất cả những thứ và cho chúng ta một API để thiết lập Camera, vật liệu, ánh sáng và các hiệu ứng.
Để tạo các Shader chúng ta sử dụng một ngôn ngữ tương tự như C, chúng ta sử dụng OpenGL Shader Language (GLSL). OpenGL ES sử dụng một phiên bản ít nghiêm ngặt hơn được gọi là Ngôn ngữ OpenGL ES Shader (còn được gọi là GLSL ES hoặc ESSL). Sự khác biệt là bạn có chức năng cố định hơn và có thể viết các biến trong GLSL hơn trong GLSL ES, nhưng sintax là như nhau.
- VERTEX SHADER
Vertex shader còn gọi là VS hay VSH, là một chương trình nhỏ được thực thi tại mỗi đỉnh của mesh (mắt lưới).Hãy nhìn cube ở trên. hình này có 8 đỉnh, trong hình này thì đỉnh 5 là không thể thấy được. Vì vậy cube sẽ sử lý 8 lần bởi GPU.
Những gì vertex shader sẽ thực hiện là định nghĩa vị trí cuối cùng của 1 vertex. Bạn có nhớ rằng đường ống dẫn lập trình đã để lại cho chúng ta chịu trách nhiệm bởi máy ảnh? Vì vậy, bây giờ là lúc ta thực hiện!
Vị trí và ống kính của 1 máy ảnh có thể can thiệp (interfere) vào vị trí cuối cùng của 1 đỉnh (Vertex). Vertex Shader cũng chịu trách nhiệm chuẩn bị và đưa ra vài biết tới fragment Shader. Trong Opengl chúng ta định nghĩa biến trong Vertex Shader nhưng không đến trực tiếp fragment Shader. Bởi vì biến của chúng ta phải đi qua Vertex Shader.
Nhưng tại sao chúng ta không thể truy cập vào fragmet shader trực tiếp? Vâng chúng ta hãy xem FSH và chúng ta sẽ hiểu
- FRAGMENT SHADER
Chúng ta hãy xem lại hình ảnh ở trênBạn thấy đỉnh 5 là không thể thấy được? điều này bởi vì tại vị trí cụ thể và việc quay được chỉ rõ, chúng ta chỉ thấy được 3 mặt và 3 mặt này, bao gồm 7 đỉnh.
Điều này là những gì Fragment Shader. FSH sẽ được sử lý tại mỗi đoạn có thể thấy được hình ảnh cuối cùng. Ở đây bạn có thể hiểu fragment giống như 1 pixel, nhưng normally thì không chính xác là 1 pixel, bởi vì giữa render của OpenGL và trình bày các hình ảnh cuối cùng trên màn hình của thiết bị có thể kéo dài. Vì vậy, một fragment shader có thể dẫn đến ít hơn một điểm ảnh thực sự hoặc nhiều hơn một điểm ảnh thực sự, tùy thuộc vào các thiết bị và cấu hình render. Trong khối lập phương trên, Shader Fragment sẽ được xử lý tại mỗi điểm ảnh đó ba mặt có thể nhìn thấy được hình thành bởi 7 đỉnh.
Bên trong Shader Fragment, chúng ta sẽ làm việc với tất cả mọi thứ liên quan đến bề mặt lưới, giống như vật liệu, hiệu ứng bump, đổ bóng và các hiệu ứng ánh sáng, phản xạ, khúc xạ, kết cấu và các loại khác của hiệu ứng mà chúng ta muốn. Kết quả cuối cùng để các Shader Fragment là một màu pixel trong RGBA định dạng.
Bây giờ, điều cuối cùng bạn cần phải biết về việc làm thế nào VSH và FSH làm việc cùng nhau. Bắt buộc một Vertex Shader tới 1 Shader Fragment, không có nhiều hơn hoặc ít hơn, phải được chính xác MỘT - MỘT. Để đảm bảo chúng sẽ không làm cho những sai lầm, OpenGL có một cái gì đó Chương trình được gọi là. Một chương trình trong OpenGL chỉ là cặp biên dịch của VSH và FSH. Chỉ cần nó, không có gì nhiều.
--------------------------------------FINISH PART ONE----------------------------------------------
Nguồn: http://db-in.com translated by: Lighting
Cứ khó hiểu cái vertex và fragment, đọc xong mới hiểu một chút
Trả lờiXóa