Upload
chung-bao-nguyen
View
375
Download
0
Embed Size (px)
Citation preview
Lập trình đồ họa trên Java 2D và 3D
Phần 1 ............................................................................................................................. 9 Lập trình đồ họa với Java 2D .......................................................................................... 9
Chương 1 .................................................................................................................. 10 Tổng quan về Java 2D API ....................................................................................... 10
1.1 Enhanced Graphics, Text, and imaging .......................................................... 10 1.2 Rendering Model ............................................................................................ 11
1.2.1 Coordinate Systems ................................................................................. 12 1.2.1.1 User Space ....................................................................................... 12 1.2.1.2 Device Space .................................................................................... 13
1.2.2 Transforms ............................................................................................... 14 1.2.3 Fonts ........................................................................................................ 15 1.2.4 Images ...................................................................................................... 16 1.2.5 Fills and Strokes ....................................................................................... 17 1.2.6 Composites ............................................................................................... 18
Backward Compatibility and Platform independence .......................................... 19 1.3.1 Backward Compatibility .......................................................................... 19 1.3.2 Platform independence ............................................................................ 21
1.4 The Java 2D™ API Packages ......................................................................... 21 Chương 2: ................................................................................................................. 25 Rendering with Graphics2D ..................................................................................... 25
2.1 Các lớp và giao diện. ...................................................................................... 26 2.2 Rendering Concepts ........................................................................................ 27
2.2.1 Rendering Process .................................................................................... 28 2.2.2 Controlling Rendering Quality ................................................................ 29 2.2.3 Stroke Attributes ...................................................................................... 31 2.2.4 Fill Attributes ........................................................................................... 32
Quá trình xử lý theo phiên ............................................................................ 34 2.2.5 Clipping Paths .......................................................................................... 34 2.2.6 Transformations ....................................................................................... 35
2.2.6.1 Constructing an AffineTransform .................................................... 37 2.2.7 Composite Attributes ............................................................................... 38
2.2.7.1 Managing Transparency .................................................................. 39 2.2.7.2 Transparency and images ................................................................. 40
2.3 Thiết lập Graphics2Context ............................................................................ 40 2.3.1 Setting Rendering Hints ........................................................................... 40 2.3.2 Specifying Stroke Attributes .................................................................... 41
2.3.2.1 Setting the Stroke Width .................................................................. 41 2.3.2.2 Specifying Join and Endcap Styles .................................................. 42 2.3.2.3 Setting the Dashing Pattern .............................................................. 42
2.3.3 Specifying Fill Attributes ......................................................................... 44 2.3.3.1 Filling a Shape with a Gradient ....................................................... 44 2.3.3.2 Filling a Shape with a Texture ......................................................... 45
2.3.4 Setting the Clipping Path ......................................................................... 46 2.3.5 Setting the Graphics2D Transform .......................................................... 48 2.3.6 Specifying a Composition Style .............................................................. 51
2.3.6.1 Using the Source Over Compositing Rule ....................................... 51 2.3.6.2 Increasing the Transparency of Composited Objects ...................... 51
2.4 Rendering Graphics Primitives ....................................................................... 53 2.4.1 Drawing a Shape ...................................................................................... 53 2.4.2 Filling a Shape ......................................................................................... 55
http://tailieuhay.com 1
Lập trình đồ họa trên Java 2D và 3D
2.4.3 Rendering Text ........................................................................................ 56 2.4.4 Rendering images .................................................................................... 56
2.5 Defining Custom Composition Rules ............................................................. 56 2.6 Rendering in a Multi-Screen Environment ..................................................... 57
Chương 3 .................................................................................................................. 75 Các đối tượng hình họa ............................................................................................. 75
3.1 Giao diện và lớp. ............................................................................................. 75 3.2 Các khái niệm hình học: ................................................................................. 78
3.2.1 Constructive Area Geometry ................................................................... 79 3.2.2 Bounds and Hit Testing ........................................................................... 80
3.3 Combining Areas to Create New Shapes ........................................................ 88 Chương 4: ................................................................................................................. 94 Hiển thị Font và văn bản ........................................................................................... 94
4.1.Giao diện và lớp. ............................................................................................. 94 4.2.Các khái niệm về Font .................................................................................... 96 4.3 Các khái niệm về Text Layout. ....................................................................... 98
4.3.1 Vẽ chữ. ..................................................................................................... 99 4.3.2 Ordering Text ......................................................................................... 101 4.3.3 Đo và định vị văn bản ............................................................................ 103 4.3.4 Hỗ trợ thao tác với văn bản. ................................................................... 104
4.3.4.1 Hiển thị dấu nhắc ............................................................................ 104 4.3.4.2 Di chuyển dấu nhắc. ....................................................................... 106 4.3.4.3 Hit Testing ..................................................................................... 107 4.3.4.4 Đánh dấu vùng lựa chọn. ............................................................... 108
4.3.5 Thực thi việc hiển thị văn bản trong ứng dụng Java™ . ........................ 109 Quản lý việc hiển thị văn bản. ............................................................................ 110
4.4.1 Trình bày văn bản. ................................................................................. 111 Hiển thị dấu nhắc kép. .................................................................................... 112 4.4.3 Di chuyển dấu nhắc. ............................................................................... 113 4.4.4 Hit Testing ............................................................................................. 114 4.4.5 Đánh dấu vùng lựa chọn. ....................................................................... 115 4.4.6 Querying Layout Metrics ....................................................................... 115 4.4.7 Vẽ văn bản trên nhiều dòng. .................................................................. 116
Chương 5 ................................................................................................................ 126 Tạo ảnh ....................................................................................................................... 126
5.1 Các giao diện và các lớp .......................................................................... 126 5.1.1 Các giao diện imaging (imaging interfaces) ......................................... 127 5.1.2 Các lớp dữ liệu ảnh(image Data Classes) .............................................. 127 5.1.3 image Operation Classes ........................................................................ 129 5.1.4 Sample Model Classes ........................................................................... 130 Color Model Classes ....................................................................................... 131 5.1.6 Exception Classes .................................................................................. 132
5.2 Immediate Mode imaging Concepts ............................................................. 133 5.2.1 Terminology ........................................................................................... 135
5.3 Using Bufferedimages .................................................................................. 136 5.3.1 Creating a Bufferedimage ...................................................................... 136 5.3.2 Drawing in an Offscreen Buffer ............................................................ 137
5.3.2.1 Creating an Offscreen Buffer ......................................................... 138 5.3.2.2 Drawing in an Offscreen Buffer .................................................... 140
5.3.3 Manipulating Bufferedimage Data Directly .......................................... 141
http://tailieuhay.com 2
Lập trình đồ họa trên Java 2D và 3D
5.3.4 Filtering a Bufferedimage ...................................................................... 142 5.3.5 Rendering a Bufferedimage .................................................................. 142
5.4 Managing and Manipulating Rasters ............................................................ 150 5.4.1 Creating a Raster .................................................................................... 150 5.4.2 Parent and Child Rasters ........................................................................ 151 5.4.4 The WritableRaster Subclass ................................................................. 151
5.5 Image Data and DataBuffers ......................................................................... 152 5.6 Extracting Pixel Data from a SampleModel ................................................. 153 5.7 ColorModels and Color Data ........................................................................ 154
5.7.1 Lookup Table ......................................................................................... 155 5.8 image Processing and Enhancement ............................................................. 155
5.8.1 Using an image Processing Operation ................................................... 158 Chương 6 ................................................................................................................ 162 Mầu sắc ................................................................................................................... 162
6.1 Các lớp ......................................................................................................... 163 6.2 Những định nghĩa về mầu sắc. ...................................................................... 163
6.2.1 Không gian mầu .................................................................................... 164 6.2.1 Biểu diễn màu ....................................................................................... 167
Chương 7 ............................................................................................................... 171 In ấn ........................................................................................................................ 171
7.1 Các giao diện và các lớp ............................................................................... 171 7.2.1 Supporting Printing ................................................................................ 174
7.2.1.1 Điều khiển in (Job Control) ........................................................... 174 7.2.2 Page Painters .......................................................................................... 175 7.2.3 Printable Jobs and Pageable Jobs ........................................................... 177
7.2.4 Typical Life-Cycle of a PrinterJob ................................................................ 178 7.3 Printing with Printables ................................................................................ 181
7.3.2 Printing a File ......................................................................................... 185 7.4.1 Using a Pageable Job ............................................................................. 191 7.4.2 Using Multiple Page Painters ................................................................ 193
Phần 2 ......................................................................................................................... 206 Lập trình đồ họa với Java 3D ...................................................................................... 206
CHƯƠNG 1 ............................................................................................................ 207 NHẬP MÔN LẬP TRÌNH TRÊN JAVA 3D ......................................................... 207
1.1 Tổng quan về Java 3D API ™ ...................................................................... 207 1.2 Các vấn đề cơ bản về Java 3D API™ .......................................................... 208 1.3 Xây dựng đồ thị khung cảnh ......................................................................... 208
1.3.1 Thừa kế cấp cao từ Java 3D API .......................................................... 214 1.4 Cách thức để viết một chương trình Java 3D .................................................... 216
1.4.1 Công thức đơn giản để viết một chương trình Java 3D ........................ 216 1.5 Một vài thuật ngữ trong Java 3D ................................................................. 221 1.6 Ví dụ đơn giản: HelloJava3Da ..................................................................... 223 1.6.1 Các lớp của Java 3D Classes được sử dụng trong HelloJava3Da .............. 229
Tạo nên hình lập phương có kích thước được định ra bởi các giá trị cho trước. .... 233 1.7 Quay hình lập phương ................................................................................. 233
1.7.1 Sự kết hợp của các phép biến hình: HelloJava3Db ............................... 235 1.8 Khả năng và hoạt động ................................................................................. 236
1.8.1 Dịch các nội dung .................................................................................. 236 1.8.2 Khả năng ............................................................................................... 237
1.9 Thêm vào các hành vi animation .................................................................. 239
http://tailieuhay.com 3
Lập trình đồ họa trên Java 2D và 3D
1.9.1 Định nghĩa các hành vi animation ......................................................... 240 1.9.2 Các hàm biến đổi về thời gian: Ánh xạ một hành vi với thời gian ........ 241 1.9.3 Lập danh mục các vùng ......................................................................... 242 1.9.4 Ví dụ về hành vi: HelloJava3Dc ........................................................... 243 1.9.5 Phép biến hình và kết hợp các hành vi .Ví dụ: HelloJava3Dd ............. 246
CHƯƠNG 2 ............................................................................................................ 251 Tạo các hình ............................................................................................................ 251
2.1 Hệ tọa độ thế giới ảo ..................................................................................... 251 2.2 Visual Object Definition Basics ................................................................... 252
2.2.1 An Instance of Shape3D Defines a Visual Object ................................ 252 2.2.2 Node Components .................................................................................. 254 2.2.3 Defining Visual Object Classes ............................................................. 255
2.3 Các lớp tiện ích hình học ............................................................................. 256 2.3.1 Box ......................................................................................................... 257 2.3.2 Cone ...................................................................................................... 259 2.3.3 Cylinder ................................................................................................. 259 2.3.4 Sphere .................................................................................................... 260 2.3.5 More About Geometric Primitives ........................................................ 261 2.3.6 ColorCube ............................................................................................. 261 2.3.7 Example: Creating a Simple Yo-Yo From Two Cones ........................ 261
2.4 Các lớp toán học ........................................................................................... 267 2.4.1 Point Classes ............................................................................................. 271
2.4.2 Color Classes ......................................................................................... 272 2.4.3 Vector Classes ........................................................................................ 274 2.4.4 TexCoord Classes .................................................................................. 275
2.5 Các lớp hình học ........................................................................................... 276 2.5.1 GeometryArray Class ........................................................................... 277 2.5.2 Subclasses of GeometryArray .............................................................. 284 2.5.3 Subclasses of GeometryStripArray ........................................................ 286 2.5.4 Subclasses of IndexedGeometryArray ................................................... 293 2.5.5 Axis.java is an Example of IndexedGeometryArray ............................ 296
2.6 Appearance and Attributes ............................................................................ 296 2.6.1 Appearance NodeComponent ................................................................ 298 2.6.2 Sharing NodeComponent Objects ........................................................ 298 2.6.3 Attribute Classes ................................................................................... 299 2.6.4 Example: Back Face Culling ................................................................ 310
2.7 Bounds and Scope ........................................................................................ 320 2.7.1 Bounds Node Components ................................................................... 321 2.7.2 BoundingLeafa Node ............................................................................ 325 2.7.3 Scope ...................................................................................................... 327
2.8 Hình học nâng cao ........................................................................................ 329 2.8.1 Multiple Geometries in a Single Shape3D ........................................... 329 2.8.2 GeometryArray ..................................................................................... 332 2.8.4 AlternateAppearance <new in 1.2> ...................................................... 340
2.9 Clipping – Cắt xén ........................................................................................ 343 2.9.1 View Defines a Frustum ........................................................................ 343 2.9.2 Clip Node .............................................................................................. 345 2.9.4 ModelClip Example .............................................................................. 346
CHƯƠNG 3 ............................................................................................................ 350 TẠO NỘI DUNG .................................................................................................... 350
http://tailieuhay.com 4
Lập trình đồ họa trên Java 2D và 3D
3.1 Nội dung chính .............................................................................................. 350 3.1.1 GeometryInfo ......................................................................................... 351
3.2.1 Một ví dụ đơn giản về GeometryInfo ........................................................ 351 3.2.2 Sử dụng GeometryInfo .......................................................................... 352 3.2.3 Một số lớp thông dụng có liên quan đến GeometryInfo ........................ 353
Loaders ................................................................................................................ 358 Một ví dụ đơn giản sử dụng leader. ................................................................ 359
Các loader phổ biến ........................................................................................... 360 3.3.3 Giao diện của gói Loader và lớp cơ sở ............................................... 361
Viết một loader ................................................................................................... 365 Công việc của một loader ............................................................................... 365 Hàm tạo lớp Loader ........................................................................................ 366 Viết một File Loader đơn giản ........................................................................ 368
Text2D ................................................................................................................ 379 3.5.1 Ví dụ Text2D đơn giản .......................................................................... 380 3.5.2 Lớp Text2D ............................................................................................ 380
Text3D ................................................................................................................ 382 Một ví dụ Text3D ........................................................................................... 382 Những lớp liên quan để tạo ra đối tượng Text3D ........................................... 384
Nền không gian đồ họa ...................................................................................... 391 Một ví dụ background ..................................................................................... 391 Lớp Background ............................................................................................. 392
CHƯƠNG 4 ............................................................................................................ 396 TƯƠNG TÁC ......................................................................................................... 396
4.1 Hành vi: Cơ sở của tương tác và hoạt hình ................................................... 397 4.1.1 Ứng dụng của hành vi ............................................................................ 397 4.1.2 Tổng quan lớp Behaviour ...................................................................... 399
4.2 Cơ bản về hành vi ......................................................................................... 399 4.2.1 Viết một lớp Behaviour ......................................................................... 400 4.2.2 Sử dụng một lớp Behaviour ................................................................... 405 4.2.3 Các hàm API trong lớp Behaviour ......................................................... 409
4.3 Điều kiện kích hoạt: Cách kích hoạt các hành vi .......................................... 412 4.3.1 Điều kiện kích hoạt ................................................................................ 413 4.3.2 WakeupCriterion .................................................................................... 414 4.3.3 Quy định lớp WakeupCriterion ............................................................. 414 4.3.4 Thành phần của WakeupCondition ....................................................... 430
4.4 Lớp Behaviour tiện ích xử lý bàn phím ........................................................ 432 4.4.1 Một ví dụ đơn giản ................................................................................. 433 4.4.2 Lớp KeyNavigatorBehaviour và KeyNavigator .................................. 435
4.5 Lớp tiện ích tương tác với chuột ................................................................... 437 4.5.1 Sử dụng lớp MouseBehaviour .............................................................. 437 4.5.2 Mouse Behaviour Foundation ................................................................ 442 4.5.3 Các lớp MouseBehaviour ..................................................................... 444 4.5.4 Mouse Navigation .................................................................................. 447
4.6 Picking Object ............................................................................................... 450 4.6.1 Using Picking Utility Classes ................................................................ 454 4.6.2 Các hàm API cơ bản trong các lớp Picking .......................................... 458 4.6.3 Các lớp picking ...................................................................................... 467 4.6.4 Các lớp Picking Behavior ..................................................................... 471
CHƯƠNG 5 ............................................................................................................ 474
http://tailieuhay.com 5
Lập trình đồ họa trên Java 2D và 3D
Hoạt Hình ................................................................................................................ 474 Animation - Hoạt hình: ....................................................................................... 476 Đối tượng Interpolator và Alpha với hoạt ảnh dựa thời gian ............................. 477 Alpha ................................................................................................................... 477 Sử dụng các đối tượng Interpolator và Alpha: ................................................... 480 Ví dụ sử dụng lớp Alpha và RotationInterpolator: ............................................. 480 Alpha API: .......................................................................................................... 486 Các lớp hành vi Interpolator : ............................................................................. 489 Core Interpolator API: ....................................................................................... 504 Các lớp đối tượng nội suy đường: ...................................................................... 513
Lớp Billboard : ........................................................................................................ 522 Sử dụng đối tượng Billboard ............................................................................. 523 Chương trình ví dụ sử dụng Billboard ............................................................... 525 Giao diện lập trình ứng dụng của Billboard (Billboard API) ........................... 529 OrientedShape3D ................................................................................................ 531 Giao diện lập trình ứng dụng của OrientedShape3D .......................................... 532 Ví dụ sử dụng OrientedShape3D ........................................................................ 533 Hoạt ảnh mức chi tiết (Level Of Detail Animations) ......................................... 535 Sử dụng đối tượng DistanceLOD ....................................................................... 536
Các lỗi thường gặp khi sử dụng LOD ............................................................ 537 Ví dụ sử dụng DistanceLOD .............................................................................. 537 Giao diện lập trình ứng dụng DistanceLOD API ............................................... 544 Morph ................................................................................................................. 545 Sử dụng đối tượng Morph .................................................................................. 546 Ví dụ sử dụng Morph ......................................................................................... 547 Giao diện lập trình ứng dụng Morph API .......................................................... 553
Giao diện GeometryUpdater ................................................................................... 554 Sử dụng GeometryUpdater ................................................................................. 555 Chương trình ví dụ hệ thống phân tử đài phun nước sử dụng GeometryUpdater ............................................................................................................................ 556
Lời nói đầu
Sự phát triển của khoa học, kĩ thuật, nghệ thuật, kinh doanh, và
công nghệ luôn luôn phụ thuộc vào khả năng truyền đạt thông tin của
chúng ta, hoặc thông qua các bit dữ liệu lưu trữ trong microchip hoặc
thông qua giao tiếp bằng tiếng nói. Câu châm ngôn từ xa xưa “một hình
ảnh có giá trị hơn cả vạn lời" hay "trăm nghe không bằng một thấy" cho
thấy ý nghĩa rất lớn của hình ảnh trong việc chuyển tải thông tin. Hình
ảnh bao giờ cũng được cảm nhận nhanh và dễ dàng hơn, đặc biệt là trong
trường hợp bất đồng về ngôn ngữ. Do đó không có gì ngạc nhiên khi mà
ngay từ khi xuất hiện máy tính, các nhà nghiên cứu đã cố gắng sử dụng
nó để phát sinh các ảnh trên màn hình. Trong suốt gần 50 năm phát triển
http://tailieuhay.com 6
Lập trình đồ họa trên Java 2D và 3D
của máy tính, khả năng phát sinh hình ảnh bằng máy tính của chúng ta đã
đạt tới mức mà bây giờ hầu như tất cả các máy tính đều có khả năng đồ
họa.Đồ họa máy tính là một trong những lĩnh vực lí thú nhất và phát triển
nhanh nhất của tin học. Ngay từ khi xuất hiện, đồ họa máy tính đã có sức
lôi cuốn mãnh liệt, cuốn hút rất nhiều người ở nhiều lĩnh vực khác nhau
như khoa học, nghệ thuật, kinh doanh, quản lí, ... Tính hấp dẫn và đa dạng
của đồ họa máy tính có thể được minh họa rất trực quan thông qua việc
khảo sát các ứng dụng của nó.
Ngày nay, đồ họa máy tính được sử dụng trong rất nhiều lĩnh vực
khác nhau như công nghiệp, thương mại, quản lí, giáo dục, giải trí, … Số
lượng các chương trình đồ họa ứng dụng thật khổng lồ và phát triển liên
tục.Trong lĩnh vực công nghiệp,CAD(computer-aided design) đã được sử
dụng hầu hết trong việc thiết kế các cao ốc, ô tô, máy bay, tàu thủy, tàu vũ
trụ, máy tính,…Trong lĩnh vực giải trí,nghệ thuật, đồ họa máy tính giúp ta
tạo ra các chương trình trò chơi,các kĩ xảo điện ảnh cho các nhà làm
phim,hay ngay chính giao diện đồ họa đã làm nâng cao khả năng giao tiếp
giữa người và máy tính.
Để có thể làm được những ứng dụng đồ họa hữu ích cho cuộc
sống,trước hết chúng ta cần phải có một nền tảng vững chắc về lập trình
đồ họa.Có rất nhiều ngôn ngữ hỗ trợ lập trình đồ họa máy tính,mỗi ngôn
ngữ được xây dưng trên những thư viện đồ họa riêng,có những thế mạnh
riêng.Và khi nói về lập trình đồ họa,chúng ta không thể không nói đến
ngôn ngữ Java,một ngôn ngữ rất mạnh trong lĩnh vực này.Với mục đích
nghiên cứu,tìm hiểu và mang đến cho những ai muốn tìm hiều về lập trình
đồ họa một tài liệu thiết thực,nhóm chúng em đã chọn đề tài làm tutorial
về lập trình đồ họa trên nền tảng ngôn ngữ lâp trình Java,dựa trên các tài
liệu training trên mạng của hãng Sun.Vì là lần đầu làm tài liệu tham khảo
http://tailieuhay.com 7
Lập trình đồ họa trên Java 2D và 3D
nên chúng em không tránh khỏi sai sót.Chúng em mong thầy xem xét và
góp ý cho tài liệu này.Chúng em chân thành cảm ơn.
http://tailieuhay.com 8
Lập trình đồ họa trên Java 2D và 3D
Phần 1
Lập trình đồ họa với Java 2D
http://tailieuhay.com 9
Lập trình đồ họa trên Java 2D và 3D
Chương 1
Tổng quan về Java 2D API
Java 2D™ API tăng cường về khả năng đồ hoạ, văn bản và ảnh của
Abstract Windowing Toolkit (AWT), giúp phát triển về giao diện người
sủ dụng và ứng dụng về JAVA trong một số lĩnh vực mới.Cùng với khả
năng mạnh về đồ hoạ ,phông chữ và ảnh trong các API, thì Java 2D API
còn hỗ trợ những thuộc tính và thành phần màu sắc đã được nâng cao, và
thành công trong việc biểu diễn các bề mặt hình học tuỳ ý và một kiểu tô
trát chuẩn cho máy in và thiết bị hiển thị. Java 2D API cũng cho phép tạo
ra các thư viện đồ hoạ mở rộng,như các thư viện của CAD-CAM và các
thư viện tạo hiệu ứng đặc biệt cho ảnh và đồ hoạ, cũng như việc tạo ra các
bộ lọc đọc/viết file ảnh và đồ hoạ.Khi được sử dụng kết hợp với Java
Media Framework Java Media APIs khác ,thì Java 2D APIs có thể được
sử dụng để tạo ra và hiển thị hiện thực ảo và các dạng đa phương tiện
khác. Java Animation và Java Media Framework APIs dưa trên Java 2D
API để hỗ trợ việc tô trát(rendering).
1.1 Enhanced Graphics, Text, and imaging
Nếu các phiên bản trước của AWT chỉ cung cấp các gói tô
trát(rendering) đơn giản chỉ phù hợp cho việc rendering các trang HTML
đơn giản,mà không đáp ứng đủ cho các dạng đồ hoạ,văn bản và ảnh phức
http://tailieuhay.com 10
Lập trình đồ họa trên Java 2D và 3D
tạp. Thì Java 2D™ API cung cấp gói tô trát đẩy đủ các tính năng bằng
cách mở rộng AWT để hỗ trợ cho đồ hoạ và các thao tác rendering. Ví dụ
như thông qua các lớp đồ hoạ cho phép vẽ hình chữ nhật,hình ôval,và các
đa giác. Đồ hoạ 2D tăng cường về khái niệm của phép tô trát hình học
bằng cách cung cấp một cơ chế cho phép rendering ảo của bất kì bề mặt
hình học nào.Tương tư như vậy với Java 2D API bạn có thể vẽ các dạng
đường với bất kì độ rộng và dạng hình học nào.
Dạng hình học được cung cấp thông qua các phần thực thi
implementations của Shape interface trong Graphic class, như hình chữ
nhật 2D và Elip 2D. Các đường cong và hình cung cũng thuộc phần
implementations của Shape. Các kiểu vẽ và tô cũng được cung cấp thông
qua phần thực thi implementations của giao tiếp Paint và Stroke
interfaces, ví dụ BasicStroke, GradientPaint, TexturePaint,và Color.
AffineTransform định nghĩa các phép biến đổi trong toạ độ 2 chiều,
gồm có phép lấy tỉ lệ,phép chuyển đổi toạ độ ,phép quay và phép xén cắt.
Khung nhìn được định nghĩa bởi các phương thức giống nhau của lớp
Shape mà chúng được dùng để định nghĩa các khung nhìn chung,ví dụ
như Rectangle2D và GeneralPath.
Thành phần màu sắc được cung cấp bởi các phương thức của lớp
Composite, ví dụ AlphaComposite.
Một kiểu Font chữ thì được định nghĩa bởi các collection của Glyphs.
1.2 Rendering Model
Kiểu tô trát đồ họa đơn giản không có gì thay đổi khi thêm vào Java
2D™ APIs. Để tô trát đồ họa thì phải thiết lập các thông số về đồ họa và
gọi phương thức của đối tượng Graphics.
Trong Java 2D API, lớp Graphics2D mở rộng lớp Graphics để hỗ trợ
thêm nhiều thuộc tính đồ họa và cung cấp thêm các phương thức cho quá
trình tô trát.
http://tailieuhay.com 11
Lập trình đồ họa trên Java 2D và 3D
The Java 2D API tự động cân chỉnh những sai khác trong các thiết bị tô
trát và cung cấp một kiểu tô trát thống nhất cho các dạng thiết bị khác
nhau. Tại tầng ứng dụng,quá trình tô trát là giống nhau cho dù thiết bị
cuối đó là màn hình hay máy in.
Với Java 2 SDK, version 1.3 , Java 2D API còn hỗ trợp cho các môi
trường đa màn hình (multi-screen environments).
1.2.1 Coordinate Systems
Java 2D API bao hàm hai hệ tọa độ:
1. Không gian người sủ dụng là hệ tọa độ logic và độc lập với thiết bị.
Các ứng dụng thường sủ dụng hệ tọa độ này,tất cả các dạng hình
học được tô trát bằng Java 2D đều được xác định trong hệ tọa độ
này.
2. Không gian thiết bị là hệ tọa độ phụ thuộc thiết bị,ứng với từng loại
thiết bị cuối mà có hệ tạo độ khác nhau.
Bằng ứng dụng máy ảo một cửa sổ hiển thị có thể mở rộng thêm nhiều
thiết bị hiển thị vậy lý tạo nên môi trường đa màn hiển thị, hệ tọa độ của
thiết bị này được sủ dụng làm hệ tọa độ của máy ảo sẽ được lấy làm hệ
tọa độ cho tất cả các màn hiể thị còn lại.
Hệ thống Java 2D sẽ tự động thực hiện những phép chuyển đổi cần
thiết giữa không gian người sử dụng và không gian thiết bị . Mặc dù hệ
tọa độ cho màn hình rất khác đối với hệ tọa độ cho máy in nhưng sự khác
biệt này trong suốt đối với các ứng dụng.
1.2.1.1 User Space
Hệ tọa độ này được chỉ ra trong hình 1-1.
(0,0) x
http://tailieuhay.com 12
Lập trình đồ họa trên Java 2D và 3D
y
Figure 1-1 User Space Coordinate System
Không gian người sử dụng biểu diễn một cách trừu tượng đồng nhất
cho các hệ tạo độ của tất cả các thiết bị có liên quan.Còn không gian thiết
bị cho một thiết bị cụ thể có thể có cùng gốc tọa độ và hướng của các trục
hoặc là có thể không.Ngoài ra các tọa độ của không gian người sử dụng
có thể chuyển đổi một cách tự động vào không gian thiết bị phù hợp mỗi
khi một đối tượng đồ họa được tô trát,thường thì các chương trình driver
của các thiết bị thực hiện điều này.
1.2.1.2 Device Space
Java 2D API định nghĩa 3 mức thông tin cấu hình để hỗ trợ cho việc
chuyển đổi từ không gian người sử dụng sang không gian thiết bị. Thông
tin này được chứa trong 3 lớp :
• GraphicsEnvironment
• GraphicsDevice
• GraphicsConfiguration
Hai trong số chúng sẽ biểu diễn tất cả các thông tin cần thiết cho việc
xác định thiết bi tô trát và cho việc chuyển đổi tọa độ từ không gian người
http://tailieuhay.com 13
Lập trình đồ họa trên Java 2D và 3D
sử dụng sang không gian thiết bị. Ứng dụng có thể truy cập thông tin này
nhưng không nhất thiết phải thực hiện bất kì phép chuyển đổi nào giũa hai
hệ tọa độchuyển .
Lớp GraphicsEnvironment mô tả tập các thiết bị mà đựợc chấp nhận bởi
các ứng dụng Java trong một môi trường cụ thể.Các thiết bị sử dụng cho
quá trình tô trát gồm có màn hình , má in và các bộ đệm ảnh.Lớp
GraphicsEnvironment cũng bao gồm tập các font phù hợp trong môi
trường đó.
Lớp GraphicsDevice mô tả thiết bị tô trát như màn hình hoặc máy in.Mỗi
cấu hình phù hợp của thiết bị được biểu diễn bởi lớp
GraphicsConfiguration. Ví dụ,một thiết bị hiển thị SVGA có thể thực
hiện trong một số chế độ màu như : 640x480x16 colors, 640x480x256
colors, and 800x600x256 colors.
Màn hình SVGA được biểu diễn bởi một đối tượng GraphicsDevice
và ứng với mỗi chế độ màu của màn hình SVGA sẽ được biểu diễn bởi
một đối tượng GraphicsConfiguration.Một đối tượng kiểu
GraphicsEnvironment có thể bao gồm 1 hay nhiều đối tượng
GraphicsDevices. Ngược lại ,mỗi đối tượng GraphicsDevice có thể có 1
hay nhiều đối tượng kiểu GraphicsConfigurations.
1.2.2 Transforms
Java 2D API có một chế độ chuyển tọa độ thống nhất. Tất cả các phép
chuyển tọa độ,bao gồm các phép chuyển từ không gian người sử dụng
đến không gian của thiết bị,đều được biểu diễn bởi đối tượng kiểu
AffineTransform .AffineTransform định nghĩa các luật cho những thao
tác trên các hệ tọa độ bằng các ma trận(các phép biến đổi ảnh bằng các bộ
lọc).
Cũng có thể thêm đối tượng AffineTransform cho các dạng đồ họa bằng
các phép xoay ,lấy tỉ lệ ,chuyển đổi hoặc cắt tọa độ cho một mặt hình học
http://tailieuhay.com 14
Lập trình đồ họa trên Java 2D và 3D
,văn bản hay ảnh khi chúng được tô trát.Các phép biến đổi được thêm vào
này sẽ được ứng dụng cho các đối tượng đồ họa được tô trát trong trường
hợp đó phép bién đổi này được thực hiện khi chuyển từ tọa độ không gian
người sử dụng sang không gian của thiết bị.
1.2.3 Fonts
Một xâu thường được hiểu là tập các kí tự tao thành.Khi một xâu
được vẽ, hình dạng của nó sẽ được xác định bởi font mà chúng ta
chọn.Tuy nhiên, hình dạng mà font sử dụng để hiển thị lên màn hình xâu
đó không phải lúc nào cũng giống với hình dáng của mỗi kí tự riêng biệt.
ví dụ sự kết hợp của 2 hay nhiều kí tự thường được thay thế bởi một hình
dạng kí hiêu nào đó được gọi là ligature.
Các hình dạng mà một phông chữ sử dụng để biểu diễn các kí tự trong
một xâu được gọi là glyphs. Một font có thể biểu diễn một kí tự như chữ
thường hoặc chữ hoa bằng cách sử dụng nhiều glyphs, hoặc biểu diễn các
liên kết kí tự như fi chỉ biểu diễn bởi 1 glyph. Trong Java 2D API, một
glyph chỉ đơn giản là một dạng (Shape) mà có thể đựoc thao tác và tô trát
một cách giống nhau như bất kì với các dạng khác Shape.
Một font có thể được xem như tập các glyph. Một font đơn có thể có
rất nhiều kiểu khác nhau như kểi chữ đậm ,vừa,nghiêng ,gôtích…tất cả
các kiểu chữ này trong một font có cùng thiết kế in và có thể ví như
chúng là các thành viên trong cùng một gia đình. Hay nói cách khác ,một
nhóm các glyphs với các kiểu riêng biệt tạo nên một dạng font,nhóm các
dạng font tao nên môt họ font ,họ các font tạo nên một tập font và tập này
có sẵn trong một đối tượng GraphicsEnvironment cụ thể nào đó.
Trong Java 2D API, các font được xác định bởi một tên mà mô tả một
dạng font riêng biệt nào đó,ví dụ Helvetica Bold. Nhưng điều này lại khác
với fần mềm JDK 1.1 ,các font được mô tả bằng các tên lôgíc mà ánh xạ
trên các dạng font khác nhau fụ thuộc liệu các dạng font đó có sắn trong
http://tailieuhay.com 15
Lập trình đồ họa trên Java 2D và 3D
môi trường đang xét không.Như để tương thích cho điều đó ; the Java 2D
API hỗ trợ việc xác định các font bằng tên lôgíc cũng như bằng tên dạng
font.
Sử dụng Java 2D API, có thể soạn thảo và tô rát các xâu bao gồm
nhiều font thuộc các họ font,hình dạng,kich thước, và thâm chí cả ngôn
ngữ khác nhau. Các dạng của văn bản được lưu riêng biệt một cách lôgíc
với sự sắp xếp các văn bản.Các đối tượng Font được sử dụng để mô tả các
hình dạng hiển thị của font, và thông tin sắp xếp được lưu trong đối tượng
TextLayout và TextAttributeSet . Việc lưu giứ các font và thông tin sắp
xếp riêng biệt nhau làm dễ dàng hơn cho việc sử dụng cùng font chữ
nhưng khác về cấu hình sắp xếp.
1.2.4 Images
Ảnh được tạo nên từ tập các pixel . Một điểm ảnh hay một pixel sẽ
định nghĩa thể hiện của một ảnh tại vùng quan sát của màn hình . Một
mảng hai chiều của điểm ảnh được gọi là một raster.
Thể hiện của một điểm ảnh có thể được định nghĩa một cách trực tiếp
hoặc như là một chỉ số trong bảng màu dành cho ảnh.
Trong ảnh màu đa màu (hơn 256 màu) các điểm ảnh thường trực tiếp
biểu diễn luôn màu sắc và các đặc trưng khác cho mỗi vùng hiển thị của
ảnh. Những ảnh như vậy sẽ có kích thước lớn hơn ảnh màu mà hiển thị
bằng chỉ số(indexed-color images), nhưng chúng nhìn sẽ thật hơn .
Trong ảnh màu hiển thị bằng chỉ số (indexed-color image), những
màu sắc của ảnh sẽ bị giới hạn bởi bảng màu , và thường số lượng màu
trong bảng màu sẽ ít hơn sovới ảnh thật. Tuy nhiên các ảnh khi được lưu
như tập các chỉ số màu sẽ làm cho kích thước ảnh nhỏ đi.Định dạng này
thường được dùng cho những ảnh có 256 màu.
Ảnh trong Java 2D API có hai thành phần chính
• Dữ liệu ảnh thô(các điểm ảnh)
http://tailieuhay.com 16
Lập trình đồ họa trên Java 2D và 3D
• Những thông tin cần thiết cho quá trình chuyển đổi các điểm ảnh
Các luật cho việc chuyển đổi các điểm ảnh được lưu bởi đối tượng
ColorModel. Đối với một điểm ảnh để hiển thị cần phải đi kèm với một
kiểu màu sắc.
Một dải màu là một thành phần của không gian màu sắc dành cho
ảnh.Ví dụ các thành phần màu đỏ là các daỉ màu trong ảnh RGB . Một
điểm ảnh trong ảnh dùng màu trực tiếp có thể được hiểu như một tập .
Gói java.awt.image bao gồm một số phương thức ColorModel cho
các biểu diễn thành phần điểm ảnh.
Một đối tượng ColorSpace chứa các luật để sao cho tập các giá trị
màu tương ứng với một màu sắc nhất định .Các phương thức của
ColorSpace trong java.awt.color sẽ biẻu diễn các không gian màu sắc
thông dụng, gồm có không gian màu RGB và gray scale. Lưu ý rằng một
không gian màu không phải là một tập các màu sắc mà tập này định nghĩ
các luật để có thể chuyển đổi các giá trị màu thành các màu tương ứng
thông dịch.
Việc chia không gian màu sắc thành các chế độ màu sẽ tạo nên sự linh
hoạt hơn trong việc biểu diễn và chuyển đổi từ phép biểu diễn màu này
sang một phếp biểu diẽn màu khác.
1.2.5 Fills and Strokes
Với Java 2D API, có thể tô các hình băng cách sử dụng các kiểu but
khác nhau và các kiểu tô khác nhau. Vì các chữ xét cho cùng cũng được
biểu diễn bằng tập các glyph, nên các xâu kí tự cũng có thể được vẽ và tô.
Các kiểu bút được định nghĩa băng các đối tượng kiểu Stroke.Có thể
xác định độ rộng cũng như các nét cho các đường thẳng và đường cong.
Các kiểu tô được định nghĩa bởi các phương thức thuộc đối tượng
Paint. Lớp Color có sắn trong các phiên bản trước của AWT đây là một
http://tailieuhay.com 17
Lập trình đồ họa trên Java 2D và 3D
dạng đơn giản của đối tượng Paint được sử dụng để định nghĩa tô màu
trơn (solid color). Java 2D API cung cấp thêm hai phương thức mới cho
Paint là TexturePaint và GradientPaint. TexturePaint định nghĩa kiểu
tô dùng mẩu ảnh đơn giản(simple image fragment ) mà được lặp như
nhau. GradientPaint định nghĩa một kiểu tô màu loang(gradient) giữa
hai màu.
Trong Java 2D, rendering một đường nét của một hình và tô hình đó
bằng một kiểu nào đó được thực hiên hai thao tác riêng biệt:
• Sử dụng một trong các thuật toán draw để render các đường nét
của hình sử dụng các kiểu bút được xác định bởi các thuộc tính của
Stroke và kiểu tô được xác định bởi thuộc tính Paint.
• Sử dụng phương thức fill để tô các vùng trong của hình với kiểu
tô đã dược xác định.
Khi một chuỗi kí tự được render,các thuộc tính hiện tại của Paint
đựơc áp dụng cho các glyphs tạo nên chuỗi đó.Lưu ý thực chất đối tượng
drawString sẽ tô các glyphs mà được render. Để vẽ các nét của các glyphs
trong chuỗi kí tự cần phải chọn các đường nét và render chúng như đối
với các hình sử dụng phương thức draw .
1.2.6 Composites
Khi render một đối tượng mà chồng lên một đối tượng đã tồn tai trước
đó cần phải xác định làm thế nào để kết hợp màu của các đối tuợng. Java
2D API có các luật cho việc kết hợp màu trong trường hợp này trong đối
tượng Composite.
Tuy nhiên có một số vấn đề trong cách tiếp cận này:
• Sẽ thật khó trong trường hợp nếu màu Red và màu Blue được thêm
vào hây không được thêm vào.
• Việc kết hợp lôgíc sẽ không được hỗ trợ trong trường hợp cácmàu
thuộc các không gian màu khác nhau.
http://tailieuhay.com 18
Lập trình đồ họa trên Java 2D và 3D
• Sự kết hợp sẽ không có ý nghĩa trong trường hợp màu được biểu
diễn bằng các gia trị màu thì khi đó sự kết hợp hai điểm ảnh là sự kết hợp
của hai giá trị màu.
Java 2D API tránh các loĩi này bằng cách thực hiện các luật pha trộn
alpha mà sẽ đưa vào các thông tin về kiểu biểu diễn điểm ảnh mỗi khi
thực hiện kết hợp màu. Một đối tượng AlphaComposite bao gồm các
kiểu về màu sắc của các màu sắc của nguồn và đích.
Backward Compatibility and Platform independence
Như đã nói,Java 2D™ API có sự tương thích đối với phần mềm JDK
1.1 . Và Java 2D™ API là một kiến trúc chính vì vậy mà các ứng dụng
của nó có tính độc lập về môi trường
1.3.1 Backward Compatibility
Để tương thích với các tính năng đã tồn tại trong đồ họa JDK .Java
2D API tăng cường thêm một số tính năng cho AWT bằng cách thêm các
phương thức mới vào các lớp đã tồn tại,mở rộng thêm các lớp đã tồn tại
và đồng thời thêm các lớp mới và các interface mới mà không ảnh hưởng
tới các API hợp lệ.
Ví dụ,Có rất nhiều tính năng củaJava 2D API được bắt nguồn từ việc
mở rộng các thuộc tính về đồ họa trong Graphics2D. Để cung cấp các
thuộc tính mở rộng về đồ họa trong đó bao gồm cả yếu tố tương thích với
các phần mềm đồ họa khác, Graphics2D mở rộng các lớp Graphics
trong JDK1.1.
• paint
• paintAll
• update
http://tailieuhay.com 19
Lập trình đồ họa trên Java 2D và 3D
• printAll
• getGraphics
JDK 1.1 applet thông dịch ngữ cảnh đồ họa mà được đưa vào như là
một thể hiện của lớp Graphics. Để có thể truy nhập những chức năng
được thực thi trong đối tượng Graphics2D, thì một applet tương thích với
Java 2D API sẽ đưa ngữ cảnh đồ họa tới đối tượng Graphics2D:
public void Paint (Graphics g) {
Graphics2D g2 = (Graphics2D) g;
...
...
g2.setTransform (t);
}
Trong môt vài trường hợp , hay đúng hơn là mở rộng một lớp thừa kế,
Java 2D API khái quat hóa nó. Có hai kĩ thuật đã được sử dụng để khái
quat hóa các lớp kế thừa:
• Một hay nhiều lớp cha được chèn vào biểu đồ phân cấp của lớp , và
các lớp thừa kế được cập nhật để mở rộng các lớp cha mới. Kĩ thuật này
được sử dụng để thêm các phương thức và các dữ liệu thể hiện cho lớp kế
thừa.
• Một hay nhiều triển khai các interface được thêm vào lớp kế thừa .
Kĩ thuật này được sử dụng để thêm các phương thức ảo tổng quát(general
abstract methods) cho lớp kế thừa .
Ví dụ, Java 2D API khái quát hóa lớp AWT Rectangle bằng cách sử
dụng cả hai kĩ thuật Sự phân cấp cho hình chữ nhật giống như:
http://tailieuhay.com 20
Lập trình đồ họa trên Java 2D và 3D
Trong phần mềm JDK 1.1 , Rectangle là một đối tuợng mở rộng đơn
giản. Bây giờ mở rộng các lớp Rectangle2D mới và triển khai cả hai
interface Shape và Serializable. Hai lớp cha được thêm vào phân cấp của
lớp Rectangle là RectangularShape và Rectangle2D. Các Applet được
viết cho phần mềm JDK 1.1 không truy cập được các lớp mới và các phần
triển khai của các interface,nhưng điều này không ảnh hưởng bởi vì lớp
Rectangle vẫn bao gồm các phương thức và các thành phần có trong các
phiên bản trước.
1.3.2 Platform independence
Có khả năng pháp triển các ứng dụng độc lập với môi trường. Java 2D
API không đảm đương về không gian màu sắc hay là chế độ màu của
thiết bị rendering và Java 2D API có bất kì định dạng ảnh cụ thể nào.
Và chỉ độc lập về font khi các font đó đã được xây dựng sẵn(được
cung cấp như là một phần của phần mềm JDK ),hay là khi chúng được
gởi tạo bằng lập trình. Java 2D API không hỗ trợ các font xây dựng sẵn
và các font được tạo nên nhờ chương trình tạo font nhưng nó lại hỗ trợ
việc định nghĩa các font thông qua tập các glyph của nó. Mỗi glyph lại có
thể được định nghĩa bởi Shape mà bao gồm các đoạn đường thẳng và các
đường cong. Có rất nhiều kiểu font với nhiều hình dang và kich thước
được bắt nguồn từ tập các glyph đơn lẻ.
1.4 The Java 2D™ API Packages
Các lớp Java 2D API được tổ chức trong các package sau:
http://tailieuhay.com 21
Lập trình đồ họa trên Java 2D và 3D
• java.awt
• java.awt.geom
• java.awt.font
• java.awt.color
• java.awt.image
• java.awt.image.renderable
• java.awt.print
Package java.awt bao gồm các lớp Java 2D API đã đề cập ở trên và
các interface đã tồn tại trước đó và các interface fát triển thêm. (Rõ dàng
là không phải tất cả các lớp trong java.awt là các lớp của Java 2D )
Package java.awt.geom bao gồm các classe và interface có liên quan đến
việc định nghĩa các dạng hình học nguyên thủy:
http://tailieuhay.com 22
Lập trình đồ họa trên Java 2D và 3D
Có nhiều dạng hình học nguyên thủy ứng với các phần
implementation. Float và Double
Điều này cho phép các implementation có thể ở hai mức chính xác là
giá trị single và double.
Gói java.awt.font chứa các lớp và các giao diện được sử dụng cho
việc bố trí văn bản và định nghĩa các kiểu font:
Gói java.awt.color chứa các lớp và các giao diện cho việc định nghĩa
các không gian màu và các mẫu màu:
Các gói java.awt.image và java.awt.image.renderable chứa các lớp
và các giao diện cho việc định nghĩa và tạo bóng của ảnh.
http://tailieuhay.com 23
Lập trình đồ họa trên Java 2D và 3D
Package java.awt.image tồn tại trong các version trước đó của AWT.
Java 2D API tăng cường thêm các lớp ảnh kế thừa từ AWT sau đây:
• ColorModel
• DirectColorModel
• indexColorModel
Các lớp chế độ màu sắc này vẫn tồn tại trong package
java.awt.image package cho sự tương thích .Để đảm bảo tính thống
nhất,các lớp cho chế độ màu mới cũng có trong package java.awt.image .
Package java.awt.print bao gồm các lớp và các interface cho phép in
tất cả các dạng văn bản ,đồ họa và ảnh dựa trên công nghệ Java 2D.
http://tailieuhay.com 24
Lập trình đồ họa trên Java 2D và 3D
Chương 2:
Rendering with Graphics2D
Graphics2D mở rộng java.awt.Graphics để tạo ra điều khiển tinh vi
hơn về biểu diễn các hình ,văn bản và ảnh .Quá trình tô trát Java 2D™
được điều khiển thông qua đối tượng Graphics2D và các thuộc tính
trạng thái của nó.
Các thuộc tính tạng thái Graphics2D , như là các kiểu đường thẳng và
các phép biến đổi,được áp dụng cho các đối tượng đồ họa khi chúng được
tô trát. Tập các thuộc tính trạng thái kết hợp với Graphics2D được tham
chiếu tới như là Graphics2DContext.
Để tô trát văn bản ,hình và ảnh,cần thiết lập Graphics2D context và sau
đó gọi một trong các phương thức tô trát Graphics2D như draw hay fill.
http://tailieuhay.com 25
Lập trình đồ họa trên Java 2D và 3D
2.1 Các lớp và giao diện.
Bảng cho sau đây sẽ liêt kê các giao diện và lớp trong việc kết hợp
với ngữ cảnh Graphics2D context,bao gồm các lớp biểu diễn các thuộc
tính trạng thái. Hầu hết các lớp này là một phần của package java.awt.
Các giao diện và mô tả chúng:
Giao diện Mô tảComposite Định nghĩa các phương thức cho việc kết hợp một
đối tượng vẽ gốc với cùng đồ họa được đánh dấu.
Được thực thi bởi phương thức AlphaComposite.CompositeContex
t
Định nghĩa một môi trương tối ưu và độc lập cho
việc thực hiện các phép kết hợp .Việc thực hiện các
luật kết hợp tùy chọn được thực hiện bơit người lập
trình.Paint Mở rộng: Transparency
Định nghĩa các màu sắc cho việc tô hoặc vẽ. Được
thực thi bởi đối tượng Color,Gradient-Paint và
TexturePaint.PaintContext Định nghĩa một môi trương tối ưu và độc lập cho
việc vẽ.Các thao tác vẽ được tùy chọn bởi người lập
trình.Stroke Tạo ra một đối tượng Shape mà các đường viền của
nó đựoc tạo bóng.Được thực thi bởi phương thức
BasicStroke.
Các lớp và mô tả sơ lược về chúng:
Lớp Mô tảAffineTransform
(java.awt.geom)
Miêu tả một phép biến đổi 2D affine ,mà thực hiện
việc ánh xạ tuyến tính từ tọa độ 2D này đến tọa độ
2D khác.
http://tailieuhay.com 26
Lập trình đồ họa trên Java 2D và 3D
AlphaComposite Thực thi : Composite
Thực hiện các luật kết hợp các giá trị alpha cơ bản cho
các đối tượng Shape,Text và Image.BasicStroke Thực thi :Stroke
Định nghĩa kiểu bút vẽ( “pen style”) được áp dụng
cho các đường bao của đối tượng Shape.
Color Thực thi: Paint
Định nghĩa một kiểu tô màu đồng nhất cho đối tượng
Shape.GradientPaint Thực thi: Paint
Định nghĩa một mẫu tô màu loang tuyến tính cho đối
tượng Shape.Mẫu này sẽ thay đổi từ màu C1 (tại điểm
P1) tới màu C2(tai điểm P2).Graphics2D Mở rộng: Graphics
Lớp cơ sở cho quá trình tạo bóng trong không gian
2D.Mở rộng lớp gốc java.awt.GraphicsTexturePaint Thực thi: Paint
Định nghĩa một kiểu tô theo mẫu cho đối tượng
Shape.Mẫu tô được tạo ra từu đối tượng
BufferedImage.
2.2 Rendering Concepts
Để tô trát một đối tượng đồ họa sử dụng Java 2D™ API, cần thiết lập
ngữ cảnh Graphics2DContext và sử dụng một trong các phương thức tô
trát Graphics2D đối với đối tượng.
Có thể thay đổi các thuộc tính trạng thái mà tạo nên ngữ cảnh
Graphics2D như :
• Thay đổi độ rộng của nét bút
• Thay đổi cho các nét bút kết hợp với nhau như thế nào.
http://tailieuhay.com 27
Lập trình đồ họa trên Java 2D và 3D
• Thiết lập một khung cắt để giới hạn vùng được tô trát.
• Chuyển đổi tọa độ ,xoay,lấy tỉ lệ hoặc cắt cá đối tượng khi
chúng được render.
• Định nghĩa các màu và các kiểu để tô các hình.
• Xác định các đối tượng đa đồ họa(multiple graphics objects) cần
phải được tạo ra như thế nào.
Graphics2D định nghĩa một số phương thức để thêm và thay đổi các
thuộc tính trong ngữ cảnh đồ họa . Hầu hết những phương thức này là
những đối tượng biểu diễn các thuộc tính riêng biệt như đối tựơng Paint
hay Stroke .
Ngữ cảnh Graphics2D cất giữ các tham chiếu tới các đối tương thuộc
tính . Nếu biến đổi một đối tượng thuộc tính mà là một phần của ngữ cảnh
Graphics2D ,thì cần phải gọi phương thức thiết lập phù hợp để khai báo
ngữ cảnh.Thay đổi một đối tượng trong quá trình thao tác render sẽ gây
nên một số biểu hiện bất thương thường và không ổn định .
2.2.1 Rendering Process
Khi một đối tượng đồ họa được render, thông tin về hình học ,ảnh và
thuộc tính được kết hợp để tính toán những giá trị điểm ảnh cần phải thay
đổi trên màn hiển thị.
Quá trình render cho một đối tượng Shape có thể được chia thành 4 bước
:
1. Nếu đối tượng Shape được taọ nét ,đối tượng Stroke quy vào ngữ
cảnh Graphics2D được sử dụng để tạo nên một đối tượng Shape mới
bao quanh những đường nét đó .
2. Tọa độ của đường thuộc đối tượng Shape được biến đổi từ không
gian người sử dụng sang không gian của thiết bị theo các thuộc tính biến
đổi trong ngữ cảng đồ họa Graphics2D .
http://tailieuhay.com 28
Lập trình đồ họa trên Java 2D và 3D
3. Đường (path)của đối tượng Shape được cắt bỏ bằng cách sử dụng
các thuộc tính cắt trong ngữ cảnh Graphics2D.
4. Phần còn lại của đối tượng Shape được tô băng cách sử dụng
thuộc tính của đối tượng Paint và Composite thuộc tính trong ngữ cảnh
của đối tượng Graphics2D.
Tạo bóng (Rendering) văn bản tương đương với việc tạo bóng các đối
tượng thuộc kiểu Shape, khi đó văn bản được tạo bóng với từng glyph và
mỗi glyph là một đối tượng thuộc kiểu Shape. Chỉ có điều khác là Java
2D API phải xác định đối tượng Font nào sử dụng cho văn bản và lấy
kiểu glyph tương ứng từ đối tượng Font trước khi tạo bóng.
Đối với ảnh thì có sự khác biệt , sự chuyển đổi và thực hiện các phép
cắt bỏ với hộp xác định biên ảnh( image’s bounding box). Thông tin về
màu sắc lấy từ chính ảnh đó và nguồn alpha(alpha channel) được sử dụng
kết hợp với thuộc tính hiện tại của Composite khi các điểm ảnh được
hợp trên bề mặt tạo bóng.
2.2.2 Controlling Rendering Quality
Java 2D API đưa ra các lựa chọn cho phép người sử dụng tạo bóng
nhanh hay tạo bóng với chất lượng cao. Những tham chiếu của người su
dụng được xác định như là các chỉ dẫn thông qua thuộc tính của đối tượng
RenderingHints trong ngữ cảnh của đối tượng Graphics2D . Không phải
tất cả các môi trường đều hỗ trợ việc thay đổi chế độ tạo bóng vì vậy xác
định các chỉ dẫn cho quá trình tạo bóng sẽ không được đảm bảo chúng sẽ
được sử dụng hay không .
Lớp RenderingHints hỗ trợ cá kiểu chỉ dẫn sau đây:
• Alpha interpolation - có thể thiết lập tùy chọn default, quality,
speed.
• Antialiasing - có thể thiết lập tùy chọn default :on hoặc off.
http://tailieuhay.com 29
Lập trình đồ họa trên Java 2D và 3D
• Color Rendering - có thể thiết lập tùy chọn default, quality, hoặc
speed.
• Dithering - có thể thiết lập tùy chọn default:disable, enable.
• Fractional Metrics - có thể thiết lập tùy chọn default, on, hoặc off.
• Interpolation- có thể thiết lập tùy chọn nearest-neighbor, bilinear,
hoặc bicubic.
• Rendering - có thể thiết lập tùy chọn default, quality, hoặc speed.
• Text antialiasing - có thể thiết lập tùy chọn default: on hoặc off.
Để thiết lập hoặc thay đổi các thuộc tính RenderingHints trong ngữ
cảnh của đối tượng Graphics2D thì gọi phương thức setRenderingHints.
Khi một chỉ dẫn được thiết lập măc định ,môi trường tạo bóng mặc định
sẽ được sử dụng .
Kĩ thuật làm trơn(Antialiasing)
Khi các thực thể cơ sở được tạo bóng trên thiết bị hiển thị ,các
biên(cạnh) của chúng có thể không trơn hay nhám là do thuộc tính
aliasing. Các đường cung và đường chéo có dạng nhám bởi vì chúng
được xấp xỉ bởi các điểm ảnh mà gần nhất về hìn dạng với chúng . Đây là
điều mà chúng ta có thể nhận thấy với các thiết bị trước đây với các cạnh
nhám xuất hiện trái ngược hoàn toàn với các cạnh trơn của đườgn nằm
ngang hay thẳng đứng.
Antialiasing là một kĩ thuật được sử dụng để tạo bóng các đối tượng
với các cạnh trơn hơn. Thay vì sử dụng các điểm ảnh gẩn giống với các
đường chéo và đường cong ,tăng mật độ các điểm ảnh bao quanh tới các
vùng được tạo bóng. Điều này làm cho cách cạnh trơn hơn và trải rộng sự
chuyển tiếp bật/tắt với các pixel đa điểm(multi pixel) . Tuy nhiên kĩ thuật
antialiasing đòi hỏi nhiều về tài nguyên máy tính và làm tăng thời gian tạo
bóng.
http://tailieuhay.com 30
Lập trình đồ họa trên Java 2D và 3D
2.2.3 Stroke Attributes
Tạo nét một đối tượng thuộc kiểu Shape như đối tượng GeneralPath
tương đươnng với việc sử dụng một bút lôgíc theo các đoạn của đối tượng
GeneralPath. Thuộc tính của Graphics2DStroke định nghĩa các tính
chất của nét bút vẽ.
Đối tượng BasicStroke được sử dụng để định nghĩa các thuộc tính
đường nét cho một ngữ cảnh của Graphics2D. BasicStroke đinh nghĩa
các thuộc tính như độ rộng cuả nét vẽ ,mẫu tô…
Để thiết lập hay thay đổi các thuộc tính Stroke trong ngữ cảnh của
Graphics2D thì gọi phương thức setStroke.
Như ví du,ảnh đầu tiên trong hình 2-3 sử dụng miter join-style,và hình
thứ hai sử dụng kiểu round join-style, a round endcap style, and a dashing
pattern.
http://tailieuhay.com 31
Lập trình đồ họa trên Java 2D và 3D
Các phương thức tạo bóng Graphics2D có sử dụng thuộc tính của
Stroke để vẽ như drawArc, drawLine, drawOval, drawPolygon,
drawPolyline, drawRect, và
drawRoundRect.Khi một trong các phương thức được gọi thì các đường
nét của đối tượng Shape đã xác định sẽ được tậo bóng. Thuộc tính
Stroke định nghĩa các tính chất của đường thẳng và các thuộc tính của
Paint định nghĩa màu sắc hay mẫu của nét bút. Ví dụ phương thức
draw(myRectangle) được gọi:
1. Thuộc tính của Stroke sẽ quy định cho đường nét của hình chữ nhật .
2. Các đường nét này sẽ được biến đổi thành một đối tượng kiểu Shape
.
3. Đối tượng Paint is được áp dụngcác điểm ảnh thuộc miền giới hạn
bởi đường bao của đối tựơng Shape.
Quá trình xử lý này được minh hạo trong hình 2-4:
2.2.4 Fill Attributes
Thuộc tính tô màu trong ngữ cảnh Graphics2D được biểu diễn bởi
đối tượng Paint. Có thể thêm một đối tượng vào ngữ cảnh của đối tượng
Graphics2D (Graphics2D context) bằng cách gọi phương thức setPaint.
Khi một đối tượng Shape hay là các glyph được vẽ (bởi các phương thức
Graphics2D.draw, Graphics2D.drawString),
http://tailieuhay.com 32
Lập trình đồ họa trên Java 2D và 3D
Đối tượng Paint này sẽ được áp dụng tới tất cả các pixel nằm trong
đối tượng Shape mà biểu diễn các đường nét bao quanh đối tượng . Khi
một đối tượng Shape được tô màu (Graphics2D.fill), đối tượng Paint
được áp dụng tới tất cả các điểm ảnh nằm trong đường bao của đối tượng
Shape.
Các kiểu tô màu đồng nhất đơn giản (solid color) được khởi tạo bởi
phương thức setColor.Color là phần triển khai (implementation) đơn giản
nhất của giao tiếp Paint (Paint interface).
Để tô các hình với các kiểu tô phức tạp hơn như là tô loang(gradient)
và tô dệt ( texture) bằng cách sử dụng các lớp trong Java 2D Paint là
GradientPaint và TexturePaint. Các lớp này sẽ loại bỏ các công việc
tiêu tốn thời gian để tạo các kiểu tô phức tạp bằng cách sử dụng các kiểu
tô mầu đồng nhất đơn giản .
Khi gọi phưong thức fill để tạo bóng một đối tượng Shape,thì hệ
thống sẽ:
1. Xác định các điểm ảnh nào để thể hiện đối tượng đó.
2. Xác định màu cho mỗi điểm ảnh từ đối tựợng Paint.
3. Chuyển các màu này tới giá trị điểm ảnh tương ứng cho các
thiết bị hiển thị.
4. Ghi các điểm ảnh ra thiết bị hiển thị đó.
http://tailieuhay.com 33
Lập trình đồ họa trên Java 2D và 3D
Quá trình xử lý theo phiên
Để tổ chức hợp lý quá trình xử lý các điểm ảnh , Java 2D API tổ chức
chúng theo từng phiên.
Mỗi phiên có thể là tập các điểm ảnh kề nhau trên một đường quét
hay là một khối (block)các điểm ảnh. Quá trình xử lý theo phiên được
thực hiện theo 2 bước:
1. Phương thức createContext của đối tượng paint được gọi để tạo
một đối tượng PaintContext. Đối tượng PaintContext này sẽ lưu thông
tin ngữ cảnh về thao tác tạo bóng hiện thời và những thông tin cần thiết
để tạo ra các màu. Phương thức createContext method is passed the
bounding boxes of thegraphics object being filled in user space and in
device space,đối tượng ColorModel là nơi để tạo các màu sắc,và thực
hiện quá trình chuyển đổi để ánh xạ từ không gian người sử dụng vào
không gian của thiết bị. Đối tượng ColorModel xem như một chỉ dẫn
không phải tất cả các đối tượng Paint có thể hỗ trợ một đối tượng
ColorModel bất kỳ.
2. Phương thức getColorModel được gọi để nhận giá trị của đối tượng
ColorModel cho màu vẽ từ đối tượng PaintContext.
Phương thức getRaster sau đó được gọi lặp lại nhiều lần để nhận giá
trị của đối tựợng Raster mà bao gồm dữ liệu màu thật cho mỗi phiên.
Thông tin này passed to the next stage in the rendering pipeline, mà vẽ
các màu đã được tạo bằng cách sử dụng đối tựợng Composite hiện thời .
2.2.5 Clipping Paths
Một khung nhìn sẽ xác định phần của đối tượng Shape hay Image
cần được tạo bóng . Khi một khung nhìn là một phần của ngữ cảnh của
đối tượng Graphics2D, thì chỉ những phần của đối tượng Shape hay
image nằm trong khung nhìn đó mới được tạo bóng.
http://tailieuhay.com 34
Lập trình đồ họa trên Java 2D và 3D
Để thêm khung nhìn cho ngữ cảnh của Graphics2D thì goị phương
thức setClip. Bất kì đối tượng Shape cũng có thể được sử dụng để định
nghĩa một khung nhìn.
Để thành đổi khung nhìn cần phải sử dụng phương thức setClip để
xác định một khung nhìn mới hay là gọi phương thức clip để thay đổi
khung nhìn cho phần giao nhau giữa khung nhìn cũ và một đối tượng
Shape.
2.2.6 Transformations
Ngữ cảnh của đối tượng Graphics2D bao gồm một phép bién đổi mà
được sử dụng để biến đổi những đối tượng từ không gian người sử dụng
vào không gian thiết bị trong quá trình tạo bóng. Để thực hiện các phép
biến đổi khác như phép quay hay lấy tỉ lệ thì cần phải thêm các phép biến
đổi khác vào ngữ cảnh của đối tượng.Các phép biến đổi được thêm vào
này sẽ trở thành một phần của ống biến đổi (pipeline of transformations)
mà được ápdụng trong suôt qua trình tạo bóng.
Graphics2D cung cấp một vài cách khác để thay đổi phép biến đổi
trong ngữ cảnh của đối tượng Graphics2D . Cách đơn giản nhất là gọi
một trong các phương thức biến đổi trong đối tượng Graphics2D như :
rotate, scale, shear, hay translate. Xác định các tính chất của phép biến
đổi để áp dụng trong suốt qúa trình tạo bóng và Graphics2D tự động tạo
ra các thay đổi phù hợp.
Cũng có thể nối một phép biến đổi AffineTransform với phép biến
đổi Graphics2D hiện tại. Phép biến đổi AffineTransform thực hiện các
phép biến đổi cho đường như phép dịch,tỉ lệ ,quay và cắt bỏ với tập các
hình cơ bản.
Khi một phép biến đổi được nối vào phép biến đổi đã tồn tại trước đó
thì phép biến đổi sau cùng sẽ được xác định như là phép biến đổi được
http://tailieuhay.com 35
Lập trình đồ họa trên Java 2D và 3D
thực hiện đầu tiên. Để tiếp nối một phép biến đổi với phép biến đổi hiện
tại , you pass an AffineTransform to Graphics2D.transform.
Lớp Graphics2D cũng bao gồm phương thức setTransform , nhưng
phương thức này không bao giờ được sử dụng để nối với các phép biến
đổi tọa độ khác của phép biến đổi đang tồn tại. Phương thức setTransform
sẽ ghi đè lên phép biến đổi hiện thời của đối tượng Graphics2D, nhưng
phương thức này cần cho môt số mục đích khác như:
• Áp dụng phép biến đổi tỉ lệ điều chỉnh cho máy in.
• Vẽ một đối tượng JComponent non-zero translation from its
parent’s origin
• Phóng to một thành phần để dễ dàng quan sát.
• Các tình huống khác mà người cung cấp đối tượng Graphics2D
muốn chuyển đổi cho quá trình tạo bóng hiệu quả .
Phương thức setTransform method được xem như để thiết lập đối
tượng Graphics2D trở lai phép biến đổi ban đầu sau quá trình tạo bóng
đồ họa ,văn bản và ảnh đã được chuyển đổi:
AffineTransform aT = g2d.getTransform();
g2d.transform(...);
g2d.draw(...);
g2d.setTransform(aT);
Graphics2D cũng cung câp một phiên bản về drawimage mà trong đó
đối tượng AffineTransform
Được xem như một tham số . Điều này cho phép áp dụng một phép
biến đổi cho đối tượng ảnh khi nó được vẽ mà không cần chỉnh sửa
đường ống cuả phép biến đổi. Ảnh này được được vẽ như khi kết nối
http://tailieuhay.com 36
Lập trình đồ họa trên Java 2D và 3D
phép biến đôit này với phép biến đôit hiện tại trong ngữ cảnh của
Graphics2D
Các phép biến đổi quan hệ(Affine Transforms)
Java 2D API cung cấp một lớp biến đổi là AffineTransform.
AffineTransforms được sử dụng để biến đổi văn bản ,hình và các ảnh
khi chúng được tạo bóng.
Cũng có thể ứng dụng các phép biến đổi cho đối tượng Font để tạo ra
các dẫn xuất font mới(new font derivations).
Một phép biến đổi đồng nhất (affine transformation) thực hiện một phép
biến đổi tuyến tính trên tập đồ hạo cơ bản. Nó luôn biến các đường thẳng
thành các đường thẳng và các đường thẳng song song thành các đường
thẳng song song,tuy nhiên khoảng cách giữa các điểm và các góc của các
đường thẳng không song song có thể thay đổi.
Các phép biến đổi có thể kết hợp để tạo ra đường ống các phép biến
đổi một cách hiệu quả nhằm áp dụng cho một đối tượng nào đó. Sự kết
hợp này xem như là sự móc nối. Khi một phép biến đổi được kết nối với
một phép biến đổi đang tồn tại như với AffineTransform.concatenate,
thì phép biến đổi cuối cùng được xác định là phép biến đổi đầu tiên được
áp dụng . Một phép biến đổi cũng có thể được móc nối trước với một
phép biến đổi đang tồn tại . Trong trường hợp này thì phép biến đổi cuối
cùng sẽ được thực hiện cuối cùng . Phép móc nối trước được được áp
dụng để thực hiện các phép biến đổi có liên quan với không gian thiết bị
thay vì không gian người sử dụng. Ví dụ có thể sử dụng phương thức
AffineTransform.preConcatenate để thực hiện phép chuyển đổi có liên
quan tới không gian các điểm ảnh..
2.2.6.1 Constructing an AffineTransform
http://tailieuhay.com 37
Lập trình đồ họa trên Java 2D và 3D
AffineTransform cung cấp một tập các phương thức cho việc xây
dựng các đối tượng AffineTransform.
• getTranslateinstance
• getRotateinstance
• getScaleinstance
• getShearinstance
Để sử dụng các phương thức này cần phải xác định các tính chất của
phép biến đổi mà cần tạo ra và lớp AffineTransform sẽ tạo ra các ma
trận chuyển đổi phù hợp. Cũng có thể xây dựng phép biến đổi đòng nhất
một cách trực tiếp mà không cần thông qua lớp AffineTransform bằng
cách xác định các thành phần của phép biến đổi đó.
2.2.7 Composite Attributes
Khi hai đối tượng đồ họa trồng lên nhau thì điều cần thiết là phải xác
định những màu nào sẽ được tạo bóng cho các điểm ảnh chồng lên nhau.
Ví dụ nếu một hình chữ nhật màu đỏ và một hình chữ nhật màu xanh
chồng lên nhau thì các điểm ảnh đó sẽ có màu đỏ hoặc màu xanh hay là
sự kết hợp của cả hai màu. Màu của những điểm ảnh trong vùng chồng
nhau đó sẽ xác định hình chữ nhật nào nằm trên và bị che khuất như thế
nào. Quá trình xử lý để xác định màu nào tạo bóng cho các điểm ảnh sẽ
được chia sẽ cho các đối tượng chồng (overlaping objects)được gọi
compositing.
Có hai interface tạo các kiểu kết hợp cơ bản trong Java 2D là :
Composite và CompositeContext.
Để xác định các kiểu kết hợp sẽ được sử dụng thì cần phải thêm vào
một đối tượng AlphaComposite cho ngữ cảnh của đối tượng
Graphics2D bằng cách gọi phương thức setComposite.
AlphaComposite,và một triển khai(implementation) của interface
Composite , có hỗ trợ một số kiểu kết hợp khác nhau . Mỗi đối tượng của
http://tailieuhay.com 38
Lập trình đồ họa trên Java 2D và 3D
lớp này là một luật kết hợp để mô tả sự pha trộn một màu mới với màu
đang tồn tại..
Một trong những luật kết hợp trong lớp AlphaComposite là SRC_OVER,
luật này chỉ ra màu mới (màu nguồn) sẽ được pha trộn với màu đang tồn
tại (màu đích ) như thế nào.
2.2.7.1 Managing Transparency
Giá trị alpha của một màu là giá trị đo đọ trong suôt của màu đó ,nó
chỉ ra (theo phần trăm) bao nhiêu phần trăm màu trước khi tô được hiển
thị ra khi các màu chồng lên nhau. Các màu tối (co giá tri alpha=1.0) thì
các màu tô đè lên chúng sẽ không được hiển thị, trong khi đó các màu
trong suốt (có giá trị alpha=0.0) cho phép các màu tô đè lên nó được hiển
thị.
Khi văn bản và hình được tạo bóng thì giá trị alpha sẽ bắt nguồn từ
thuộc tính của đối tượng Paint trong ngữ cảnh của đối tượng
Graphics2D . Khi các hình và văn bản được làm trơn thì giá trị alpha từ
thuộc tính Paint (trong ngữ cảnh của Graphics2D) được kết hợp với
thông tin về các điểm ảnh bị che từ “rasterized path”. Các ảnh lưu thông
tin về giá trị alpha của chính nó .
Khi tạo một đối tượng AlphaComposite , có thể xác định được giá trị
alpha được thêm vào . Khi thêm đối tượng AlphaComposite này tới ngữ
http://tailieuhay.com 39
Lập trình đồ họa trên Java 2D và 3D
cảnh của Graphics2D ,giá trị alpha thêm vào này sẽ làm tăng giá trị trong
suốt của bất kì đối tượng đồ họa nào khi chúng được tạo bóng - giá trị
alpha của mỗi đối tượng đồ họa được nhân lên bởi giá trị alpha của đối
tượng AlphaComposite.
2.2.7.2 Transparency and images
Các ảnh có thể lưu thông tin về độ trong suốt cho mỗi điểm ảnh của
nó. Thông tin này đựoc gọi là kênh alpha( alpha channel,) ,nó được sử
dụng kêts hợp với đối tượng Composite trong ngữ cảnh của Graphics2D
để pha trộn màu của ảnh đó các đồ họa đang tồn tại.
2.3 Thiết lập Graphics2Context
Để cấu hình ngữ cảnh Graphics2D cho quá trình tạo bóng phải sử
dụng các phương thức khởi tạo cho đối tượng Graphics2D để xác định
các thuộc tính như RenderingHints, Stroke, Paint,Clipping path,
Composite, and Transform.
2.3.1 Setting Rendering Hints
Đối tượng RenderingHints đóng gói tất các tham chiếu để xác định
một đối tượng sẽ được tạo bóng như thế nào . Để tạo các chỉ dẫn cho quá
http://tailieuhay.com 40
Lập trình đồ họa trên Java 2D và 3D
trình tạo bóng trong ngữ cảnh Graphics2D ,thì cần tạo một đối tượng
RenderingHints và chuyển nó vào lớp Graphics2D.setRendering
Tạo chỉ dẫn cho quá trình tạo bóng sẽ không đảm bảo việc sẽ sử dụng
một thuật toán tạo bóng cụ thể: không phải môi trường cũng hỗ trợ chế độ
tạo bóng .
Trong ví dụ cho sau đây thì cho phép sử dụng kĩ thuật làm trơn
(antialiasing) và tạo ra các tham chiếu để xác định chất lượng cho quá
trình tạo bóng:
qualityHints = new
RenderingHints(RenderingHints.KEY_ANTiALiAS
iNG,
RenderingHints.VALUE_ANTiALiAS_ON);
qualityHints.put(RenderingHints.KEY_RENDERi
NG,
RenderingHints.VALUE_RENDER_QUALiTY);
g2.setRenderingHints(qualityHints);
2.3.2 Specifying Stroke Attributes
Một đối tượng BasicStroke sẽ định nghĩa các tính chất đuwoc áp
dụng cho đường viền bao quanh một đối tượng Shape, gồm có độ rộng và
kiểu đường (dashing pattern),để làm thế nào các đoạn thẳng được kết hợp
với nhau. Để khởi tạo các thuộc tính về đường nét trong ngữ cảnh
Graphics2D ,thì khởi tạo một đối tượng BasicStroke và chuyền nó vào
phương thức setStroke
2.3.2.1 Setting the Stroke Width
Để khởi tạo độ rộng đường nét thì khởi tạo đối tượng BasicStroke với
độ rộng mong muốn và sau đó gọi phương thức setStroke
http://tailieuhay.com 41
Lập trình đồ họa trên Java 2D và 3D
Trong ví dụ cho sau đây ,độ rộng đường nét được khởi tạo với 12
điểm và giá trị mặc định được sử dụng cho việc bố trí kiểu jont và kiểu
endcap.
wideStroke = new BasicStroke(12.0f);
g2.setStroke(wideStroke);
2.3.2.2 Specifying Join and Endcap Styles
Để khởi tạo cho các kiểu join và endcap ,cần tạo một đối tượng
BasicStroke với các thuộc tính mong muốn .
Trong ví dụ cho sau đây,độ rộng đường nét được khởi tạo với 12 điểm
và các kiểu join và endcap được sử dụng thay cho các gia tri mặc định:
roundStroke = new BasicStroke(4.0f,
BasicStroke.CAP_ROUND,
BasicStroke.JOiN_ROUND);
g2.setStroke(roundStroke);
2.3.2.3 Setting the Dashing Pattern
Các kiểu đường phức tạp có thể dễ dàng được định nghĩa với một đối
tượng BasicStroke.
Khi tạo một đối tượng BasicStroke ,phải xác định 2 tham số để kiểm
soát kiểu đường:
• dash - là một mảng biểu diễn kiểu đường. Các phần tử xen kẽ
của mảng biểu diễn kích thước nét gạch và khoảng cách giữa các nét
gạch .
Phần tử 0 biểu diễn nét gạch đầu tiên, phần tử thứ 1 biểu diễn khoảng
trắng đầu tiên.
http://tailieuhay.com 42
Lập trình đồ họa trên Java 2D và 3D
• dash_phase - là một offset định nghĩa nơi bắt đầu của mẫu nét
gạch.
Trong ví dụ sau đây, hai mẫu nét gạch được áp dụng cho một đường
thẳng. Trong mẫu thứ nhất ,kích thước của các nét gạch và khoảng trống
giữa chúng là không thay đổi. Mẫu thứ hai thì phức tạp hơn ,sử dụng
mảng sáu phần tử để định nghĩa
float dash1[] = {10.0f};
BasicStroke bs = new BasicStroke(5.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOiN_MiTER, 10.0f, dash1,
0.0f);
g2.setStroke(bs);
Line2D line = new Line2D.Float(20.0f,
10.0f, 100.0f, 10.0f);
g2.draw(line);
float[] dash2 = {6.0f, 4.0f, 2.0f,
4.0f, 2.0f, 4.0f};
bs = new BasicStroke(5.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOiN_MiTER, 10.0f, dash2,
0.0f);
g2.setStroke(bs);
g2.draw(line)
Cả hai mẫu đều sử dụng offset(địa chỉ bắt đầu của hai mẫu) 0 khi đó
các nét gạch đầu tiên sẽ ổ vị trí đầu của mẫu. Hai mẫu này được minh họa
trong hình2-7
http://tailieuhay.com 43
Lập trình đồ họa trên Java 2D và 3D
2.3.3 Specifying Fill Attributes
Thuộc tính cảu đối tượng Paint trong ngữ cảnh Graphics2D xác
định các màu tô hay các mẫu (kiểu )tô khi một đối tượng văn bản và
Shape được tạo bóng.
2.3.3.1 Filling a Shape with a Gradient
Lớp GradientPaint cung cấp một cách đơn giản để tô một hình bằng
kiểu tô loang . Khi khởi tạo đối tượng GradientPaint, cần xác định vị trí
đầu tiên cùng với màu tô và vị trí cuối cùng một màu tô. Kiểu tô này sẽ
thay đổi tỉ lệ từ màu này sang màu khác dọc theo đường nối của hai vị trí
đã chọn, minh họa trong hình 2-8.
Trong ngôi sao thứ ba,cả hai điểm đều nằm trong cùng một hình.Tất
cả các điểm dọc theo đường tô loang mở rộng qua điểm P1 sẽ nhận được
màu ban đầu và các điểm dọc theo đường tô loang được mở rộng ngoài
điểm P2 sẽ nhận màu kết thúc.
Các bước cần thực hiện để tô loang theo hai màu:
1. Khởi tạo đối tượng GradientPaint .
2. Gọi phương thức Graphics2D.setPaint.
3. Khởi tạo đối tượng Shape.
http://tailieuhay.com 44
Lập trình đồ họa trên Java 2D và 3D
Trong ví dụ sau đây, một hình chữ nhật được tô với mẫu dệt đơn giản
từ một đối tượng buffered image.
GradientPaint gp = new
GradientPaint(50.0f, 50.0f, Color.blue
50.0f, 250.0f, Color.green);
g2.setPaint(gp);
g2.fillRect(50, 50, 200, 200);
2.3.3.2 Filling a Shape with a Texture
Lớp TexturePaint cung cấp một cách đơn giản để tô hình bằng mẫu lặp.
Khi tạo một đối tượng Bufferedimage để sử dụng như là một mẫu tô. Cần
chuyển hàm khởi tạo một hình chữ nhật để định nghĩa tần số lặp cho
mẫu ,được chi ra trong hình 2-9.
Để tô hình theo mẫu dệt:
1. Tạo đối tượng TexturePaint
2. Gọi phương thức Graphics2D.setPaint.
3. Tạo đối tượng Shape.
4. Gọi phương thức Graphics2D.fill(shape).
Trong ví dụ sau đây, một hình chữ nhật được tô với mẫu dệt
đơn giản từ một đối tượng bufferedimage.
// Create a buffered image texture patch
of size //5x5
Bufferedimage bi = new Bufferedimage(5, 5,
Bufferedimage.TYPE_iNT_RGB);
Graphics2D big = bi.createGraphics();
big.setColor(Color.green);
http://tailieuhay.com 45
Lập trình đồ họa trên Java 2D và 3D
big.fillRect(0,0,5,5);
big.setColor(Color.lightGray);
big.fillOval(0,0,5,5);
// Create a texture paint from the
buffered image
Rectangle r = new Rectangle(0,0,5,5);
TexturePaint tp = new
TexturePaint(bi,r,TexturePaint.NEAREST_NEiGHBOR);
// Add the texture paint to the graphics
context. g2.setPaint(tp);
// Create and render a rectangle filled
with the texture. g2.fillRect(0,0,200,200);
}
2.3.4 Setting the Clipping Path
Để định nghĩa một khung nhìn:
1. Khởi tạo một đối tượng Shape mà biểu diễn vùng muốn tạo
bóng.
2. Gọi phương thức Graphics2D.setClip để sử dụng đối tuợng
shape như là một khung nhìn cho ngữ cảnh Graphics2D .
Để thu hẹp khung nhìn:
1. Khởi tạo đối tượng Shape mà giao với khung hnìn hiện tại.
2. Gọi phương thức clip để thay đổi khung nhìn cho phần giao
nhau của khung nhìn hiện tại và đối tượng Shape mới.
Trong ví dụ cho sau đây, một khung nhìn được tạo ra từ một elip và
sau đó được thay đổi băng cách gọi phương thức clip.
public void paint(Graphics g) {
http://tailieuhay.com 46
Lập trình đồ họa trên Java 2D và 3D
Graphics2D g2 = (Graphics2D) g;
// The width and height of the canvas
int w = getSize().width;
int h = getSize().height;
// Create an ellipse and use it as
the clipping path
Ellipse2D e = new
Ellipse2D.Float(w/4.0f,h/4.0f,
w/2.0f,h/2.0f);
g2.setClip(e);
// Fill the canvas. Only the area
within the clip is rendered
g2.setColor(Color.cyan);
g2.fillRect(0,0,w,h);
// Change the clipping path, setting
it to the intersection of
// the current clip and a new
rectangle.
Rectangle r = new
Rectangle(w/4+10,h/4+10,w/2-20,h/2-20);
g2.clip(r);
// Fill the canvas. Only the area
within the new clip
// is rendered
http://tailieuhay.com 47
Lập trình đồ họa trên Java 2D và 3D
g2.setColor(Color.magenta);
g2.fillRect(0,0,w,h);
2.3.5 Setting the Graphics2D Transform
Để biến đổi đối tượng Shape,xâu văn bản, hay ảnh cần phải thêm vào
một phép biến đổi mới AffineTransform cho đường ống phép biến đổi
tronh ngữ cảnh của Graphics2D trước khi tạo bóng . phép biến đổi được
áp dụng khi đối tượng đồ họa được tạo bóng .
Ví dụ để vẽ một hình chữ nhật nghiêng 45 độ:
1. Lấy một phép biến đổi Graphics2D trước khi thực hiện bất
kì phép biến đổi nào . Luôn gọi phương thức getTransform
trong đối tượng Graphics2D trước khi thêm vào một phép biến
đổi cho ngữ cảnh đồ họa bởi vì ngữ cảnh đồ họa có thể đã tồn
tại một phép biến đổi cho một lí do khác ,định vị Swing và các
thành phần trong một cửa sổ.
2. Lấy phép quay bằng cách gọi AffineTransform.
getRotateinstance.
3. Gọi phương thức Graphics2D.transform để thêm vào các
phép biến đổi mới cho đường ống biến đổi. Không được sử
dụng phương thức setTransform để thêm một phép biến đổi tọa
độ mới,bởi vì setTransform sẽ ghi đè lên phép biến đổi hiện tại
trong ngữ cảnh đồ họa
1. 4.Tạo đối tượng Rectangle2D.Float .
4. Gọi phươn thức Graphics2D.draw để tạo bóng hình chữ
nhật.
5. Sau khi tạo bóng cho hình chữ nhật đã được biến đổi , thì
reset phép biến đổi của Graphics2D trở về phép biến đổi ban
http://tailieuhay.com 48
Lập trình đồ họa trên Java 2D và 3D
đầu mà đã lưu trong bước 1 bằng cách gọi phương thức
setTransform cho phép biến đổi ban đầu .
Trong ví dụ sau đây, một thể hiện của AffineTransform được sử
dụng để quay hình chữ nhật đi 45 độ khi nó được tạo bóng.
AffineTransform aT = g2.getTransform();
Rectangle2D rect = new
Rectangle2D.Float(1.0,1.0,2.0,3.0);
AffineTransform rotate45 =
AffineTransform.getRotateinstance(Math.Pi
/4.0,0.0,0.0)
g2.transform(rotate45);
g2.draw(rect);
g2.setTransform(aT);
Còn trong ví dụ này,một đối tượng AffineTransform được sử dụng
để quay các câu text xung quang một điểm trung tâm.
// Define the rendering transform
AffineTransform at = new
AffineTransform();
// Apply a translation transform to
make room for the
// rotated text.
http://tailieuhay.com 49
Lập trình đồ họa trên Java 2D và 3D
at.setToTranslation(400.0, 400.0);
g2.transform(at);
// Create a rotation transform to
rotate the text
at.setToRotation(Math.Pi / 2.0);
// Render four copies of the string
“Java” at 90 degree angles
for (int i = 0; i < 4; i++) {
g2.drawString(“Java”, 0.0f, 0.0f);
g2.transform(at);
}
Có thể biến đổi ảnh trong cách tương tự -phép biến đổi trong ngữ
cảnh Graphics2D được áp dụng trong quá trình tạo bóng mà không cần
quan tâm đến kiểu đối tượng đồ hạo đang được tạo bóng
Để áp dụng phép biến đổi cho ảnh mà không cần thay đổi phép biến
đổi trong ngữ cảnh Graphics2D , thì chuyển AffineTransform sang
drawimage:
AffineTransform rotate45 =
AffineTransform.getRotateinstance(Math.Pi
/4.0,0.0,0.0)
g2.drawimage(myimage, rotate45);
Các phép biến đổi cũng được áp dụng cho đối tượng Font để tạo ra
một kiểu.
http://tailieuhay.com 50
Lập trình đồ họa trên Java 2D và 3D
2.3.6 Specifying a Composition Style
Một đối tượng AlphaComposite chứa các luật kết hợp để xác định
các màu sẽ được tạo bóng như thế nào khi đối tượng nàu đè lên đối tượng
khác . Để xác định các kiểu kết hợp cho ngữ cảnh Graphics2D , cần tạo
một đối tượng AlphaComposite và chuyền nó vào phương thức
setComposite. Kiểu thông dụng nhất là SRC_OVER.
2.3.6.1 Using the Source Over Compositing Rule
Luật kết hợp SRC_OVER sẽ kết hợp các điểm ảnh nguồn (source
pixel) với các điểm ảnh đích (destination pixel). Ví dụ ,nếu tạo bóng một
hình chữ nhật màu xanh nước biển (blue) và sau đó tạo bóng một hình
chữ nhật màu đỏ mà đè lên một phần của hình chữ nhật kia,thì vùng giao
nhau đó sẽ có màu đỏ. Hay nói cách khác ,đối tương mà được tạo bóng
cuối cùng sẽ xuất hiện ở trên cùng .
Để sử dụng luật kết hợp SRC_OVER :
1. Tạo một đối tượng AlphaComposite bằng cách gọi phương
thức getinstance và xác định luật
SRC_OVER .
AlphaComposite ac
=AlphaComposite.getinstance(AlphaComposite.SRC_OV
ER);
2. Gọi phương thức setComposite để thêm đối tuợng
AlphaComposite cho ngữ cảnh của Graphics2D.
g2.setComposite(ac);
Mỗi khi đối tượng kết hợp này được thiết lập ,thì đối tượng đè lên
được tạo bóng bằng cách sử dụng luật kết hợp đã xác định.
2.3.6.2 Increasing the Transparency of Composited Objects
http://tailieuhay.com 51
Lập trình đồ họa trên Java 2D và 3D
AlphaComposite cho phép xác định một giá trị hằng số alpha thêm
vào mà được nhân với giá trị alpha của các điểm ảnh nguồn để tăng độ
trong suốt.
Ví dụ ,để khởi tạo một đối tượng AlphaComposite mà tạo bóng đối
tượng nguồn có độ trong suốt là 50% ,xác định một giá trị alpha là .5:
AlphaComposite ac
=AlphaComposite.getinstance(AlphaComposite.SRC_OV
ER, .5f);
Trong ví dụ cho sau đây, a source over alpha composite object is
created with an alpha of .5 and added to the graphics context, causing
subsequent shapes to be
rendered 50% transparent.
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.translate(100,50);
// radians=degree * pie / 180
g2.rotate((45*java.lang.Math.Pi)/180);
g2.fillRect(0,0,100,100);
g2.setTransform(new AffineTransform()); //
set to identity
// Create a new alpha composite
AlphaComposite ac =
http://tailieuhay.com 52
Lập trình đồ họa trên Java 2D và 3D
AlphaComposite.getinstance(AlphaComposite.SR
C_OVER,0.5f);
g2.setComposite(ac);
g2.setColor(Color.green);
g2.fillRect(50,0,100,100);
g2.setColor(Color.blue);
g2.fillRect(125,75,100,100);
g2.setColor(Color.yellow);
g2.fillRect(50,125,100,100);
g2.setColor(Color.pink);
g2.fillRect(-25,75,100,100);
}
2.4 Rendering Graphics Primitives
Graphics2D cung cấp các phương thưc tạo bóng cho các cơ sở đồ
họa như Shapes, Text, và images:
• draw—tạo nét cho đường viền của đối tựợng Shape bằng cách sử
dụng các đối tượng Stroke và Paint trong ngữ cảnh Graphics2D .
• fill—tô một đối tượng Shape bằng cách sử dụng đối tượng Paint
trong ngữ cảnh Graphics2D .
• drawString—tạo bóng các xâu văn bản đã dược xác định bằng cách
sư dụng đối tượng Paint trong ngữ cảnh Graphics2D .
• drawimage—tạo bóng các ảnh đã được xác định
2.4.1 Drawing a Shape
Đường biên của bất kì đối tượng Shape cũng được tạo bóng bằng
phương thức Graphics2D.draw.
http://tailieuhay.com 53
Lập trình đồ họa trên Java 2D và 3D
Phương thức vẽ từ các phiên bản trước cũng được hỗ trợ : drawLine,
drawRect, drawRoundRect, drawOval, drawArc,drawPolyline,
drawPolygon, draw3DRect.
Khi một đối tượng Shape được vẽ , thì đường biên của nó sẽ được tạo
nét bằng đối tượng Stroke trong ngữ cảnh Graphics2D
Bằng việc thiét lập đối tượng BasicStroke phù hợp trong ngữ cảnh
Graphics2D ,thò có thể vẽ đường thẳng với độ rộng và mẫu nét gạch bất
kì . Đối tượng BasicStroke cũng định nghĩa các thuộc tính endcap và
join của đường thẳng .
Để tạo bóng cho các đường biên của đối tượng shape:
1. Khởi tạo cho đối tượng BasicStroke
2. Gọi phương thức Graphics2D.setStroke
3. Khởi tạo cho đối tượng Shape.
4. Gọi phương thức Graphics2D.draw(shape).
Trong ví dụ sau,đối tượng GeneralPath được sử dụng để định nghĩa
một ngôi sao và một đối tượng BasicStroke được thêm vào ngữ cảnh
Graphics2D để định nghĩa cho các cạnh của ngôi sao với các thuộc tính
join .
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
// create and set the stroke
g2.setStroke(new BasicStroke(4.0f));
// Create a star using a general path
object
http://tailieuhay.com 54
Lập trình đồ họa trên Java 2D và 3D
GeneralPath p = new
GeneralPath(GeneralPath.NON_ZERO);
p.moveTo(- 100.0f, - 25.0f);
p.lineTo(+ 100.0f, - 25.0f);
p.lineTo(- 50.0f, + 100.0f);
p.lineTo(+ 0.0f, - 100.0f);
p.lineTo(+ 50.0f, + 100.0f);
p.closePath();
// translate origin towards center of
canvas g2.translate(100.0f, 100.0f);
// render the star's path
g2.draw(p);
}
2.4.2 Filling a Shape
Phương thức Graphics2D.fill có thể được sử dụng để tô bất kì đối
tượng Shape. Khi một đối tượng Shape được tô, thì phần bị giới hạn bởi
đương bao của đối tượng sẽ được tạo bóng với ngữ cảnh Graphics2D của
thuộc tính Paint attribute—như Color, TexturePaint, or GradientPaint.
Phương thức tô từ các phiên bản trước đó của phần mềm JDK cũng
được hỗ trợ: fillRect, fill3DRect, fillRoundRect, fillOval, fillArc,
fillPolygon,clearRect.
Để tô một đối tượng Shape:
1. Xác định màu tô và kiểu tô trong ngữ cảnh đồ họa bằng
cách sử dụng Graphics2D.setColor hay
Graphics2D.setPaint.
http://tailieuhay.com 55
Lập trình đồ họa trên Java 2D và 3D
1. Khởi tạo đối tượng Shape.
2. Gọi phương thức Graphics2D.fill để tạo bóng đối tựơng
Shape.
Trong ví dụ sau đây ,phương thức setColor được gọi để định nghĩa
màu tô là green fill cho một đối tượng Rectangle2D.
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(Color.green);
Rectangle2D r2 = new
Rectangle2D.Float(25,25,150,150);
g2.fill(r2);
}
2.4.3 Rendering Text
Để tạo bóng văn bản ,cần gọi Graphics2D.drawString, sau đó chuyển
vào xâu mà bạn muốn tạo bóng
2.4.4 Rendering images
Để tạo bóng văn bản ,cần gọi Graphics2D.drawimage, sau đó chuyển
vào xâu mà bạn muốn tạo bóng .
2.5 Defining Custom Composition Rules
Có thể tạo một kiểu mới hoàn toàn của phép kết hợp băng cách thực
thi các interface Composite và CompositeContext . Một đối tượng
Composite cung cấp một đối tượng CompositeContext mà thực chất là
lưu trạng thái và thưc hiện công việc kết hợp. Nhiều đối tượng
http://tailieuhay.com 56
Lập trình đồ họa trên Java 2D và 3D
CompositeContext có thể được tạo từ một đối tượng Composite để lưu
các trạng thái riêng biệt trong môi trường đa luồng (multithreaded
environment.)
2.6 Rendering in a Multi-Screen Environment
TrongJavaTM 2 SDK, version 1.3, Java 2DTM API hỗ trợ những cấu
hình đa màn hiển thi khác nhau mà có thể được cấu hình bởi một môi
trường mà :
• Có hai hoặc nhiều màn hình độc lập
• Có hai hoặc nhiều màn hình nơi chỉ có một màn hình chính và
các màn hiển thị khác sẽ copy những hình ảnh xuát hiện trên màn
hình chính
• Hai hoặc nhiều màn hình mà có dạng như một máy ảo và nó cho
phép gọi các thiết bị ảo.
Java 2D API cho phép tạo các đối tượng Frame, JFrame, Window,
hoặc Jwindow .Với một đối tượng GraphicsConfiguration để xác định
các thiết bị hiển thị cho quá trình tạo bóng. Trong cả ba cấu hình,mỗi thiết
bị hiển thị được biểu diễn bởi một đối tượng GraphicsDevice.Một đối
tượng GraphicsDevice có nhiều đối tượng GraphicsConfiguration kết
hợp với nó .
Khi hai hoặc nhiều màn hình được sử dụng để tạo một thiết bị ảo ,hệ
tọa độ ảo (mà tồn tại độc lập với thiết bị hiển thị vật lý )được sử dụng để
biểu diễn thiết bị ảo đó . Các biên cảu mỗi đối tượng
GraphicsConfiguration trong cấu hình đa màn hiển thị có quan hệ với
hệ tọa độ ảo . Một màn hiển thị trong môi trường này được xác định như
là màn hiển thị chính và tạ vị trí (0, 0) của hệ tọa độ ảo . Dựa trên vị trí
của màn hiển thị chính ,thiết bị ảo có thể có tọa độ âm ,như trong hình 2-
10:
http://tailieuhay.com 57
Lập trình đồ họa trên Java 2D và 3D
Để xác định nếu là môi trường thiết bị ảo nơi mà một đối tượng
Window
hay Frame có thể xuất hiện trên hai hay nhiều màn hình vật lý ,thì gọi
phương thức getBounds trên mỗi đối tượng GraphicsConfiguration
trong hệ thống và kiểm tra nếu gốc tọa độ khác vị trí (0, 0). Phương thức
getBounds của đối tượng GraphicsConfiguration trả về một đối tượng
hình Rectangle trong hệ tọa độ ảo .Vì vậy ,nếu một gốc tọa độ không phải
vị trí (0, 0), thì môi trường đó chính là môi trường ảo.
Trong môi trường thiết bị ảo ,các tọa độ của các đối tượng
GraphicsConfiguration có quan hệ với hệ tọa độ ảo . Vì vậy, phải sử
dụng tọa độ ảo khi gọi phương thức setLocation của đối tượng Frame
hay Window. Cho ví dụ,Đoạn mã này sẽ lấy đường bao của một đối
tượng GraphicsConfiguration và sử dụng các đường bao để thiết lập vị
trí của đối tượng Frame tại tọa độ (10, 10) trong hệ tọa độ của màn hiển
thị vật lý .
Frame f = new Frame(GraphicsConfiguration
gc);
Rectangle bounds = gc.getBounds();
http://tailieuhay.com 58
Lập trình đồ họa trên Java 2D và 3D
f.setLocation(10 + bounds.x, 10 +
bounds.y);
Nếu các đường bao của đối tượng GraphicsConfiguration không
được tính đến , thì đối tượng Frame được hiển thị tại vị trí (10, 10) trên
mà hình vật lý chính , điều này có thể khác với mà hình vật lý của đối
tượng GraphicsConfiguration đã được xác định .
Phương thức getBounds có thể được sử dụng để xác định các đường
biên cảu thiết bị ảo. Gọi phương thức getBounds trên mỗi đối tượng
GraphicsConfiguration trong hệ thống . Để xác dịnh các đường bao cảu
thiết bị ảo , tính toán sự kết hợp của các đường bao. Kĩ thuật này được sử
dụng trong ví dụ sau.
Rectangle virtualBounds = new
Rectangle();
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnviron
ment();
GraphicsDevice[] gs =
ge.getScreenDevices();
for (int j = 0; j < gs.length; j+
+) {
GraphicsDevice gd = gs[j];
GraphicsConfiguration[] gc =
gd.getConfigurations();
http://tailieuhay.com 59
Lập trình đồ họa trên Java 2D và 3D
for (int i = 0; i < gc.length; i+
+) {
virtualBounds =
virtualBounds.union(gc[i].getBounds());
}
}
Applet sau sẽ tạo một đối tượng JFrame với mỗi đối tượng
GraphicsConfiguration của mỗi đối tượng GraphicsDevice trong đối
tượng GraphicsEnvironment. Mỗi đối tượng JFrame hiển thị một tập
các vạch đỏ, xanh đậm ,xanh nhạt,số lượng các màn hiển thị số lượng các
đối tượng GraphicsConfiguration và các đường bao cuả đối tượng
GraphicsConfiguration. Đoạn mã sau phải được chạy với JavaTM 2
SDK, version 1.3 hoặc cao hơn.
/*
* Transform.java
* 1.0
* 27/03/06
* Day la doan chuong trinh mieu ta cac phep bien
doi.
*/
import java.awt.*;
import javax.swing.*;
http://tailieuhay.com 60
Lập trình đồ họa trên Java 2D và 3D
/*
* Chuong trinh nay tao bong mot hinh duoc chon
boi nguoi su dung.Voi cac phuong
* thuc paint,stroke, va rendering cung duoc lua
chon boi nguoi su dung.
*/
/**
* @author Administrator
*
*/
public class Transform extends JApplet implements
itemListener, ActionListener {
/**
*
*/
private static final long serialVersionUiD =
-2514519718222913151L;
JLabel primLabel, lineLabel, paintLabel,
transLabel, strokeLabel;
TransPanel display;
static JComboBox primitive, line, paint,
trans, stroke;
JButton redraw;
public static boolean no2D = false;
http://tailieuhay.com 61
Lập trình đồ họa trên Java 2D và 3D
public void init() {
GridBagLayout layOut = new
GridBagLayout();
getContentPane().setLayout(layOut);
GridBagConstraints c = new
GridBagConstraints();
c.weightx = 1.0;
c.fill = GridBagConstraints.BOTH;
primLabel = new JLabel();
primLabel.setText("Hình g c");ố
Font newFont = getFont().deriveFont(1);
primLabel.setFont(newFont);
primLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(primLabel, c);
getContentPane().add(primLabel);
lineLabel = new JLabel();
lineLabel.setText("Các ng");đườ
lineLabel.setFont(newFont);
lineLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(lineLabel, c);
getContentPane().add(lineLabel);
paintLabel = new JLabel();
paintLabel.setText("Ki u v ");ể ẽ
http://tailieuhay.com 62
Lập trình đồ họa trên Java 2D và 3D
paintLabel.setFont(newFont);
paintLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(paintLabel, c);
getContentPane().add(paintLabel);
c.gridwidth =
GridBagConstraints.RELATiVE;
transLabel = new JLabel();
transLabel.setText("Các phép bi n i");ế đổ
transLabel.setFont(newFont);
transLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(transLabel, c);
getContentPane().add(transLabel);
c.gridwidth =
GridBagConstraints.REMAiNDER;
strokeLabel = new JLabel();
strokeLabel.setText("Tô trát");
strokeLabel.setFont(newFont);
strokeLabel.setHorizontalAlignment(JLabel.CENTER)
;
layOut.setConstraints(strokeLabel, c);
getContentPane().add(strokeLabel);
http://tailieuhay.com 63
Lập trình đồ họa trên Java 2D và 3D
GridBagConstraints ls = new
GridBagConstraints();
ls.weightx = 1.0;
ls.fill = GridBagConstraints.BOTH;
primitive = new JComboBox(new Object[]
{ "Hình ch nh t", "Hình elip",ữ ậ
"V n b n" });ă ả
primitive.additemListener(this);
newFont = newFont.deriveFont(0, 14.0f);
primitive.setFont(newFont);
layOut.setConstraints(primitive, ls);
getContentPane().add(primitive);
line = new JComboBox(new Object[]
{ "M nh", " m", "Nét t" });ả Đậ đứ
line.additemListener(this);
line.setFont(newFont);
layOut.setConstraints(line, ls);
getContentPane().add(line);
paint = new JComboBox(new Object[]
{ " ng nh t", "Tô loang", "polka" });Đồ ấ
paint.additemListener(this);
paint.setFont(newFont);
layOut.setConstraints(paint, ls);
getContentPane().add(paint);
ls.gridwidth =
GridBagConstraints.RELATiVE;
http://tailieuhay.com 64
Lập trình đồ họa trên Java 2D và 3D
trans = new JComboBox(new Object[]
{ "identity", "Quay", "T l ",ỉ ệ
"shear" });
trans.additemListener(this);
trans.setFont(newFont);
layOut.setConstraints(trans, ls);
getContentPane().add(trans);
ls.gridwidth =
GridBagConstraints.REMAiNDER;
stroke = new JComboBox(new Object[]
{ " ng nét", "Tô y",Đườ đầ
" ng nét va Tô y" });Đườ đầ
stroke.additemListener(this);
stroke.setFont(newFont);
layOut.setConstraints(stroke, ls);
getContentPane().add(stroke);
GridBagConstraints button = new
GridBagConstraints();
button.gridwidth =
GridBagConstraints.REMAiNDER;
redraw = new JButton("V l i");ẽ ạ
redraw.addActionListener(this);
redraw.setFont(newFont);
layOut.setConstraints(redraw, button);
getContentPane().add(redraw);
GridBagConstraints tP = new
GridBagConstraints();
http://tailieuhay.com 65
Lập trình đồ họa trên Java 2D và 3D
tP.fill = GridBagConstraints.BOTH;
tP.weightx = 1.0;
tP.weighty = 1.0;
tP.gridwidth =
GridBagConstraints.REMAiNDER;
display = new TransPanel();
layOut.setConstraints(display, tP);
display.setBackground(Color.white);
getContentPane().add(display);
validate();
}
public void itemStateChanged(itemEvent e) {
}
public void actionPerformed(ActionEvent e) {
display.setTrans(trans.getSelectedindex());
display.renderShape();
}
@SuppressWarnings("deprecation")
public static void main(String[] argv) {
if (argv.length > 0 && argv[0].equals("-
no2d")) {
Transform.no2D = true;
}
http://tailieuhay.com 66
Lập trình đồ họa trên Java 2D và 3D
JFrame frame = new JFrame("Các phép
chuy n i");ể đổ
frame.addWindowListener(new
WindowAdapter() {
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet applet = new Transform();
frame.getContentPane().add(BorderLayout.CENTER,
applet);
applet.init();
frame.setSize(550, 400);
frame.show();
}
}
@SuppressWarnings("serial")
class TransPanel extends JPanel {
AffineTransform at = new AffineTransform();
int w, h;
http://tailieuhay.com 67
Lập trình đồ họa trên Java 2D và 3D
Shape shapes[] = new Shape[3];
Bufferedimage bi;
boolean firstTime = true;
public TransPanel() {
setBackground(Color.white);
shapes[0] = new Rectangle(0, 0, 100,
100);
shapes[1] = new Ellipse2D.Double(0.0,
0.0, 100.0, 100.0);
TextLayout textTl = new
TextLayout("Brother Hood", new Font("Tomaha",
1, 76), new
FontRenderContext(null, false, false));
AffineTransform textAt = new
AffineTransform();
textAt.translate(0, (float)
textTl.getBounds().getHeight());
shapes[2] = textTl.getOutline(textAt);
}
public void setTrans(int transindex) {
switch (transindex) {
case 0:
at.setToidentity();
at.translate(w / 2, h / 2);
break;
http://tailieuhay.com 68
Lập trình đồ họa trên Java 2D và 3D
case 1:
at.rotate(Math.toRadians(45));
break;
case 2:
at.scale(0.5, 0.5);
break;
case 3:
at.shear(0.5, 0.0);
break;
}
}
public void renderShape() {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!Transform.no2D) {
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
w = d.width;
h = d.height;
String instruct = "Nh p m t hình cậ ộ ơ
s ban u, ki u ng,ki u v , phép bi n i,";ở đầ ể đườ ể ẽ ế đổ
TextLayout thisTl = new
TextLayout(instruct, new Font("Helvetica",
http://tailieuhay.com 69
Lập trình đồ họa trên Java 2D và 3D
0, 10),
g2.getFontRenderContext());
float width = (float)
thisTl.getBounds().getWidth();
float height = (float)
thisTl.getBounds().getHeight();
thisTl.draw(g2, w / 2 - width / 2,
15);
instruct = "và các ph ng th c t oươ ứ ạ
bóng sau ó nh n nút VE LAi.";đ ấ
thisTl = new TextLayout(instruct,
new Font("Helvetica", 0, 10), g2
.getFontRenderContext());
width = (float)
thisTl.getBounds().getWidth();
thisTl.draw(g2, w / 2 - width / 2,
height + 17);
// initialize the transform.
if (firstTime) {
at.setToidentity();
at.translate(w / 2, h / 2);
firstTime = false;
}
// Sets the Stroke.
Stroke oldStroke = g2.getStroke();
http://tailieuhay.com 70
Lập trình đồ họa trên Java 2D và 3D
switch
(Transform.line.getSelectedindex()) {
case 0:
g2.setStroke(new
BasicStroke(3.0f));
break;
case 1:
g2.setStroke(new
BasicStroke(8.0f));
break;
case 2:
float dash[] = { 10.0f };
g2.setStroke(new
BasicStroke(3.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOiN_MiTER,
10.0f, dash, 0.0f));
break;
}
// Sets the Paint.
Paint oldPaint = g2.getPaint();
switch
(Transform.paint.getSelectedindex()) {
case 0:
g2.setPaint(Color.blue);
break;
case 1:
g2.setPaint(new GradientPaint(0,
0, Color.lightGray, w - 250,
http://tailieuhay.com 71
Lập trình đồ họa trên Java 2D và 3D
h, Color.blue, false));
break;
case 2:
Bufferedimage buffi = new
Bufferedimage(15, 15,
Bufferedimage.TYPE_iNT_RGB);
Graphics2D buffig =
buffi.createGraphics();
buffig.setColor(Color.blue);
buffig.fillRect(0, 0, 15, 15);
buffig.setColor(Color.lightGray);
buffig.translate((15 / 2) - (5 /
2), (15 / 2) - (5 / 2));
buffig.fillOval(0, 0, 7, 7);
Rectangle r = new Rectangle(0,
0, 25, 25);
g2.setPaint(new
TexturePaint(buffi, r));
break;
}
// Sets the Shape.
Shape shape =
shapes[Transform.primitive.getSelectedindex()];
Rectangle r = shape.getBounds();
// Sets the selected Shape to the
center of the Canvas.
http://tailieuhay.com 72
Lập trình đồ họa trên Java 2D và 3D
AffineTransform saveXform =
g2.getTransform();
AffineTransform toCenterAt = new
AffineTransform();
toCenterAt.concatenate(at);
toCenterAt.translate(-(r.width / 2),
-(r.height / 2));
g2.transform(toCenterAt);
// Sets the rendering method.
switch
(Transform.stroke.getSelectedindex()) {
case 0:
g2.draw(shape);
break;
case 1:
g2.fill(shape);
break;
case 2:
Graphics2D tempg2 = g2;
g2.fill(shape);
g2.setColor(Color.darkGray);
g2.draw(shape);
g2.setPaint(tempg2.getPaint());
break;
}
g2.setStroke(oldStroke);
g2.setPaint(oldPaint);
http://tailieuhay.com 73
Lập trình đồ họa trên Java 2D và 3D
g2.setTransform(saveXform);
}
}
}
Kết quả sau khi chạy chương trình :
http://tailieuhay.com 74
Lập trình đồ họa trên Java 2D và 3D
Chương 3
Các đối tượng hình họa
Java 2D™ API cung cấp một số lớp để định nghĩa các đối tượng
geometric (hình học),chẳng hạn như điểm,đường thẳng,đường
cong,hình chữ nhật.Những lớp hình học mới đó là một phần của gói
java.awt.geom.Để có thể tương thích với các phiên bản cũ,các lớp
geometry có chứa trong các phiên bản trước đó của bộ JDK software,như
rectangle,point và polygon,được chứa trong gói java.awt.
Các đối tượng hình học trong Java 2D API như GenneralPath,Arc2D
và Rectangle2D cho phép thực thi việc tạo giao diện bệ mặt được định nghĩa trong
gói java.awt.Hình dáng cụ thể cung cấp cho ta một phương thức chung cho việc
miêu tả và kiểm tra đường dẫn của các đối tượng hình học.Một giao diện mới
Pathlterator,cung cấp các phương thức định nghĩa việc khôi phục các phần tử từ
một đối tượng hình học. Sử dụng các lớp hình học bạn có thể dễ dàng xác định và
thao tác với nhiều đối tượng hai chiều.
3.1 Giao diện và lớp.
Bảng dưới đây liệt kê những giao diện và các lớp chính của các đối
tượng hình học.Hầu hết trong sô các giao diện và các lớp là thành phần
của gói java.awt.geom.Một số,chẳng hạn như Shape,là thành phần của
gói java.awt,thành phần chính để có thể tương thích với các phiên bản
trước đây của bộ JDK.
Các lớp và giao diện của java.awt.geom
http://tailieuhay.com 75
Lập trình đồ họa trên Java 2D và 3D
Giao diện Mô tảPathIterator Định nghĩa các phương thức cho việc phục hồI các
phần tử từ một đường dẫn.Shape
(java.awt)
Cung cấp một tập các phương thức cho việc miêu tả
và kiểm tra đường dẫn hình học.Được thực thi bởI
GaneralPath và các lớp hình học khác.
Các lớp
Arc2D Arc2D.Double
Arc2D.Float
Mở rộng:RectangularShape
Miêu tả một đường cong được định nghĩa bằng
một hình chữ nhật có giớI hạn,góc ban đầu,và
một kiểu đóng kín.Việc thực thi chỉ rõ những
đường cong trong kiểu số float và double.
Chính xác:Arc2D.Float và Arc2D.Double.AreaArea Lớp thực thi:Shape,Cloneable.
Miêu tả một diện tích hình học mà hỗ trợ các
phép toán nhị phân.
CubicCurve2D
CubicCurve2D.Doubl
e
CubicCurve2D.Float
Implements: Shape
Lớp thực thi:Shape.
Miêu tả các đoạn đường cong tham số bậc ba
trong không gian tọa độ.Việc thực thi để chỉ rõ
các đường cong bậc ba vớI độ chính xác float và
double do hai lớp: CubicCurve2D.Float and
CubicCurve2D.Double.
Dimension2D Đóng gói cả chiều rộng và chiều cao.Một siêu
lớp trìu tượng cho tất cả các đốI tượng lưu trữ
dùng để lưu trữ các đốI tượng hai chiều.
http://tailieuhay.com 76
Lập trình đồ họa trên Java 2D và 3D
Ellipse2D
Ellipse2D.Double
Ellipse2D.Float
Mở rộng: RectangularShape
Miêu tả việc định nghĩa đường e-lip bằng các
hình chữ nhật giớI hạn.Công cụ để chỉ rõ các
đường cong elip vớI độ chính xác float và
double: Ellipse2D.Float và Ellipse2D.DoubleFlatteningPathIterator Trả về một flattened view của một đối tượng
PathLterator.
Có thể sử dụng để cung cấp các flattening
behavior cho các đối tượng Shape mà nó không
thực hiện việc tính toán các thành phần thêm vào.GeneralPath Thực thi đối tượng Shape
Miêu tả một khung hinhg được xây dựng từ các
đường thẳng và các đường bậc hai và bậc baLine2D
Line2D.Double
Line2D.Float
Thực thi đối tượng Shape.
Miêu tả một đoạn thẳng trong không gian tọa độ
(x,y) .Được thưc thi để xác định các đường thẳng
với độ chính xác float và double:: Line2D.Float
và Line2D.Double.Point2D
Point2D.Double
Point2D.Float
Một điểm miêu tả một vị trí trong không gian tọa
độ (x,y).Được thực thi để xác đinh các điểm với
độ chính xác float và double: Point2D.Float và
Point2D.Double.QuadCurve2D
QuadCurve2D.Doubl
e
QuadCurve2D.Float
Thực thi đối tượng Shape.
Miêu tả một đoạn đường cong tham số bậc hai
trong không gian tọa độ (x,y).Được thực thi để
xác định các đường bậc hai với độ chính xác
float và double: QuadCurve2D.Float và
QuadCurve2D.Double.Rectangle2D Mở rộng: RectangularShape
http://tailieuhay.com 77
Lập trình đồ họa trên Java 2D và 3D
Rectangle2D.Double
Rectangle2D.Float
Miêu tả một hình chữ nhật được định nghĩa bởi
một vị trí (x,y) và kích thước(w,x,h). Được thực
thi để xác đinh các hình chũ nhật với độ chính
xác float và double: Rectangle2D.Float và
Rectangle2D.Double.RectangularShape Thực thi đối tượng Shape.
Cung cấp sự thao tác chung cho các tác động lên
các đối tượng Shape mà nó có các hình chữ nhật
biên.RoundRectangle2D
RoundRectangle2D.D
ouble
RoundRectangle2D.Fl
oat
Mở rộng: RectangularShape
Miêu tả một hình chữ nhật các góc được làm tròn
được định nghĩa bằng một vị trí (x, y),một kích
thước (w x h),và chiều rộng và chiều cao của
góc cung. Được thực thi để xác đinh các hình chữ
nhật có góc tròn với độ chính xác float và double:
RoundRectangle2D.Float và
RoundRectangle2D.Double.
3.2 Các khái niệm hình học:
Shape là một thể hiện của nhiều lớp mà nó thực thi Shape
interface,như
GeneralPath or Rectangle2D .Float . Đường viền (outline) còn được
định nghĩa là path.
Khi một Shape được vẽ,kiểu đường nét vẽ được địng nghĩa bởi đối
tượng Stroke trong thư viện đồ họa 2D,được áp dụng cho Shape’s
path.Khi một Shape được phủ đầy,Paint trong thư viện đồ họa 2D được
áp dụng cho phần diện tích bên trong đường viền của nó.Để biết thêm
thông tin,bạn xem thêm phần “Rendering with Graphics2D”.
http://tailieuhay.com 78
Lập trình đồ họa trên Java 2D và 3D
Đường viền của một hình cũng có thể được sử dụng để định nghĩa
một clipping path.Một clipping path xác định những điểm ảnh nào được
đưa ra(render). clipping path là một phần của Graphics 2D. Để biết thêm
thông tin,bạn xem thêm phần “Setting the Clipping Path”.
Một GeneralPath là một shape mà nó có thể được sử dụng
để miêu tả một số đối tượng 2 chiều có thể được vẽ từ các đường
và các đường bậc hai hoặc bậc ba.Để thuận lợi, java.awt.geom
cung cấp thêm các thành phần thực thi của giao tiếp Shape mà
nó miêu tả các đối tượng đồ họa phổ biến như hình chữ
nhật,hình elip,cung tròn và các đường cong. The Java2D™ API còn
cung cấp một kiểu shape đặc biệt hỗ trợ cho việc xây dựng diện tích hình
học.
3.2.1 Constructive Area Geometry
Constructive Area Geometry (CAG) là một quá trình tạo ra các đối
tượng hình học mới bằng việc thực hiện các phép toán nhị phân trong các
đối tượng đã tồn tại.Trong Java 2D API một kiểu đặc biệt của Shape
được gọi là Area hỗ trợ các phép toán nhị phân.Bạn có thể tạo ra một đối
tượng Area từ một số Shape.
Các Area hỗ trợ các phép toán nhị phân sau:
• Union(hợp)
• intersection(giao)
• Subtraction(trừ)
• Exclusive OR (XOR) (OR dành riêng)
Các phép toán đó được miêu tả như hình 3-1 dưới đây:
http://tailieuhay.com 79
Lập trình đồ họa trên Java 2D và 3D
3.2.2 Bounds and Hit Testing
Một bounding box là một hình chữ nhật bao bọc hoàn toàn một một
thể thiện hình học. bounding box được sử dụng để quết định một đối
tượng có được chọn hay không hoặc được “hit” bởi người sử dụng.
Giao diện Shape xác định hai phương thức cho việc truy lại một
shape’s bounding box,đó là getBounds và getBounds2D.Phương thức
getBounds2D trả về một đối tượng Rectangle2D , một thể hiện của
Rectangle .Cung cấp một độ chính xác cao hơn trong việc miêu tả
shape’s bounding box.
Shape cũng cung cấp nhiều phương thức cho việc xác định :
• Một điểm cụ thể bên trong bao đóng của hình
thể(contains )
• Một hình chữ nhật cụ thể nằm hoàn toàn bên trong một
bao đóng của hình thể. (contains )
• Một hình chữ nhật cụ thể phân cắt hình thể (intersects )
/*
* Composite.java
* 1.0
* 20/03/06
*/
import java.awt.*;
http://tailieuhay.com 80
Lập trình đồ họa trên Java 2D và 3D
import javax.swing.*;
/*
* Chuong trinh nay la mot vi du ve cac luat ket
hop giua cac hinh.
*/
@SuppressWarnings("serial")
public class Composite extends JApplet implements
itemListener {
CompPanel comp;
JLabel alphaLabel, rulesLabel;
JComboBox alphas, rules;
String alpha = "1.0";
int rule = 0;
public void init() {
GridBagLayout layOut = new
GridBagLayout();
getContentPane().setLayout(layOut);
GridBagConstraints l = new
GridBagConstraints();
l.weightx = 1.0;
http://tailieuhay.com 81
Lập trình đồ họa trên Java 2D và 3D
l.fill = GridBagConstraints.BOTH;
l.gridwidth =
GridBagConstraints.RELATiVE;
alphaLabel = new JLabel();
alphaLabel.setText("C ng m u");ườ độ ầ
Font newFont = getFont().deriveFont(1);
alphaLabel.setFont(newFont);
alphaLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(alphaLabel, l);
getContentPane().add(alphaLabel);
getContentPane().setLayout(layOut);
l.gridwidth =
GridBagConstraints.REMAiNDER;
rulesLabel = new JLabel();
rulesLabel.setText("Các lu t k t h p.");ậ ế ợ
newFont = getFont().deriveFont(1);
rulesLabel.setFont(newFont);
rulesLabel.setHorizontalAlignment(JLabel.CENTER);
layOut.setConstraints(rulesLabel, l);
getContentPane().add(rulesLabel);
GridBagConstraints a = new
GridBagConstraints();
a.gridwidth =
GridBagConstraints.RELATiVE;
a.weightx = 1.0;
http://tailieuhay.com 82
Lập trình đồ họa trên Java 2D và 3D
a.fill = GridBagConstraints.BOTH;
alphas = new JComboBox();
layOut.setConstraints(alphas, a);
alphas.additem("1.0");
alphas.additem("0.75");
alphas.additem("0.50");
alphas.additem("0.25");
alphas.additem("0.0");
alphas.additemListener(this);
getContentPane().add(alphas);
a.gridwidth =
GridBagConstraints.REMAiNDER;
rules = new JComboBox();
layOut.setConstraints(rules, a);
rules.additem("SRC");
rules.additem("DST_iN");
rules.additem("DST_OUT");
rules.additem("DST_OVER");
rules.additem("SRC_iN");
rules.additem("SRC_OVER");
rules.additem("SRC_OUT");
rules.additem("CLEAR");
rules.additemListener(this);
getContentPane().add(rules);
GridBagConstraints fC = new
GridBagConstraints();
fC.fill = GridBagConstraints.BOTH;
fC.weightx = 1.0;
http://tailieuhay.com 83
Lập trình đồ họa trên Java 2D và 3D
fC.weighty = 1.0;
fC.gridwidth =
GridBagConstraints.REMAiNDER;
comp = new CompPanel();
layOut.setConstraints(comp, fC);
getContentPane().add(comp);
validate();
}
public void itemStateChanged(itemEvent e) {
if (e.getStateChange() !=
itemEvent.SELECTED) {
return;
}
Object choice = e.getSource();
if (choice == alphas) {
alpha = (String)
alphas.getSelecteditem();
} else {
rule = rules.getSelectedindex();
}
comp.changeRule(alpha, rule);
}
public static void main(String s[]) {
JFrame f = new JFrame("K t h p");ế ợ
f.addWindowListener(new WindowAdapter() {
http://tailieuhay.com 84
Lập trình đồ họa trên Java 2D và 3D
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet applet = new Composite();
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(300, 300));
f.show();
}
}
class CompPanel extends JPanel {
AlphaComposite ac =
AlphaComposite.getinstance(AlphaComposite.SRC);
float alpha = 1.0f;
public CompPanel() {
}
public void changeRule(String a, int rule) {
alpha = Float.valueOf(a).floatValue();
ac =
AlphaComposite.getinstance(getRule(rule), alpha);
repaint();
}
http://tailieuhay.com 85
Lập trình đồ họa trên Java 2D và 3D
public int getRule(int rule) {
int alphaComp = 0;
switch (rule) {
case 0:
alphaComp = AlphaComposite.SRC;
break;
case 1:
alphaComp = AlphaComposite.DST_iN;
break;
case 2:
alphaComp = AlphaComposite.DST_OUT;
break;
case 3:
alphaComp = AlphaComposite.DST_OVER;
break;
case 4:
alphaComp = AlphaComposite.SRC_iN;
break;
case 5:
alphaComp = AlphaComposite.SRC_OVER;
break;
case 6:
alphaComp = AlphaComposite.SRC_OUT;
break;
case 7:
alphaComp = AlphaComposite.CLEAR;
break;
}
return alphaComp;
http://tailieuhay.com 86
Lập trình đồ họa trên Java 2D và 3D
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
int w = d.width;
int h = d.height;
Bufferedimage buffimg = new
Bufferedimage(w, h,
Bufferedimage.TYPE_iNT_ARGB);
Graphics2D gbi =
buffimg.createGraphics();
g2.setColor(Color.white);
g2.fillRect(0, 0, d.width, d.height);
int rectx = w / 4;
int recty = h / 4;
gbi.setColor(new Color(0.0f, 0.0f, 1.0f,
1.0f));
gbi.fill(new Rectangle2D.Double(rectx,
recty, 150, 100));
gbi.setColor(new Color(1.0f, 0.0f, 0.0f,
1.0f));
gbi.setComposite(ac);
gbi.fill(new Ellipse2D.Double(rectx +
rectx / 2, recty + recty / 2,
http://tailieuhay.com 87
Lập trình đồ họa trên Java 2D và 3D
150, 100));
g2.drawimage(buffimg, null, 0, 0);
}
}
Kết quả của chương trình :
3.3 Combining Areas to Create New Shapes
Các Area có thể được sử dụng để tạo ra một cách nhanh chóng
các Shape phức tạp như các hình tròn và các hình vuông.Tạo một
hình thể phức tạp mới bằng cách kết hợp các Area như sau:
1.Sử dụng các Shape,tạo ra các Area để kết hợp lại.
2.Gọi các toán tử nhị phân thích hợp: add,subtract ,intersect ,
exclusiveOr
Ví dụ,CAG có thể được sử dụng để tạo ra quả lê giống như hình 3-2 dưới
đây:
http://tailieuhay.com 88
Lập trình đồ họa trên Java 2D và 3D
Cách thực hiện:
Thân của quả lê được tạo ra bằng cách kết hợp các thao tác trong 2
over- lapping Areas : circle và oval.Cái lá được tạo ra bằng cách thực
hiện một phép giao trên hai vòng tròn chồng lên nhau và sau đó được đưa
vào một Shape đơn thông qua phép hợp.Việc nạp chồng các vòng tròn
còn được sử dụng để tạo cuống lá thông qua hai phép trừ.
Chương trình:
/*
* @(#)Pear.java 1.0 27/03/06
*/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
http://tailieuhay.com 89
Lập trình đồ họa trên Java 2D và 3D
/*
* Chuong trinh nay ve mot qua le,su dung phuong
thuc ket hop giua cac vung.
*/
@SuppressWarnings("serial")
public class Pear extends JApplet {
Ellipse2D.Double circle, oval, leaf, stem;
Area circ, ov, leaf1, leaf2, st1, st2;
public void init() {
circle = new Ellipse2D.Double();
oval = new Ellipse2D.Double();
leaf = new Ellipse2D.Double();
stem = new Ellipse2D.Double();
circ = new Area(circle);
ov = new Area(oval);
leaf1 = new Area(leaf);
leaf2 = new Area(leaf);
st1 = new Area(stem);
st2 = new Area(stem);
setBackground(Color.white);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Dimension d = getSize();
http://tailieuhay.com 90
Lập trình đồ họa trên Java 2D và 3D
int w = d.width;
int h = d.height;
double ew = w / 2;
double eh = h / 2;
g2.setColor(Color.green);
leaf.setFrame(ew - 16, eh - 29, 15.0,
15.0);
leaf1 = new Area(leaf);
leaf.setFrame(ew - 14, eh - 47, 30.0,
30.0);
leaf2 = new Area(leaf);
leaf1.intersect(leaf2);
g2.fill(leaf1);
leaf.setFrame(ew + 1, eh - 29, 15.0,
15.0);
leaf1 = new Area(leaf);
leaf2.intersect(leaf1);
g2.fill(leaf2);
g2.setColor(Color.black);
stem.setFrame(ew, eh - 42, 40.0, 40.0);
st1 = new Area(stem);
stem.setFrame(ew + 3, eh - 47, 50.0,
50.0);
st2 = new Area(stem);
st1.subtract(st2);
g2.fill(st1);
g2.setColor(Color.yellow);
circle.setFrame(ew - 25, eh, 50.0, 50.0);
oval.setFrame(ew - 19, eh - 20, 40.0,
70.0);
http://tailieuhay.com 91
Lập trình đồ họa trên Java 2D và 3D
circ = new Area(circle);
ov = new Area(oval);
circ.add(ov);
g2.fill(circ);
}
public static void main(String s[]) {
JFrame f = new JFrame("Qu lê");ả
f.addWindowListener(new WindowAdapter() {
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet applet = new Pear();
f.getContentPane().add("Center", applet);
applet.init();
f.pack();
f.setSize(new Dimension(600, 400));
f.show();
}
}
Kết quả của chương trình:
http://tailieuhay.com 92
Lập trình đồ họa trên Java 2D và 3D
Chương 4:
Hiển thị Font và văn bản
Bạn có thể sử dụng các phép biến đổi và các công cụ drawing của
Java 2D™ API với văn bản.Hơn nữa, Java 2D™ API còn cung cấp các
lớp liên quan tới văn bản hỗ trợ các điều khiển font và các cách bố trí văn
bản phức tạp.Nó còn bao gồm cả lớp Font và lớp TextLayout.
Chương này tập chung vào khả năng hỗ trợ các kiểu font và các cách
bố trí văn bản(text layout) bằng việc sử dụng các giao diện và các lớp
trong java.awt và java.awt.font.
Để có thêm thông tin về phân tích văn bản,bạn tham khảo thêm văn
bản hướng dẫn về java.text và theo dõi phần “Writing Global Programs”
trong bộ Java Tutorial.
Để có thêm thông tin về cách sử dụng công cụ bố trí văn bản bằng cách
sử dụng Swing,bạn xem thêm phần java.awt.swing.text và “Using the
JFC/Swing Packages” trong Java Tutorial.
4.1.Giao diện và lớp.
Bảng dưới đây liệt kê các giao diện và các lớp chính sử dụng cho font
và textlayout.Hầu hết trong số giao diện và lớp này là thành phần của gói
ava.awt.font.Một số,như Font,là một phần của gói java.awt được sử
dụng để đảm bảo tính tương thích với các phiên bản trước đó của bộ JDK.
Bảng mô tả giao diện và lớp :
Giao diện Miêu tảMultipleMaste
r
Miêu tả các font kiểu 1 với nhiều đường.Được thực thi
bởi các đối tượng Font mà chúng là các kiểu font nhiều
đường để có thể truy cập đến các thiết kế điều khiển.OpenType Miêu tả các font kiểu mở(Open Type)và kiểu thực(True
http://tailieuhay.com 94
Lập trình đồ họa trên Java 2D và 3D
Type).Được thực thi bởi các đối tượng Font mà chúng là
các font Open Type hoặc True Type có thể truy cập đến
các bảng font’s sfnt.
Lớp Mô tảFont
(java.awt)
Miêu tả một thể hiện của bề mặt font(font face)
từ tập hợp các font face đã có sẵn trong máy.Hỗ
trợ việc đặc tả chi tiết về thông tin font và cung
cấp khả năng truy cập tới các thông tin về các
kiểu font và các đường nét của nó.FontRenderContext Đóng gói thông tin cần thiết cho các phép đo văn
bản một cách chính xác.GlyphJustificationInfo Miêu tả các thông tin về đặc tính căn lề của một
đường nét,như trọng lượng (chữ),độ ưu tiên,sự
thu hút và giới hạn.GlyphMetrics Cung cấp các phép đo cho một đường nét đơn.GlyphVector Một tập hợp các đường nét và các vị trí.GraphicAttribute Là lớp cơ sở cho thuộc tính TextLayout mà nó
đặc tả một đối tượng Graphics để được nhungd
vào văn bản.Được thực thi bởi
ShapẻGaphicAttribute và
ImageGraphicAttribute,mà nó có thể cho phép
các đối tượng Shape và đối tượng Image nhúng
vào một đối tượng TextLayout.Có thể phân lớp
để thực thi kí tự tùy chọn để thay thế các
graphic.ImageGraphicAttribute Mở rộng:GraphicAttribute
Một đối tượng GraphicsAttribute được sử dụng
để vẽ các ảnh bên trong một TextLayout.LineBreakMeasurer Chia một khối văn bản thành nhiều dòng trong
các đối tượng TextLayout mà nó khit bên trong
một dong.
http://tailieuhay.com 95
Lập trình đồ họa trên Java 2D và 3D
LineMetrics Cung cấp khả năng truy cập đến các thước đo
font cần thiết để hiển thị các kí tự trên một hàng
và hiển thị tập các hàng đó.Các thước đo bao
gồm phần nhô lên,phần phía dưới,phần mũ,chiều
cao và thông tin đường cơ bản(ascent, descent,
leading, height, and baseline information).ShapeGraphicAttribute Mở rộng:GraphicAttribute
Một đối tượng GraphicsAttribute được sử
dụng để vẽ các đối tượng Shape trong một đối
tượng TextLayoutTextAttribute Định nghĩa các thuộc tính quan trọng và các giá
trị được sử dụng cho việc tạo bóng văn bản(text
rendering).TextHitInfo Miêu tả thông tin hit test cho các kí tự trong một
đối tượng TextLayoutTextLayout Thực thi:Cloneable
Cung cấp một sự biểu diễn đồ họa cố định của
các dữ liệu kí tự đã được định kiểu,bao gồm cả
các văn bản hai chiều.
4.2.Các khái niệm về Font
Lớp Font đã được cải tiến để hỗ trợ việc đặc tả chi tiết thông tin về
kiểu font và có thể sử dụng các đặc tính phức tạp.
Một đối tượng Font miêu tả một thể hiện của kiểu font trong tập hợp
các font của hệ thống.Các font thương hay được sử dụng như font Helvet
Bold và Courier Bold italic.
Có ba kiểu tên cho một đối tượng Font-đó là logical name, family
name, và font face name:
http://tailieuhay.com 96
Lập trình đồ họa trên Java 2D và 3D
Một logical name của đối tượng Font là tên được ánh xạ đến một
trong nhiều font cụ thể đã có sẵn trong platform. logical name là tên font
được sử dụng để chỉ rõ một đối tượng Font trong JDK 1.1 và các phiên
bản trước đó.Khi chỉ định một đối tượng Font trong Java™ 2 SDK bạn
nên sử dụng font face name thay cho logical name.Bạn có thể nhận
logical name từ đối tượng font bằng cách goi j phương thức getName.Để
nhận được danh sách các logical name,hãy gọi
java.awt.Toolkit.getFontList.
Một family name của đối tượng Font là tên trong họ font mà nó định
nghĩa cách thiết kế việc in thông qua một số bề mặt,chẳng hạn như kiểu
chữ Helvetica.Bạn lấy họ tên font bằng cách sử dụng phương thức
getFamily.
Một font face name của đối tượng Font dùng để ám chỉ kích thước
thật của font được cài đặt trong hệ thống.Đó là tên mà bạn có thể sử dụng
khi chỉ rõ một kiểu font trong Java 2 SDK.Nó cũng thường được ám chỉ
cho font name.Bạn có thể lấy tên font bằng cách gọi phương thức
geFontName.Để xác định kiểu font nào được sử dụng trong hệ thống,bạn
có thể gọi phương thức GraphicsEnvironment.getAllFonts.
Bạn có thể truy xuất các thông tin về một đối tượng Font bằng việc
gọi phương thức getAttributes. Các thuộc tính của Font bao gồm tên,kích
cỡ font,transform,đặc tính font như hình dáng font.
Một đối tượng LineMetrics đóng gói các thông tin về các số đo của
Font,như ascent,descent và khoảng cách giữa các dòng chữ.
• Ascent là khoảng cách từ đường baseline đến đường
ascender.Khoảng cách này miêu tả chiều cao của các chữ viết hoa,nhưng
một số kí tự có thể mở rộng về phía trên của đường ascender.
• Descent là khoảng cách từ đường baseline đến đường
descender.Điểm thấp nhất của hầu hết các kí tự sẽ nằm bên trong
http://tailieuhay.com 97
Lập trình đồ họa trên Java 2D và 3D
descent,nhưng có một số kí tự có thể mở rộng về phía dưới của đường
descender.
• Leading được nói tới như là khoảng cách từ đáy của đường
descender đến đỉnh của dòng tiếp theo.
Thông tin này được sử dụng để định vị một cách chính xác các kí
tự dọc theo một dòng,và các đường có thể liên quan đến các đường khác.
Bạn có thể truy xuất những phép đo các line bằng việc sử dụng các
phương thức getAscent, getDescent, và getLeading .Bạn cũng có thể
truy xuất thông tin vê weight, baseline và underline của Font thông qua
LineMetrics.
4.3 Các khái niệm về Text Layout.
Trước khi một đoạn chữ có được hiển thị,nó cần phải được chỉ rõ về
hình dáng cũng như vị trí hiển thị bằng việc sử dụng các nét chữ và các
cách kết hợp một thích hợp.Quá trình này được gọi là text layout,bao gồm
các giai đoạn sau:
• Sắp đặt các chữ sử dụng các nét chữ và các cách kết hợp thích
hợp.
• Ordering các đoạn text thích hợp.
• Đánh giá và bố trí các đoạn text.
http://tailieuhay.com 98
Lập trình đồ họa trên Java 2D và 3D
Các thông tin cho được sử dụng để hiển thị text cũng rất cần thiết cho
việc biểu diễn text như caret positioning, hit detection, và highlighting.
Để phát triển các phần mềm có thể triển khai trên toàn cầu,text phải được
thể hiện trên nhiều ngôn ngữ khác nhau bằng nhiều để có thể thích hợp
với quy tắc của các hệ thống văn bản thích hợp.
4.3.1 Vẽ chữ.
Gyph(nét chữ) là một cách hiển thị trực quan cho một hay nhiều kí
tự.Hình dáng,kích thước,và vị trí của glyph phụ thuộc vào văn cảnh của
nó.Rất nhiều loại glyph có thể được sử dụng để miêu tả một kí tự đơn
hoặc nhiêu kí tự kết hợp với nhau,phụ thuộc vào font và kiểu dáng(style).
Ví dụ như trong đoạn text viết bằng tay,các kí tự đặc biệt có thể thể
hiện các hình dáng chữ khác nhau phụ thuộc vào cách nó kết hợp với các
kí tự liền kề với nó.
Trong một số hệ thống văn bản,đặc biệt là chữ Ả Rập, the context of a
glyph must always be taken into account .Không giống tiếng Anh,các
cursive form có tính bắt buộc trong chữ Ả Rập.
Phụ thuộc vào từng context,các cursive form có thể khác nhau hoàn
toàn về hình dáng.Ví dụ,chữ heh trong tiếng Ả Rập có bốn cursive form
http://tailieuhay.com 99
Lập trình đồ họa trên Java 2D và 3D
như trong hình 4-2 dưới đây:
Mặc dù bốn kiểu form này chỉ khác nhau đôi chút so với cá form
khác,nhưng những sự thay đổi về hình dáng không phải là sự khác biệt cơ
bản về cursive trong tiêng Anh.
Trong một số ngữ cảnh,hai glyph có thể thay đổi hình dáng một cách
cơ bản và kết hợp vào form một glyph đơn.Kiểu kết hợp này được gọi là
ligature.Ví dụ,hầu hết các font tiếng anh chứa ligature như trong hình 4-
3.Việc hòa hợp glyph đưa vào tính toán phần nhô ra trong kí tự f và kết
hợp các kí tự theo một cách tự nhiên,thay vì các kí tự kề nhau
http://tailieuhay.com 100
Lập trình đồ họa trên Java 2D và 3D
Các chữ ghép cũng được sử dụng trong tiếng Ả rập và cách sử dụng
của một số chữ ghép is mandatory-nó không được chấp nhận để hiển thị
các kí tự kết hợp chính xác mà không sử dụng chữ ghép thích hợp.Khi các
chữ ghép được tạo thành từ các kí tự Ả Rập,hình dáng thay đổi một cách
cơ bản hơn so với tiếng Anh.Ví dụ,như trong hình 4-4 miêu tả cách hai
chữ cái Ả rập kết hợp với nhau thành một chữ ghép khi chúng xuất hiện
cùng nhau.
4.3.2 Ordering Text
Trong ngôn ngữ lập trình Java,văn bản được mã hóa bằng cách sử
dụng các kí tự mã hóa Unicode.Văn bản sử dụng kí tự mã hóa Unicode
được lưu trữ trong bộ nhớ trong logical order. logical order là nơi mà
trong đó các kí tự và các từ được đọc và ghi. logical order không nhất
thiết phải giống như visual order,là nơi mà trong đó các glyph tương ứng
được hiển thị.
Visual order cho các glyph trong hệ thống ghi cụ thể(script) được gọi
là script order.Ví dụ, script order cho văn bản kiểu Roman được bố trí từ
trái qua phải và script order cho các văn bản Arabic và Hebrew được bố
trí từ phải sang trái.
Một số hệ thống ghi(writing systems) có các nguyên tắc trong việc thêm
các script order cho việc sắp xếp các glyph và các từ trong nhiều dòng của
văn bản.Ví dụ, các số Arabic và Hebrew chạy từ trái qua phải,mặc dú các
http://tailieuhay.com 101
Lập trình đồ họa trên Java 2D và 3D
kí tự chạy từ phải qua trái.(Điều này có nghĩa Arabic và Hebrew,ngay cả
khi không có các văn bản bằng tiếng Anh nhúng vào,chúng vẫn thực sự là
(kĩ thuật) hai chiều)
Một hệ thống ghi visual order phải không được thay đổi ngay cả khi
các ngôn ngữ hòa trộn với nhau.Điều này được mô tả trong hình 4-5,miêu
tả một nhóm từ Arabic nhúng vào một câu văn bản tiếng Anh.
Chú ý:Trong ví dụ này và trong các ví dụ sau, các văn bản Arabic và
Hebrew được hiển thị bằng các chữ cái in hoa và các khoảng cách giữa
các chữ được hiển thị bằng dấu gạch dưới.Mỗi phần miêu tả chia thành
hai phần:việc hiển thị của các kí tự được lưu trữ trong bộ nhớ(các kí tự
trong logical order) sau đó là cách hiển thị của những kí tự được hiển
thị(các kí tự trong visual order).Các số bên dưới khung kí tự chỉ định
insertion offsets.
Hình 4-5 Bidirectional Text
Cho dù chúng là một phần trong một câu tiếng Anh,các từ Arabic
được hiển thị trong các Arabic script,từ phải qua trái.
Khi một dòng văn bản với một sự pha trộn hai cách bố trí từ trái qua
phải và từ phải qua trái được hiển thị, base direction sẽ được chỉ
định.Base direction là một script order của hệ thống ghi.Ví dụ,nếu văn
http://tailieuhay.com 102
Lập trình đồ họa trên Java 2D và 3D
bản gốc là tiếng Anh với một số chữ Arabic được nhúng vào,thì base
direction sẽ là từ trái qua phải.Ngược lại,nếu văn bản gốc là tiếng Arabic
với một số chữ Anh nhúng vào hoặc các con số,thì base direction sẽ là từ
phải qua trái.
Base direction xác định các bố trí trong mỗi đoạn của văn bản với một
common direction được hiển thị.Trong ví dụ 5-4, base direction là từ trái
qua phải.Có ba hướng bố trí văn bản trong ví dụ này,văn bản tiếng Anh ở
đoạn đầu của câu chạy từ trái qua phải,văn bản Arabic chạy từ phải qua
trái,và các văn bản khác chạy từ trái qua phải.
4.3.3 Đo và định vị văn bản
Trừ khi bạn làm việc với font đơn cách,các kí tự khác nhau trong kiểu
font có chiều rộng khác nhau.Điều này có nghĩa tất cả các vị trí và kích
thước của các văn bản phải được tính toán một cách chính xác với các kí
tự được sử dụng.Ví dụ, một cột các chữ số được căn lề phải được hiển thị
trong kiêu font cân xứng,bạn không thể dễ dàng sử dụng các không gian
mở rộng cho vị trí của các văn bản.Đẻ căn lề các cột một cách đúng
đắn,bạn cần phải biết chính xác chiều rộng của mỗi số mà bạn có thể điều
chỉnh sao cho phù hợp.
Các văn bản thường sử dụng cách hiển thị theo nhiều dòng và nhiều
kiểu dáng,như theo kiểu nét đậm và in nghiêng.Trong trường hợp này,các
kí tự giống nhau có thể có các hình dáng khác nhau về chiều rộng,phụ
thuộc vào cách nó thể hiện kiể u dáng.Để có vị trí ,kích thước và render
text chính xác,bạn cần phải kiểm tra mỗi kí tự riêng lẻ và kiểu dáng được
sử dụng cho kí tự đó.Thật may là lớp TextLayout đã làm điều này cho
bạn.
Để hiển thị các văn bản đúng trong nhiều ngôn ngũ chẳng hạn như
Hebrew và Arabic,mỗi kí tự cần phải được cân nhắc và đặt vào bên trong
một ngữ cảnh với các kí tự bên cạnh.Bởi vì hình dáng và vị trí của các kí
http://tailieuhay.com 103
Lập trình đồ họa trên Java 2D và 3D
tự có thể thay đổi được phụ thuộc vào từng ngữ cảnh,việc cân nhắc và sắp
đặt các đoạn văn bản mà không cần xét đến văn cảnh là một điều không
được tán thành.
4.3.4 Hỗ trợ thao tác với văn bản.
Để cho phép người dùng có thể sửa đổi text đã được hiển thị,bạn phải:
• Hiển thị dấu caret mà nó chỉ địn nơi một kí tự mới sẽ được thêm
vào khi người dùng thêm vào text.
• Di chuyển dấu caret và điểm chèn trong câu trả lời khi người dùng
đưa vào.
• Phát hiện sự lựa chọn của người dùng(hit detection).
• Làm nổi bật đoạn text được lựa chọn.
4.3.4.1 Hiển thị dấu nhắc
Trong các text có thể chỉnh sửa được,dấu caret được sử dụng để hiển
thị điểm chèn hiện tại,vị trí trong đoạn text nơi mà các kí tự mới sẽ được
chèn vào.Thông thường,một dấu caret được thể hiện là một thanh thẳng
đứng nhấp nháy giữa hai glyph.Kí tự mới được chèn vào và được hiển thị
tại vị trí của dấu caret.
Việc tính toán vị trí dấu caret có thể rất phức tạp,đặc biệt là trong các
text hai chiều.Các đoạn chèn vào trong các đường biên định hướng có hai
vị trí có thể chèn bởi vì hai glyph đó phù hợp với khoảng kí tự không
được hiển thị sát ngay các kí tự khác.Điều này được miêu tả trong hình 4-
6.Trong hình vẽ này,các dấu caret được thể hiện là các dấu ngoặc vuông.
http://tailieuhay.com 104
Lập trình đồ họa trên Java 2D và 3D
Hình 4-6 Dual Carets
Kí tự ở vị trí thứ 8 nằm sau dấu _ và nằm trước kí tự A.Nếu người
dùng muốn thêm một kí tự Arabic vào chỗ đó,glyph của nó được hiển thị
bên phải(phía trước) của kí tự A.Còn nếu người dùng muốn chèn một kí
tự English,glyph của nó được hiển thị bên trái(phía sau) của dấu _.
Để làm đươc điều này một số hệ thống hiển thị hai dấu caret,một
dấu là chính (primary) còn một dấu là phụ (secondary).Dấu caret chính
chỉ định nơi mà một kí tự chèn vào được hiển thị khi hướng của kí tự đó
cùng với hướng cơ sở của cả đoạn text.Còn dấu caret phụ cho biết một kí
tự chèn vào sẽ được hiển thị khi hướng của kí tự đó ngược với hướng cơ
sở của đoạn text.Lớp TextLayOut tự động hỗ trợ cả hai dấu caret,còn lớp
JtextComponent thì không.
Khi làm việc với văn bản hai chiều,bạn không thể đơn giản thêm vào
bề rộng của các glyph trước một khoảng trống của kí tự để tính toán vị trí
dấu caret.Nếu bạn làm vậy,dấu caret có thể hiện ra tại vị trí sai như bạn
thấy trong hình 4-7:
Figure 4-7 Caret Drawn incorrectly
Để dấu caret có thể hiển thị ở một vị trí hợp lý,bề rộng của các glyph
ở phía bên trái của khoảng trống cần phải được thêm vào và ngữ cảnh
http://tailieuhay.com 105
Lập trình đồ họa trên Java 2D và 3D
hiện tại đưa vào tính toán.Trừ khi ngữ cảnh được đưa vào tính toán,các
phép đo glyph sẽ không cần thiết khớp với việc hiển thị.
4.3.4.2 Di chuyển dấu nhắc.
Tất cả các trình biên soạn văn bản đều cho phép người sử dụng di
chuyển dấu caret với các phím mũi tên.Người sử dụng mong muốn dấu
caret sẽ di chuyển theo hướng của các phím mũi tên đước ấn.Từ trái qua
phải của đoạn text,việc di chuyển các khoảng trống thêm vào rất đơn
giản:Phím mũi tên phải làm tăng khoảng trống được thêm vào bằng còn
phím mũi tên trái làm giảm đi.Trong các văn bản hai chiều hoặc các văn
bản có nhiều chữ ghép,cách làm này có thể khiến dấu caret nhẩy qua các
glyph theo hướng của đường biên và di chuyển trong theo hướng ngược
lại.
Để di chuyển dấu caret một cách mượt mà(smoothly) qua văn bản hai
chiều,bạn cần phải tính toán hướng của văn bản thi hành..Bạn ko thể đơn
giản tăng khoảng trống thêm vào khi phím mũi tên phải được ấn và giảm
nó khí phím mũi tên trái được ấn.Nếu khoảng trống thêm vào hiện tại
nằm bên trong một thi hành của các kí tự từ phải qua trái,thì phím mũi
tên phải có thể làm giảm khoảng trống thêm vào và phím mũi tên trái sẽ
làm tăng nó.
Di chuyển dấu caret ngang qua hướng đường biên là một việc khá
phức tạp như trong hình 4-8 dưới đây:
http://tailieuhay.com 106
Lập trình đồ họa trên Java 2D và 3D
Figure 4-8 Caret Movement
Chắc chắn các glyph sẽ không bao giờ có dấu caret giữa chúng.thay
vào đó dấu caret di chuyển qua các hiển thị của glyph một kí tự đơn.Ví
dụ,không bao giờ có một dấu caret bên trong chữ o và một sự biến âm(an
umlaut) nếu chúng được hiển thị bằng hai kí tự phân cách.Lớp
TextLayOut cung cấp các phương thức getNextRightHit and
getNextLeftHit để có thể dễ dàng di chuyển dấu caret một cách mượt mà
qua các văn bản hai chiều.
4.3.4.3 Hit Testing
Thông thường,một vị trí trong không gian của công cụ phải được
chuyển thành không gian trống của text.Ví dụ như,khi người sử dụng
nhấn chuột vào văn bản được chọn,vị trí của chuột được chuyển thành
khoảng trống và được sử dụng như điểm cuối của vùng lựa chọn.Theo
một cách logic,nó được chuyển ngược thành vị trí của dấu caret.
Khi bạn làm việc với văn bản hai chiều,một vị trí trực quan trong
phần hiển thị có thể đáp ứng cho hai offset khác nhau trong đoạn văn bản
gốc,như trong hình 4-9 dưới đây:
Hình 4-9 Hit Testing Bidirectional Text
Bởi vì một vị trí trực quan có thể đáp ứng cho hai offset khác nhau,
hit testing các văn bản hai chiều không phải là quan trọng của các phép đo
bề rộng của các đường nét (measuring glyph widths) trừ glyph tại các vị
http://tailieuhay.com 107
Lập trình đồ họa trên Java 2D và 3D
trí chính xác được tìm thấy và sau đó ánh xạ vị trí đó đến một character
offset.
Bạn có thể thực hiên hit testing bằng việc sử dụng lớp
TextLayout.hitTestChar. Thông tin về hit được đóng gói trong đối
TextHitinfo bao gồm các thông tin về cạnh mà việc hit được thấy trên đó.
4.3.4.4 Đánh dấu vùng lựa chọn.
Một vùng các kí tự được lực chọn được hiển thị đồ họa bằng một
vùng được tô sáng,đó là vùng mà mỗi đường nét được hiển thị với màu
trái ngược với màu nền.
Vùng được tô sáng,giống như dấu caret,có nhiều phức tạp trong các văn
bản hai chiều hơn là trong các văn bản một chiều(monodirectional
text).Trong văn bản hai chiều,một dải liên tục các kí tự có thể không có
một vùng được tô sáng liên tục khi hiển thị.Ngược lại,một vùng sáng liên
tục cho thấy một cách trực quan một dải liên tục các nét có thể không phù
hợp với một kí tự đơn,dải liên tiếp của các kí tự.
Có hai cách để lựa chọn vùng sáng trong văn bản hai chiều:
• Logical highlighting(vùng sáng logic) - Với vùng sáng logic,các
kí tự được lựa chọn thường liên tiếp nhau trong mo hình văn bản(text
model),và vùng sáng được lựa chọn một cách liên tiếp.Xem ví dụ về
logical highlighting,xem hình 4-10.
• Visual highlighting(vùng sáng trực quan) - với visual
highlighting,bạn có thể có nhiều dải các kí tự được lựa chọn,nhưng vùng
sáng thông thường liên tiếp nhau.Ví dụ về visual highlighting,xem hình 4-
11.
http://tailieuhay.com 108
Lập trình đồ họa trên Java 2D và 3D
Hình 4-10 Logical Highlighting (contiguous characters)
Hình 4-11 Visual Highlighting (contiguous highlight region)
Logical highlighting đơn giản hơn trong việc thực thi,các kí tự được lựa
chọn thường liên tiếp nhau.
4.3.5 Thực thi việc hiển thị văn bản trong ứng dụng Java™ .
Phụ thuộc vào Java™ APIs mà bạn sử dụng,bạn có thể có ít hoặc
nhiều các điều khiển về text layout (hiển thị văn bản) như bạn cần:
1. • Nếu bạn muốn hiển thị cả một khối text hoặc cần các điều khiển
chỉnh sửa text,bạn có thể sử dụng JtextComponent,nó sẽ thực hiện
text layout cho bạn. JtextComponent được thiết kế để điều khiển
việc cần thiết của hầu hết các ứng dụng và hỗ trợ cho các văn bản
hai chiều.Để thêm thông tin về JtextComponent bạn xem thêm
phần “Using the JFC/Swing Packages” của bộ Java Tutorial.
2. • Nếu bạn muốn hiển thị một đoạn chuỗi kí tự đơn giản,bạn có thể
gọi đối tượng Graphics2D.drawString và yêu cầu Java 2D hiển thị
chuỗi kí tự cho bạn.Bạn cũng có thể sử dụng drawString để
http://tailieuhay.com 109
Lập trình đồ họa trên Java 2D và 3D
render(trả về) kiểu của xâu kí tự và các xâu kí tự đó chứa kiểu văn
bản hai chiều.Để có thêm thông tin về rendering text qua lớp
Graphics2D,bạn xem thêm phần “Rendering Graphics Primitives”.
3. • Nếu bạn muốn thực thi việc chỉnh sửa văn bản của bạn,bạn có thể
sử dụng TextLayout để điều khiển việc hiển thị văn bản(text
layout),tô sáng( highlighting),và hit detection.Các tiện lợi được
cung cấp bởi lớp TextLayout cho hầu hết các trường hợp phổ
biến,bao gồm các xâu văn bản với việc pha trộn các kiểu Font,pha
trộn các kiểu ngôn ngữ,và văn bản hai chiều.Để có thêm thông tin
về cách sử dụng TextLayout,bạn xem thêm phần Managing Text
Layout.
4. •Nếu bạn muốn điều khiển toàn bộ việc làm thế nào để text được
shape và được định vị trí,bạn có thể xây dựng lớp Glyphvector của
bạn bằng cách sử dụng Font và sau đó render chúng dựa trên lớp
Graphics2D.Để có thêm thông tin về cách thực thi công cụ text
layput của bạn,bạn xem thêm phần “implementing a Custom Text
Layout Mechanism” .
Thông thường,bạn không cần phải thực hiện text layout.Cho hầu hết
các ứng dụng,JtextComponent là giải pháp tốt nhất cho việc hiển thị các
văn bản tĩnh và văn bản có thể chỉnh sửa.Tuy nhiên, JtextComponent
không hỗ trợ việc hiển thị dấu caret kép hoặc các đoạn lựa chọn liên tiếp
trong văn bản hai chiều.Nếu ứng dụng của bạn yêu cầu những đặc tính
trên,hoặc bạn thích thực hiện việc chỉnh sửa văn bản của bạn,bạn có thể
sử dụng Java 2D text layout APIs.
Quản lý việc hiển thị văn bản.
Lớp TextLayout hỗ trợ các text mà nó chứa đựng nhiều kiểu
dáng(style) và nhiều kí tự từ các hệ thống writing khác nhau,bao gồm
http://tailieuhay.com 110
Lập trình đồ họa trên Java 2D và 3D
Arabic và Hebrew(Arabic và Hebrew là các kiểu đặc biệt khó để hiển thị
bởi vì bạn phải reshape và reorder văn bản để được chấp nhận hiển thị).
Lớp TextLayout làm đơn giản việc sử lý cách hiển thị mà các phép
đo văn bản nếu bạn làm việc với các văn bản chỉ có tiếng Anh.Bằng việc
sử dụng TextLayout bạn có thể đạt được việc tạo chữ với chất lượng cao
mà không tốn nhiều công sức.
Text Layout Performance
Lớp TextLayout giúp bạn trong việc xác định vị trí và thứ tự của các
đường nét.Bạn có thể dùng TextLayout để:
• Hiển thị các văn bản một hướng và văn bản hai hướng.
• Hiển thị và di chuyển dấu caret.
• Thực hiện hit testing trên văn bản.
• Tô sáng vùng văn bản được lựa chọn.
ờng hợp,bạn có thể tính toán cách bố trí văn bản của bạn bằng cách
điều khiển một cách chính xác các đường nét mà bạn sử dụng và nơi
chúng sẽ được đặt(vào văn bản).Việc sử dụng các thông tin như các kích
cỡ đường nét(glyph sizes),các bảng co kéo(kerning tables),và cách ghép
chữ(ligature information),bạn có thể xây dựng giải thuật của bạn để tính
toán cách bố trí văn bản,bypassing công cụ bố trí của hệ thống(bypassing
the sys- tem’s layout mechanism).Để có thêm thông tin bạn xem thêm
phần “implementing a Custom Text Layout Mechanism”.
4.4.1 Trình bày văn bản.
Lớp TextLayout sẽ đặt văn bản một cách tự động,kể cả các văn bản
một hướng(BiDi-bidirectional),với việc tạo hình dáng(shaping) và
ordering chính xác.Để shape và order một cách chính xác,các đường nét
phải miêu tả các đường(line) của văn bản, TextLayout phải biết toàn bộ
ngữ cảnh của văn bản:
http://tailieuhay.com 111
Lập trình đồ họa trên Java 2D và 3D
• Nếu văn bản nằm trên một đường đơn(single line) ,chẳng hạn như
một từ đơn của nhãn(label) cho một nút lệnh hoặc một đường trong hộp
thoại(dialog box),bạn có thể xây dựng một đối tượng TextLayout trực
tiếp từ văn bản.
• Nếu bạn có nhiều văn bản hơn là chỉ có một dòng hoặc bạn muốn
chia văn bản từ các single line thành các đoạn,bạn không thể xây dựng
đối tượng TextLayout một cách trực tiếp.Bạn phải sử dụng đối tượng
LineBreakMeasure để đáp ứng đủ các ngữ cảnh.
Hướng cơ bản của một văn bản thường được thiết lập bằng các thuộc
tính(kiểu dáng) trên văn bản.Nếu thuộc tính đó bị thiếu,lớp TextLayout
sử dụng giải thuật của bảng mã hai chiều Unicode,và nhận được hướng
cơ bản từ các kí tự bắt đầu trong đoạn.
Hiển thị dấu nhắc kép.
Lớp TextLayout chứa các thông tin về dấu caret như hình dáng của
dấu(caret shape),vị trí và góc(angle).Bạn có thể sử dụng các thông tin này
để dễ dàng hiển thị dấu caret trong cả văn bản một hướng và hai
hướng.Khi bạn vẽ dấu caret cho văn bản một chiều,việc sử dụng lớp
TextLayout sẽ đảm bảo dấu caret được đặt vị trí một cách chính xác.
TextLayout cung cấp cho ta nhiều hình dáng mặc định của dấu caret
và hỗ trợ một cách tự động dấu caret kép,như bạn thấy trong hình 4-
12.Các ví trí của dấu caret đó cũng được sử dụng như đường biên giữa
các đường nét cho việc tô sáng và hit testing.
Hình 4-12 Angled Carets
http://tailieuhay.com 112
Lập trình đồ họa trên Java 2D và 3D
Căn cứ vào khoảng trống được thêm vào,phương thức
getCaretShapes trả về một mảng hai phần tử của shape:phần tử thứ nhất
chứa dấu caret chính và phần tử thứ hai chứa dấu caret phụ,nếu chúng
cùng tồn tại.Để hiển thị cả hai dấu caret(dấu caret kép),bạn đơn giản chỉ
là vẽ cả hai shape của dấu caret;các dấu caret sẽ được render một cách tự
động tại những vị trí chính xác.
Nếu bạn muốn sử dụng shape của dấu caret một cách tùy thích,bạn có
thể tìm đến vị trí và góc của các dấu caret bằng đối tượng TextLayout và
vẽ chúng theo cách của bạn.
Trong ví dụ dưới đây,hình dáng của dấu caret chính và phụ mặc định
được vẽ trên các màu khác nhau.Đây là cách phổ biến để tạo sự khác biệt
của hai dấu caret .
Shape[] caretShapes =
layout.getCaretShapes(hit);
g2.setColor(PRiMARY_CARET_COLOR);
g2.draw(caretShapes[0]);
if (caretShapes[1] != null){
g2.setColor(SECONDARY_CARET_COLOR);
g2.draw(caretShapes[1]);
}
4.4.3 Di chuyển dấu nhắc.
Bạn cũng có thể sử dụng lớp TextLayout để xác định kết quả của
việc thêm vào các khoảng trống khi người sử dụng ấn các phím mũi tên
trái hoặc phải.Dựa vào đối tượng TextHitinfo,nó cho ta biết vị trí hiện tại
của khoảng trống thêm vào,phương thức getNextRightHit trả về kiểu đối
tượng TextHitinfo mà nó cho biết chính xác vị trí của khoảng trống thêm
http://tailieuhay.com 113
Lập trình đồ họa trên Java 2D và 3D
vào khi phím mũi tên phải được nhấn.Còn phương thức getNextLeftHit
cho ta thông tin như vậy khi phím mũi tên trái được nhấn.
Trong ví dụ dưới đây,vị trí hiện tại của khoảng trống chèn vào được
di chuyển đến nơi tương ứng khi mà phím phải được ấn.
TextHitinfo newinsertionOffset =
layout.getNextRightHit(insertionOffset);
if (newinsertionOffset != null)
{
Shape[] caretShapes =
layout.getCaretShapes(newinsertionOffset);
// draw carets
...
insertionOffset = newinsertionOffset;
}
4.4.4 Hit Testing
Lớp TextLayout cho ta một công cụ đơn giản để hit testing văn
bản.Phương thức hitTestChar sẽ lấy tọa độ x và y từ chuột(takes x and y
coordinates from the mouse) như các đối số và trả về kiểu đối tượng
TextHitinfo.Đối tượng TextHitinfo chứa khoảng trống chèn vào cho vị
trí và cạnh mà việc hit was on.
Trong ví dụ dưới đây,phương thức hitTestChar được gọi trong đối tượng
TextLayout và sau đó phương thức getinsertindex được sử dụng để lấy
lại khoảng chứa trống.
TextHitinfo hit = layout.hitTestChar(x, y);
int insertindex = hit.getinsertindex();
http://tailieuhay.com 114
Lập trình đồ họa trên Java 2D và 3D
4.4.5 Đánh dấu vùng lựa chọn.
Bạn có thể nhận một đối tượng Shape mà nó hiển thị vùng sáng từ đối
tượng TextLayout. Đối tượng TextLayout sẽ tự động giữ ngữ cảnh trong
một mảng khi tính toán số chiều của vùng được tô sáng.Lớp TextLayout
hỗ trợ cả vùng sáng logic và vùng sáng trực quan.
Trong ví dụ dưới đây,vùng sáng được điền với màu sáng và sau đó
đối tượng TextLayout sẽ vẽ toàn bộ vùng được điền đó.Đây là một cách
đơn giản để hiển thị đoạn văn bản được tô sáng.
Shape highlightRegion =
layout.getLogicalHighlightShape(hit1,
hit2);
graphics.setColor(HiGHLiGHT_COLOR);
graphics.fill(highlightRegion);
graphics.drawString(layout, 0, 0);
4.4.6 Querying Layout Metrics
Lớp TextLayout cung cấp cách truy cập đến các phép đo đồ họa cho
toàn bộ dải văn bản hiển thị.Các phép đo đã có sẵn trong lớp TextLayout
bao gồm ascent,descent,leading(khoảng cách giữa các dòng chữ so với
dòng cơ sở), advance, visible advance và bounding rectangle (giới hạn
của khung hình chữ nhật).
Có nhiều hơn một đối tượng Font có thể được liên kết với một đối
tượng TextLayout:sự khác nhau về kiểu dáng khi thực thi có thể sử dụng
các kiều font khác nhau.Các giá trị ascent và descent của toàn bộ kiểu
font được sử dụng trong đối tượng TextLayout.Việc tính toán giá trị
leading của đối tượng TextLayout thì phức tạp hơn nhiều,nó không có giá
trị leading cực đại.
http://tailieuhay.com 115
Lập trình đồ họa trên Java 2D và 3D
Giá trị advance của đối tượng TextLayout chính là chiều dài của
nó:đó là khoảng cách từ cạnh bên trái của nét bên trái nhất đến cạnh bên
phải của nét bên phải nhất.Giá trị advance thường được chỉ định là total
advance.Còn giá trị visible advance là chiều dài của đối tượng
TextLayout mà không có các khoảng trắng.
Khung giới hạn của một đối tượng TextLayout bao quanh toàn bộ
văn bản trong phần bố trí..Nó bao gồm toàn bộ các đườn nét trực
quan(thấy được) và các dấu caret biên.(Một số trong đó có thể được lấy từ
gốc hoặc gốc + advance).Khung giới hạn có quan hệ với nguồn gốc của
đối tượng TextLayout,không liên quan đến vị trí trên màn hình.
Trong ví dụ dưới đây,văn bản trong một đối tượng TextLayout được
vẽ bên trong một khung giới hạn.
graphics.drawString(layout, 0, 0);
Rectangle2D bounds = layout.getBounds();
graphics.drawRect(bounds.getX()-1,
bounds.getY()-1,
bounds.getWidth()+2, bounds.getHeight()+2);
4.4.7 Vẽ văn bản trên nhiều dòng.
Lớp TextLayout còn có thể được sử dụng để hiển thị đoạn text mà
nó có nhiều dòng.Ví dụ như,bạn có thể lấy một đoạn của văn bản,chồng
các line của văn bản đó một bề rộng nào đó,và hiển thị các đoạn như
nhiều dòng của văn bản.
Để làm được điều này,bạn không phải làm trực tiếp bằng việc tạo ra
nhiều đối tượng TextLayout mà bạn hiển thị mỗi dòng của văn bản-
phương thức LineBreakMeasure sẽ làm điều đó cho bạn.Các kiểu văn bản
hai chiều không thể thực hiện điều này một cách chính xác trừ khi tất cả
http://tailieuhay.com 116
Lập trình đồ họa trên Java 2D và 3D
văn bản trong một đoạn đã có sẵn.Phương thức LineBreakMeasure đóng
gói toàn bộ thông tin về ngữ cảnh để tạo ra các đối tượng TextLayout
chính xác.
Khi văn bản được hiển thị qua nhiều dòng,chiều dài của những dòng
đó thường được xác định bằng chiều rộng của vùng hiển thị.Sự chia
dòng(Line breaking hay line wrapping) là việc xác định nơi mà những
dòng bắt đầu và kết thúc.
/*
* FontSelection.java
* 1.0
* 12/03/06
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.event.itemEvent;
import java.awt.event.itemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;
import javax.swing.JApplet;
http://tailieuhay.com 117
Lập trình đồ họa trên Java 2D và 3D
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/*
* Applet nay hien thi mot xau voi lua chon cua
nguoi su dung.
*/
public class FontSelection extends JApplet
implements itemListener {
/**
*
*/
private static final long serialVersionUiD =
5469031020823166920L;
JLabel fontLabel, sizeLabel, styleLabel;
FontPanel fontC;
JComboBox fonts, sizes, styles;
int index = 0;
String fontchoice = "L a ch n Font";ự ọ
int stChoice = 0;
http://tailieuhay.com 118
Lập trình đồ họa trên Java 2D và 3D
String siChoice = "10";
@SuppressWarnings("unchecked")
public void init() {
getContentPane().setLayout(new
BorderLayout());
JPanel topPanel = new JPanel();
JPanel fontPanel = new JPanel();
JPanel sizePanel = new JPanel();
JPanel stylePanel = new JPanel();
JPanel sizeAndStylePanel = new JPanel();
topPanel.setLayout(new BorderLayout());
fontPanel.setLayout(new GridLayout(2,
1));
sizePanel.setLayout(new GridLayout(2,
1));
stylePanel.setLayout(new GridLayout(2,
1));
sizeAndStylePanel.setLayout(new
BorderLayout());
topPanel.add(BorderLayout.WEST,
fontPanel);
sizeAndStylePanel.add(BorderLayout.WEST,
sizePanel);
http://tailieuhay.com 119
Lập trình đồ họa trên Java 2D và 3D
sizeAndStylePanel.add(BorderLayout.CENTER,
stylePanel);
topPanel.add(BorderLayout.CENTER,
sizeAndStylePanel);
getContentPane().add(BorderLayout.NORTH,
topPanel);
fontLabel = new JLabel();
fontLabel.setText("Fonts");
Font newFont = getFont().deriveFont(1);
fontLabel.setFont(newFont);
fontLabel.setHorizontalAlignment(JLabel.CENTER);
fontPanel.add(fontLabel);
sizeLabel = new JLabel();
sizeLabel.setText("Kích C ");ỡ
sizeLabel.setFont(newFont);
sizeLabel.setHorizontalAlignment(JLabel.CENTER);
sizePanel.add(sizeLabel);
styleLabel = new JLabel();
styleLabel.setText("Ki u ch ");ể ữ
styleLabel.setFont(newFont);
styleLabel.setHorizontalAlignment(JLabel.CENTER);
http://tailieuhay.com 120
Lập trình đồ họa trên Java 2D và 3D
stylePanel.add(styleLabel);
GraphicsEnvironment gEnv =
GraphicsEnvironment
.getLocalGraphicsEnvironment();
String envfonts[] =
gEnv.getAvailableFontFamilyNames();
Vector vector = new Vector();
for (int i = 1; i < envfonts.length; i++)
{
vector.addElement(envfonts[i]);
}
fonts = new JComboBox(vector);
fonts.setMaximumRowCount(9);
fonts.additemListener(this);
fontchoice = envfonts[0];
fontPanel.add(fonts);
sizes = new JComboBox(new Object[]
{ "10", "12", "14", "16", "18" });
sizes.setMaximumRowCount(9);
sizes.additemListener(this);
sizePanel.add(sizes);
styles = new JComboBox(new Object[]
{ "PLAiN", "BOLD", "iTALiC",
"BOLD & iTALiC" });
styles.setMaximumRowCount(9);
styles.additemListener(this);
sizes.setMaximumRowCount(9);
http://tailieuhay.com 121
Lập trình đồ họa trên Java 2D và 3D
stylePanel.add(styles);
fontC = new FontPanel();
fontC.setBackground(Color.white);
getContentPane().add(BorderLayout.CENTER,
fontC);
}
public void itemStateChanged(itemEvent e) {
if (e.getStateChange() !=
itemEvent.SELECTED) {
return;
}
Object list = e.getSource();
if (list == fonts) {
fontchoice = (String)
fonts.getSelecteditem();
} else if (list == styles) {
index = styles.getSelectedindex();
stChoice = index;
} else {
siChoice = (String)
sizes.getSelecteditem();
}
fontC.changeFont(fontchoice, stChoice,
siChoice);
}
http://tailieuhay.com 122
Lập trình đồ họa trên Java 2D và 3D
public static void main(String s[]) {
JFrame f = new JFrame("Ch n ki u Font");ọ ể
f.addWindowListener(new WindowAdapter() {
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
JApplet fontSelection = new
FontSelection();
f.getContentPane().add(fontSelection,
BorderLayout.CENTER);
fontSelection.init();
f.setSize(new Dimension(550, 250));
f.setVisible(true);
}
}
class FontPanel extends JPanel {
/**
*
*/
private static final long serialVersionUiD =
7850814263388447528L;
Font thisFont;
public FontPanel() {
http://tailieuhay.com 123
Lập trình đồ họa trên Java 2D và 3D
thisFont = new Font("Arial", Font.PLAiN,
10);
}
public void changeFont(String f, int st,
String si) {
integer newSize = new integer(si);
int size = newSize.intValue();
thisFont = new Font(f, st, size);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
int w = getWidth();
int h = getHeight();
g2.setColor(Color.darkGray);
g2.setFont(thisFont);
String change = "Ch n Font ,c ch vàọ ỡ ữ
ki u ch .";ể ữ
FontMetrics metrics =
g2.getFontMetrics();
int width = metrics.stringWidth(change);
int height = metrics.getHeight();
g2.drawString(change, w / 2 - width / 2,
h / 2 - height / 2);
}
}
http://tailieuhay.com 124
Lập trình đồ họa trên Java 2D và 3D
Kết quả của chương trình:
http://tailieuhay.com 125
Lập trình đồ họa trên Java 2D và 3D
Chương 5
Tạo ảnh
Java 2D™ API hỗ trợ 3 model vẽ ảnh.
•Model khách chủ (producer/consumer) đã hỗ trợ trong phiên bản
trước củan bản JDK.
•Model trung gian (immediate mode model) được giới thiệu tr
ong Java™ 2 SDK release.
•Model đường ống tương thích với model trung gian và sex được
cài đặt đầy đủ trong bản Java Advanced imaging API sắp tới.
Trong chương này chúng ta tập trung vào các đối tượng và các công
nghệ của model tạo ảnh mode trung gian(immediate mode). Các lớp mode
trung gian và các giao diện củan Java 2D API cuang cấp các công nghệ
cho việc xử lý ánh xạ các điểm với dữ liệ của nó trong bộ nhớ. Hàm API
này hỗ trợ cho việc truy nhập dữ liệu ảnh tỏng các định dạng lưu trữ khác
nhau và thao tác với dữ liệu ảnh qua vàiloại phép toán lọc.
5.1 Các giao diện và các lớp
Các API tạo ảnh mode trung gian trong Java 2D™ API có thể
được nhóm lại trong 6
Cataloge sau: Các giao diện, các lớp dữ liệu ảnh, các lớp thao toán tử ảnh,
các lớp model mẫu, các lớp model màu, các ngoại lệ (exceptions).
http://tailieuhay.com 126
Lập trình đồ họa trên Java 2D và 3D
5.1.1 Các giao diện imaging (imaging interfaces)
Interface DescriptionBufferedImageOp Mô tả các thao tác vào đơn ra đơn thực hiện
trên đối tượng Bufferedimage. Được cài đặt
bởi AffineTransformOp, ColorConvertOp,
ConvolveOp, LookupOp và RescaleOp.RasterOp Định nghĩa các thao tác vào ra đơn thực hiện
trên các đôi tượng Raster Được cài đặt bởi
AffineTransformOp, BandCombineOp,
ColorConvertOp, ConvolveOp, LookupOp và
RescaleOp.
RenderedImage Định nghĩa giao thức cho các đối tượng chứa
hoặc có thể sản sinh dữ liệu ảnh trong kiểu
RastersWritableRenderedImag
e
Mở rộng Renderedimage
Định nghĩa cac giao thức cho các đói tượng
chứa hoặc sản sinh dữ liệu ảnh trong kiêu
Raster có thể được thay đổi.
TileObserver Định nghĩa các đối tượng muốn được báo khi
trang thái chỉnh sủa của một
WritableRenderedimage thay đổi.
.
5.1.2 Các lớp dữ liệu ảnh(image Data Classes)
Clases DescriptionBufferedimage Mở rông image cài đặt WriteableRenderedimage
Một ảnh với một bộ đệm dữ liệu có thể truy cập.
http://tailieuhay.com 127
Lập trình đồ họa trên Java 2D và 3D
Một Bufferedimage có một ColorModel và một
Raster dữ liệu ảnh.ByteLookupTable Mở rộng LookupTable
Một LookupTable chứa các bye dữ liệu.DataBuffer Bao bọc một hay nhiều các mảng dữ liệu chứa dữ
liệu điểm. Mỗi mảng được gọi là “bank”DataBufferByte Mở rộng DataBuffer. Một bộ đệm dữ liệu chứa các
byte dữ liệu. (đã dùng trong Java Advanced
imaging API)DataBufferint Mở rộng DataBuffer (Final))
Một bộ đệm dữ liệu chứa dữ liệu số nguyên (đa
dùng trong Java Ađvance imaging API)DataBufferShort Mở rộng DataBuffer (Final)
Một bộ đệm dữ liệu chứa dữ liệu số nguyên short
(đã dùng trong Java Advanced imanging API). DataBufferUShort Mở rộng DataBuffer (Final)
Một bộ đệm dữ liệu chứa dữ liệu số nguyên short
không dấu.
Kernel Một ma trận mô tả cách nhập một dữ
liệu và các điểm biên của nó tác động đến giá trị
của điểm trong bộ lọc ConvolveOPLookupTable Mở rộng Object
Một bảng ánh xạ các giá trị từ dữ liệu điểm đơn
băng tới các giá trị màu.Raster Một mảng các điểm góc từ đó bạn có thể nhận về
các dữ liệu điểm. Một Raster chứa một DataBuffer
và một SampleModel.ShortLookupTable Mở rộng LookupTable
Một bảng tham chiếu chứa các dữ liệu số nguyên
shortWritableRaster Mở rộng Raster
Một Raster có thể chỉnh sửa.
http://tailieuhay.com 128
Lập trình đồ họa trên Java 2D và 3D
5.1.3 image Operation Classes
Clases DescriptionAffineTransformOp Cài đặt : BufferedimageOp, RasterOp
Một lớp định nghĩa một biến đổi affine để thực
hiện một sự ánh xạ tuyến tính từ các toạ độ 2D
trong một ảnh nguồn hoặc Raster sang các toạ độ
2D trong ảnh đích hoặc Raster. Lớp này có thể thực
hiện cả ánh xạ song ánh và các phép toán biến đổi
láng giềng gần nhất.BandCombineOp Cài đặt RasterOp
Dùng một ma trận xác định, thao tác này thực hiện
một sự kết hợp tuyến tính tuỳ ý của các dải band
trong một Raster.BufferedimageFilter Mở rộng imageFilter
Một imageFilter cung cấp một cách đơn giản của
việc sùng một BufferedimageOp(toán tử một
nguồn đơn /một đích đơn) để lọc một
Bufferedimage hoặc Raster.ColorConvertOp Cài đặt BufferedimageOp, RasterOp
Thực hiên sự chuyển đổi dữ liệu màu điểm theo
điểm trong ảnh nguồn. ConvolveOp Cài đặt BufferedimageOp, RasterOp
Dùng một Kernel để thực hiện cải thiện ảnh nguồn.
Một sự cải thiện là một sự tao tác không gian nơi
các điểm cận biên vào được nhân bội bởi một giá
trị Kernel để tạo giá trị của điểm ra. Kernel định
nghĩa một cách toán học quan hệ giữa các điểm
trong quan hệ láng giềng trung gian của điểm vào
và điểm ra.
http://tailieuhay.com 129
Lập trình đồ họa trên Java 2D và 3D
LookupOp Cài đặt BufferedimageOp, RasterOp
Thực hiện thao tác tham chiếu từ nguồn tới đích.
Với các Raster, các thao tác tham chiếu trên các giá
trị mẫu, các Bufferedimage, thao tác tham chiếu
trên thành phần màu và thành phần alpha.RescaleOp Cài đặt BufferedimageOp, RasterOp
Thực hiện việc vẽ lại điểm bởi điểm (pixel by pixel
rescaling) của dữ liệ trong ảnh nguồn bởi việc nhân
mỗi giá trị điểm với hệ số và sau đó thêm vào một
phần chênh (an offset).
5.1.4 Sample Model Classes
Clases DescriptionBandedSampleModel Mở rộng ComponentSampleModel
(Final)
Cung cấp truy cập dữ liệu ảnh đã chứa
giống như các mẫu đã chứa như những
dải (bands) trong các bank riêng biệt
của DataBuffer. Một điểm bao gồm
một mẫu từ mỗi dải (band)ComponentSampleModel Mở rộng SampleModel
Cung cấp truy cạp tới dữ liệu ảnh chứa
với mỗt mẫu của môt điểm tâp trung
trong mỗi phần tử riêng biệt của
DataBuffer. Các loại chèn điểm khác
nhau được hỗ trợMultiPixelPackedSampleModel Mở rộng SampleModelPixelinterleavedSampleModel Mở rộng ComponentSampleModel
Cung cấp truy nhập tới dữ liệu ảnh đã
chứa dữ liệu mẫu cho mỗi điểm trong
http://tailieuhay.com 130
Lập trình đồ họa trên Java 2D và 3D
các phần tử hiệu chỉnh của mảng dữ
liệu, và tất cả các phần tử trong bank
đơn của một DataBuffer.SampleModel Một lớp trừu tượng định nghĩa một cơ
chế cho viễc xuất ra dữ liệu mẫu từ một
ảnh mà không biết cách dữ liệu được
chứa trong một DataBuffer.SinglePixelPackedSampleMode
l
Mở rộng SampleModel
Cung cấp truy nhập tới dữ liệu ảnh đã
được bảo quản với tất cả các mẫu phụ
thuộc vào các điểm riêng lẻ đã gói vào
trong một phần tử của một DataBuffer.
Color Model Classes
Clases DescriptionColorModel Cài đặt lớp trong suốt định nghĩa các
phương thức cho việc chuyển đổi từ các giá
trị điểm ánh tới các thành phần màu như đỏ,
xanh lá cây, xanh da trời (red, green, blue).ComponentColorModel Mở rộng ColorModel
Một ColorModel có thể giữ một ColorSpace
có thể thay đổi, một mảng các thành phần
màu ứng với ColorSpace. Lớp này có thể
được dùng để biểu diễn hầu hết các model
màu trên hầu hết các loại thiết bị đồ hoạ
(GraphicsDevices)
http://tailieuhay.com 131
Lập trình đồ họa trên Java 2D và 3D
DirectColorModel Mở rộng lớp PackedColorModel JDK1.1 .
Một ColorModel biểu diễn các giá trị có
các thành phần màu RGB đã nhúng trực tiếp
trong các bit của điểm. Model màu này
tương tự với một X11 TrueColor. RGB
ColorModel mặc định được trả về bởi
ColorModel.getRGBdefault như một
DirectColorModel. indexColorModel
Extends: ColorModelPackedColorModel Mở rộng ColorModel.
Một ColorModel trừu tượng biểu diễn các
giá trị điểm có các thành phần nhúng trực
tiếp trong các bit của một điểm.
DirectColorModel mở rộng
PackedColorModel để hỗ trợ các điểm chứa
các thành phần màu RGB.SampleModel Một lớp trừu tượng định nghĩa một cơ chế
cho viễc xuất ra dữ liệu mẫu từ một ảnh mà
không biết cách dữ liệu được chứa trong
một DataBuffer.
5.1.6 Exception Classes
Clases DescriptionimagingOpException Mở rộng RuntimException.
Đưa ra nếu một trong các phương thức
BufferedimageOp hoặc RasterOp không thể
xử lý ảnh.RasterFormatException Mở rộng RuntimException.
http://tailieuhay.com 132
Lập trình đồ họa trên Java 2D và 3D
Tạo ra nếu có một thông tin bố trí không
hợp lệ trong Raster.
5.2 Immediate Mode imaging Concepts
Model tạo ảnh mode trung gian hỗ trợ các phân giải cố định đã chứa
trong bộ nhớ. Model cũng hỗ trợ các thao tác lọc trên dữ liệu ảnh. Một số
các lớp và các giao diện được dùng trong model này
Hình 5-1 Bufferedimage và các lơp hỗ trợ.
Như hình 5-1, Bufferedimage cung cấp việc quản lý ảnh chung. Một
Bufferimage có thể được tạo trực tiếp trong bộ nhớ và được dùng để giữ
và thao tác dữ liệu ảnh đã nhận từ một file hoặc URL. Một
Bufferedimage có thể được hiển thì dùng bất cứ đối tượng Graphics2D
nào cho một thiết bị màn hình, hoặc đẩy tới bất cứ đích nào khác dùng
ngữ cảnh tương thích Graphics2D. Một đối tượng Bufferedimage chứa 2
đối tượng khác: một Raster và một ColorModel.
Lớp Raster cung cấp quản lý dữ liệu ảnh. Nó biểu diễn toạ độ de-cac
của ảnh và duy trì dữ liệu ảnh trong bộ nhớ, và cung cáp một cơ chế cho
http://tailieuhay.com 133
Lập trình đồ họa trên Java 2D và 3D
tao ảnh vớ nhiều ảnh nhỏ từ một bộ đệm dữ liệu ảnh đơn. Nó cũng cung
cấp các phương thức cho việc truy cập các điểm xác định với một
ảnh(image). Một đới tượng Raster chứa hai đối tượng khác, một
DataBuffer và một SampleModel.
Lớp DataBuffer giữ dữ liệu điểm trong bộ nhớ.
Lớp SampleModel thể hiện dữ liệu trong bộ đệm và cung cấp no như
các điểm riêng rẽ hoặc dải điểm chữ nhật.
image Package cung cấp thêm các lớp định nghĩa các thao tác lọc
trên các đối tượng Bufferedimage và Raster. MỖi thao tác xử lý ảnh
được nhúng trong lớp cài đặt giao diện BufferedimageOp, giao diện
RasterOp, hoặc cả hai giao diện. lớp thao tác định nghĩa các phương thức
lọc (filter) thực hiện thao tác ảnh thực sự.
Hình 5-2 minh hoạ model cơ bản cho Java 2D™ API image xử lý
ảnh.
Các thao tác đã hỗ trợ bao gồm:
• Biến đổi Affine
• Amplitude scaling
• Lookup-table modification
• Linear combination of bands
• Color conversion
http://tailieuhay.com 134
Lập trình đồ họa trên Java 2D và 3D
• Convolution
Chú ý rằng nếu bạn thích hiển thị và thao tác các ảnh, bạn chỉ cần
hiểu lớp Bufferedimage và các lớp thao tác lọc. Mặt khác, nếu bạn có ý
định viết các bộ lọc hoặc trực tiếp truy nhập dữ liệu ảnh, bạn cần phải
hiểu các lớp liên quan với Bufferedimage.
5.2.1 Terminology
Ở đây có vài khái niệm được dùng qua các thảo luận dưới đây:
Các phần tử dữ liệu-Data Elements: các loại nguyên tố dùng như là các
đơn vị lưu trữ dữ liệu ảnh. Các Data element là các thành viên riêng lẻ
của một mảng DataBuffer. Bố trí (layout)của các phần tử trong bộ đệm dữ
liệu là độc lập với cách biểu điễn của dữ liệu như là các điểm bởi một
SampleModel của ảnh.
Các mẫu - Samples: Các thành viên riêng biệt của các điểm của một
ảnh. Một SampleModel cung cấp một cơ chế cho việc chuyển đổi các
phần tử trong DataBuffer sang các điểm và các mẫu của nó. Các mẫu của
một điểm có thể biểu diễn các giá trị nguyên thuỷ trong model màu cụ
thể. Ví dụ, một điểm trong model màu RGB bao gồm 3 mẫu : red, green
và blue.
Các thành phần - Components: Các giá trị của các điểm độc lập với
sự biểu diễn màu. Sự phân biệt giữa thành phần(component) và
mẫu(sample) là hữu ích với indexColorModel, nơi mà các thành phần
điểm được đánh chỉ số sang LookupTable.
Dải - Band: Tập tất cả các mẫu của một loại trong một ảnh, giống như
tất cả các mẫu màu đỏ hoặc tất cả các mẫu màu xanh lá cây. Dữ liệu điểm
có thể được chứa trong một số cách, hỗ trợ hai trong Java 2D API đang
được tụ họp và thêm vào. Lưu trữ tập hợp tổ chức dữ liệu ảnh bởi các dải
(bands), và một điểm được trang bị mọt dữ liệu mẫu từ vị trí mẫu với
http://tailieuhay.com 135
Lập trình đồ họa trên Java 2D và 3D
mảng đơn chứa tất cả các điểm, và các dải bao gồm tập các mẫu cùng chỉ
số vị trí trong mỗi điểm.
Các nguyên tố - Primaries: Các thành viên phân biệt của một giá trị
màu trong một model màu xác định, ví dụ model RGB dạng các giá trị
màu từ các nguyên tố red, green, và blue.
5.3 Using Bufferedimages
Lớp Bufferedimage là lớp chính hỗ trợ mode tạo ảnh trung gian. Nó
cũng quản lý mọt ảnh trong bộ nhớ, cung cấp các cách để lưu các dữ liệu
điểm, biểu diễn dữ liệu điểm, và đẩy dữ liệu điểm tới một Graphics hoặc
ngữ cảnh Graphics2D.
5.3.1 Creating a Bufferedimage
Để tạo một Bufferedimage, gọi Component.createimaget, hàm này
trả về mọt Bufferedimage các đặc tính vẽ của nó tương ứng các thành
phần đã dùng tạo nó. Ảnh được tạo là không rõ , phần nổi và phần nền
có các màu của các thành phần bạn không thể hiệu chỉnh độ trong của
một ảnh.Bạn có thể dùng kỹ thuật này khi bạn muốn làm gấp đôi bộ đêm
vẽ ảnh cho sự động trong một thành phần.
public Graphics2D createDemoGraphics2D(Graphics
g) {
Graphics2D g2 = null;
int width = getSize().width;
int height = getSize().height;
if (offimg == null || offimg.getWidth() !=
width ||
offimg.getHeight() != height) {
http://tailieuhay.com 136
Lập trình đồ họa trên Java 2D và 3D
offimg = (Bufferedimage) createimage(width,
height);
}
if (offimg != null) {
g2 = offimg.createGraphics();
g2.setBackground(getBackground());
}
// .. clear canvas .. g2.clearRect(0, 0,
width, height);
return
}
Bạn cũng có thể tạo một Bufferedimage trống trong bộ nhớ dùng
một vài hàm tạo đã được cung cấp.
5.3.2 Drawing in an Offscreen Buffer
Lớp Bufferedimage có thể đuợc đùng để chuẩn bị các phần tử đồ hoạ
không hiêển thị (offscreen )sau đó copy chúng ra màn hình. Kỹ thuật này
hữu ích đặc biệt khi một graphic phức tạp hoặc dùng lặp lại. Ví dụ, nếu
bạn muốn hiển thị`hình ảnh tinh vi trong vài lần, bạn có thể vẽ nó một lần
trong bộ đệm offscreen và sau đó copy nó tới các vị trí khác nhau trên cửa
sổ. Bằng việc vẽ các hình một lần và việc sao chép nó bạn có thể hiển thị
đồ hoạ nhanh hơn.
Java.awt package có khả năng dùng các bộ đệm offsceam bởi điều
này bạn vẽ một đối tượng ảnh cùng cách mà bạn vẽ ra cửa sổ. Tất cả các
http://tailieuhay.com 137
Lập trình đồ họa trên Java 2D và 3D
tính năng đẩy (rendering) ở Java 2D™ API có thể được dùng khi vẽ các
ảnh offscreen.
Các bộ đệm offscreen thường được dùng cho hoạt hoạ. Ví dụ, bạn có
thể dùng một bộ đệm offscreen để vẽ một đối tượng một lần và sau đó
cho nó chuyển động trong một cửa sổ. Tương tự, bạn có thể dùng một bộ
đệm offscreen để cung cấp sự hồi tiếp như khi người dùng di chuyển một
hình dùng chuột. Thay vào việc vẽ lại hình tại mỗi vị trí, bạn có thể vẽ
hình một lần ra bộ đệm offscreen và sau đó copy nó tới vị trí chuột như
khi người dùng thả chuột(drag the mouse).
Hình 5-3Using an Offscreen Buffer
Hình 5-3 mô tả cách một chương trình có thể vẽ ra một offscreen
image sau đó sao chép nó ra một cửa sổ nhiều lần. Lần cuối cùng ảnh
được sao chép, nó đã được biến đổi. Chú ý rằng sự biến đổi ảnh thay cho
việc vẽ lại nó với sự biến đổi có thể kết quả không được thoả mãn.
5.3.2.1 Creating an Offscreen Buffer
http://tailieuhay.com 138
Lập trình đồ họa trên Java 2D và 3D
Cách đơn giản nhất để tạo ra một image mà bạn có thể dùng như một
offscreen buffer là dùng phương thức Component.createimage.
Bằng việc tạo một image mà không gian màu của nó, sâu, và bố trí
các điểm chính xác với cửa sổ trong đó bạn đang vẽ, image có thể được
đưa tới (blitted) thiết bị đồ hoạ một cách hiệu quả. Điều này cho phép
hàm drawimage làm việc nhanh chóng.
Bạn cũng có thể tạo một đối tượng Bufferedimage trực tiếp để dùng như
là một offscreen buffer. Điều này rất hữu ích khi bạn cần điều khiển qua
kiểu của offscreen hoặc trong suốt.
Bufferedimage hỗ trợ vài kiểu định nghĩa trước:
• TYPE_3BYTE_BGR
• TYPE_4BYTE_ABGR
• TYPE_4BYTE_ABGR_PRE
• TYPE_BYTE_BiNARY
• TYPE_BYTE_GRAY
• TYPE_BYTE_iNDEXED
• TYPE_CUSTOM
• TYPE_iNT_ARGB_PRE
• TYPE_iNT_ARGB
• TYPE_iNT_BGR
• TYPE_iNT_RGB
• TYPE_USHORT_555_RGB
• TYPE_USHORT_565_RGB
• TYPE_iNT_GRAY
Một đối tượng Bufferedimage có thể chứa một kênh alpha. Trong
hình 5-3, một kênh alpha được dùng để phân biệt các vùng được vẽ và
không được vẽ, cho phép một hình dạng bất quy tắc xuất hiện qua các
hình mà bạn đã vẽ (trong trường hợp này, một hình chữ nhật bóng). Trong
http://tailieuhay.com 139
Lập trình đồ họa trên Java 2D và 3D
vài trường hợp khác, bạn có thể dùng một kênh alpha để trộn các màu của
một ảnh mới vào nó trong một ảnh đã tồn tại.
Chú ý : trừ khi bạn cần một dữ liệu ảnh alpha cho rõ ràng, như với
một hình ảnh dạng bất thường biểu diễn trong hình 5-2, bạn nên tránh
tạo một bộ đệm offscreem alpha. Dùng alpha ở nơi nó không cần làm
chậm hiệu năng render.
GraphicsConfiguration cung cấp các phương thức thuận tiện tự động tạo
các bộ đệm ảnh trong định dạng tương thích với cấu hình của bạn. Bạn
cũng có thể lấy về cấu hình đồ hoạ liên kết với thiết bị đồ hoạ trên đó cửa
sổ tập trung để lấy thông tin, bạn cần khởi tạo một đối tượng
Bufferedimage thích hợp
5.3.2.2 Drawing in an Offscreen Buffer
Để vẽ trong một bộ đệm ảnh, Gọi Bufferimage.createGraphics() , tra
về một đối tượng Graphics2D. Với đối tượng này, có thể gọi tát cả các
phương thức Graphics2D để vẽ các hình ảnh nguyên tố, text, và render
các hình ảnh khác trong image. Kỹ thuật vẽ này hỗ trợ việc rung động và
các cải thiện khác được cung cấp bởi 2D imaging package.
Đoạn code dưới đây minh hoạ sử dụng offscreen buffering :
public void update(Graphics g){
Graphics2D g2 = (Graphics2D)g;
if(firstTime){
Dimension dim = getSize();
int w = dim.width;
int h = dim.height;
area = new Rectangle(dim);
bi = (Bufferedimage)createimage(w, h);
big = bi.createGraphics();
http://tailieuhay.com 140
Lập trình đồ họa trên Java 2D và 3D
rect.setLocation(w/2-50, h/2-25);
big.setStroke(new BasicStroke(8.0f));
firstTime = false;
}
// Clears the rectangle that was previously
drawn. big.setColor(Color.white);
big.clearRect(0, 0, area.width, area.height);
// Draws and fills the newly positioned
rectangle to the buffer.
big.setPaint(strokePolka);
big.draw(rect); big.setPaint(fillPolka);
big.fill(rect);
// Draws the buffered image to the screen.
g2.drawimage(bi, 0, 0, this);
}
5.3.3 Manipulating Bufferedimage Data Directly
Cùng với việc vẽ ảnh trực tiếp trong Bufferedimage, bạn có thể truy
cập trực tiếp và xử lý dữ liệu điểm ảnh trong 2 cách. Những cách này hữu
ích nếu vạn đang cài đặt giao diện bộ lọc BufferedimageOp như đã được
mô tả trong chương xử lý và cải thiện ảnh.
Bạn cũng có thể dùng phương thức Bufferedimage.setRGB để đặt
trực tiếp giá trị của một điểm hoặc một mảng các điểm tới một giá trị
RGB xác định. Chú ý rằng, không có sự lay động khi bạn modify các
http://tailieuhay.com 141
Lập trình đồ họa trên Java 2D và 3D
điểm một cách trực tiếp. Bạn cũng có thể xử lý dữ liệu điểm ảnh bởi việc
xử lý một đối tượng WritableRaster liên kết với một Bufferedimage
5.3.4 Filtering a Bufferedimage
Bạn có thể ứng dụng một bộ lọc cho một Bufferedimage dùng một
đối tượng cài đặt BufferedimageOp. Việc lọc và các lớp cung cấp giao
diện lọc đã thảo luân trong phần Xử lý và cải thiện ảnh (image Processing
and Enhancement).
5.3.5 Rendering a Bufferedimage
Để render một bộ đệm ảnh vào trong một ngữ cảnh cụ thể, gọi hàm
drawiamge của ngữ cảnh của đối tượng Graphics. Ví dụ khi rendering
trong phương thức Component.paint, bạn gọi drawimage() trên đối
tượng đồ hoạ đã truyền cho phương thức.
public void paint(Graphics g) {
if (getSize().width <= 0 || getSize().height
<= 0)
return;
Graphics2D g2 = (Graphics2D) g;
if (offimg != null && isShowing()) {
g2.drawimage(offimg, 0, 0, this);
}
}
Chương trình ví dụ:
http://tailieuhay.com 142
Lập trình đồ họa trên Java 2D và 3D
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.awt.image.*;
public class BufferedShapeMover extends Applet {
static protected Label label;
public void init() {
setLayout(new BorderLayout());
add(new BSMCanvas());
label = new Label("Đặt hình chữ nhật này
xung quanh vùng frame.");
add("South", label);
}
public static void main(String s[]) {
Frame f = new
Frame("BufferedShapeMover");
f.addWindowListener(new WindowAdapter() {
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
});
Applet applet = new BufferedShapeMover();
f.add("Center", applet);
http://tailieuhay.com 143
Lập trình đồ họa trên Java 2D và 3D
applet.init();
f.pack();
f.setSize(new Dimension(550, 250));
f.show();
}
}
class BSMCanvas extends Canvas implements
MouseListener, MouseMotionListener {
Rectangle rect = new Rectangle(0, 0, 100,
50);
Bufferedimage bi;
Graphics2D big;
int last_x, last_y;
boolean firstTime = true;
TexturePaint fillPolka, strokePolka;
Rectangle area;
boolean pressOut = false;
public BSMCanvas() {
http://tailieuhay.com 144
Lập trình đồ họa trên Java 2D và 3D
setBackground(Color.white);
addMouseMotionListener(this);
addMouseListener(this);
bi = new Bufferedimage(5, 5,
Bufferedimage.TYPE_iNT_RGB);
big = bi.createGraphics();
big.setColor(Color.pink);
big.fillRect(0, 0, 7, 7);
big.setColor(Color.cyan);
big.fillOval(0, 0, 3, 3);
Rectangle r = new Rectangle(0, 0, 5, 5);
fillPolka = new TexturePaint(bi, r);
big.dispose();
bi = new Bufferedimage(5, 5,
Bufferedimage.TYPE_iNT_RGB);
big = bi.createGraphics();
big.setColor(Color.cyan);
big.fillRect(0, 0, 7, 7);
big.setColor(Color.pink);
big.fillOval(0, 0, 3, 3);
r = new Rectangle(0, 0, 5, 5);
strokePolka = new TexturePaint(bi, r);
big.dispose();
}
public void mousePressed(MouseEvent e) {
last_x = rect.x - e.getX();
http://tailieuhay.com 145
Lập trình đồ họa trên Java 2D và 3D
last_y = rect.y - e.getY();
if (rect.contains(e.getX(), e.getY())) {
updateLocation(e);
} else {
BufferedShapeMover.label
.setText("Đầu tiên đặt con
trỏ lên hình chữ nhật và kéo.");
pressOut = true;
}
}
public void mouseDragged(MouseEvent e) {
if (!pressOut) {
updateLocation(e);
} else {
BufferedShapeMover.label
.setText("Đầu tiên đặt con
trỏ lên hình chữ nhật và kéo.");
}
}
public void mouseReleased(MouseEvent e) {
if (rect.contains(e.getX(), e.getY())) {
updateLocation(e);
} else {
BufferedShapeMover.label
http://tailieuhay.com 146
Lập trình đồ họa trên Java 2D và 3D
.setText("Đầu tiên đặt con
trỏ lên hình chữ nhật và kéo.");
pressOut = false;
}
}
public void mouseMoved(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void updateLocation(MouseEvent e) {
rect.setLocation(last_x + e.getX(),
last_y + e.getY());
if (checkRect()) {
BufferedShapeMover.label.setText("Hình chữ
nhật ở vị trí : "
+ rect.getX() + "- " +
rect.getY());
} else {
http://tailieuhay.com 147
Lập trình đồ họa trên Java 2D và 3D
BufferedShapeMover.label
.setText("Đừng cố gắng đưa
hình ra ngoài frame.");
}
repaint();
}
public void paint(Graphics g) {
update(g);
}
public void update(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
if (firstTime) {
Dimension dim = getSize();
int w = dim.width;
int h = dim.height;
area = new Rectangle(dim);
bi = (Bufferedimage) createimage(w,
h);
big = bi.createGraphics();
rect.setLocation(w / 2 - 50, h / 2 -
25);
big.setStroke(new
BasicStroke(8.0f));
firstTime = false;
}
http://tailieuhay.com 148
Lập trình đồ họa trên Java 2D và 3D
big.setColor(Color.white);
big.clearRect(0, 0, area.width,
area.height);
big.setPaint(strokePolka);
big.draw(rect);
big.setPaint(fillPolka);
big.fill(rect);
g2.drawimage(bi, 0, 0, this);
}
boolean checkRect() {
if (area == null) {
return false;
}
if (area.contains(rect.x, rect.y, 100,
50)) {
return true;
}
int new_x = rect.x;
int new_y = rect.y;
if ((rect.x + 100) > area.width) {
new_x = area.width - 99;
}
if (rect.x < 0) {
new_x = -1;
}
if ((rect.y + 50) > area.height) {
http://tailieuhay.com 149
Lập trình đồ họa trên Java 2D và 3D
new_y = area.height - 49;
}
if (rect.y < 0) {
new_y = -1;
}
rect.setLocation(new_x, new_y);
return false;
}
}
5.4 Managing and Manipulating Rasters
Một đối tượng Bufferedimage dùng một Raster để quản lý mảng dữ
liệu điểm 2 chiều. Lớp Raster định nghĩa các trường cho toạ độ hệ thống
của ảnh- độ rộng , độ cao, và gốc toạ độ. Một đối tượng Raster tự nó dùng
2 đối tượng để quản lý dữ liệu điểm, một DataBuffer và một
SampleModel. DataBuffer là đối tượng lưu giữ dữ liệu điểm cho raster
cung cấp sự biểu diễn bên trong của dữ liệu điểm từ DataBuffer.
5.4.1 Creating a Raster
Trong hầu hết các trường hợp, không cần phải tạo một Raster trực
tiếp, bởi vì một Raster được cung cấp với bất cứ Bufferedimage bạn tạo
trong bộ nhớ. Tuy nhiên, một trong những hàm khởi tạo của
Bufferedimage cho phép tạo một Raster bởi truyền vào trong một
WritableRaster.
Lớp Raster cung cấp một số sản sinh (factory) hàm tĩnh cho tạo ra
các Raster với DataBuffers và SampleModels bạn xác định. Bạn cũng có
thể dùng các bộ sản sinh này khi cài đặt các lớp bộ lọc RasterOp.
http://tailieuhay.com 150
Lập trình đồ họa trên Java 2D và 3D
5.4.2 Parent and Child Rasters
Lớp Raster kết hợp ý tưởng các raster cha và con. Điều này có thể cải
tiến hiệu quả lưu trữ bằng việc cho phép tạo bất kỳ số bộ đệm ảnh từ cùng
một cha. Cha và các con của nó tham chiếu tới cùng một bộ đệm dữ liệu,
và mỗi con có một (độ lệch) offset xách định và danh giới chỉ định tới vị
trí ảnh của nó trong bộ đệm. Một con xác định cha của nó qua bằng hàm
getParent().
Để tạo ra một Raster con (subraster), dùng phương thức
Raster.createSubRaster. Khi tạo một subraster, xác định vùng của cha
của nó mà nó chiếm và xác định offset của nó từ góc toạ độ của cha.
Operations on a Raster
Lớp Raster định nghĩa một số cách để truy cập trực tiếp các điểm và
dữ liệu điểm. Điều đó rất hữu ích khi khi bạn cài đặt giao diện RasterOp,
nó cung cấp bộ lọc cấp và xử lý dữ liệu của ảnh, hoặc khi cài đặt bất cứ
một phương thức nào mà cần thực hiện xử lý điểm ở mức thấp.
Các phương thức Raster.getPixel cho phép lấy về một điểm riêng
biệt, nó trả về như là một mẫu riêng biệt trong một mảng. Các phương
thức Raster.getDataElements trả về một phần tử thực thi cụ thể của diễn
dữ liệu ảnh không thể hiện từ DataBuffer. Phương thức
Raster.getSample() trả về mẫu của một điểm cụ thể. Phương thức
getSamples trả về một dải (band) cho một vùng cụ thể của một image.
Cùng với các phương thức đó, Cũng có thể truy cập dữ bộ đệm và
model mẫu qua các biến thể nghiệm (instance variables) của lớp Raster .
Các đối tượng này cung cấp thêm các cách truy cập và biểu diễn dữ liệu
điểm của Raster.
5.4.4 The WritableRaster Subclass
Lớp con WritableRaster cung cáp các phương thức để đặt dữ liệu
điểm và các mẫu. Raster liên kết với một Bufferedimage thực ra là một
http://tailieuhay.com 151
Lập trình đồ họa trên Java 2D và 3D
WritableRaster vì cung cấp truy cập đầy đủ để xử lý dữ liệu điểm của
nó.
5.5 Image Data and DataBuffers
DataBuffer phụ thuộc vào một Raster biểu diễn một mảng các dữ
liệu ảnh. Khi bạn tạo một Raster trực tiếp hoặc qua các hàm tạo
Bufferedimage, bạn xác định độ rộng và chiều cao trong các pixel, cùng
với một SampleModel cho dữ liệu ảnh. Các thông tin đó cũng được dùng
để tạo một DataBuffer với dữ liệu và kiểu và kích thước phù hợp.
Có 3 lớp con của DataBuffer, mỗi lớp biểu diễn một loại khác nhau
của một phần tử dữ liệu:
• DataBufferByte (represents 8-bit values)
• DataBufferint (represents 32-bit values)
• DataBufferShort (represents 16-bit values)
• DataBufferUShort (represents unsigned short values)
Như đã định nghĩa từ trước, các phần tử là các thành phần rời rạc của
mảng dữ liệu bộ đệm, và các thành phần hoặc các mẫu là các giá trị rời
rạc kết hợp với nhau tạo nên một điểm. Có nhiều cách ánh xạ giữa kiểu
của phần tử trong một DataBuffer và kiểu của điểm được biểu diễn bởi
một SampleModel. Các lớp con SampleModel cũng có khả năng cài đặt
ánh xạ và cung cấp cách để lấy các điểm xác định từ một DataBuffer cụ
thể.
Các hàm tạo DataBuffer cung cấp các cách để tạo các bộ đệm với
một cỡ xác định và một số các bank xác định.
Bạn có thể truy cập dữ liệu của một ảnh trong DataBuffer một cách
trực tiếp, bạn cũng dễ dàng và thuận tiện làm điều đó hơn qua các phương
thức của các lớp Raster và WritableRaster.
http://tailieuhay.com 152
Lập trình đồ họa trên Java 2D và 3D
5.6 Extracting Pixel Data from a SampleModel
Lớp trừu tượng SampleModel định nghĩa các phương thức cho
extracting các mẫu của một ảnh mà không cần biết cách dữ liệu được lưu
trữ ở bên dưới. Lớp cung cấp các trường cho việc ghi lại chiều cao và
chiều rộng cả dữ liệu ảnh trong DataBuffer liên kêt nó , và cho việc mô
tả số lượng các band và kiểu dữ liệu đệm. Các phương thức SampleModel
cung cấp dữ liệu ảnh như tập(collection) các điểm, với mỗi điểm bao gồm
có một số các mẫu hoặc các thành phần.
java.awt.image package cung cấp năm loại model mẫu:
• ComponentSampleModel— Được dùng để extract các điểm từ các
image chứa các mẫu dữ liệu trong các phần tử mảng dữ liệu riêng trong
một bank của một DataBuffer
• BandedSampleModel— Được dùng để extract các điểm từ các
image chứa mỗi mẫu trong một phần tử dữ liệu riêng với các band chứa
trong một dãy các phần tử dữ liệu.
• PixelinterleavedSampleModel— Được dùng để extract các điểm từ
các image chứa mỗi sample trong một phần tử riêng vói các điểm được
lưu trong một dãy tuân tự (sequence) của các phần tử dữ liệu.
• MultiPixelPackedSampleModel— Được dùng để extract các điểm
từ các iamge đơn band chứa nhiều mẫu một các điểm trong một phần tử
dữ liệu( used to extract pixels from single banded images that store
multiple one-sample pixels in one data element ).
• SinglePixelPackedSampleModel—used to extract samples from
images
that store sample data for a single pixel in one data array element in the
first
bank of a DataBuffer.
Dữ liệu điểm được biểu diễn bởi SampleModel có hoặc không thể
liên quan trực tiếp tới một dữ liệu màu biểu diễn một model màu cụ thể.
http://tailieuhay.com 153
Lập trình đồ họa trên Java 2D và 3D
phụ thuộc vào dữ liệu nguồn. Ví dụ, trong dữ liệu ảnh đồ hoạ photo, các
mẫu có thể biểu diễn dữ liệu RGB. Trong dữ liệu ảnh từ một thiết bị ảnh y
tế, các mẫu có thể biểu diễn các loại dữ liệu khác nhau giông như nhiệt độ
hoặc mật độ xương.
Có ba category của các phương thức cho truy cập dữ liệu ảnh. Các
phương thức getPixel trả về cả một điểm trong một mảng, với mỗi đầu
vào cho mỗi mẫu. Các phương thức getDataElement cung cấp truy cập tới
dữ liệu thô, không thể hiện được chứa trong DataBuffer. Các phương
thức getSample cung cấp truy nhập tới các thành phần điểm cho một band
xác định.
5.7 ColorModels and Color Data
Cùng với Raster cho quản lý dữ liệu ảnh, lớp Bufferedimage bao
gồm một ColorModel cho biểu diễn dữ liệu như các giá trị điểm màu.
Lớp trừu tượng ColorModel định nghĩa các phương thức cho việc đặt các
điểm của image một giá trị màu trong ColorSpace liên kết với nó.
Gói java.awt.image cung cấp bốn loại model màu:
• PackedColorModel— Một ColorModel trừu tượng biểu diễn các
giá trị điểm có các thành phần màu được nhúng trực tiếp trong các bit của
một điểm nguyên. DirectColorModel là một lớp con (subclass) của
PackedColorModel.
• DirectColorModel—một ColorModel biểu diễn các giá trị điểm có
các thành phần màu RGB được nhúng trực tiếp trong các bit của điêm.
DirectColorModel model tương tự với một X11 TrueColor visual.
• ComponentColorModel—một ColorModel có thể handle một
ColorSpace thay đổi và một mảng các thành phần màu tương ứng với
ColorSpace.
• indexColorModel— Một ColorModel biểu diễn các giá trị màu vào
trong bản đồ màu trong không gian màu sRGB.
http://tailieuhay.com 154
Lập trình đồ họa trên Java 2D và 3D
Dựa trên dữ liệu trong DataBuffer, SampleModel cung cấp
ColorModel cho điểm, ColorModel sau đó biểu diễn như một màu.
5.7.1 Lookup Table
Một bảng tham chiếu (lookup table) chứa dữ liệu cho một hoặc nhiều
kênh hoặc các thành phần, ví dụ, các mảng riêng R, G và B. Goi
java.awt.image định nghĩa 2 kiểu bảng tham chiếu mở rộng lớp
LookupTable trừu tượng, một chứa byte dữ liệu và một chứa short data
(ByteLookupTable and ShortLookupData).
5.8 image Processing and Enhancement
Image package cung cấp một cặp giao diện định nghĩa các thao tác
trên Bufferedimage và Raster : BufferedimageOP và RasterOp.
Các lớp cài đặt những giao diện này bao gồm AffineTransformOp,
BandCombineOp, ColorConvertOp, ConvolveOp, LookupOp,
RescaleOp. Các lớp này có thể được dùng để biến đổi hình học, làm mờ,
làm sắc, thiện độ tương phản, ngưỡng, và làm đúng màu.( blur, sharpen,
enhance contrast, threshold, and color correct images).
Hình 5-4 minh hoạ phát hiện biên và cải thiện , một thao tác làm bóng
,thay đổi tăng cường độ trong một ảnh. Phát hiện biên thường được dùng
trong xử lý ảnh y tế và các ứng dụng bản đồ. Phát hiện biên được dùng
tăng độ tương phản giữa cấu trúc kề trong một ảnh, cho phép viewer để
phân biệt chi tiết hơn.
http://tailieuhay.com 155
Lập trình đồ họa trên Java 2D và 3D
Figure 5-4 Phát hiện biên và cải thiện ảnh
Đoạn code sau đây minh hoạ phát hiện biên:
float[] elements = { 0.0f, -1.0f, 0.0f,
-1.0f, 4.f, -1.0f,
0.0f, -1.0f, 0.0f};
...
Bufferedimage bimg = new
Bufferedimage(bw,bh,Bufferedimage.TYPE_iNT_RGB);
Kernel kernel = new Kernel(3, 3, elements);
ConvolveOp cop = new ConvolveOp(kernel,
ConvolveOp.EDGE_NO_OP, null);
cop.filter(bi,bimg);
Hình 5 -5 demo xử lý bảng tham chiếu. Xử lý bảng tham chiếu có thể
được dùng để thay cho các thành phần riêng lẻ của một điểm.
Hình 5-5 Xử lý Lookup-Table
Đoạn code sau demo thao tác Lookup-table:
http://tailieuhay.com 156
Lập trình đồ họa trên Java 2D và 3D
byte reverse[] = new byte[256];
for (int j=0; j<200; j++){
reverse[j]=(byte)(256-j);
}
ByteLookupTable blut=new ByteLookupTable(0,
reverse);
LookupOp lop = new LookupOp(blut, null);
lop.filter(bi,bimg);
Hình 5-6 minh hoạ rescaling. Rescaling có thể tăng hoặc giảm cường
độ của tất cả các điểm. Rescaling có thể được dùng để tăng dải động của
các ảnh tự nhiên khác, đưa ra chi tiết trong các vùng tự nhiên hoặc
phẳng.
Hình 5-6 Rescaling
Đoạn Code dưới đây minh hoạ rescaling:
http://tailieuhay.com 157
Lập trình đồ họa trên Java 2D và 3D
RescaleOp rop = new RescaleOp(1.5f, 1.0f,
null);
rop.filter(bi,bimg);
5.8.1 Using an image Processing Operation
Convolution là quá trình bên dưới hầu hết các thoật toán lọc không
gian. Convolution la quá trình đánh giá (weighting) hoặc làm đều
(averaging) giá trị của mỗi điểm trong một ảnh với các gía trị điểm lân
cận. Điều này cho phép mỗi điểm ra được đạt bởi lân cận trung gian
trong cách màd có thể được xác định với một nhân (kernel)
Hình 5 -7 minh hoạ Convolution
Đoạn mã sau minh hoạ cách dùng một trong các lớp xử lý hình ảnh,
lớp ConvolveOp. Trong ví dụ này, mỗi điểm tỏng ảnh nguồn được làm
cân bằng với 8 điểm xung quanh nó.
float weight = 1.0f/9.0f;
float[] elements = new float[9]; // create
2D array
// fill the array with nine equal elements
for (i = 0; i < 9; i++) {
elements[i] = weight;
}
http://tailieuhay.com 158
Lập trình đồ họa trên Java 2D và 3D
// use the array of elements as argument
to create a Kernel
private Kernel myKernel = new Kernel(3, 3,
elements);
public ConvolveOp simpleBlur = new
ConvolveOp(myKernel);
// sourceimage and destimage are instances
of Bufferedimage
simpleBlur.filter(sourceimage, destimage) //
blur the image
Biến simpleBlur chứa một thể nghiệm mới của ConvolveOP cài đặt
toán tử blur trên một Bufferedimage hoặc một Raster. Giả định rằng
sourceimage và destimage là 2 thể nghiệm của Bufferedimage. Khi bạn
gọi filter, các phương thức chính của lớp ConvolveOp đặt giá trị của mỗi
điểm trong ảnh đích bởi việc bằng giá trị trung bình của 8 điểm xung
quanh điểm tương ứng với nó trong ảnh nguồn.
Nhân convolution trong ví dụ này có thể được biểu diễn bởi ma trận
dưới đây, với các phần tử đã xác định tới 4 phần:
Khi một ảnh được vonvolved, giá trị của mỗi điểm trong ảnh đích
được tính toán bới việc dùng một nhân như là một tập với trung bình của
các giá trị xung quanh mỗi điểm tương ứng trong ảnh nguồn. Việc xử lý
này được thực hiện dựa trên mỗi kênh của ảnh.
http://tailieuhay.com 159
Lập trình đồ họa trên Java 2D và 3D
Công thức sau biểu diễn cách các trọng số trong nhân được liên hệ với
các điểm trong ảnh nguồn khi thực hiện convolution. Mỗi giá trị tỏng
nhân được tied tới các vị trí trong hình ảnh.
Giá trị của điểm đích tỏng tổng các kết quả của trọng số trong nhân
được nhân với giá trị của các điểm nguồn tương ứng. Với nhiều bộ lọc
đơn giản, kernel là một ma trận vuông
Convolution kernel trong ví dụ này liên quan đơn giản. Nó đo
(weights) mỗi điểm từ hình ảnh nguồn bởi chọn một nhân đo (weights)
ảnh nguồn ở mức cao hơn hoặc thấp hơn, một chương trình có thể tăng
hoặc giảm cường độ của ảnh đích. Đối tượng Kernel, được đặt trong khởi
tạo của ConvolveOP , xác định kiểu bộ lọc nó thực thi. Bởi việc đặt các
gía trị khác, bạn có thể thực hiện các kiểu convolution khác nhau bao gồm
blurring (như Gaussian blur, radial blur, và motion blur), sharpening, và
smoothing
Hình 5-8 minh hoạ sharpening dùng Convolution.
Hình 5-8 Sharpening with Convolution
Đoạn code dưới đây minh hoạ sharpening với
float[] elements = { 0.0f, -1.0f, 0.0f,
http://tailieuhay.com 160
Lập trình đồ họa trên Java 2D và 3D
-1.0f, 5.f, -1.0f,
0.0f, -1.0f, 0.0f };
...
Kernel kernel = new Kernel(3,3,elements);
ConvolveOp cop = new ConvolveOp(kernel,
ConvolveOp.EDGE_NO_OP,
null);
cop.filter(bi,bimg);
http://tailieuhay.com 161
Lập trình đồ họa trên Java 2D và 3D
Chương 6
Mầu sắc
Vẽ ảnh màu là một trong những thành phần nền tảng của các hệ thống
đồ họa và nó luôn là nguồn gốc của sự phức tạp trong những ô hình tạo
ảnh.Thư viện Java 2D™ API cung cấp
Sự hỗ trợ cho sự tạo ảnh màu chất lượng cao nhưng lại dễ dàng sử dụng
Các lớp quản lý màu trong Java 2D API gôm CorlorSpace, Color.
Một ColorSpace biểu diễn cho một hệ thông cho việc định lượng
màu, Tiêu biểu như biểu diễn bằng 3 giá trị số(RGB) họăc các thành
phần.. Lớp ColorSoace chứa các phương thức cho chuyển đổi các không
gian màu và hai không gian màu chuẩn là CiEYZ và GRB.
Một Color là một màu cố định đa được xác định trong định nghĩa
của các thành phần của nó trong một ColorSpace cụ thể. Để vẽ một
Shape với một màu. chẳng hạn màu đỏ. bạn phải truyền mọt đối tượngc
Color bỉêu diễn màu với ngữ cảnh đồ hoạ 2D. Color được đinh nghĩa
trong java.awt.ColorModel miêu tả một cách cụ thể những điểm được
ánh xạ tới các màu.
ColorModel đựoc hệ tiêu biểu với một image hoặc một Bộ đệm hình
ảnh(Bufferimage) và cung cấp thông tin cần thiêt thíc hợp để biểu diễn
các gía trị đỉêm. ColorModel được định nghĩa trong java.awt.image
http://tailieuhay.com 162
Lập trình đồ họa trên Java 2D và 3D
6.1 Các lớp
Clases DescriptionColorSpace Identifies the color space of a Color object,
Image, BufferedImage, or GraphicsDevice.
Has methods to transform between RGB and
CIEXYZ color spaces.ICC_ColorSpace Extends: ColorSpace
Represents device-independent and device-
dependent color spaces based on the ICC
Profile Format Specification.ICC_Profile A representation of color profile data for
device independent and device dependent
color spaces based on the ICC Profile
Format Specification. ICC_ProfileGray Extends: ICC_Profile
A representation of color space type gray.ICC_ProfileRGB Extends: ICC_Profile
A representation of color space type RGB.
6.2 Những định nghĩa về mầu sắc.
Một ColorModel được sử dụng để biểu diễn một dữ liệu diểm trong
ảnh. Điều này bao gồm cả ánh xạ các thành phần trong những dải(bands)
của một ảnh tới các thành phần của một không gian màu cụ thể. Nó có thể
cũng bao hàm cả xuất các thành phần điểm từ một dữ liệu diểm dóng gói
hay nhận về nhiều thành phần từ một dải đơn bằng sử dụng các mặt nạ. và
chuyển dữ liệu điểm qua một bảng tham chiếu(lookup table)
Để xác định được giá trị màu của một điểm cụ thể trong ảnh bạn phải
biết các mã hoá thông tin cho mỗi điểm. ColorModel liên hệ với một ảnh
sẽ đóng gói dữ liệu và các phương thức cần thiết cho việc chuyển đổi giá
trị điểm tới và từ các đơn vị thành phần màu.
http://tailieuhay.com 163
Lập trình đồ họa trên Java 2D và 3D
Java 2D™ API cung cấp 2 color model va thêm vào DirectColor –
Model và indexColorModel được định nghĩa trong JDK 1.1 release.:
ComponentColorModel co thể giữ một ColorSpace không hạn
chế và một mảng thành phần màu ứng với ColorSpace. Model này có thể
sử dụng để biểu diễn hầu hết các model màu trến hầu hết các loại Thiết bị
đồ hoạ(GrphicsDevices ).
PackedColorModel là lớp cơ sở cho các model biểu diễn giá trị
điểm bao gồm các thành phần màu nhúng trực tiếp trong các bit của một
điểm nguyên.
PackedColorModel chứa cac thông tin gói mô tả cách các thành phần
màu và alpha được xuất ra từ một kênh. ĐirectColorModel trong JDK 1.1
release la một PackedColorModel.
6.2.1 Không gian mầu
Đối tượng ColorSpace biểu diễn một hệ thống cho việc định lượng
các màu, tiêu biểu như việc sử dụng 3 giá trị số riêng biệt.Ví dụ RGB,
CMYK là các không gian màu.(ColorSpace).
Một đối tượng ColorSpace dùng như là thẻ một colorspace xác định
không gian màu cụ thể của đối tưọng màu hoặc qua một đối tượng
ColorModel , của một imae , một Bufferedimage, hoặc một
GraphicsConfiguration. ColorSpace cung cấp các phương thức chuyển
đổi các màu trong không gian xác định tới và từ RGB và tới và từ không
gian CiEXYZ.
Tất cả đối tượng ColorSpace phải có thể ánh xạ một màu từ không
gian biểu diễn sang sRGB và chuyển đổi một màu sRGB sang không gian
biểu diễn màu đó. Vì mỗi Color chứa một đối tượng ColorSpace đặt
tường minh hoặc mặc định. mỗi Color cũng có thể chuyển từ sRGB, Mỗi
GraphicsConfiguration dược liên hệ với một đối tượng ColorSpace khi
có được liên hệ với ColorSpace. Một màu được xác định trong bất cứ
http://tailieuhay.com 164
Lập trình đồ họa trên Java 2D và 3D
không gian màu nào cung có thể hiển thị được bởi bất cứ thiết bị nào bởi
việc ánh xạ nó tới sRGB như một không gian màu trung gian.
Các phương thức được dùng cho quá trình này là toRGB() và
fromRGB(), toRGB chuyển một Color trong không gian màu tới một màu
trong sRGB fromRGB nhận một màu trong sRGB và chuyển nó sang
không gian mầu
Mặc dù việc ánh xạ qua sRGB luôn thực hiện nhưng nó không luôn
luôn la pháp tốt nhất.
Ví dụ. sRGB không thể biểu diễn mọi màu trong cả giải màu CiEXYZ.
Nếu một màu đựơc xác định trong một vài không gian có giải phổ
màu khác nhau hơn sRGB
Thì việc sử dụng sRGB như là một không gian trung gian và ở đó bị mất
thông tin. để giải quyết vấn đề này, lớp ColorSpace có thể ánh xạ các
màu tới và từ không gian màu khác , như CiEXYZX
Các phương thức toCiEXYZ và fromCiEXYZ ánh xạ giá trị màu từ
không gian màu tới không gian khác (CiEXYZ). Các phương thức này bổ
trợ chuyển đổi giữa hai không gian màu bất kỳ với mật độ và cấp độ cao,
với một Color một lúc.Tuy nhiên cũng hi vọng rằng cài đặt Java 2D API
se bổ trợ cho chuyển đổi với hiệu năng cao dựa trên hệ thông quản lý
màu, thao tác trên toàn ảnh.( Xem ColorConvertOp trong imaging trang
67)
Hình 6-1 và 6-2 minh hoạ quá trình translating một màu được xác
định trong không gian màu CMYK để hiển thị trên màn hình RGB. Hình
6-1 biểu diễn mapping qua sRGB. Như hình minh hoạ, sự chuyển đổi của
màu CMYK sang màu RGB không chính xác bởi sự không tương ứng
hoàn toàn.
Tất nhiên, những màu được sử dụng trong các này mang tính chất
biểu đồ minh hoạ và không chính xác. Những điêm màu sẽ không được
http://tailieuhay.com 165
Lập trình đồ họa trên Java 2D và 3D
ánh xạ đúng giữa các không gian màu trừ khi có một sự chuyển đổi không
gian phù hợp được sử dụng.
Hình 6-2 biểu diễn cùng quá trình sử dụng CiEXYZ như là không
gian màu chuyển đổi. Khi CiEXYZ được sử dụng, màu được chuyển qua
một cách đứng đắn.
ColorSpace la thực ra là một lớp trừu tượng. Java 2D API cung cấp
sự cài đặt iCC_Profile lớp dựa trên dữ liệu iCC Profile như được biểu
diễn bởi lớp iCC_Profile. Bạn có thể định nghĩa lớp con của bạn để biểu
diễn các không gian màu chuyển đổi miễn là các phương thức được thảo
luận trên được cài đặt. Tuy nhiên hầu hết các developers có thể sử dụng
một cách đơn giản lớp ColorSpace mặc định hoặc các không gian màu
được biểu diễn bởi các iCC Profiles thông thường, giống như các thông
tin cho màn hình và máy in, hoặc thông tin được nhứng trong dữ liệu ảnh.
ColorSpace trong trang 90 miêu tả cách đối tượng ColorSpace biểu
diễn một không gian màu và biểu diễn các màu trong không gian màu có
thể ánh xạ tới và từ một không gian chuyển đổi. Các hệ thống quản lý
màu thường được sử dụng để giữ ánh xạ giữa các không gian màu. Tiêu
http://tailieuhay.com 166
Lập trình đồ họa trên Java 2D và 3D
biểu như hệ thông quản lý màu (CMS) quản lý các thông tin iCC (iCC
profiles) nó giông như đối tượng ColorSpace; iCC profiles mô tả một
không gian vào và không gian kết nối, và định nghĩa cách ánh xạ giữ
chúng. Hệ thống quản lý màu rất tốt ở việc chỉ ra cách ánh xạ một màu
được gắn với một profile vào trong không gian màu của một profile khác.
Java 2D API định nghĩa một lớp gọi là iCC_Profile giữ dữ liệu cho
một bộ chuyển đổi iCC profile. iCC_ColorSpace là một sự cài đặt của lớp
trừu tượng ColorSpace. Các đối tượng iCC_ColorSpace có thể được khởi
tạo từ các iCC_Profile.(Có một số giới hạn – không phải tất cả các iCC
Profile là thích hợp cho việc định nghĩa một
iCC_ColorSpace)iCC_Profile có vài lớp con tương ứng với các loại
không gian màu như iCC_ProfileRGB và iCC_ProfileGray. Mỗi lớp con
của nó có một không gian vào được định nghĩa thích hợp(giông như
không gian RGB) và không gian kết nối thích hợp (không gian CiEXYZ).
Java 2D API có thể sử dụng hệ thông nền CMS (platform’s CMS ) để truy
nhập các thông tin màu co nhiều loại thiết bị đa dạng giông như
scanner ,máy in, màn hình. Cũng có thể sử dụng CMS để tìm sự ánh xạ
tốt nhất giữa các profiles
6.2.1 Biểu diễn màu
Lớp Color cung cấp sự mô tả màu trong không gian màu cụ thể. một
thể nghiệm của Color chứa giá trị các thành phần màu và một đối tượng
ColorSpace. Bởi một đối tượng ColorSpace có thể được xác định thêm
vào các thành phần màu khi một thể nghiệm mới của mà được tạo ra nên
lớp Color có thể giữ các màu trong bất cứ không gian màu nào.
Lớp Color có một số phương thức bổ trợ cho không gian màu chuẩn
RGB được gọi là sRGB(tham khảo http:// www. W3.
org/pub/www/Graphics/color/sRGB.html). sRGB la không gian màu mặc
định cho Java 2D API. Vai hàm khởi tạo được định nghĩa bởi lớp Color
http://tailieuhay.com 167
Lập trình đồ họa trên Java 2D và 3D
cho phép bỏ qua tham số ColorSpace. Các khởi tạo này mặc định rằng
giá trị màu RGB được định nghĩa trong sRGB, và sử dụng thể nghiệm
mặc định của ColorSpace để biểu diễn cho không gian đó.
Java 2D API dùng sRGB tạo thuận lơi cho các lập trình viên lập trình
ứng dụng, không phải là tham chiếu không gian màu cho sự chuyển đổi
màu. Nhiều ứng dụng chủ yếu tập trung vào anh RGB và màn hình và việc
định nghĩa không gian màu RGB lam cho việc viết chúng dễ dàng hơn.
Lóp ColorSpace định nghĩa các phương thức toRGB và frỏmGB làm cho
các developers có thể nhận các màu một cách đễ dàng trong không gian
chuẩn này. Các phương thức này không mong đợi sử dụng cho màu với độ
chính xác cao hay việc chuyển đổi. (xem ColorSpace trang 90 )
Để tạo ra một màu (color) trong một không gian màu không phải là sRGB,
ban dùng hàm tạo Color với đối tượng ColorSpace và một mảng so thực
biểu diễn các thành phần màu tương ứng với không gian đó. Đối tượng
ColorSpace xác định không gian màu.
Để hiển thị một hình chữ nhật đúng màu giống như màu cyan, bạn
cần một cách để mô tả màu này cho hệ thống. Có một số cách khác nhau
để mô tả một màu, ví dụ một màu có thể được mô tả bằng một tập hợp
các thành phần (RGB) đỏ(red), xanh lá cây(green), xanh da trời(blue) hay
tập hợp các thành phần(CMYK) Cyan, Magenta, Yellow, Black . Các kỹ
thuật khác nhau này cho việc xác định màu được gọi là các không gian
màu (color spaces).
Như bạn biết, các màu trên một màn hình máy tình được tạo bởi sự pha
trộn lượng khác nhau của ba thành phần đỏ (Red), xanh lá cây (Green), xanh
da trời (Blue). Vì thế nên dùng không gian màu RGB làm chuẩn cho vẽ ảnh
trên man hình máy tính. Tương tự, quá trình in 4 màu dùng cyan, magenta,
yellow, black để tạo ra màu trên trang giây in ,các màu in được xác định
bằng tỉ lệ phần trăm trong không gian màu CMYK.
http://tailieuhay.com 168
Lập trình đồ họa trên Java 2D và 3D
Để thích hợp vơi sự phổ biến của cả màn hình và máy in màu, cả hai
không gian màu RGB và CMYK được dùng để biểu diễn màu. Tuy nhiên,
cả 2 loại không gian màu có một hạn chế là phụ thuộc thiết bị. mực cẩm
thạch(cyan) được sử dụng bởi một máy in có thể không tương ứng với
mực cyan của một máy in khác. Tương tự, một màu biểu diễn bằng một
màu RGB có thể trông giông màu xanh da trời (blue) trên một màn hình
và màu đỏ tía (purplish) trên một màn hình khác .
Mapping Colors qua sRGB và CiEXYZ
Java 2D API dùng RGB và CMYK la 2 loại không gian màu. Một
model màn hình phôt pho cụ thể xác định một không gian màu RGB của
nó. Tương tự, môt model máy in cũng có không gian CMYK của nó.
Không gian khác nhau , Không gian RGB hoặc không gian CMYK có thể
liên hệ với nhau qua không màu gian độc lập thiết bị
Các chuẩn cho việc xác đinh màu độc lập thiết bị đã được định nghĩa
bởi international Commission on illumination (CiE). Không gian màu độc
lập thiết bị thường đựơc dùng nhất là không gian 3 thành phần màu
(three-component XYZ ) được phát triển bởi CiE. Khi bạn xác định một
màu dùng CiEXYZ, bạn được cách ly với độc lập thiết bị.
Thật không may mắn, không phải lúc nào cũng dùng không gian màu
CiEXYZ, có một số lý do cho việc biểu diễn màu trong các không gian
màu khác. Để đạt được kết quả ổn định khi một màu đựơc biểu diễn dung
không gian phụ thuộc thiết bị như không gian RGB, cần biểu diễn chác
không gian RGB liên hệ vớ không gian độc lập thiết bị giống như
CiEXYZ.
Một cách để ánh xạ giữa các không gian màu là thêm thông tin vào
cách không gian phụ thuộc thiết bị liên hệ với không gian độc lập thiết bị.
Những thông tin thêm này được gọi là profile. Color profile thường sử
dụng là iCC Color Profile, được định nghĩa bởi international Color
http://tailieuhay.com 169
Lập trình đồ họa trên Java 2D và 3D
Consortium. Chi tiết xem iCC Color Format Specification, phiên bản 3.4
trên trang http:// www.color. Org.
Hình 6-3 minh hoạ một màu đơn (Solid color) và một ảnh quét được
truyền cho Java 2D API và cách chúng hiển thị bởi các thiết bị ra đa dạng.
Như bạn thấy trong 6-3 cả màu vào và ảnh có các profile được gắn vào.
Khi API có một màu xác định một cách chính xác, nó phải tạo lại màu
trên thiết bị ra, như màn hình và máy in. Các thiết bị này có các đặc tính
tạo ảnh của nó đảm bảo rằng kết quả tạo ra là chính xác. Một profile được
liên kết với mỗi thiết bị ra để mô tả cách các màu cần được chuyển đổi để
tạo ra kết quả chính xác.
Việc đạt được màu ổn định và chính xác yêu cầu cả màu vào và thiết
bị ra đưa thêm thông tin trở lại cho không gian màu chuẩn. Ví dụ, một
màu vào có thể ánh xạ từ không gian màu gốc của nó sang không gian
màu độc lập thiết bị chuẩn, và sau đó từ không gian đó sang không gian
màu thiết bị ra. Trong nhiều khía cạnh, sự chuyển đổi màu bắt chước sự
chuyển đổi của đối tượng đồ hoạ trong không gian toạ độ x, y. Cả 2
trường hợp, sự chuyển đổi được dùng để xác định toạ độ trong không gian
http://tailieuhay.com 170
Lập trình đồ họa trên Java 2D và 3D
chuẩn và sau đó ánh xạ toạ độ đó sang không gian thiết bị xác định cho
đầu ra.
Chương 7
In ấn
Java Printing API cho phép ứng dụng cho:
1. In với AWT và đồ hoạ Java 2D™ , bao gồm đồ hoạ đa hợp
(composited graphics) và hình ảnh.
2. Các hàm điều khiển các hàm tài liệu đa hợp như so sánh mềm,
thứ tự in, và booklet printing.
3. Các hàm in xác định trợ giúp như in duplex (duplex printing)
và stapling.
4. In với tất cả các platform, cả Windows và Solaris. Điều này bao
gồm máy in đã được gắn trực tiếp với máy tính cũng như với
platform software cho phép truy cập sử dụng các giao thức in
qua mạng.
Không phải tất cả các tính năng đó được bổ trợ và được cài đặt trong
in ấn với Java™ 2 SDK API. Nhưng API sẽ được mở rộng để bộ trợ cho
tất cả các thuộc tính này ở các bản release trong tương lai.
7.1 Các giao diện và các lớp
http://tailieuhay.com 171
Lập trình đồ họa trên Java 2D và 3D
Interface DescriptionPrintable The Printable interface is implemented by each page
painter, the application class(es) called by the
printing system to render a page. The system calls the
page painter’s print method to request that a page be
rendered.Pageable The Pageable interface is implemented by a
document that is to be printed by the printing system.
Through the Pageable methods, the system can
determine the number of pages in the document, the
format to use for each page, and the page painter to
use to render each page.PrinterGraphics The Graphics2D objects that a page painter uses to
render a page implement the PrinterGraphics
interface. This enables an application to get the
PrinterJob object that is controlling the printing.Printable The Printable interface is implemented by each page
painter, the application class(es) called by the
printing system to render a page. The system calls the
page painter’s print method to request that a page be
rendered.
Class DescriptionBook Implements: Pageable
Represents a document in which pages can have
different page
formats and page painters. This class uses the
Pageable
interface to interact with a PrinterJob.PageFormat Describes the size and orientation of a page to be
http://tailieuhay.com 172
Lập trình đồ họa trên Java 2D và 3D
printed, as
well as the Paper used to print it. For example,
portrait
and landscape paper orientations are rep- resented by
PageFormat.Paper Describes the physical characteristics of a piece of
paper.PrinterJob The principal class that controls printing. The
application calls PrinterJob methods to set up a job,
display a print dialog to the user (optional), and to
print the pages in the job.
Các định nghĩa về in
Java Printing API dựa trên mô hình in callback trong đó hệ thông in,
không phải úng dụng sẽ điều khiển khi các trang được in. Ứng dụng cung
cấp thông tin về tài liệu được in và hệ thống in sẽ yêu cầu ứng dụng đẩy
tới các trang in khi nó cần chúng.
Hệ thống in có thể yêu cầu rằng một trang in riêng biệt được đưa ra
hơn một lần hoặc yêu cầu các trang được đưa ra ngoài theo thứ tự. Ứng
dụng phải cho phép tạo ra hình ảnh đúng của trang, không phụ thuộc
trang nào hệ thống in yêu cầu. Trong khía cạnh đó, hệ thống in giông như
window toolkit, có thể yêu cầu các thành phần để vẽ lại bât cư lúc nào
trong thứ tự nào.
Mô hình in callback mềm dẻo hơn các mô hình ứng dụng điều khiển in
truyền thống và bổ trợ cho việc in trên dải rộng hơn các hệ thống và các
máy in.
http://tailieuhay.com 173
Lập trình đồ họa trên Java 2D và 3D
Ví dụ, nếu một máy in thực hiện đưa ra các trang trong thứ tự đảo ngược,
hệ thống in có thể yêu cầu ứng dụng tạo các trang trong thứ tự đảo ngược
sao cho tác vụ cuối cùng là đúng thứ tự đọc .
Mô hình này cũng cho phép ứng dụng để in ra các máy in ảnh nhị
phân từ máy tính mà không có đủ bộ nhớ hày không gian đĩa để đệm cho
toàn trang bitmap. Trong tình huống này, một trang được in như là một
dãy cá bitmap nhỏ hay các dải (bands). Ví dụ, nều bộ nhớ chỉ đủ đệm cho
1/10 trang in, thi trang sẽ được chỉ thành 10 dải. Hệ thống in đòi hỏi ứng
dụng đẩy mỗi trang 10 lần, mỗi lần điền vào mỗi dải. Ứng dụng không
cần biết số lượng hay cỡ của các dải, nó chỉ đơn giản khả đẩy mỗi trang
khi được yêu cầu.
7.2.1 Supporting Printing
Một ứng dụng phải thực hiện 2 tác vu để bổ trợ cho việc in là:
1. Điều khiển in(Job control)- Khởi tạo và quản lý việc in.
2. In (imaging) – Đẩy (rendering) dữ liệu ra mỗi trang khi hệ thống in
yêu cầu nó
7.2.1.1 Điều khiển in (Job Control)
Người sử dụng thường khởi tạo việc in bởi việc kích một nút hoặc
chọn mục in trên menu trong một ứng dụng. Khi một thao tác in được
kích hoạt bởi người sử dụng, ứng dụng tạo ra một đối tượng PrinterJob
và dùng nó để quản lý quá trình in.
Ứng dụng có khả năng đáp ứng cho việc cài đặt điều khiển in, hiển thị
các hộp thoại cho người sử dụng, và bắt đầu quá trình in.
imaging
Khi một tài liệu được in, ứng dụng phải đẩy dữ liệu mỗi trang khi hệ
thống in yêu cầu nó. Để bổ trợ cho kỹ thuật này, ứng dụng cung cấp một
http://tailieuhay.com 174
Lập trình đồ họa trên Java 2D và 3D
page painter cài đặt giao diện Printable. Khi hệ thống in cần một trang
được đây ra, nó gọi phương thức in của page painter.
Khi một phương thức của page painter được gọi, nó được truyền cho
một ngữ cảnh đồ hoạ (Graphics context) dùng để đẩy hình anh trang. Nó
cũng được truyền cho một đối tượng PageFormat xác định (specifies)
hình hiện ra của trang, và chỉ số xác định thứ tự vị trí của trang trong việc
in.
Hệ thống in hỗ trợ cả việc đẩy Graphics và Graphics2D, để in Java
2D™ Shapes ,Text và images, bạn đưa một đối tượng Graphics cho
phương thức in cho raphics2D
Để in các tài liệu trong đó các trang dùng các page painter khác nhau
và có các định dạng khác nhau, bạn dùng một pageablejob. Để tạo một
pageable job, bạn có thể dùng lớp Book hoặc cài đặt giao diện Pageable
của bạn.
Để cài đặt các thao tác in đơn giản, bạn không cần dùng một pageable
print job, Print- able có thể được dùng miễn là tất cả các trang chia sẻ cùn
một định dạng và một máy in
7.2.2 Page Painters
Việc chủ yếu của một page painter là đẩy ra một trang dùng ngữ cảnh
đồ hoạ được cung cấp bởi hệ thống in. Một page painter cài đặt phưong
thức Printable.print:
public int print(Graphics g, PageFormat pf,
int pageindex)
Ngữ cảnh đồ hoạ được truyền cho phương thức in là một thể nghiệm
của Graphics hoặc Graphics2D, phụ thuộc vào các package được load
trong Java Vỉtual Machine của bạn. Để dùng các tính năng Graphics2D ,
http://tailieuhay.com 175
Lập trình đồ họa trên Java 2D và 3D
bạn có thể thay đối tượng Graphics bằng Graphics2D. Thể nghiệm
Graphics được truyền để in cũng cài đặt giao diện PrinterGraphics.
PageFormat được truyền cho một Printable mô tả hình ảnh của một
trang được in. Hệ tọa độ của ngữ cảnh đồ hoạ được truyền để in được
fixed với trang : gốc toạ độ của hệ thống là góc trái trên của trang, X tăng
theo chiều phải sang trái, Y theo chiều từ trên xưống dưới, với đơn vì là
1/72 inch.
Nếu trang trong hướng portrait, trục x căn theo chiều rộng của trang giấy,
và trục y theo chiều cao của trang. (Thông thường, nhưng không phải
luôn luôn, chiều cao của trang dài hơn với chiều rộng của nó). Nếu trang
theo hướng landscape, thì ngược lại: trục x căn theo chiều cao của trang
còn trục y căn theo chiều rộng của nó.
Bởi nhiều máy in không thể trên cả bề mặt trang, PageFormat xác
định (specifies) vùng in (imageable area) của trang: phần của trang mà nó
đẩy ra an toàn. Sự xác định của vùng in không thay đổi theo toạ độ hệ
thống, nó được cung cấp sao cho nội dung của trang có thể được đẩy ra
sao cho chúng không thể mở rông vào trong vung mà máy in không thể
in.
Ngữ cảnh đồ hoạ được truyền để in có một miền xén mô tả phần miền
có thể in mà cần được in. Nó cũng luôn an toàn để in toàn bộ trang vào
trong ngữ cảnh đó, hệ thống in sẽ nắm dữ vùng xén cần thiết.
Tuy nhiên, để loại overhead của các phần vẽ của trang không được in,
bạn có thể dùng miền cắt xén để giới hạn vùng đẩy ra. Để lấy vùng cắt
xén từ ngữ cảnh đồ hoạ, gọi hàm Graphics.getClip. Vùng cắt xén rất
mạnh mẽ để giảm bớt rendering overhead.
Đôi khi mong muốn cả thao tác in thực hiện ngầm để cho người dùng
có thể tiếp tục tao tác vói úng dụng trong khi các trang đang được đẩy ra
(đang in). Để làm điều này, gọi hàm PrinterJob.print trong một tuyến
riêng.
http://tailieuhay.com 176
Lập trình đồ họa trên Java 2D và 3D
Nếu có thể, bạn nên tránh các thao tác đồ hoạ mà yêu cầu thông tin về
nội dung của image trước đó, giống như copyArea, setXOR, và sự liên
hợp (compositing).
Các thao tác này có thể đẩy ra chậm và các kết quả có thể không ổn
định.
7.2.3 Printable Jobs and Pageable Jobs
Một Printable job cung cấp cách đơn giản nhất để in. Chỉ một page
painter được dùng , ứng dụng cung cấp một lớp đơn cài đặt giao diện
Printable. Khi in, hệ thống goi phương thức in của page painter để đẩy ra
mỗi trang. Các trang được yêu cầu theo thứ tự, bắt đầu với trang có chỉ số
là 0. Tuy nhiên, page painter có thể được yêu cầu để đẩy mỗi trang vài lần
trước khi nó sang trang tiếp. Khi trang cuối cùng được in, phương thức in
của page painter trả về NO_SUCH_PAGE.
Trong một Printable job:
1. Tất cả các trang dùng cung một page painter và PageFormat. Nếu
một hộp thoại in được hiển thị, nó cũng sẽ không hiển thị số trang
trong tài liệu vì thông tin đó không có với hệ thống in.
2. Hệ thống in luôn đòi hỏi page painter để in mỗi trang đúng thứ tự,
bắt đầu với trang có chỉ số là 0. Không trang nào bị quên. Ví dụ,
nếu người dùng yêu cầu in trang 2 và trang 3 của một tài liệu, thì
page painter sẽ được gọi với các chỉ số 0, 1, 2. Hệ thống in có thể
yêu cầu một trang được đẩy ra nhiều lần trước khi chuyển sang
trang kế.
3. Page painter báo cho hệ thống in khi nó đã đến cuối tài liệu.
4. Tất cả các page painter được gọi trong cùng một tuyến.
5. Đôi khi hệ thống in có thể không có khả năng biết được mục đích
đưa ra. Ví dụ, tác vụ của các trang hiện ra từ máy in có thể là thứ tự
http://tailieuhay.com 177
Lập trình đồ họa trên Java 2D và 3D
sai, hoặc các trang có thể không được kiểm tra thứ tự nếu nhiều bản
sao được yêu cầu.
6. Một Pageable job linh hoạt hơn một Printable job. Không giống
như các trang trong Printable job, các trang trong Pageable job có
thể khác về cách bố trí và cài đặt.
Để quản lý một Pageable job, bạn có thể dùng lớp Book hay cài đặt
lớp Pageable của bạn. Qua Pageable, hệ thống in có thể xác định số
lượng trang để in, và page painter dùng cho mỗi trang, và PageFormat
cho mỗi trang. Các ứng dụng cần in các tài liệu có một cấu trúc đã định và
định dạng nên dùng các Pageable job.
Trong một Pageable job:
Các trang khác nhau có thể dùng các page painter và các
PageFormat khác nhau.
Hệ thống in có thể đòi hỏi các page painter để in các trang trong
một thứ tự tuỳ ý và một trang có thể được bỏ qua. Ví dụ, Nếu người dùng
yêu cầu in các trang 2 và 3 của một tài liệu, thì page painter se được gọi
với chỉ số 1 và 2 còn trang chỉ số 0 sẽ được bỏ qua.
Pageable job không cần biết có bao nhiêu trang tiếp theo trong tài
liệu. Tuy nhiên, không giống với Printable job, chúng phải có khả năng
đẩy ra các trang trong bất kỳ thứ tự. Có thể có các chỗ trống trong thứ tự
và hệ thống in có thể yêu cầu một trang được đẩy ra nhiều lần trước khi
chuyển sang trang tiếp theo. Ví dụ, yêu cầu để in trang 2 và 3 của một tài
liệu có thể kết quả trong dãy lời gọi là các trang yêu cầu với chỉ số 2, 2, 1,
1 và 1.
7.2.4 Typical Life-Cycle of a PrinterJob
Một ứng dụng hướng theo đối tượng PrinterJob qua một dãy các
bước để hoàn thành công việc in. Thứ tự đơn giản nhất được dùng bởi
ứng dụng là:
http://tailieuhay.com 178
Lập trình đồ họa trên Java 2D và 3D
Lấy một đối tượng PrinterJob mới bởi việc gọi
PrinterJob.getPrintJob
Xác định PageFormat để dùng cho việc in. Một PageFormat mặc
định có thể lấy về bởi gọi hàm defaultPage. hoặc bạn có thể gọi
một hộp thoại cho phép người dùng xác định định dạng .
Xác định các đặc điểm của công việc để in cho PrinterJob. Cho
một Printable job, gọi setPrintable; với Pageable job, gọi
setPageable. Chú ý một đối tượng Book là một mẫu truyền cho
setPageable.
Xác định các thuộc tính thêm cho việc in, giống như số bản sao để
in hay tên của công việc trên đầu đề trang.
Gọi hàm printDialog để hiển thị hộp thoại cho người dùng. Điều này
là tuỳ chọn. Những nội dung và hình dạng của hộp thoại có thể đa
dạng với các platform và các máy in khác nhau. Trên hầu hết các
platform, người dùng có thể dùng hộp thoại này để thay đổi các lựa
chọn của máy in. Nếu người dùng huỷ việc in, phương thức
printDialog trả về FALSE.
Gọi Printerjob.print để in. Phương thức này khi trả về gọi print
trên các page painter tương ứng.
Một công việc có thể bị ngắt quá trình in nếu:
Một PrinterException được đưa vào ngoại lệ được bắt boẻi
phương thức in và công việc sẽ bị dừng. Một page painter đưa ra
một PrinterException nếu nó phát hiện một trầm trọng lỗi (fatal
error).
PrinterJob.cancel được gọi. vòng lặp in sẽ bị chấm dứt và công
việc bị huỷ bỏ. Phương thức cancel có thể được gọi từ một tuyến
riêng biệt cái hiển thị một hộp thoại và cho phép người dùng hủy
bỏ việc in bởi bấm vào một nút trên hộp thoại đó.
http://tailieuhay.com 179
Lập trình đồ họa trên Java 2D và 3D
Các trang phân ra trước khi một công việc in bị dừng có thể là không
được in hoặc được in. Việc in thường không kêt thúc (finished) khi
phương thức in tra về. Việc này thường vẫn đang được thực hiện bởi trình
điều khiến máy in.
Trạng thái của đối tượng PrinterJob có thể không phản ánh trạng thái
thực tế của công việc đang được in.
Do trạng thái của một PrinterJob thay đổi trong quá trình vòng đời
của nó. Không hợp lý yêu cầu các phương thức vào nhiều lúc. Ví dụ, việc
gọi setPageable sau khi bạn đã gọi hàm print là không hợp lý. Khi có các
lời gọi không hợp lý được phát hiện PrinterJob sẽ đưa vào một ngoại lệ
java.lang.illegalStatException.
Dialogs
Java Printing API yêu cầu các ứng dụng cần đến hộp thoại giao tiếp
với người dùng một cách tường minh. Các hộp thoại này có thể được
cung cấp bởi hệ điều hành (platform software) hoặc bởi sự cài đặt phần
mềm Java™ 2 SDK . Với các ứng dụng tương tác, nên dùng hộp thoại.
Tuy nhiên, các ứng dụng in kết qủa(production printing application), các
hộp thoại không cần thiết, ví dụ như, bạn không cần hiển thị hộp thoại khi
tự động tạo và in một báo cáo cơ sở dữ liệu. Một việc in không yêu cầu
tương tác với người dùng đôi khi được gọi là “silent print job”.
Page setup dialog
Bạn có thể cho phép người dung thay đổi thông tin cài đặt trang(page
setup information) chứa trong PageFormat bởi hiển thị hộp thoại page
setup. Để hiển thị một hộp thoại page setup bạn gọi hàm
PrinterJob.pageDialog. Hộp thoại page setup được khởi tạo dùng tham
số truyền cho pageDialog. Nếu người dùng click vào nút OK trong hộp
thoại, thị một thể nghiệm của PageFormat được tạo(cloned), và thay đổi
http://tailieuhay.com 180
Lập trình đồ họa trên Java 2D và 3D
theo tới các chọn lựa của người dùng rồi trả về. Nều người dùng ấn
cancel, thì pageDialog trả về PageFormat chưa bị thay đổi.
Print dialog
Thông thường, một ứng dụng hiển thị một hộp thoại in cho người
dung khi được kích hoạt ở thực đơn hay bởi nút bấm. Để hiển thị hộp
thoại in này, bạn gọi hàm printDialog của PrinterJob. Các lựa chọn của
người dùng trong hộp thoại được ràng buộc dựa trên số và định dạng của
các trang trong Printable hoặc Pageable đã được cung cấp cho
PrinterJob. Nếu người dùng click OK trong hộp thoại in, printDialog trả
về TRUE. Còn click vào Cancel nó trả về FALSE và việc in coi như bỏ
qua.
7.3 Printing with Printables
Cung cấp bổ hỗ trợ in cơ bản:
1. Cài đặt giao diện Printable để cung cấp một page painter có thể
đẩy mỗi trang ra để in.
2. Tạo một PrinterJob.
3. Gọi setPrintable để thông báo cho PrinterJob cách thức in tài liệu.
Gọi hàm print của đối tượng PrinterJob để bắt đầu công việc.
Trong ví dụ dưới đây, một Printabble job được dùng để in 5 trang,
mỗi cái hiển thị một số trang màu xanh. Điều khiển công việc được quản
lý trong phương thức chính, phương thức lấy về và điều khiển PrinterJob.
Việc đẩy ra (Rendering) được thực hiện trong phương thức print của page
painter.
import java.awt.*; import java.awt.print.*;
public class SimplePrint implements Printable
{
http://tailieuhay.com 181
Lập trình đồ họa trên Java 2D và 3D
private static Font fnt = new
Font("Helvetica",Font.PLAiN,24);
public static void main(String[] args)
{
// Get a PrinterJob
PrinterJob job = PrinterJob.getPrinterJob();
// Specify the Printable is an instance of
SimplePrint job.setPrintable(new SimplePrint());
// Put up the dialog box if
(job.printDialog())
{
// Print the job if the user didn't
cancel printing
try { job.print(); }
catch (Exception e)
{ /* handle exception */ }
}
System.exit(0);
}
public int print(Graphics g, PageFormat pf,
int pageindex)
throws PrinterException
{
// pageindex 0 to 4 corresponds to page
numbers 1 to 5.
http://tailieuhay.com 182
Lập trình đồ họa trên Java 2D và 3D
if (pageindex >= 5) return
Printable.NO_SUCH_PAGE;
g.setFont(fnt);
g.setColor(Color.green);
g.drawString("Page " + (pageindex+1), 100,
100);
return Printable.PAGE_EXiSTS;
}
}
Using Graphics2D for Rendering
Bạn có thể cần các hàm Graphics2D trong phương thức print của
page painter bởi trước tiên chuyển ngữ cảnh Graphics tới một
Graphics2D
Trong ví dụ dưới đây, các số trang được đẩy ra dùng một hướng red-
green(red-green gradient). Để làm điều này, một GradientPaint được đặt
trong ngữ cảnh Graphics2D.
import java.awt.*; import java.awt.print.*;
public class SimplePrint2D implements
Printable
{
private static Font fnt = new
Font("Helvetica",Font.PLAiN,24);
private Paint pnt = new GradientPaint(100f,
100f, Color.red,
http://tailieuhay.com 183
Lập trình đồ họa trên Java 2D và 3D
136f, 100f, Color.green, true);
public static void main(String[] args)
{
// Get a PrinterJob
PrinterJob job = PrinterJob.getPrinterJob();
// Specify the Printable is an instance of
SimplePrint2D
job.setPrintable(new SimplePrint2D());
// Put up the dialog box
if (job.printDialog())
{
// Print the job if the user didn't
cancel printing
try { job.print(); }
catch (Exception e) { /* handle exception
*/ }
}
System.exit(0);
}
public int print(Graphics g, PageFormat pf,
int pageindex)
throws PrinterException
{
// pageindex 0 to 4 corresponds to page
numbers 1 to 5.
if (pageindex >= 5) return
Printable.NO_SUCH_PAGE;
http://tailieuhay.com 184
Lập trình đồ họa trên Java 2D và 3D
Graphics2D g2 = (Graphics2D) g;
// Use the font defined above
g2.setFont(fnt);
// Use the gradient color defined above
g2.setPaint(pnt);
g2.drawString("Page " + (pageindex+1), 100f,
100f);
return Printable.PAGE_EXiSTS;
}
}
7.3.2 Printing a File
Khi môt phương thức in của page painter được yêu cầu vài lần cho
cùng trang, nó phải được sinh ra cùng đầu ra mỗi lần.
Có nhiều cách để chắc chắn rằng các yêu cầu lặp lại để đẩy ra một
trang thuận tiện ra cùng đầu ra. Ví dụ, để chắc chắn rằng cùng đầu ra
được sinh ra mỗi lần hệ thống in yêu cầu các trang cụ thể của một file
văn bản, page painter có thể lưu trữ và sử dụng lại các con trỏ file cho
mỗi trang hoặc chứa dữ trang thực tế.
Trong ví dụ dưới đây, một danh sách các file văn bản được in. Tên
của file được truyền như là đối số cho hàm main. Lớp
PrintListingPainter chứa con trỏ file thực tế ở lúc bắt đầu của mỗi trang
mới nó được yêu cầu để đẩy ra(to render). Khi cùng trang được đây ra lần
nữa, con trỏ file được reset tới vị trí đã nhớ.
import java.awt.*;
import java.awt.print.*;
import java.io.*;
http://tailieuhay.com 185
Lập trình đồ họa trên Java 2D và 3D
public class PrintListing
{
public static void main(String[] args)
{
// Get a PrinterJob
PrinterJob job = PrinterJob.getPrinterJob();
// Ask user for page format (e.g.,
portrait/landscape)
PageFormat pf =
job.pageDialog(job.defaultPage());
// Specify the Printable is an instance of
// PrintListingPainter; also provide given
PageFormat
job.setPrintable(new
PrintListingPainter(args[0]), pf);
// Print 1 copy
job.setCopies(1);
// Put up the dialog box
if (job.printDialog())
{
// Print the job if the user didn't
cancel printing
try { job.print(); }
catch (Exception e) { /* handle exception
*/ }
}
System.exit(0);
}
http://tailieuhay.com 186
Lập trình đồ họa trên Java 2D và 3D
}
class PrintListingPainter implements Printable
{
private RandomAccessFile raf;
private String fileName;
private Font fnt = new Font("Helvetica",
Font.PLAiN, 10);
private int rememberedPageindex = -1;
private long rememberedFilePointer = -1;
private boolean rememberedEOF = false;
public PrintListingPainter(String file)
{
fileName = file;
try{
// Open file
raf = new RandomAccessFile(file, "r");
}
catch (Exception e) { rememberedEOF = true;
}
}
public int print(Graphics g, PageFormat pf,
int pageindex)
throws PrinterException
{
try
{
http://tailieuhay.com 187
Lập trình đồ họa trên Java 2D và 3D
// For catching iOException
if (pageindex != rememberedPageindex)
{
// First time we've visited this page
rememberedPageindex = pageindex;
// if encountered EOF on previous page,
done
if (rememberedEOF) return
Printable.NO_SUCH_PAGE;
// Save current position in input file
rememberedFilePointer = raf.getFilePointer();
}
else raf.seek(rememberedFilePointer);
g.setColor(Color.black);
g.setFont(fnt);
int x = (int) pf.getimageableX() + 10;
int y = (int) pf.getimageableY() + 12;
// Title line
g.drawString("File: " + fileName + ", page:
" +
(pageindex+1), x, y);
// Generate as many lines as will fit in
imageable area
y += 36;
while (y + 12 < pf.getimageableY()
+pf.getimageableHeight())
{
String line = raf.readLine();
if (line == null)
http://tailieuhay.com 188
Lập trình đồ họa trên Java 2D và 3D
{
rememberedEOF = true;
break;
}
g.drawString(line, x, y);
y += 12;
}
return Printable.PAGE_EXiSTS;
}
catch (Exception e) { return
Printable.NO_SUCH_PAGE;}
}
}
Giao diện của chương trình:
http://tailieuhay.com 189
Lập trình đồ họa trên Java 2D và 3D
Printing with Pageables and Books
Các Pageable được làm phù hợp với các ứng dụng dựa trên biểu diễn lại
tương minh dữ liệu, trang bởi trang. Lớp Book là một cách thuận lợi để
dùng các Pageable, nhưng bạn cũng có thể xây dựng cầu trúc Pageable
của chính bạn nếu Book không phù hợp với cái của bạn cần. Phần này chỉ
cho bạn cách dùng Book.
Các Pageable job được đề cập qua các Printable job bởi vì hệ thống in
có khả năng linh hoạt hơn. Một cải tiến chính của Pageable là số trang
trong tài liệu thường được biết và có thể hiện thị cho người dùng trong
hộp thoại in. Điều này trợ giúp cho người dùng để chắc chắn rằng công
việc (job) được thực hiện (specified) chính xác hoặc chọn một dải các
trang để in.
Một Book biểu diễn một tập các trang. Các trang trong một book không
phải cũng cỡ, cùng hướng, hoặc page painter. Ví dụ, một Book có thể
chứa các trang với 2 cỡ chữ trong hướng portrait và một trang cỡ chữ
trong hướng landscape.
Khi một Book khởi tạo đàu tiên, nó trống rỗng. Để thêm các trang vào
một Book, bạn dùng phương thức append. Phương thức này nhận 2 đối
tượng PageFormat xác định (defines) cỡ trang, vùng có thể in, hướng và
một page painter cài đặt giao diện Printable.
Nhiều trang trong một Book có thể dùng chung cùng định dang và
painter. Phương thức append được nạp chồng để cho phép bạn thêm vào
một dãy các trang mf có cùng thược tính bởi việc xác định tham số thứ 3,
số lượng các trang.
Nếu bạn không biết tổng số trang trong một Book, bạn có thể chuyển
cho giá trị UNKNOW_NUMBER_OF_PAGES cho phương thức append.
Hệ thống in sau đó sẽ gọi các page painter của bạn theo thứ tụ tăng dần
chỉ số trang đế khi một trong chúng trả về NO_SUCH_PAGE.
http://tailieuhay.com 190
Lập trình đồ họa trên Java 2D và 3D
Phương thức setPage có thể được dùng để thay đổi định dạng trang
hoặc painter. Trang để thay đổi được xác định (identified) bởi chỉ số trang
cái chỉ ra vị trí của trang trong Book.
Ban gọi setPageable và truyền trong Book để chuẩn bị cho việc in.
Hàm setPageablbe và hàm setPrintable là loại trừ nhau. Do đó bạn gọi
một hoặc cái này hoặc cái kia chứ không thể cả hai khi đang chuẩn bị in
PrinterJob.
7.4.1 Using a Pageable Job
Ví dụ sau, một Book được dùng để tạo lại ví duj in đơn giản đầu
tiên( Do trường hợp này qúa đơn giản, có rất it lợi ích trong việc dùng
một Pageable job thay cho một Printable job, nhưng nó minh hoạ cơ bản
cách cùng một Book) Chú ý rằng bạn vẫn phải cài đặt giao diện Printable
và thực hiện page rendering trong phương thức print của page painter.
import java.awt.*;
import java.awt.print.*;
public class SimplePrintBook implements
Printable
{
private static Font fnt = new
Font("Helvetica",Font.PLAiN,24);
public static void main(String[] args)
{
// Get a PrinterJob
PrinterJob job = PrinterJob.getPrinterJob();
// Set up a book
Book bk = new Book();
http://tailieuhay.com 191
Lập trình đồ họa trên Java 2D và 3D
bk.append(new SimplePrintBook(),
job.defaultPage(), 5);
// Pass the book to the PrinterJob
job.setPageable(bk);
// Put up the dialog box
if (job.printDialog())
{
// Print the job if the user didn't
cancel printing
try { job.print(); }
catch (Exception e) { /* handle exception
*/ }
}
System.exit(0);
}
public int print(Graphics g, PageFormat pf,
int pageindex)
throws PrinterException
{
g.setFont(fnt);
g.setColor(Color.green);
g.drawString("Page " + (pageindex+1), 100,
100);
return Printable.PAGE_EXiSTS;
}
}
Giao diện của chương trình:
http://tailieuhay.com 192
Lập trình đồ họa trên Java 2D và 3D
7.4.2 Using Multiple Page Painters
Ví dụ dưới đây, có hai page painter khác nhau được sử dụng: một cho
bìa và một cho các trang bên trong. Trang bìa được in trong landscape
mode và nội dung in portrait mode.
import java.awt.*;
import java.awt.print.*;
public class PrintBook
{
public static void main(String[] args)
{
// Get a PrinterJob
PrinterJob job = PrinterJob.getPrinterJob();
// Create a landscape page format
PageFormat pfl = job.defaultPage();
pfl.setOrientation(PageFormat.LANDSCAPE);
// Set up a book
Book bk = new Book();
http://tailieuhay.com 193
Lập trình đồ họa trên Java 2D và 3D
bk.append(new PaintCover(), pfl);
bk.append(new PaintContent(),
job.defaultPage(), 2);
// Pass the book to the PrinterJob
job.setPageable(bk);
// Put up the dialog box
if (job.printDialog())
{
// Print the job if the user didn't
cancel printing
try { job.print(); }
catch (Exception e) { /* handle exception
*/ }
}
System.exit(0);
}
}
class PaintCover implements Printable
{
Font fnt = new Font("Helvetica-Bold",
Font.PLAiN, 72);
public int print(Graphics g, PageFormat pf,
int pageindex)
throws PrinterException
{
g.setFont(fnt);
g.setColor(Color.black);
http://tailieuhay.com 194
Lập trình đồ họa trên Java 2D và 3D
int yc = (int) (pf.getimageableY() +
pf.getimageableHeight()/2);
g.drawString("Widgets, inc.", 72, yc+36);
return Printable.PAGE_EXiSTS;
}
}
class PaintContent implements Printable
{
public int print(Graphics g, PageFormat pf,
int pageindex)
throws PrinterException
{
Graphics2D g2 = (Graphics2D) g;
int useRed = 0;
int xo = (int) pf.getimageableX();
int yo = (int) pf.getimageableY();
// Fill page with circles or squares,
alternating red & green
for (int x = 0; x+28 <
pf.getimageableWidth(); x += 36)
for (int y = 0; y+28 <
pf.getimageableHeight(); y += 36)
{
if (useRed == 0) g.setColor(Color.red);
else g.setColor(Color.green);
useRed = 1 - useRed;
http://tailieuhay.com 195
Lập trình đồ họa trên Java 2D và 3D
if (pageindex % 2 == 0) g.drawRect(xo+x+4,
yo+y+4, 28, 28);
else g.drawOval(xo+x+4, yo+y+4, 28, 28);
}
return Printable.PAGE_EXiSTS;
}
Giao diện cua chương trình:
Ví dụ in một một chương trình.
import java.awt.geom.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.print.PrinterJob;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
http://tailieuhay.com 196
Lập trình đồ họa trên Java 2D và 3D
import java.awt.print.*;
public class ShapesPrint extends JPanel
implements Printable, ActionListener {
final static Color bg = Color.white;
final static Color fg = Color.black;
final static Color red = Color.red;
final static Color white = Color.white;
final static BasicStroke stroke = new
BasicStroke(2.0f);
final static BasicStroke wideStroke = new
BasicStroke(8.0f);
final static float dash1[] = { 10.0f };
final static BasicStroke dashed = new
BasicStroke(1.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOiN_MiTER, 10.0f, dash1, 0.0f);
final static JButton button = new
JButton("in");
http://tailieuhay.com 197
Lập trình đồ họa trên Java 2D và 3D
public ShapesPrint() {
setBackground(bg);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
PrinterJob printJob =
PrinterJob.getPrinterJob();
printJob.setPrintable(this);
if (printJob.printDialog()) {
try {
printJob.print();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
drawShapes(g2);
}
public void drawShapes(Graphics2D g2) {
Dimension d = getSize();
int gridWidth = 400 / 6;
http://tailieuhay.com 198
Lập trình đồ họa trên Java 2D và 3D
int gridHeight = 300 / 2;
int rowspacing = 5;
int columnspacing = 7;
int rectWidth = gridWidth -
columnspacing;
int rectHeight = gridHeight - rowspacing;
Color fg3D = Color.lightGray;
g2.setPaint(fg3D);
g2.drawRect(80, 80, 400 - 1, 310);
g2.setPaint(fg);
int x = 85;
int y = 87;
g2.draw(new Line2D.Double(x, y +
rectHeight - 1, x + rectWidth, y));
x += gridWidth;
g2.setStroke(stroke);
g2.draw(new Rectangle2D.Double(x, y,
rectWidth, rectHeight));
x += gridWidth;
g2.setStroke(dashed);
g2
.draw(new
RoundRectangle2D.Double(x, y, rectWidth,
rectHeight,
10, 10));
x += gridWidth;
g2.setStroke(wideStroke);
g2.draw(new Arc2D.Double(x, y, rectWidth,
rectHeight, 90, 135,
http://tailieuhay.com 199
Lập trình đồ họa trên Java 2D và 3D
Arc2D.OPEN));
x += gridWidth;
g2.setStroke(stroke);
g2.draw(new Ellipse2D.Double(x, y,
rectWidth, rectHeight));
x += gridWidth;
int x1Points[] = { x, x + rectWidth, x, x
+ rectWidth };
int y1Points[] = { y, y + rectHeight, y +
rectHeight, y };
GeneralPath polygon = new
GeneralPath(GeneralPath.WiND_EVEN_ODD,
x1Points.length);
polygon.moveTo(x1Points[0], y1Points[0]);
for (int index = 1; index <
x1Points.length; index++) {
polygon.lineTo(x1Points[index],
y1Points[index]);
}
;
polygon.closePath();
g2.draw(polygon);
x = 85;
y += gridHeight;
int x2Points[] = { x, x + rectWidth, x, x
+ rectWidth };
int y2Points[] = { y, y + rectHeight, y +
rectHeight, y };
http://tailieuhay.com 200
Lập trình đồ họa trên Java 2D và 3D
GeneralPath polyline = new
GeneralPath(GeneralPath.WiND_EVEN_ODD,
x2Points.length);
polyline.moveTo(x2Points[0],
y2Points[0]);
for (int index = 1; index <
x2Points.length; index++) {
polyline.lineTo(x2Points[index],
y2Points[index]);
}
;
g2.draw(polyline);
x += gridWidth;
g2.setPaint(red);
g2.fill(new Rectangle2D.Double(x, y,
rectWidth, rectHeight));
g2.setPaint(fg);
x += gridWidth;
GradientPaint redtowhite = new
GradientPaint(x, y, red, x + rectWidth,
y, white);
g2.setPaint(redtowhite);
g2
.fill(new
RoundRectangle2D.Double(x, y, rectWidth,
rectHeight,
10, 10));
g2.setPaint(fg);
x += gridWidth;
http://tailieuhay.com 201
Lập trình đồ họa trên Java 2D và 3D
g2.setPaint(red);
g2.fill(new Arc2D.Double(x, y, rectWidth,
rectHeight, 90, 135,
Arc2D.OPEN));
g2.setPaint(fg);
x += gridWidth;
redtowhite = new GradientPaint(x, y, red,
x + rectWidth, y, white);
g2.setPaint(redtowhite);
g2.fill(new Ellipse2D.Double(x, y,
rectWidth, rectHeight));
g2.setPaint(fg);
x += gridWidth;
int x3Points[] = { x, x + rectWidth, x, x
+ rectWidth };
int y3Points[] = { y, y + rectHeight, y +
rectHeight, y };
GeneralPath filledPolygon = new
GeneralPath(GeneralPath.WiND_EVEN_ODD,
x3Points.length);
filledPolygon.moveTo(x3Points[0],
y3Points[0]);
for (int index = 1; index <
x3Points.length; index++) {
filledPolygon.lineTo(x3Points[index],
y3Points[index]);
}
;
http://tailieuhay.com 202
Lập trình đồ họa trên Java 2D và 3D
filledPolygon.closePath();
g2.setPaint(red);
g2.fill(filledPolygon);
g2.setPaint(fg);
g2.draw(filledPolygon);
}
public int print(Graphics g, PageFormat pf,
int pi) throws PrinterException {
if (pi >= 1) {
return Printable.NO_SUCH_PAGE;
}
drawShapes((Graphics2D) g);
return Printable.PAGE_EXiSTS;
}
public static void main(String s[]) {
WindowListener l = new WindowAdapter() {
public void
windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowClosed(WindowEvent
e) {
System.exit(0);
}
};
JFrame f = new JFrame();
http://tailieuhay.com 203
Lập trình đồ họa trên Java 2D và 3D
f.addWindowListener(l);
JPanel panel = new JPanel();
panel.add(button);
f.getContentPane().add(BorderLayout.SOUTH,
panel);
f.getContentPane().add(BorderLayout.CENTER,
new ShapesPrint());
f.setSize(580, 500);
f.show();
}
}
Giao diện của chương trình:
http://tailieuhay.com 204
Lập trình đồ họa trên Java 2D và 3D
Phần 2
Lập trình đồ họa với Java 3D
http://tailieuhay.com 206
Lập trình đồ họa trên Java 2D và 3D
CHƯƠNG 1
NHẬP MÔN LẬP TRÌNH TRÊN JAVA 3D
1.1 Tổng quan về Java 3D API ™
Java 3D API được thừa kế từ các lớp của java cho phép tạo các giao
diện phức tạp như hệ thống âm thanh và hình ảnh 3 chiều. Người lập trình
có thể sử dụng nó để xây dựng điều khiển các đối tượng hình học 3 chiều.
Những đối tượng này cư trú trên một môi trường ảo sau đó mới được
dựng hình lại. Các hàm API được thiết kế rất linh động cho phép tạo một
trường ảo đó chính xác với rất nhiều dạng kích cỡ từ lớn đến bé.
Dù có nhiều chức năng như vậy nhưng các hàm API vẫn có thể sử
dụng rõ ràng. Các chi tiết được dưng hình tự động. Sử dụng lợi thế của
các luồng trong java, việc dựng hình trong Java 3D cho phép làm song
song, đồng thời cũng cho phép tối hưu hóa việc dựng hình. Chương trình
Java 3D tạo các instances của các đối tượng và đưa chúng vào cơ sở dữ
liệu đồ thị khung cảnh. Đồ thị khung cảnh là một sắp xếp các đối tượng
Java 3D trên một cấu trúc cây cho phép chỉ ra nội dụng của một thế giới
ảo và chúng có thể được dựng hình như thế nào.
Chương trình Java 3D có thể được viết để chạy độc lập hay như là một
applet trên các trình duyệt hỗ trợ Java 3D hoặc cả 2.
http://tailieuhay.com 207
Lập trình đồ họa trên Java 2D và 3D
1.2 Các vấn đề cơ bản về Java 3D API™
Java 3D API định nghĩa hơn 100 lớp trong gói javax.media.j3d
những lớp này được coi như là những lớp cơ bản nhất của Java 3D.
Có đến hàng trăm trường và phương thức trong các lớp của Java 3D
API tuy nhiên một môi trường ảo đơn giản chỉ cần dùng một vài lớp.
Chương này mô tả tập nhỏ nhất các đối tượng và tương tác giữa chúng để
dựng nên một môi trường ảo.
Chương này còn bao gồm ví dụ HelloJava3D hiển thi một khối lập
phương quay. Ví dụ này được phát triển theo từng bước lần lượt thể hiện
các phần xử lí trong lập trình Java 3D.
Ngoài gói nhân Java 3D chúng ta còn sử dụng thêm một gói nữa là
com.sun.j3d.utils thường gọi là các lớp tiện dụng, chúng bổ sung thêm
những tính năng hiệu quả và rất mạnh cho nhân.
Lớp utility gồm 4 mục: content loader(nạp nội dung), hỗ trợ xây dựng
đồ thị khung cảnh, các lớp hình học, và các công cụ tiện ích.
Tất nhiên là ngoài gói nhân và gói tiện ích thì mọi chương trình java
đều sử dụng các lớp từ gói java.awt và javax.vecmath. Gói java.awt
định nghĩa các lớp AWT cho phép tạo cửa sổ cho việc dựng hình. Gói
javax.vecmath định nghĩa các lớp cho điểm, vector ma trận và những đối
tượng toán học khác.
Trong phần còn lại của giáo trình này từ visual object(đối tượng quan sát)
được sử dụng thay cho “một đối tượng trong đồ thị khung cảnh”.(chẳng
hạn: một hình lập phương hay hình cầu). Từ object được sử dụng cho một
instance của một lớp. Content tương ứng với những đối tượng quan sát
trong một đồ thị khung cảnh.
1.3 Xây dựng đồ thị khung cảnh
Môi trường ảo trong Java 3D được tạo từ một đồ thị khung cảnh, một
đồ thị khung cảnh được tạo nên bởi các instance của các lớp Java 3D. Đồ
http://tailieuhay.com 208
Lập trình đồ họa trên Java 2D và 3D
thị khung cảnh đó được ghép nối bởi các đối tượng được định nghĩa về
mặt hình học, âm thanh và ánh sáng, vị trí, hướng và bề ngoài về trực
quan cũng như âm thanh của đối tượng. Với một đồ thị bình thường thì
cấu trúc dữ liệu hay dùng là các nút và các cung. Một nút của đồ thị
khung cảnh là một instance của một lớp Java 3D. Các cung đại diện cho 2
dạng quan hệ giữa các instances của Java 3D.
Quan hệ hay gặp nhất là quan hệ cha con – một nút cha có rất nhiều nút
con. Một quan hệ khác là quan hệ tham chiếu. Một tham chiếu liên kết
một đối tượng NodeComponent với một nút của đồ thị khung cảnh.
NodeComponent định nghĩa về mặt hình học và các thuộc tính bề mặt
được sử dụng để dựng nên đối tượng quan sát.
Đồ thị khung cảnh trong Java 3D được cấu thành từ các nút đối tượng
trong các mối liên hệ cha con định ra một cấu trúc cây. Trong cây này chỉ
có một nút gốc. Các nút còn lại được truy cập tới thông qua các cung đi từ
nút gốc, các cung trên cây không tạo thành chu trình. Một đồ thị khung
cảnh được định dạng từ các cây mà gốc tại các đối tượng xảy ra.
NodeComponent và các cung tham chiếu không phải là một phần của đồ
thị khung cảnh.
Chỉ tồn tại một đường duy nhất từ gốc của cây đến một lá, từ đó chỉ có
một đường đi duy nhất từ gốc của một đồ thị khung cảnh đến mỗi nút lá.
Đường đi đó gọi là đường đi của đồ thị khung cảnh. Từ đó chỉ có một
đường đi đồ thị khung cảnh đến mỗi lá trong một đồ thị khung cảnh.
Mỗi dường đi đồ thị khung cảnh trong đồ thị khung cảnh của Java 3D
chỉ ra thông tin về trạng thái của lá. Thông tin trạng thái đó bao gồm địa
điểm, hướng, và kích thước của đối tượng quan sát. Kết quả là các thuộc
tính trực quan của mỗi đối tượng quan sát phụ thuộc vào mỗi đường đi
trên đồ thị khung cảnh của nó. Bộ dựng hình Java 3D dựa trên điểm này
để dựng nên các lá theo thứ tự hiệu quả nhất. Những người lập trình Java
3D thường không phải điều khiển quá trình này.
http://tailieuhay.com 209
Lập trình đồ họa trên Java 2D và 3D
Về mặt đồ họa thì một đồ thị khung cảnh được dùng như là một công
cụ thiết kế hoặc tài liệu hóa cho các trương trình Java 3D. Đồ thị khung
cảnh được vẽ trên các biểu tượng như hình 1.1. Chương trình Java 3D có
thể có nhiều đối tượng hơn so với những đối tượng ở trong đồ thị này.
Như vậy để thiết kế môi trường ảo, đồ thị khung cảnh được vẽ dựa
trên những biểu tượng chuẩn. Sau khi việc thiết kế hoàn thành, sơ đồ đồ
thị khung cảnh sẽ là tiêu chí của chương trình. Sau khi chương trình hoàn
thành, một đồ thị khung cảnh tương tự đại diện cho chương trình (giả sử
là những đặc điểm đó được tuân theo). Đồ thị được vẽ từ chương trình
minh chứng cho đồ thị mà chương trình tạo ra.
Mỗi một biểu tượng ở phía bên trái của hình 1.1 đại điện cho một đối
tượng đơn lẻ khi sử dụng trong đồ thị khung cảnh. 2 biểu tượng đầu tiên
đại diện cho các đối tượng của 2 lớp đặc biệt VirtualUniverse và Locale.
3 biểu tượng tiếp theo đại diện cho các đối tượng của các lớp Group,
Leaf và NodeComponent. 3 biểu tượng sau đó thường được dùng để chỉ
các lớp con của những đối tượng trên. Biểu tượng cuối cùng bên trái đại
diện cho bất cứ lớp của đối tượng nào.
Mũi tên liền đại diện cho một liên kết cha con giữa 2 đối tượng. Nét đứt
chỉ tham chiếu đến một đối tượng khác. Đối tượng được tham chiếu có
http://tailieuhay.com 210
Lập trình đồ họa trên Java 2D và 3D
thể chia sẻ giữa các nhánh khác nhau của một đồ thị khung cảnh. Dưới
đây là một ví dụ (Hình 1.2)
Rất dễ xây dựng một đồ thị khung cảnh sai. Một ví dụ sai đơn giản có
thể xem ở hình 1-3. Đồ thị này sai bởi vì nó vi phạm những đặc tính của
DAG. Vấn đề nằm ở chỗ chỉ với 2 đối tượng TransformGroup có chung
một đối tượng lá Shape3D là con. Nhớ rằng một đối tượng lá chỉ có thể
có 1 cha duy nhất. Nói cách khác chỉ có một đường đi từ đối tượng
Locale đến 1 lá (hay là đường từ một lá đến một Locale).
Bạn có thể nghĩ cấu trúc xây dựng trong hình 1-3 định nghĩa 3 đối
tượng quan sát trong một môi trường ảo, Nó xuất hiện trên biểu đồ khung
cảnh dựa trên định nghĩa 2 đối tượng quan sát thông qua sử dụng đối
tượng quan sát Shape3D phía bên phải của đồ thị. Mà dựa trên các khái
niệm, mỗi đối tượng TransformGroup cha chung của đối tượng
Shape3D phải đặt một hình ảnh của đối tượng quan sát trên các vị trí
khác nhau. Tuy nhiên đây là một đồ thị không hợp lệ vì cung cha con
http://tailieuhay.com 211
Lập trình đồ họa trên Java 2D và 3D
không định ra một cây. Trong ví dụ này, kết quả là đối tượng Shape3D có
hơn 1 cha.
Sự tranh cãi về cấu trúc của cây và DAG là chính xác. Tuy nhiên hệ
thống runtime của Java 3D đưa ra thông báo có lỗi trong mối quan hệ cha
con. Vì kết quả của sự giới hạn cấu trúc cây mà mỗi đối tượng Shape3D
bị hạn chế chỉ có một cha. Với ví dụ trong hình 1-3, lỗi thông báo là chính
là việc có nhiều cha. Trên hình 1-4 đưa ra giải pháp cho vấn đề này.
Chương trình Java 3D mà có đồ thị khung cảnh không hợp lệ có thể
dịch được nhưng không thể dịch được. Khi một chương trình Java 3D có
đồ thị khung cảnh không hợp lệ được chạy, hệ thông Java 3D sẽ phát hiện
ra vấn đề. Và khi vấn đề được phát hiện thì hệ thống Java 3D sẽ thông
báo lỗi. Chương trình có thể vẫn chạy nhưng vẫn cần phải dừng lại vì
chẳng có hình ảnh nào dựng nên cả.
Mỗi đồ thị khung cảnh chỉ có một môi trường ảo. Đối tượng môi trường
ảo có một danh sách các đối tượng Locale. Một đối tượng Locale cung
cấp một điểm tham chiếu trong môi trường ảo đó. Có thể coi như đối
http://tailieuhay.com 212
Lập trình đồ họa trên Java 2D và 3D
tượng Locale là cột mốc sử dụng để xác định vị trí của các đối tượng
quan sát trong môi trường ảo.
thể có nhiều môi trường ảo trong một chương trình Java 3D, vì thế có
thể định nghĩa nhiều hơn một môi trường ảo. Tuy nhiên, không có cách
cố định nào cho việc liên lạc giữa các môi trường ảo này. Xa hơn, một đối
tượng đồ thị khung cảnh không thể tồn tại trong đa môi trường ảo cùng
một lúc. Do đó chỉ nên sử dụng một và chỉ một instance của môi trường
ảo trong mỗi chương trình Java 3D.
Trong khi một đối tượng môi trường ảo có thể tham chiếu đến nhiều đối
tượng Locale thì hầu hết các chương trình Java 3D chỉ có một đối tượng
Locale. Mỗi đối tượng Locale có thể phục vụ như là gốc của nhiều đồ thị
con của đồ thị khung cảnh. Theo ví dụ ở hình 1-2 có thể thấy đối tượng
Locale có 2 nhánh đồ thị con từ nó.
Các đồ thị con thì phân ra làm 2 loại nhánh hình thức và nhánh nội
dung. Nhánh nội dung chỉ ra nội dung của môi trường ảo – hình học, bề
mặt, hành vi, địa điểm, âm thanh, và ánh sáng. Nhánh hình thức chỉ ra các
tham số cho phép xem như địa điểm xem và hướng xem.
http://tailieuhay.com 213
Lập trình đồ họa trên Java 2D và 3D
1.3.1 Thừa kế cấp cao từ Java 3D API
Có 3 cấp thừa kế từ Java 3D API thể hiện trong hình 5-1. Thông qua
cấu trúc này chúng ta sẽ hình dung được chương trình Java 3D như thế
nào.
Lớp node
Lớp node là lớp cha của 2 lớp Group và Leaf, định nghĩa những
phương thức chung và rất quan trọng cho các lớp con của nó. Thông tin
về các phương thức này sẽ được mô tả ở phần sau của tài liệu
Lớp Group
Lớp group là lớp gốc sử dụng để chỉ ra vị trí và hướng của đối tượng
quan sát trong một môi trường ảo. 2 lớp con của là BranchGroup và
TransformGroup. Trong đồ thị khung cảnh hình ảnh đại diện của 2 lớp
này có biểu tượng là hình tròn và thường được viết tắt thành BG và TG.
Lớp Leaf
http://tailieuhay.com 214
Lập trình đồ họa trên Java 2D và 3D
Lớp Leaf là lớp gốc để định nghĩa hình dạng, âm thanh, và hành vi
của đối tượng quan sát trong mội trường ảo. Một vài lớp con của lớp này
là Shape3D, Light, Behavior và Sound. Những đối tượng này có thể
không có lớp con nhưng phải tham chiếu đến NodeComponent.
Lớp NodeComponent
Lớp NodeComponent là lớp gốc sử dụng để mô tả về hình học, bề
mặt, texture và những thuộc tính của node Shape3D. NodeComponent
không phải là một phần của đồ thị khung cảnh nhưng lại được tham chiếu
đến. Một NodeComponent có thể được tham chiếu bới nhiều đối tượng
Shape3D.
http://tailieuhay.com 215
Lập trình đồ họa trên Java 2D và 3D
1.4 Cách thức để viết một chương trình Java 3D
Việc xây dựng một chương trình Java 3D gồm có 7 bước được giới
thiệu trong hình 1-6. Đây là công thức hữu ích để xây dựng các ứng dụng
Java 3D.
Công thức này cũng bỏ qua môt vài chi tiết nhưng diễn tả phần lớn
những công việc cần làm trong đó việc tạo các nhánh đồ thị của đồ thị
khung cảnh là công việc quan trọng nhất của việc lập trình. Trong phần
tới chúng ta sẽ được biết làm thể nào để tạo một đồ thị khung cảnh mà
không phải lập trình nhiều.
1.4.1 Công thức đơn giản để viết một chương trình Java 3D
Các chương trình của Java 3D được viết sử dụng công thức trên có
nhánh đồ thị hình thức có cấu trúc đúng đắn, và cấu trúc này đã sẵn có
trong lớp SimpleUniverse. Mỗi instance của lớp này thực hiện các bước
2,3,4 trên công thức cơ bản trên điều đó giúp cho người lập trình giảm
thiểu thời gian và công sức để tạo nhánh hình thức qua đó tập trung vào
công việc chính là nội dung hơn. Công việc thực sự khi viết một chương
trình Java 3D là như vậy.
1. Create a Canvas3D object
2. Create a VirtualUniverse object
3. Create a Locale object, attaching it to the VirtualUniverse object
4. Construct a view branch graph
a. Create a View object
b. Create a ViewPlatform object
c. Create a PhysicalBody object
d. Create a PhysicalEnvironment object
e. Attach ViewPlatform, PhysicalBody, PhysicalEnvironment, and
Canvas3D objects to View object
http://tailieuhay.com 216
Lập trình đồ họa trên Java 2D và 3D
5. Construct content branch graph(s)
6. Compile branch graph(s)
7. Insert subgraphs into the Locale
Việc sử dụng lớp này cho phép người lập trình tạm quên đi nhánh đồ
thị hình thức. Tuy nhiên nó không cho phép có nhiều view trong môi
trường ảo của nó.
SimpleUniverse Class
Hàm khởi tạo của đối tượng SimpleUniverse tạo nên đồ thị khung
cảnh bao gồm các đối tượng VirtualUniverse và Locale và một nhánh đồ
thị hình thức hoàn thiện.
Nhánh này sử dụng instances của các lớp ViewingPlatform và Viewer
trong nhân của lớp để tạo thành nhánh đồ thị hình thức. Đối tượng
SimpleUniverse cung cấp tất cả các chức năng được chỉ ra trong hình 1-
7.
Gói com.sun.j3d.utils.universe chứa các lớp SimpleUniverse,
ViewingPlatform và Viewer.
http://tailieuhay.com 217
Lập trình đồ họa trên Java 2D và 3D
Việc sử dụng lớp SimpleUniverse là cho công việc đơn giản hơn rất
nhiều. Hình 1-8 đưa ra công thức đơn giản hơn trong đó các bước 2,3,4 đã
được thay bằng bước 2 của công thức mới.
1. Create a Canvas3D Object
2. Create a SimpleUniverse object which references the earlier
Canvas3D object
a. Customize the SimpleUniverse object
3. Construct content branc h
4. Compile content branch graph
5. Insert content branch graph into the Locale of the SimpleUniverse
SimpleUniverse Constructor gói com.sun.j3d.utils.universe
Lớp tiện ích này cho phép dễ dàng cài đặt môi trường người dùng, tạo
các đối tượng cần thiết cho đồ thị nhánh hình thức. Lớp này tạo nên các
đối tượng Locale, VirtualUniverse, ViewingPlatform và Viewer (với tất
cả các giá trị mặc định của chúng). Các đối tượng này liên hệ với nhau để
tạo nên đồ thị nhánh hình thức.
Phương thức khởi tạo quan trọng
SimpleUniverse ()
Khởi tạo một môi trường ảo
SimpleUniverse (Canvas3D canvas3D)
Khởi tạo một môi trường ảo với tham chiếu đến đối tượng được đặt
tên là Canvas3D
Đối tượng SimpleUniverse tạo thành một đồ thị nhánh hình thức
hoàn thiện cho một môi trường ảo. Đồ thị này bao gồm một bảng hình
ảnh. Một bảng hình ảnh là một dạng hình chữ nhật là nơi mà nội dung của
được chiếu đến để định dạng hình ảnh cần dựng. Đối tượng Canvas3D
cung cấp hình ảnh trên một cửa sổ trên màn hình hiển thị của máy tính, có
thể coi như là một bảng hình ảnh vậy. Để rõ hơn chúng ta quan sát hình
http://tailieuhay.com 218
Lập trình đồ họa trên Java 2D và 3D
ảnh dưới đây, hình 1-9 chỉ ra mối quan hệ giữa bảng hình ảnh (image
plate) và vị trí của mắt, môi trường ảo. Vị trí của mắt là đằng sau bảng
hình ảnh. Đối tượng quan sát đứng trước bảng hình ảnh được dựng trên
bảng hình ảnh. Việc dựng hình cũng ví như chiếu một đối tượng quan sát
lên bảng hình ảnh.
Mặc định bảng hình ảnh đặt trung tâm của SimpleUniverse ban đầu,
hướng mặc định là nhìn theo trục z,. Từ vị trí này trục x là đường biên
ngang của bảng hình ảnh với hướng dương là bên phải. Trục y là cạnh
ngang của bảng hình ảnh với giá trị dương hướng lên trên. Thông thường
thì vị trí (0,0,0) là tâm của bảng hình ảnh.
Chương trình Java 3D thông thường sẽ chuyển điểm nhìn ra phía sau
(hướng dương của trục z) để làm cho đối tượng ở vị trí hoặc gần so với vị
trí ban đầu giữa hướng nhìn. Lớp SimpleUniverse có một lớp thành viên
là ViewingPlatform, lớp này có phương thức
setNominalViewingTransform cho phép chuyển vị trí của mắt nhìn tới
trung tâm là (0,0, 2.41) nhìn từ phía âm của trục z so với vị trí ban đầu.
Lớp ViewingPlatform, phương thức setNominalViewingTransform ()
Package: com.sun.j3d.utils.universe
http://tailieuhay.com 219
Lập trình đồ họa trên Java 2D và 3D
Lớp ViewingPlatform được sử dụng để thiết lập đồ thị nhánh hình
thức của đồ thị khung cảnh Java 3D với đối tượng SimpleUniverse.
Phương thức này thường được sử dụng để kết nối với phương thức
getViewingPlatform của lớp SimpleUniverse.
void setNominalViewingTransform()
Set tầm nhìn khoảng cách khoảng 2.41 mét từ trong biến đổi tầm
nhìn của một SimpleUniverse. Tại khoảng cách này và thì đối tượng với
chiều cao khoảng 2 mét so thể vừa vặn với bảng hình ảnh.
Sau khi tạo xong các đối tượng Canvas3D và SimpleUniverse, bước
tiếp theo là tạo đồ thị nhánh nội dung. Quy tắc của cấu trúc được tìm thấy
trong đồ thị nhánh hình thức (do việc sử dụng lớp SimpleUniverse). Đồ
thị nhánh nội dung biến đổi khác nhau từ chương trình này đến chương
trình khác do đó có thể xây dựng chi tiết trong công thức. Điều đó có
nghĩa là không có những lớp nội dung đơn giản cho bất cứ môi trường
nào mà bạn muốn thiết lập.
Sau khi tạo xong đồ thị nhánh nội dung, nó được chèn vào môi trường sử
dụng phương thức addBranchGraph của SimpleUniverse. Phương thức
này lấy một instance của BranchGroup như là tham số duy nhất.
BranchGroup này chỉ được thêm vào như là một con của đối tượng
Locale được tạo bởi SimpleUniverse.
Các phương thức SimpleUniverse
Package: com.sun.j3d.utils.universe
void addBranchGraph(BranchGroup bg)
Sử dụng để thêm nút vào đối tượng Locale của đồ thị khung cảnh
được tạo bởi SimpleUniverse. Điều này sử dụng để thêm vào một đồ thị
nhánh nội dung tới môi trường ảo.
ViewingPlatform getViewingPlatform()
http://tailieuhay.com 220
Lập trình đồ họa trên Java 2D và 3D
Sử dụng để lấy thông tin từ đối tượng ViewingPlatform mà
SimpleUniverse chỉ ra. Phương thức này sử dụng với phương thức
setNominalViewingTransform () của lớp ViewingPlatform để điều chỉnh
vị trí quan sát.
1.5 Một vài thuật ngữ trong Java 3D
Hai thuật ngữ được nói trong phần này là “live” và “compiled”. Khi
chèn một đồ thị nhánh vào Locale làm cho nó có thể sống (“live”) và kết
quả là mỗi đối tượng của đồ thị nhánh trở thành sống. Những đối tượng
sống là những đối tượng mà chuẩn bị được dựng hình, cho nên những
tham số của một đối tượng sống không thể thay đổi trừ khi khả năng
tương ứng của nó được thiết lập trước khi đối tượng sống (capability được
mô tả trong phần 1.8.2).
Khi các đối tượng BranchGroup được dịch (compiled). Việc dịch
BrandGroup chuyển đối tượng BranchGroup và tất cả những hình thức
sơ khai của nó thành dạng phù hợp để dựng hình. Mục đích của công việc
này là chuẩn bị bước cuối cùng trước khi làm cho đối tượng đó sống.
Phương thức
BranceGroup compile ()
Void compile ()
Dịch nguồn BranchGroup tương ứng với đối tượng bằng cách tạo và
đệm một đồ thị khung cảnh đã được dịch.
Cơ sở của việc dịch và sống được bổ sung trong lớp
SceneGraphObject. 2 phương thức của SceneGraphObject được mô tả
dưới đây.
Danh sách các phương thức cơ bản của SceneGraphObject
SceneGraphObject là lớp cơ bản của tất cả các lớp lân cận dùng để tạo đồ
thị khung cảnh bao gồm Group, Leaf, và NodeComponent.
http://tailieuhay.com 221
Lập trình đồ họa trên Java 2D và 3D
SceneGraphObject cung cấp khá nhiều phương thức và thuộc tính cho các
lớp con của nó, 2 phương thức được trình bày dưới đây.
boolean isCompiled()
Trả về một giá trị cờ chỉ ra khi nào thì node (là một phần của đồ thị
khung cảnh được dịch)
boolean isLive ()
Trả về giá trị cờ chỉ ra khi nào node là một phần của đồ thị khung
cảnh sống
Chú ý rằng không có bước “bắt đầu dựng hình”cả trong công thức cơ
bản lẫn công thức đơn giản đã nói ở trên. Bộ dựng hình của Java 3D bắt
đầu chạy trong một vòng lặp vô hạn khi một đồ thị nhánh chứa một
instance của View băt đầu sống trong một môi trường ảo. Khi đã bắt đầu,
bộ dựng hình Java 3D thực hiện hoạt động như hình 1-10
while(true) {
Process input
If (request to exit) break
Perform Behaviors
Traverse the scene graph
and render visual objects
}
Cleanup and exit
Phần trước đó đã giải thích cấu trúc của một môi trường ảo đơn giản
mà không có đồ thị nhánh nội dung. Việc tạo đồ thị nhánh nội dung là chủ
đề của một số phần tiếp theo. Những thảo luận xung quanh đồ thị nhánh
nội dung được xoay quanh các ví dụ của chương trình.
http://tailieuhay.com 222
Lập trình đồ họa trên Java 2D và 3D
1.6 Ví dụ đơn giản: HelloJava3Da
Chương trình Java 3D bắt đầu bằng việc định nghĩa lớp mới mở rộng
từ lớp Applet. Trong ví dụ HelloJava3Da.java dưới đây ta cũng có lớp
HelloJava3Da được mở rộng từ lớp Applet, và việc sử dụng nó giúp đơn
giản đi rất nhiều so với chương trình Java 3D được viết như ứng dụng độc
lập.
Lớp chính của chương trình Java 3D thường định nghĩa phương thức
thiết lập đồ thị nhánh nộ dung. Trong ví dụ này phương thức như thế
được đặt tên là creatSceneGraph().
Mọi bước theo công thức phía trên đều được thể hiện trong lớp
HelloJava3Da. Bước 1,tạo đối tượng Canvas3D (dòng 4 đến dòng 6).
Bước 2 tạo đối tượng SimpleUniverse hoàn thành ở dòng 17.
Bước 3 tạo nhánh nội dung, được hoàn thành bằng lời gọi ở đến
phương thức creatSceneGraph().
Bước 4 dịch đồ thị nhánh nội dung được thực hiện trong dòng 10.
Cuối cùng bước thứ 5 chèn đồ thị nhánh nội dung vào Locale của
SimpleUniverse thực xong ở dòng 19.
public class HelloJava3Da extends Applet {
public HelloJava3Da() {
setLayout(new BorderLayout());
Canvas3D canvas3D = new Canvas3D(null);
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
// SimpleUniverse is a Convenience
Utility class
http://tailieuhay.com 223
Lập trình đồ họa trên Java 2D và 3D
SimpleUniverse simpleU = new
SimpleUniverse(canvas3D);
// This will move the ViewPlatform back a
bit so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalViewingTra
nsform();
simpleU.addBranchGraph(scene);
} // end of HelloJava3Da (constructor)
Ta thấy bước 3 của công thức này là tạo đồ thị nhánh nội dung. Một
đồ thị nhánh nội dung được tạo trong đoạn mã 1-2. Đó là đồ thị nhánh nội
dung đơn giản nhất có thể. Nó chứa một đối tượng đồ họa tĩnh đó là hình
lập phương màu. Hình này được đặt ở vị trí ban đầu trong hệ thống thế
giới ảo. Với vị trí và hướng nhìn này, hình lập phương này xuất hiện như
hình chữ nhật khi được dựng lên.
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
objRoot.addChild(new ColorCube(0.4));
return objRoot;
http://tailieuhay.com 224
Lập trình đồ họa trên Java 2D và 3D
} // end of CreateSceneGraph method of
HelloJava3Da
Lớp HelloJava3Da được thừa kế từ Applet nhưng chương trình có
thể chạy như là một ứng dụng với việc sử dụng lớp MainFrame. Lớp
Applet được sử dụng là lớp cơ sở để dễ dàng cho việc viêt một chương
trình Java 3D chạy trên một cửa sổ. MainFrame cung cấp một AWT
frame (cửa sổ) cho một apple điều đó cho phép apple chạy như một ứng
dụng. Kích thước của cửa sổ được chỉ ra trong phần thiết lập của lớp
MainFrame. Đoạn mã 1-3 bên dưới sẽ chỉ ra cách sử dụng trong
HelloJava3Da.java.
MainFrame ConStructor
package: com.sun.j3d.utils.applet
MainFrame giúp cho một applet có thể chạy như một ứng dụng. Một
lớp thừa kế từ applet có thể có phương thức main() dùng để gọi hàm khởi
tạo của MainFrame. MainFrame mở rộng từ java.awt.Frame và bổ sung
thêm từ java.lang.Runnable, java.applet.AppletStub, và
java.applet.AppletContext.
Hàm
MainFrame(java.applet.Applet applet, int width, int height)
Tạo tạo đối tượng Mainframe cho phép applet chạy như ứng dụng độc
lập.
Tham số: Applet – Hàm tạo của một lớp thừa kế từ applet.
MainFrame cung cấp AWT frame
public static void main(String[] args) {
Frame frame = new MainFrame(new
HelloJava3Da(), 256, 256);
http://tailieuhay.com 225
Lập trình đồ họa trên Java 2D và 3D
} // end of main (method of HelloJava3Da)
Ba đoạn mã 1-1, 1-2, 1-3 trên định nên một chương trình Java 3D
hoàn thiện khi các câu lệnh import được sử dụng. Hầu hết các lớp sử dụng
trong chương trình Java 3D ở trong các gói javax.media.j3d, hoặc
javax.vecmath. Trong ví dụ này lớp tiện ích ColorCube được tìm thấy
trong gói com.sun.j3d.utils.geometry kết quả là hầu hết chương trình
Java 3D đều có những câu lệnh để import các thư viện như hình 1-4,
ngoại trừ lớp tiện ích ColorCube.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
Trong ví dụ phía trên một đối tượng đồ họa đơn được đặt trong một vị
trí đơn. Ta có đồ thị khung cảnh như bên dưới:
http://tailieuhay.com 226
Lập trình đồ họa trên Java 2D và 3D
Mã nguồn của chương trình là:
package HelloJava3D;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
// HelloJava3Da renders a single, rotating cube.
public class HelloJava3Da extends Applet {
public HelloJava3Da() {
setLayout(new BorderLayout());
Canvas3D canvas3D = new Canvas3D(null);
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
// SimpleUniverse is a Convenience Utility class
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
// This will move the ViewPlatform back a bit so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalViewingTransform();
http://tailieuhay.com 227
Lập trình đồ họa trên Java 2D và 3D
simpleU.addBranchGraph(scene);
} // end of HelloJava3Da (constructor)
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
objRoot.addChild(new ColorCube(0.4));
return objRoot;
} // end of CreateSceneGraph method of HelloJava3Da
// The following allows this to be run as an application
// as well as an applet
public static void main(String[] args) {
Frame frame = new MainFrame(new HelloJava3Da(), 256,
256);
} // end of main (method of HelloJava3Da)
} // end of class HelloJava3Da
Kết quả của chương trình chạy là:
http://tailieuhay.com 228
Lập trình đồ họa trên Java 2D và 3D
1.6.1 Các lớp của Java 3D Classes được sử dụng trong
HelloJava3Da
Để hiểu chi tiết hơn về các lớp Java 3D và ví dụ trên chúng ta quan
tâm đến những lớp sau:
Lớp BranchGroup
Đối tượng kiểu này thường được dùng để định dạng đồ thị khung cảnh.
Mỗi instance của BranchGroup là gốc của một đồ thị con. Đối tượng
BranchGroup chỉ được phép là con của đối tượng Locale.
BranchGroup có thể có nhiều con, con của nó có thể là Group hoặc
Leaf.
BranchGroup constructor
BranchGroup ()
Instance của BranchGroup được coi là gốc của một nhánh đồ thị, mỗi
đối tượng BranchGroup chỉ là đối tượng có thể chèn vào tập các đối
tượng của Locales.
http://tailieuhay.com 229
Lập trình đồ họa trên Java 2D và 3D
Lớp Canvas3D
Lớp Canvas3D được thừa kế từ Canvas của AWT. Tối thiểu một đối
tượng Canvas3D phải được tham chiếu đến trong một đồ thị nhánh hình
thức của đồ thị khung cảnh.
Canvas3D constructor
Canvas3D(GraphicsConfiguration graphicsconfiguration)
Khởi tạo và thiết lập một đối tượng Canvas3D mới cho phép Java 3D
có thể dựng nên cấu hình đúng đắn của đối tượng
(GraphicsConfiguration). Nó là phần mở rộng của lớp AWT Canvas.
Lớp Transform3D
Đối tượng Transform3D đại điện cho việc biến hình của hình học 3D
như dịch và quay. Những đối tượng này thường chỉ sử dụng để tạo một
đối tượng TransformGroup. Đầu tiên đối Transform3D được khởi tạo,
có khả năng liên kết với các đối tượng Transform3D khác. Sau đó
TransformGroup được khởi tạo sử dụng Transform3D vừa tạo.
Transform3D Default Constructor
Mội đối tượng tổng quan khi thay đổi hình dáng thông qua một ma
trận 4x4 với các điểm thực. Đối tượng Transform3D không được sử dụng
trong đồ thị khung cảnh. Nó chỉ được dùng để chỉ ra sự biến hình của một
đối tượng TransformGroup.
Transform3D()
Tạo đối tượng Transform3D mà đại diện cho ma trận ban đầu (không
có biến đổi)
Một đối tượng Transform3D có thể đại diện cho tịnh tiến, quay, biến
hình theo quy mô,hoặc là kết hợp các phương pháp trên lại. Khi có hiện
tượng quay, góc được thể hiện dưới dạng radians. Một vòng quay đầy đủ
http://tailieuhay.com 230
Lập trình đồ họa trên Java 2D và 3D
là 2 PI radians. Một cách để chỉ ra góc quay là sử dụng hằng Math.PI, nếu
không thì có thể chỉ ra góc quay chính xác.
Các phương thức của Transform3D
Đối tượng Transform3D đại diện cho các phép biến đổi hình học như
quay,dịch phóng lớn thu nhỏ. Transform3D là một trong số it các lớp
không trực tiếp sử dụng trong đồ thị khung cảnh. Việc biến hình do
Transform3D điều khiển đều được tác động lên đối tượng
TransformGroup mà được sử dụng trên đồ thị khung cảnh.
void rotX(double angle)
Phép quay với trục X ngược chiều kim đồng hồ, với góc (angle) là giá
trị radian.
void rotY(double angle)
Phép quay với trục Y ngược chiều kim đồng hồ, với góc (angle) là giá
trị radian.
void rotZ(double angle)
Phép quay với trục Z ngược chiều kim đồng hồ, với góc (angle) là giá
trị radian.
void set(Vector3f translate)
Tạo giá trị biến đổi của ma trận cho giá trị của tham số Vertor3f, và
tạo các thành phần khác của ma trận nếu việc biến hình dựa trên ma trận.
Lớp TransformGroup
Đây là lớp con của lớp Group, mỗi instance của TransformGroup
được sử dụng để tạo đồ thị khung cảnh và có một tập các đối tượng nút
con. Đối tượng TransformGroup giữ giá trị biến hình. Việc biến hình
thường được tạo trên đối tượng Transform3D vốn không phải là một đối
tượng của đồ thị khung cảnh.
TransformGroup Constructors
http://tailieuhay.com 231
Lập trình đồ họa trên Java 2D và 3D
TransformGroup()
Khởi tạo và thiết lập một đối tượng TransformGroup sử dụng phép
biến đổi đồng nhất
TransformGroup(Transform3D t1)
Khởi tạo và thiết lập một đối tượng TransformGroup từ một đối tượng
Transform3D
Tham số: t1 – đối tượng Transform3D
Phép biến hình lưu trong đối tượng Transform3D được copy vào một
đối tượng TransformGroup khi đối tượng TransformGroup được tạo hoặc
bằng cách sử dụng phương thức Transform ().
TransformGroup setTransform()
void setTransform(Transform3D t1)
Lập thành phần biến hình của TransformGroup cho giá trị của phép
biến hình trước đó
Tham số: T1 – phép biến hình cần sao chép
Lớp Vertor3f
Là lớp toán học trong gói javax.vecmath để định ra một vertor sử
dụng 3 điểm số thực. Các đối tượng vertor thường được sử dụng để chỉ ra
phép biến hình trong hình học. Đối tượng Vertor3f không được sử dụng
trực tiếp trong cấu trúc của đồ thị khung cảnh. Chúng thường được sử
dụng để chỉ ra các đặc đính biến đổi.
Vector3f Constructors
Vector3f()
Tạo và thiết lập các giá trị Vertor3f cho (0,0,0)
Vector3f(float x, float y, float z)
Tạo và thiết lập các giá trị Vertor3f cho (x,y,z)
ColorCube
http://tailieuhay.com 232
Lập trình đồ họa trên Java 2D và 3D
ColorCube Constructors
Package: com.sun.j3d.utils.geometry
Là một hình lập phương các mặt có các màu khác nhau, được mở
rộng từ lớp Shape3D, từ đó là một nút lá. ColorCube rất dễ sử dụng khi
đưa vào trông một môi trường ảo.
ColorCube ()
Tạo một hình lập phương với kích thước mặc định, vị trí ở 1 mét cách
mỗi trục tọa xyz
ColorCube(double scale)
Tạo nên hình lập phương có kích thước được định ra bởi các
giá trị cho trước.
1.7 Quay hình lập phương
Để quay hình lập phương chúng ta vừa tạo thì bước đầu tiên là tạo
phép biến hình mong muốn sử dụng đối tượng Transform3D. Đoạn mã
1-5 đưa ra một đối tượng Transform3D trong đồ thị khung cảnh để quay
hình lập phương quanh trục x. Do đó phép biến hình đầu tiên là quay. Đối
tượng Transform3D được tạo ra ở dòng 6, sử dụng phương thức rotX() ở
dòng 8. Đối tương TransformGroup sau đó được tạo giữ thông tin quay
ở dòng thứ 10.
tham số chỉ ra phép quay này:là trục và góc quay. Trong đó góc quay
được xác định thông qua tham số đầu vào. Đối tượng Transform3D được
tạo xong thì được sử dụng để tạo đối tượng TransformGroup là
objRotate. Đối tượng Transform3D được sử dụng trong đồ thị khung
cảnh đối tượng objRotate sau đó lấy đối tượng ColorCube làm con của
nó. Đến lượt objRoot lại lấy objRotate làm con.
public BranchGroup createSceneGraph() {
http://tailieuhay.com 233
Lập trình đồ họa trên Java 2D và 3D
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
// rotate object has composited
transformation matrix
Transform3D rotate = new Transform3D();
Transform3D tempRotate = new Transform3D();
rotate.rotX(Math.PI/4.0d);
tempRotate.rotY(Math.PI/5.0d);
rotate.mul(tempRotate);
TransformGroup objRotate = new
TransformGroup(rotate);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
return objRoot;
}
Như vậy bên đồ thị nhánh nội dung có các đối tượng như hình dưới,
chú ý là đối tượng BranchGroup bao giờ cũng là con của một Locale.
http://tailieuhay.com 234
Lập trình đồ họa trên Java 2D và 3D
1.7.1 Sự kết hợp của các phép biến hình: HelloJava3Db
Trong trường hợp có nhiều phép biến hình đồng thời xảy ra, ở ví dụ
của chúng ta là sẽ có 2 phép biến hình đồng thời, sẽ được chỉ trên một đối
tượng quan sát duy nhất. 2 phép biến đổi có thể thông qua một ma trận
biến đổi và được giữ bởi một đối tượng TransformGroup.
Trong ví dụ hình 1-6 chúng ta quan sát dưới đây thực hiện 2 phép
quay trên 2 trục x và y. 2 đối tượng Transform3D với mỗi phép quay
được tạo ra ở dòng 6 và 7. Sau đó 2 phép quay riêng rẽ này được chỉ ra
trên 2 đối tượng TransformGroup (dòng 9 và 10). Sau đó các phép quay
được nối lại với nhau bằng các nhân đối tượng
Dưới đây là đồ thị khung cảnh và kết quả chạy chương trình
Kết quả:
http://tailieuhay.com 235
Lập trình đồ họa trên Java 2D và 3D
1.8 Khả năng và hoạt động
Đồ thị khung cảnh được tạo bởi chương trình Java 3D có thể sử dụng
trực tiếp trong việc dựng hình, tuy nhiên mô tả của nó lại không hiệu quả.
Với một miêu tả tốt hơn của môi trường ảo sẽ tăng cường khả năng dựng
hình rất nhiều.
1.8.1 Dịch các nội dung
Đối tượng BranchGroup có một phương thức dịch. Phương thức này
chuyển toàn bộ đồ thị nhánh dưới thành các mô tả Java 3D trong của đồ
thị nhánh. Thêm vào đó, những mô tả bên trong này có thể tối ưu hóa theo
cách này hay cách khác.
Một trong những cách đó là, kết hợp TransformGroups với đường đi đồ
thị khung cảnh . Ví dụ nếu một đồ thị khung cảnh có 2 đối tượng
TransformGroup trong một mối liên hệ cha con chũng có thể đại diện
bằng một đối tượng TransformGroup. Một cách khác là liên kết đối
tượng Shape3D vốn có mối liên hệ vật lí tĩnh.
Hình 1-16 dưới đây đưa ra một mô tả mới hiệu quả hơn.
http://tailieuhay.com 236
Lập trình đồ họa trên Java 2D và 3D
1.8.2 Khả năng
Một khi đồ thị nhánh được làm cho sống và dịch, hệ thống dựng hình
của Java 3D chuyển đồ thị nhánh sang một mô tả bên trong hiệu quả hơn,
qua đó cũng tăng cao hiệu năng dựng hình.
Việc biến đổi qua mô tả bên trong có những tác động khác nhau. Một
trong số đó là cố định giá trị biến hình và các đối tượng trong đồ thị
khung cảnh. Trừ phi có chỉ ra chi tiết của chương trình, thì sẽ không có
khả năng thay đổi giá trị của các đối tượng đồ thị khung cảnh sau khi
chúng “sống”.
Có những trường hợp một chương trình vẫn cần khả năng thayđỏi giá
trị của chúng trong một đối tượng đồ thị khung cảnh sau khi nó “sống”.
Ví dụ như việc thay đổi giá trị của một đối tượng TransformGroup tạo
hoạt họa. Một danh sách các tham số có thể truy cập được và khi đó
người ta gọi là năng lực (capability) của một đối tượng.
Mỗi đối tượng SceneGraphObject có một tập các bit năng lực. Giá
trị của các bit này xác định khả năng có thể tồn tại cho đối tượng sau khi
http://tailieuhay.com 237
Lập trình đồ họa trên Java 2D và 3D
nó được dịch hay sống. Tập các năng lực này biến đổi khác nhau trên các
lớp.
SceneGraphObject Methods
SceneGraphObject là lớp gốc thường được sử dụng để tạo một đồ thị
khung cảnh bao gồm cả Group, Leaf và NodeComponent.
void clearCapability(int bit)
Xóa các bit khả năng
boolean getCapability(int bit)
Phục hồi.
Như trong một ví dụ đã nói, để có thể đọc được giá trị biến hình đại
diện cho một đối tương TransformGroup, thì các khả năng của nó phải
được thiết lập trước khi hoặc nó được dịch hoặc trở nên sống.
Trong phần tới, các hoạt họa có thể được tạo ra tùy theo các thời gian
khác nhau của phép biến hình. Muốn có điều này TransformGroup phải
có tập khả năng ALLOW_TRANSFORM_WRITE trước khi nó được
dịch hoặc sốngViệc điều khiển khẳ năng truy cập đến các lĩnh vực khác
của đối tượng TransformGroup cũng như vậy. Đối tượng
TransformGroup.
TransformGroup Capabilities
khả năng dưới đây là một trong những khả năng được định nghĩa bởi
TransformGroup. TransformGroup thừa kế rất nhiều bit khẳ năng của lớp
tiền bối của nó là Group và Node. Các khả năng như set,reset hay retrieve
được địng nghĩa ở SceneGraphObject.
ALLOW_TRANSFORM_READ
Chỉ ra các nút cho phép truy cập tới thông tin biến hình của đối tượng
của nó.
ALLOW_TRANSFORM_WRITE
Cho phép ghi tới thông tin biến hình của đối tượng của nó.
http://tailieuhay.com 238
Lập trình đồ họa trên Java 2D và 3D
Group Capabilities
TransformGroup thừa kế các khả năng từ các lớp cha của nó.
ALLOW_CHILDREN_EXTEND
Thiết lập khả năng cho phép con có thể thêm vào nut Group sau khi nó
được dịch hoặc sống.
ALLOW_CHILDREN_READ
Thiết lập khả năng cho phép các tham chiếu đến con của nút Group có thể
được đọc sau khi nó được dịch hoặc sống.
ALLOW_CHILDREN_WRITE
Thiết lập khả năng cho phép them chiếu đến các con của nút Group để ghi
hay thay đổi sau khi nó được dịch hoặc sống.
1.9 Thêm vào các hành vi animation
Trong Java 3D, Behavior là một lớp quan trọng về animation với các
tương tác của các đối tượng. Người lập trình có thể thay đổi bất cứ thuộc
tính nào của một đối tượng quan sát.
Sự khác nhau giữa animation và interaction là khi nào thuộc tính được
kích hoạt khi phàn hồi qua thời gian hay phản hồi qua các hành động của
người sử dụng.
Với mỗi đối tượng quan sát trong một môi trường ảo có thể có những
hành vi sẵn có của nó. Thực tế thì thường có nhiều hành vi . Để chỉ ra một
hành vi cho một đối tượng quan sát, người lập trình tạo một đối tượng mà
chỉ ra hành vi đó, thêm vào các đối tượng quan sát tới đồ thị khung cảnh
và xây dựng những tham chiếu giữa các đối tượng đồ thị và các đối tượng
hành vi.
Trong một môi trường ảo với rất nhiều hành vi, thì cần một lượng tính
toán rất lớn. Khi cả việc dựng hình và các hành vi sử dụng cùng chung
nhiều process, thì thật khó có thể nâng cao hiệu năng hoạt động được.
http://tailieuhay.com 239
Lập trình đồ họa trên Java 2D và 3D
Java 3D cho phép lập trình viên có thểm quản lí vấn đề này bằng cách
chỉ ra vị trí của một hành vi. Khu vực này được gọi là scheduling region.
Một hành vi không hoạt động trì phi activation volume của
ViewPlatform phân cắt một vùng danh mục đó. Nói cách khác,không có
chỗ trong rừng để lá rơi thì sẽ không có lá rơi. Tính năng vùng danh mục
làm cho Java 3D hiệu qua hơn trong việc nắm bắt một môi trường ảo với
rất nhiều hành vi.
Hình 1-7 chỉ ra các bước bao gồm cả việc định ra một animation với
một đối tượng thêm vào.
1. Create a target TransformGroup
Set the ALLOW_TRANSFORM_WRITE capability
2. Create an Alpha5 object
Specify the time parameters for the alpha
3. Create the interpolator object
Have it reference the Alpha and TransformGroup objects
Customize the behavior parameters
4. Specify a scheduling region
Set the scheduling region for the behavior
5. Make the behavior a child of the TransformGroup
1.9.1 Định nghĩa các hành vi animation
Một hành vi có thể thay đổi trên địa điểm (PositionInterpolator),
hướng (RotationInterpolator), kích cỡ(ScaleInterpolator), màu
sắc(ColorInterpolator) hoặc độ trong suốt(TransparencyInterpolator) của
một đối tượng quan sát. Như đã nói ở phía trên Interpolator là các lớp
hành vi được định nghĩa trước. Tất cả các hành vi nói trên đều có thể sử
dụng mà không cần định trước tuy nhiên việc định trước cho phép việc
http://tailieuhay.com 240
Lập trình đồ họa trên Java 2D và 3D
tạo các hành vi trở nên dễ dàng hơn rất nhiều. Các lớp định trước này
cung cấp các hành động khác nhau thậm chí kết nối các hành động đó.
Lớp RotationInterpolator
Lớp này sử dụng để chỉ ra một hành vi quay của một đối tượng quan sát
hoặc một nhóm các đối tượng như vậy. Một đối tượng
RotationInterpolator thay đổi một đối tượng TransformGroup qua một
phép quay khi phản hồi giá trị của một đối tượng Alpha. Khi giá trị của
đối tượng Alpha thay đổi qua thời gian việc thay đổi phép quay cũng dễ
dàng. Một đối tượng RotationInterpolator rất linh động trong việc chỉ ra
trục quay, góc quay ban đầu góc quay kết thúc.
RotationInterpolator Constructor
RotationInterpolator(Alpha alpha, TransformGroup target)
Hàm khởi tạo này sử dụng các giá trị mặc định cho một vài tham số
của hành vi mặc định để khởi tạo một phép quay đầy đủ trên trục y, bằng
đối tượng TransformGroup được chỉ ra bằng hành vi mặc định.
Tham số:
alpha – thời gian hàm thay đổi để tham chiếu
target – đối tượng TransformGroup cần thay đổi
5 Alpha là một lớp trong Java 3D để tạo ra các hàm biến đổi thời gian.
1.9.2 Các hàm biến đổi về thời gian: Ánh xạ một hành vi với thời gian
Việc ánh xạ một đối tượng với thời gian thông qua một đối tượng Alpha.
Lớp Alpha
Lớp này được sử dụng để tạo hàm biến đổi theo thời gian. Lớp này
cung cấp các giá trị giữa 0 và 1,. Giá trị này phụ thuộc vào thời điểm và
thông số của đối tượng Alpha. Đối tượng Alpha thường được sử dụng
với các đối tượng hành vi sẵn có để thực hiện các thay đổi hoạt họa của
các đối tượng quan sát.
http://tailieuhay.com 241
Lập trình đồ họa trên Java 2D và 3D
Có 10 tham số cho Alpha, do đó giúp cho người lập trình sử dụng
linh động. Mỗi instance của đối tượng Alpha có thể dễ dàng kết hợp với
một hành vi để đưa ra các phép quay đơn giản, cánh bay, cửa mở,hay bắn
rocket.
Alpha Constructor
Alpha()
Liên tục lặp với thời gian định kì là 1 giây
Alpha(int loopCount, long increasingAlphaDuration)
Hàm khởi tạo này lấy loopCount và increasingAlphaDuration như là
tham số và đăng kí giá trị mặc định cho tất cả các tham số còn lại. Đối
tượng Alpha tạo ra cung cấp giá trị khởi đầu từ 0 lên 1. Điều này lặp đi
lặp lại nhiều lần thông qua loopCount. Nếu loopCount = -1 đối tượng
alpha lặp đi lặp lại vô hạn.
Tham số:
loopCount – số lần chạy đối tượng alpha này, giá trị bằng -1 lặp
vô hạn
increasingAlphaDuration – thời gian tính bằng giây giữa bước
nhẩy từ 0 lên 1
1.9.3 Lập danh mục các vùng
Như đã nói ở phần 1-9 mỗi hành vi có một vùng danh mục. Vùng này
quanh các hành vi được thiết lập dựa trên phương thức
setSchedulingBounds của lớp Behavior.
Có rất nhiều cách để định nghĩa vùng danh mục này nhưng cách đơn giản
nhất là tạo đối tượng BoundSphere . Các tùy chọn khác như bounding
box, hoặc bouding polytope.
Behavior setSchedulingBounds method
void setSchedulingBounds(Bounds region)
http://tailieuhay.com 242
Lập trình đồ họa trên Java 2D và 3D
Xác định ranh giới cho vùng danh mục của hành vi
Parameters:
region – ranh giới chứa Behavior's scheduling region.
Lớp BoundingSphere
Việc định nghĩa một vùng cầu phải đi đôi với việc chỉ ra điểm trung
tâm và bán kính của nó. Cách thường làm là để tâm của hình cầu ở vị trí
trung tâm là (0,0,0). Bán kính sau đó được lựa chọn đủ sao cho hình cầu
chứa đối tượng quan sát, bao gồm tất cả các vị trí mà đối tượng có thể ở
đó.
Bounding Sphere Constructors
BoundingSphere()
Tạo một hình cầu bao mà tâm ở vị trí (0,0,0) với bán kính bằng 1
BoundingSphere(Point3d center, double radius)
2 tham số lần lượt là
center – tọa độ của tâm trong không gian
radius – bán kính của hình cầu
1.9.4 Ví dụ về hành vi: HelloJava3Dc
Đoạn mã hình 1-7 đưa ra một ví dụ hoàn thiện về việc sử dụng lớp
thêm vào để tạo animation. Animation được tạo trong đoạn mã này là
hình lập phương quay liên tục trong thời gian 4 giây.
Bước đầu tiên của công thức là tạo đối tượng TransformGroup để
sửa đổi tại thời điểm chạy. Đối tượng TransformGroup của môt hành vi
sẵn có phải có khả năng ghi. Đối tượng TransformGroup tên là objSpin
được tạo ở dòng 7. Khả năng của nó được thiết lập ở dòng thứ 8.
http://tailieuhay.com 243
Lập trình đồ họa trên Java 2D và 3D
Bước 2 là tạo đối tượng Alpha, rotationAlpha, được sử dụng để xác
định thời gian quay liên tục. 2 tham số chỉ ra trong dòng 16 của đoạn mã
là số vòng lặp và thời gian cho mỗi vòng . Giá trị “-1” của số vòng lặp thể
hiện việc lặp liên tục. Thời gian được tính theo mili giây giá trị 4000 được
sử dụng trong chương trình tương đương với 4 giây. Từ đó hành vi là
quay một lần trên 4 giâys.
Bước 3 là tạo đối tượng thêm vào. Đối tượng quay
RotationInterpolator được tạo ra ở dong 21 và 22. Đối tượng thêm vào
phải tham chiếu đến đối tượng biến hình và alpha. Điều này được mô tả
trong hàm khởi tạo. Trong ví dụ này hành vi mặc định
RotationInterpolator là được sử dụng, để thực hiện phép quay hoàn toàn
quanh trục y.
Bước 4 chỉ ra vùng danh mục. Trong đoạn mã, một đối tượng
BoundingSphere được sử dụng với giá trị mặc định, được tạo ra ở dòng
25. Vùng cầu này là vùng bao quanh của hành vi trong dòng 26.
Cuối cùng là bước 5 trong công thức, biến hành vi thành một con của
TransformGroup trên dòng 27.
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
// Create the transform group node and
initialize it to the
// identity. Add it to the root of the
subgraph.
TransformGroup objSpin = new
TransformGroup();
objSpin.setCapability(TransformGroup.ALL
OW_TRANSFORM_WRITE);
http://tailieuhay.com 244
Lập trình đồ họa trên Java 2D và 3D
objRoot.addChild(objSpin);
// Create a simple shape leaf node, add
it to the scene graph.
// ColorCube is a Convenience Utility
class
objSpin.addChild(new ColorCube(0.4));
// Create a new Behavior object that
will perform the desired
// operation on the specified transform
object and add it into
// the scene graph.
Alpha rotationAlpha = new Alpha(-1,
4000);
RotationInterpolator rotator =
new
RotationInterpolator(rotationAlpha, objSpin);
// a bounding sphere specifies a region
a behavior is active
// create a sphere centered at the
origin with radius of 100
BoundingSphere bounds = new
BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
http://tailieuhay.com 245
Lập trình đồ họa trên Java 2D và 3D
return objRoot;
} // end of CreateSceneGraph method
Code Fragment 1-7 createSceneGraph method with RotationInterpolator
Behavior
Đồ thị khung cảnh của chương trình và kết quả chạy trên màn hình.
Kết quả
1.9.5 Phép biến hình và kết hợp các hành vi .Ví dụ: HelloJava3Dd
Tất nhiên chúng ta có thể kết hợp các hành vi với các phép biến hình
quay với ví dụ dưới đây. Trong đồ thị nhánh nội dung có những đối tượng
http://tailieuhay.com 246
Lập trình đồ họa trên Java 2D và 3D
objRotate và objSpin, phân biệt với những phép quay tĩnh và hành vi của
đối tượng hình lập phương.
Đồ thị khung cảnh
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
// rotate object has composited
transformation matrix
Transform3D rotate = new Transform3D();
Transform3D tempRotate = new Transform3D();
rotate.rotX(Math.PI/4.0d);
tempRotate.rotY(Math.PI/5.0d);
rotate.mul(tempRotate);
TransformGroup objRotate = new
TransformGroup(rotate);
// Create the transform group node and
initialize it to the
// identity. Enable the TRANSFORM_WRITE
capability so that
// our behavior code can modify it at
runtime. Add it to the
// root of the subgraph.
TransformGroup objSpin = new
TransformGroup();
http://tailieuhay.com 247
Lập trình đồ họa trên Java 2D và 3D
objSpin.setCapability(TransformGroup.ALLOW_TRANSF
ORM_WRITE);
objRoot.addChild(objRotate);
objRotate.addChild(objSpin);
// Create a simple shape leaf node, add it to
the scene graph.
// ColorCube is a Convenience Utility class
objSpin.addChild(new ColorCube(0.4));
// Create a new Behavior object that will
perform the desired
// operation on the specified transform
object and add it into
// the scene graph.
Transform3D yAxis = new Transform3D();
Alpha rotationAlpha = new Alpha(-1, 4000);
RotationInterpolator rotator =
new RotationInterpolator(rotationAlpha,
objSpin, yAxis,
0.0f, (float)
Math.PI*2.0f);
// a bounding sphere specifies a region a
behavior is active
// create a sphere centered at the origin
with radius of 1
http://tailieuhay.com 248
Lập trình đồ họa trên Java 2D và 3D
BoundingSphere bounds = new BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
return objRoot;
} // end of CreateSceneGraph method of
HelloJava3Dd
Kết quả
http://tailieuhay.com 249
Lập trình đồ họa trên Java 2D và 3D
CHƯƠNG 2
Tạo các hình
2.1 Hệ tọa độ thế giới ảo
Trong chương 1 ta đã biết với mỗi instance của một lớp
VirtualUniverse có chức năng như một gốc của đồ thị khung cảnh trong
tất cả chương trình Java 3D. Từ khóa virtual universe là chỉ một không
gian ảo 3 chiều trong đó có các đối tượng 3D. Mỗi đối tượng Locale trong
một môi trường ảo thiết lập một thế giới ảo Cartesian. Đối tượng này
tương đương với một con trỏ tham chiếu cho một đối tượng quan sát
trong một môi trường ảo. Với một đối tượng Locale trong
SimpleUniverse có một hệ tọa độ duy nhất.
Hệ tọa độ của môi trường ảo Java 3D là thuận phải tức là trục X
hướng dương bên tay phải, trục Y hướng dương chỉ lên trên, trục Z hướng
dương chỉ vào người nhìn với đơn vị là mét. Hình 2-1 dưới đây chỉ ra
hướng nhìn trong SimpleUniverse.
http://tailieuhay.com 251
Lập trình đồ họa trên Java 2D và 3D
2.2 Visual Object Definition Basics
Phần 2.2.1 giới thiệu lớp Chen code lai cho ro rang ., còn lớp Chen
code lai cho ro rang .được giới thiệu ở phần 2.2.2, sau khi đi vào những
định nghĩa cơ bản về hình học trong gói tiện ích, phần còn lại của chương
này sẽ thảo luận về góc độ hình học và hình dáng của các nút thành phần.
2.2.1 An Instance of Shape3D Defines a Visual Object
Nút đồ thị khung cảnh Shape3D định nghĩa một đối tượng quan sát.
Shape3D là một trong các lớp con của lớp Leaf từ đó đối tượng Shape3D
chỉ có thể là lá trong đồ thị khung cảnh. Đối tượng Shape3D không chứa
thông tin về hình dạng hay màu sắc của một đối tượng quan sát. Thông tin
này được lưu trong đối tượng NodeComponent được chuyển đến bới đối
tượng Shape3D. Một đối tương Shape3D có thể quy vào một nút thành
phần hình học và một nút thành phần giao diện.
Trong đồ thị khung cảnh Hellojava3D ở chương 1, biểu tượng hình tứ
giác dùng để đại diện cho đối tượng ColorCube. Đồ thị khung cảnh trong
hình 2-2 chỉ ra đối tượng quan sát được đại diện bởi một lá Shape3D
(hình tam giác) và 2 NodeComponent (ô van) thay cho hình dạng tứ giác.
http://tailieuhay.com 252
Lập trình đồ họa trên Java 2D và 3D
Một đối tượng quan sát có thể định nghĩa bằng cách sử dụng chỉ dối
tượng Shape3D và một nút thành phần hình học. Với tùy chọn này, đối
tượng Shape3D quy cho một nút Appearance. Hàm tạo cho đối tượng
Shape3D cho phép đối tượng Shape3D được tạo mà không cần tham
chiếu của nút thành phần, hoặc chỉ với tham chiếu thành phần hình học,
hoặc cả 2 dạng.
Shape3D Constructors
Shape3D()
Khởi tạo và thiết lập đối tượng Shape3D mà không có nút thành phần
hình học và giao diện
Shape3D(Geometry Geometry)
Khởi tạo và thiết lập chỉ với thành phần hình học
Shape3D(Geometry Geometry, Appearance Appearance)
Khởi tạo và thiết lập chỉ với cả 2 thành phần.
Cho đến khi đối tượng Shape3D không sống hoặc không được dịch
nữa thì tham chiếu nút thành phần có thể thay đổi với các phương thức
dưới đây.
Shape3D Methods
http://tailieuhay.com 253
Lập trình đồ họa trên Java 2D và 3D
Đối tượng Shape3D tham chiếu đến đối tượng nút thành phần hình
học và giao diện.
void setGeometry(Geometry Geometry)
void setAppearance(Appearance Appearance)
Shape3D Capabilities
Đối tượng Shape3D thừa kế các khả năng từ SceneGraphObject, Node và
Leaf.
ALLOW_GEOMETRY_READ | WRITE
ALLOW_APPEARANCE_READ | WRITE
ALLOW_COLLISION_BOUNDS_READ | WRITE
2.2.2 Node Components
Đối tượng NodeComponent chứa các định nghĩa chính xác về các
thuộc tính của một đối tượng quan sát. Với mỗi lớp con của
NodeComponent định nghĩa đích xác các thuộc tính quan sát. Hình 2-3
chỉ ra các phần thừa kế của Java 3D API chứa lớp NodeComponent và
lớp trước nó. Phần 2-5 sẽ giới thiệu về NodeComponent Germetry. Phần
2-6 giới thiệu về Appearance NodeComponent.
http://tailieuhay.com 254
Lập trình đồ họa trên Java 2D và 3D
2.2.3 Defining Visual Object Classes
Cùng một đối tượng quan sát sẽ thường xuất hiện nhiều lần trong một
môi trường ảo. Điều đó gợi ý cho việc định nghĩa một lớp để tạo đối
tượng quan sát thay vì thiết lập mỗi đối tượng quan sát riêng lẻ. Có nhiều
cách để thiết kế một lớp để định nghĩa một đối tượng quan sát.
Tổ chức của lớp VisualObject cũng giống như lớp ColorCube mà
trong đó nó được thừa kế từ đối tượng VisualObject. Lớp VisualObject
là một điểm đề nghị đầu tiên cho việc định nghĩa các lớp nội dung để sử
dụng trong xây dựng đồ thị khung cảnh. Mỗi người lập trình Java 3D sẽ
tùy biến lớp VisualObject theo ý của họ. Chúng ta có thêm xem một ví
dụ đầy đủ về lớp ColorCube trong gói com.sun.j3d.utils.Geometry .
Sử dụng Shape3D như là lớp cơ bản cho việc tạo một đối tượng quan
sát cho phép dễ dàng sử dụng trong chương trình Java 3D. Lớp đối tượng
quan sát có thể được sử dụng dễ dàng như lớp ColorCube trong ví dụ
HelloJava3D từ chương, Hàm tạo có thể được gọi và những đối tượng
http://tailieuhay.com 255
Lập trình đồ họa trên Java 2D và 3D
mới nhất được thêm vào như là con của một vài Group trên một dòng của
đoạn mã. Trong đoạn mã dưới đây objRoot là một instance của Group.
Đoạn mã này tạo một VisualObject và thêm nó vào như là cong của
objRoot trong đồ thị khung cảnh.
objRoot.addChild(new VisualObject());
Hàm tạo của VisualObject tạo đối tượng quan sát bằng cách tạp một
đối tượng Shape3D tham chiếu đến NodeComponent được tạo bởi
phương thức createGeometry()và createAppearance().
Phương thức createGeometry()tạo một nút thành phần hình học được
sử dụng trong đối tượng quan sát. Phương thức createAppearance()có
trách nhiệm cho việc tạo NodeComponent để định nghĩa bề ngoài cho
đối tượng quan sát.
Hàm tạo của VisualObject tạo đối tượng quan sát bằng cách định
nghĩa một lớp container không không thừa kế tù Java 3D API. Trong thiết
kế này lớp đối tượng quan sát sẽ chứa một Group Node hoặc Shape3D
như là gốc của một nhánh đồ thị nó định nghĩa. Lớp này phải định nghĩa
phương thức để trả về một tham chiếu đến gốc. Công nghệ này có thể có
nhiều việc hơn nhưng lại dễ dàng để hiểu. Ngoài ra còn có các lớp khác
trong gói về hình học như Box, Cone, Cylinder và Sphere. Mỗi lớp mở
rộng từ Primitive, vốn mở rộng từ Group.
2.3 Các lớp tiện ích hình học
Phần này bao gồm tất cả các lớp tiện ích dùng để tạo hình hộp, hình
nón, hình trụ, và hình cầu cơ bản. Các hình cơ bản này là cách dễ thứ hai
để tạo một môi trường ảo. Còn cách dễ nhất đương nhiên là dùng hình lập
phương.
Các lớp cơ bản này cung cấp cho người lập trình tính linh động hơn
rất nhiều so với lớp hình lập phương màu đưa ra. Lớp ColorCube định
http://tailieuhay.com 256
Lập trình đồ họa trên Java 2D và 3D
nghĩa về mặt hình học và màu trên các nút thành phần hình học. Kết quả
là mọi thứ xung quanh nó trở nên cố định trừ kích thước của nó. Kích
thước hình lập phương chỉ được xác định khi đối tượng được tạo.
Một lớp cơ bản được gọi là linh động nếu nó xác định hình dạng mà
không phải xác định màu sắc đi kèm. Trong các lớp tiện ích cơ bản hình
học, người lập trình không thể thay đổi hình học nhưng có thể thay đổi bề
ngoài. Các lớp này cung cấp cho người lập trình tính linh động khi có
nhiều instance trên một hình cơ bản ở đó mỗi phần có một diện mạo khác
nhau bằng cách tham chiếu đến các NodeComponent Appearance khác
nhau.
Các lớp này được định nghĩa trong gói com.sun.j3d.utils.Geometry.
Lớp cơ bản nhất của các lớp này là lớp Primitive, dưới đây là hình2-4 thể
hiện cây thừa kế các lớp này.
2.3.1 Box
Lớp gốc Box (hình hộp) tạo đối tượng quan sát hình hộp 3D. Chiều
dài chiều rộng chiều cao mặc định là 2 met, với tâm ở gốc. Chiều dài
http://tailieuhay.com 257
Lập trình đồ họa trên Java 2D và 3D
chiều rộng chiều cao được xác định trong thời gian đối tượng được tạo.
Tất nhiên TransformGroup, dọc theo đường đồ thị khung cảnh tới Box,
có thể được sử dụng để thay đổi vị trí và hướng của các instance của Box
và các đối tượng quan sát khác.
Box Constructors
Package: com.sun.j3d.utils.Geometry
Box mở rộng từ Primitive, một lớp khác trong gói
com.sun.j3d.utils.Geometry
Box()
Thiết lập một hình hộp với mặc định chiều cao chiều dài chiều rộng là 2
met, tâm ổ gốc.
Box(float xdim, float ydim, float zdim, Appearance Appearance)
Thiết lập hình hộp với hướng, bề ngoài, và tâm ở gốc.
Box, Cone, and Cylinder Methods
Package: com.sun.j3d.utils.Geometry
Các phương thức này được định nghĩa trong mối lớp cơ bản: Box, Cone,
và Cylinder. Các lớp cơ bản này được kết hợp từ các đối tượng Shape3D
trong một nhóm.
Shape3D getShape(int id)
Lấy một trong những mặt Shape3D từ lớp cơ bản chứa hình học và bề
mặt.Đối tượng Box, Cone, và Cylinder được tập hợp từ nhiều đối tượng
Shape3D, với nút thành phần hình học của nó. Giá trị đưa ra để xác định
nút thành phần nào được lấy.
void setAppearance(Appearance Appearance)
http://tailieuhay.com 258
Lập trình đồ họa trên Java 2D và 3D
2.3.2 Cone
Hình nón định nghĩa đối tượng hình nón, bịt nắp tâm tại gốc tọa độ
với trục song song với trục Y.
Bán kính là 1 và chiều cao là 2. Tâm của hình nón được coi như là
tâm của hình bao củanó hơn là tâm thực.
Cone Constructors
Package: com.sun.j3d.utils.Geometry
Cone()
Hàm khởi tạo mặc định với bán kính là 1, đường kính là 2.
Cone(float radius, float height)
Hàm khởi tạo với 2 tham số bán kính và chiều cao
2.3.3 Cylinder
Lớp Cylinder (hình trụ) tạo một đối tượng hình trụ bị bịt tâm ở gốc
với trục dọc theo trục Y. Giá trị mặc định là bán kính là 1, chiều cao là 2.
Cylinder Constructors
Package: com.sun.j3d.utils.Geometry
Cylinder()
Hàm khởi tạo mặc định với bán kính là 1, chiều cao là 2.
Cylinder(float radius, float height)
Khởi tạo với tham số bán kính và chiều cao.
Cylinder(float radius, float height, Appearance Appearance)
Khởi tạo với bán kính, chiều cao và bề mặt.
http://tailieuhay.com 259
Lập trình đồ họa trên Java 2D và 3D
2.3.4 Sphere
Lớp này tạo đối tượng hình cầu tâm ở gốc, bán kính mặc định là 1.
Sphere Constructors
Package: com.sun.j3d.utils.Geometry
Sphere()
Hàm khởi tạo mặc định, bán kính là 1.
Sphere(float radius)
Hàm khởi tạo với bán kính xác định
Sphere(float radius, Appearance Appearance)
Hàm khởi tạo với bán kính, bề mặt cho trước.
Sphere Methods
Package: com.sun.j3d.utils.Geometry
Shape3D getShape()
Lấy đối tượng Shape3D chứa dạng hình học và bề mặt.
Shape3D getShape(int id)
Phương thức này cũng được sử dụng với các lớp cơ bản phía trên. Tuy
nhiên 1 Sphere chỉ có một đối tượng Shape3D nên id =1.
void setAppearance(Appearance Appearance)
Lập bề mặt cho hình cầu.
http://tailieuhay.com 260
Lập trình đồ họa trên Java 2D và 3D
2.3.5 More About Geometric Primitives
Các cơ bản chưa được định nghĩa về màu sắc. Các hình không định
nghĩa màu mà thừa kế màu từ nút thành phần bề mặt của nó. Nếu không
có tham chiếu đến nút thành phần bề mặt, đối tượng quan sát sẽ có màu
mặc định là trắng.
2.3.6 ColorCube
Lớp ColorCube được trình bày ở đây thể hiện sự tương phản với các
lớp hình cơ bản như Box, Cone, Cylinder và Sphere. Lớp này mở rộng
theo hướng thừa kế khác, nó là lớp con của Shape3D. Cây thừa kế được
chỉ ra trong hình 2-5.
Lớp này cũng là lớp duy nhất cung cấp với Java 3D API cho phép
người lập trình bỏ qua các phần như màu sắc và ánh sáng. Vì lí do này
nên nó thường được dùng để nhanh chóng tạo ra một đồ thị khung cảnh
để kiểm thử hình nguyên mẫu.
2.3.7 Example: Creating a Simple Yo-Yo From Two Cones
Phần này giới thiệu ví dụ đơn giản qua việc sử dụng lớp Cone, mục
tiêu của chương trình là dựng nên một con yo-yo. Chúng ta phải dùng 2
http://tailieuhay.com 261
Lập trình đồ họa trên Java 2D và 3D
hình nón để tạo nên được Yo-Yo. Các hành của Java 3D API cho phép
yo-yo có thể di chuyển lên xuống nhưng trong phần này sẽ không trình
bày đến.
Hình 2-5 dưới đây hiển thị đồ thị khung cảnh của chương trình thiết
kế lớp ConeYoyo và ConeYoyoApp. Ví trị mặc định của một đối tượng
Cone thông qua hình bao của nó tâm ở gốc. Hướng của hình nón là hướng
dương, đỉnh nằm trên trục Y. Yo-yo định ra 2 hình nón mà được quay
quanh Z và dịch theo trụ X để đỉnh của chúng trùng nhau ở gốc. Những
kết hợp của phép quay và dịch cho phép ghép các đối tượng hình nón với
nhau.
Nhánh đồ tị này bắt đầu bằng đối tượng BranchGroup được tạo bơi
ConeYoyo, đường của đồ thị khung cảnh tới mỗi đối tượng Cone bắt đầu
bằng đối tượng TransformGroup chỉ ra phép dịch, theo đó là
TransformGroup xác định phép quay và hủy đối tượng Cone.
http://tailieuhay.com 262
Lập trình đồ họa trên Java 2D và 3D
Một vài đồ thị khung cảnh có thể đại diện cho cùng một môi trường
ảo. Trong ví dụ hình 2-6 có một vài thay đổi, thay đổi đầu tiên là đối
tượng BranchGroup có con là ConeYoyo và được chèn vào đối tượng
ConeYoyo trực tiếp trên Locale. BranchGroup này sau đó là để thêm vào
các đối tượng quan sát trong tương lai tới thế giới quan sát. Một thay đổi
khác là kết nối 2 đối tượng TransformGroup trong đối tượng
ConeYoyo. Phép biến đổi được mô tả đơn giản như dưới đây.
Nút Shape3D của đối tượng Cone tham chiếu đến nút thành phần
hình học. Đối tượng Shape3D của Cone là con của Group trong Cone.
Khi đối tượng Cone thừa kế từ Group, thì Cone còn lại không thể sử dụng
thêm lần nào nữa trong đồ thị khung cảnh. Hình 2- đưa ra một ví dụ về
thông báo lỗi khi cố gắng sử dụng cùng một đối tượng Cone trong đồ thị
khung cảnh. Lỗi này không tồn tại trong ví dụ chương trình đưa ra.
Hình 2-8 chỉ ra một hình ảnh được dịch với ví dụ vừa qua. Lớp
ConeYoyo được sửa lại như trong đoạn mã 2-2.
http://tailieuhay.com 263
Lập trình đồ họa trên Java 2D và 3D
Dòng 14 đến 21 tạo các đối tượngcủa ½ đồ thị yo-yo . Dòng 23 đến
25 tạo mối quan hệ giữa các đối tượng. Tiến trình này được lặp lại trên
một nửa đồ thị còn lại từ dòng 27 đến dòng 38.
Dòng 12 tạo yoyoApear, một nút thành phần bề mặt với giá trị mặc
định được sử dụng bởi đối tượng Cone. Dòng 21 đến 34 thiết lập bề mặt
cho 2 hình nón.
// //////////////////////////////////////
////
//
// create Shape3D with geometry and
appearance
// the geometry is created in method
yoyoGeometry
// the appearance is created in method
yoyoAppearance
//
public ConeYoyo() {
yoyoBG = new BranchGroup();
Appearance app = new Appearance();
// rotate object has composited
transformation matrix
Transform3D rotate = new
Transform3D();
Transform3D translate = new
Transform3D();
http://tailieuhay.com 264
Lập trình đồ họa trên Java 2D và 3D
translate.set(new Vector3f(0.1f,
0.0f, 0.0f));
TransformGroup yoyoTGT1 = new
TransformGroup(translate);
yoyoBG.addChild(yoyoTGT1);
rotate.rotZ(Math.PI / 2.0d);
TransformGroup yoyoTGR1 = new
TransformGroup(rotate);
Cone cone1 = new Cone(0.6f, 0.2f);
cone1.setAppearance(app);
yoyoTGR1.addChild(cone1);
yoyoTGT1.addChild(yoyoTGR1);
translate.set(new Vector3f(-0.1f,
0.0f, 0.0f));
TransformGroup yoyoTGT2 = new
TransformGroup(translate);
yoyoBG.addChild(yoyoTGT2);
rotate.rotZ(-Math.PI / 2.0d);
TransformGroup yoyoTGR2 = new
TransformGroup(rotate);
Cone cone2 = new Cone(0.6f, 0.2f);
cone2.setAppearance(app);
yoyoTGR2.addChild(cone2);
yoyoTGT2.addChild(yoyoTGR2);
http://tailieuhay.com 265
Lập trình đồ họa trên Java 2D và 3D
yoyoBG.compile();
} // end of ConeYoyo constructor
Code Fragment 2-2 Class ConeYoyo From ConeYoyoApp.java Example
Program
Advanced Topic: Geometric Primitive – Các dạng hình học cơ bản
Cây thừa kế trong hình 2-4 chỉ ra Primitive là lớp cha của tất cả các
lớp Cone, Box, Cylinder, và Spheres. Nó định nghĩa một lượng lớn các
trường và phương thức cũng như giá trị mặc định của các trường. Mỗi lớp
con của Primitive có một hàm khởi tạo cho phép thiết lập các cờ khi đối
tượng được xây dựng. Ví dụ như lớp Sphere có hàm khởi tạo Sphere (int).
Danh sách các cờ ở dưới đây:
GEOMETRY_NOT_SHARED Normals are generated along with the
positions.
GENERATE_NORMALS_INWARD Normals are flipped along the
surface.
GENERATE_TEXTURE_COORDS Texture coordinates are generated.
GEOMETRY_NOT_SHARED The Geometry created will not be
shared by another
node.
Lớp này cũng cho phép chia sẻ nút thành phần hình học giữa các instance
của một primitive với cùng một kích cỡ. Mặc định tất các các primitives
là cùng một kích thước, chia sẻ một nút thành phần hình học. Một ví dụ
của một trường được định nghĩa trong lớp Primitive là giá trị integer
GEOMETRY_NOT_SHARED. Trường này chỉ ra dạng hình học được
sẽ không được chia sẻ với những instance khác. Thiết lập cờ này để tránh
http://tailieuhay.com 266
Lập trình đồ họa trên Java 2D và 3D
việc chia sẻ giữa các primitive của cùng một tham số (chẳng hạn với hình
cầu bán kính 1).
Cone myCone = new Cone(Primitive.GEOMETRY_NOT_SHARED);
Primitive Methods
Package: com.sun.j3d.utils.Geometry
Primitive mở rộng từ Group và là lớp cha của của các lớp Box, Cone,
Cylinder và Sphere.
public void setNumVertices(int num)
Thiết lập tổng số đỉnh trong primitive này.
void setAppearance(int partid, Appearance Appearance)
Thiết lập bề mặt của các phần con. Các đối tượng Box, Cone, Cylinder
được gom lại với hơn một đối tượng Shape3D, mỗi thứ có tiềm năng sử
dụng nút thành phần bề mặt của nó. Giá trị cho mỗi phần này được xác
định khi mỗi nút thành phần bề mặt được thiết lập.
void setAppearance()
Thiết lập bề mặt chính của primitive (tất cả các phần con) tới bề mặt trắng
mặc định.
2.4 Các lớp toán học
Để tạo đối tượng quan sát, cần cả lớp hình học và các lớp con của nó.
Rất nhiều lớp con của lớp hình họcmo tả dựa trên các hình cơ bản véc tơ,
như điểm đường thẳng và đa giác. Các lớp con của lớp hình học sẽ được
mô tả trong phần 2-5 nhưng trước đó chúng ta quan tâm đến các lớp toán
http://tailieuhay.com 267
Lập trình đồ họa trên Java 2D và 3D
học như điểm, màu, vertor và textcord dùng để định nghĩa các dữ liệu liên
đỉnh.
Chú ý rằng với mỗi kí hiệu có “*” đằng sau đại diện cho một lớp tên.
Ví dụ Tuple* tương đương với Tuple2f, Tuple2d Tuple3i….
Trong đó các chữ số đằng sau chỉ ra số thành phần trong tuple, còn
các chữ cái nhỏ cuối cùng đại diện cho kiểu. ‘f’ chỉ float, ‘d’ chỉ double,
‘b’ đại diện cho byte, ‘i’ là integer. Vì thế lớp Tuple3f là một lớp mà quản
lí 3 giá trị điểm thực.
Tất cả các lớp toán học này đều nằm trong gói javax.vecmath.* Gói
này định nghĩa một số lớp Tuple như là các lớp trừu tượng. Rất nhìều các
lớp hữu ích thừa kế từ các lớp này. Dưới đây là hình 2-9 cây thừa kế.
http://tailieuhay.com 268
Lập trình đồ họa trên Java 2D và 3D
Mỗi đỉnh của một đối tượng quan sát có thể chỉ ra tới 4 đối tượng
trong javax.vecmath đại diện cho tọa độ, màu bề mặt bình thường và bề
mặt tọa độ. Các lớp thường được sử dụng:
Point* (for coordinates)
Color* (for colors)
Vector* (for surface normals)
TexCoord* (for texture coordinates, see Chapter 7)
Tuple2f Constructors
Chú ý rằng tọa độ (Point* object) là cần thiết để địa chỉ mỗi đỉnh.
Các dữ liệu khác là tùy chọn ,tùy thuộc vào các hình cơ bản được dựng
hình như thế nào. Ví dụ như một màu có thể được định nghĩa tại mỗi đỉnh
và các màu của các hình cơ bản là được thêm vào giữu các màu tại các
đỉnh. Nếu ánh ánh sáng được thiết lập, bề mặt bình thường (Vertor*
object) là cần thiết. Nếu bề mặt ánh xạ được thiết lập thì tọa độ bề mặt
cũng cần thiết vậy.
Tât cả các lớp cần thiết được trình bày bên dưới đây.
Tuple2f Constructors
Package: javax.vecmath
Các lớp Tuple* thường không được sử dụng trực tiếp trong chương trình
Java 3D nhưng cung cấp nền tảng cho Point*, Color*, Vector*,
TexCoord*. Ví dụ như Tuple2f cung cấp cơ sở cho Point2f, Color2f, và
TexCoord2f. Các hàm khởi tạo dưới đây đều đúng với các lớp con tương
tụ như Tuple3f và Tuple4f.
Tuple2f()
Khởi tạo và thiết lập đối tượng Tuple với tọa độ (0,0).
Tuple2f(float x, float y)
http://tailieuhay.com 269
Lập trình đồ họa trên Java 2D và 3D
Khởi tạo và thiết lập đối tượng Tuple với tọa độ (x,y).
Tuple2f(float t[])
Khởi tạo và thiết lập đối tượng Tuple từ một mảng đặc biệt.
Tuple2f(Tuple2f t)
Khởi tạo và thiết lập đối tượng Tuple từ dữ liệu của một Tuple khác
Tuple2f(Tuple2d t)
Khởi tạo và thiết lập đối tượng Tuple từ dữ liệu của một Tuple khác
Tuple2f Methods (partial list)
Package: javax.vecmath
Các lớp Tuple* thường không được sử dụng trực tiếp trong chương trình
Java 3D nhưng cung cấp nền tảng cho Point*, Color*, Vector*,
TexCoord*. Ví dụ như Tuple2f cung cấp cơ sở cho Point2f, Color2f, và
TexCoord2f. Các hàm khởi tạo dưới đây đều đúng với các lớp con tương
tụ như Tuple3f và Tuple4f. Các phương thức của chúng cũng tương tự
như vậy.
void set(float x, float y)
void set(float t[])
Lập giá trị của tuple này từ một giá trị định trước.
boolean equals(Tuple2f t1)
Trả về giá trị true nêu trong Tuple t1 bằng với giá trị sẵn có của tuple.
final void add(Tuple2f t1)
Lập giá trị của tuple này tới vertor tổng của nó và Tuple t1.
void add(Tuple2f t1, Tuple2f t2)
Lập giá trị của tuple này tới vertor tổng của nó và Tuple t1 và t2.
void sub(Tuple2f t1, Tuple2f t2)
http://tailieuhay.com 270
Lập trình đồ họa trên Java 2D và 3D
Lập giá trị của tuple này tới vertor khác của t1 và t2 (this = t1 - t2).
void sub(Tuple2f t1)
Lập giá trị của tuple này tới vertor khác của nó và t1 (this = this - t1).
void negate()
Loại bỏ giá trị của một vertor.
void negate(Tuple2f t1)
Lập giá trị cho tuple sau khi loại bỏ giá trị của nó
void absolute()
Đổi tất cả thành phần của tuple này thành giá trị tuyệt đối.
void absolute(Tuple2f t)
Lập giá trị của các thành phần thành giá trị tuyệt đối và ghi vào tuple.
2.4.1 Point Classes
Đối tượng Point* thường được đại diện cho tọa độ của một đỉnh,
chẳng hạn như một vạch quét ảnh, một điểm nguồn sáng, nguồn âm thanh
và các dữ liệu điểm khác. Hàm tạo cho lớp Point* giống như hàm tạo của
Tuple* ngoại trừ chúng trả về đối tượng Point*.
Point3f Methods (partial list)
Package: javax.vecmath
Lớp Point* được thừa kế từ lớp Tuple*. Mỗi instance của lớp Tuple* đại
diện cho một điểm đơn trong 2, 3 hoặc 4 không gian. Thêm vào các
phương thức của Tuple*, lớp Point* có thêm các phương thức riêng của
nó, được chỉ ra dưới đây.
float distance(Point3f p1)
Trả về khoảng cách giữa điểm này và điểm p1.
http://tailieuhay.com 271
Lập trình đồ họa trên Java 2D và 3D
float distanceSquared(Point3f p1)
Trả về khoảng cách bình phương giữu 2 điểm p và p1.
float distanceL1(Point3f p1)
Trả về khoảng cách L1 (Manhattan) giữa điểm này và điểm p1. Khoảng
cách L1 là:
abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2)
2.4.2 Color Classes
Đối tượng lớp màu đại diện cho một màu, có thể là một đỉnh, thuộc
tính của chất liệu, sương mù hoặc các đối tượng quan sát khác. Các màu
được chỉ ra hoặc là Color3* hoặc Color4* kiểu dữ liệu thường là kiểu
thực. Color3* xác định màu thông qua 3 màu đỏ, xanh da trời và xanh
nước biển.Giá trị của màu là từ 0 đến 255, đối với giá trị alpha là từ 0.0
đến 1.0. Đối với đối tượng Color4* có thêm giá trị về độ sâu. Khi giá trị
alpha bằng 1 thì màu hiện nguyên vẹn. Giá trị của màu là kiểu byte có giá
trị [-128,127] tuy nhiên Java vẫn xử lí giá trị màu [0,255].
Ví dụ về một lớp màu:
import javax.vecmath.*;
class ColorConstants{
public static final Color3f red = new
Color3f(1.0f,0.0f,0.0f);
public static final Color3f green = new
Color3f(0.0f,1.0f,0.0f);
public static final Color3f blue = new
Color3f(0.0f,0.0f,1.0f);
http://tailieuhay.com 272
Lập trình đồ họa trên Java 2D và 3D
public static final Color3f yellow = new
Color3f(1.0f,1.0f,0.0f);
public static final Color3f cyan = new
Color3f(0.0f,1.0f,1.0f);
public static final Color3f magenta = new
Color3f(1.0f,0.0f,1.0f);
public static final Color3f white = new
Color3f(1.0f,1.0f,1.0f);
public static final Color3f black = new
Color3f(0.0f,0.0f,0.0f);
}
Ta có thể thấy hàm tạo của lớp Color* giống như lớp Tuple*, ngoại
trừ là nó trả về đối tượng Color*. Lớp này chỉ có một hàm khởi tạo và 2
phương thức thêm vào so với lớp cha của nó Tuple*.
Color* Constructors (partial list)
Package: javax.vecmath
Mỗi instance trong lớp Color* đại diện cho một màu đơn trong 3 thành
phần đỏ, xanh lá cây và xanh nước biển (RGB), hoặc một trong bốn thành
phần 3 màu và thêm độ alpha (RGBA). Giá trị alpha bằng 0 là trong suốt
còn bằng 1 là hiện nguyên bản.
Color*(Color color) <new in 1.2>
Tạo đối tượng Java 3D Color*() (Color3b, Color3f, Color4b, Color4f)
sử dụng một đối tượng AWT Color. Khi khởi tạo đối tượng Color4* sử
dụng đối tượng AWT Color giá trị alpha được thiết lập bằng 1.
http://tailieuhay.com 273
Lập trình đồ họa trên Java 2D và 3D
Color* Methods
Package: javax.vecmath
Lớp Color* (Color3b, Color3f, Color4b, Color4f) thừa kế từ lớp Tuple*.
Mỗi instance của lớp này đại điện cho một màu trong 3 (RGB) hoặc 4
(RGBA) thành phần. Dưới đây là một vài phương thức trong Color3* và
Color4*.
void set(Color color) <new in 1.2>
Lập màu sử dụng mầu từ đối tượng AWT Color
Color get() <new in 1.2>
Lấy một màu coi là một màu của đối tượng AWT Color.
2.4.3 Vector Classes
Vector* objects often represent surface normals at vertices although
they can also represent the direction of a light source or sound source.
Again, the constructors for Vector* classes are similar to the Tuple*
constructors. However, Vector* objects add many methods that are not
found in the Tuple* classes.
Đối tượng Vertor* đại diện cho bề mặt bình thường tại các định dù
chúng cũng có thể đại diện cho hướng của một nguồn sáng hoặc nguồn
âm thanh. Một lần nữa ta có thể thấy các hàm tạo của Vertor* cũng tương
tự như Tuple*.
Vector3f Methods (partial list)
Package: javax.vecmath
http://tailieuhay.com 274
Lập trình đồ họa trên Java 2D và 3D
Lớp Vector* thừa kế từ Tuple*. Mỗi instances của lớp Vector* đại diện
cho một đỉnh vertor trong không gian 1,2,3,4 chiều. Ngoài ra nó còn có
thêm những phương thức như dưới đây.
float length()
Trả về độ dài của một vertor
float lengthSquared()
Trả về giá trị bình phương độ dài của một vertor.
void cross(Vector3f v1, Vector3f v2)
Lập một vertor trở thành vertor pháp tuyến của 2 vertor v1 và v2.
float dot(Vector3f v1)
Tính toán và trả về tích số điểm của product hiện tại và vertor v1.
void normalize()
Bình thường hóa vertor hiện tại
void normalize(Vector3f v1)
Lập giá trị của vertor này với giá trị của vertor v1 được bình thường hóa.
float angle(Vector3f v1)
Trả về góc radians giữa vertor hiện tại với vertor tham số, giá trị này được
rằng buộc trong khoảng [0,PI].
2.4.4 TexCoord Classes
Chỉ có 2 lớp TexCoord* được sử dụng như là một tập các kết cấu bề
mặt tọa độ tại một đỉnh, là TexCoord2f và TexCoord3f. Với TexCoord2f
có một cặp tọa độ là (s, t), với TexCoord3f thì có 3 tọa độ là (s, t, r). Hàm
tạo của lớp này cũng tương tự như lớp Tuple* và không có thêm phương
thức nào so với lớp cha của nó.
http://tailieuhay.com 275
Lập trình đồ họa trên Java 2D và 3D
2.5 Các lớp hình học
Trong đồ họa 3D, mọi thứ từ hình tam giác đơn giản đến hình phức
tạp như một chiếc máy bay đều được mô hình hóa và dựng dưới dạng dữ
liệu theo đỉnh. Trong Java 3D mỗi đối tượng Shape3D có thể gọi phương
thức setGeometry() của nó để tham chiếu đến một hoặc chỉ một đối tượng
Geometry. Chính xác hơn Geometry là lớp trừu tượng, cho nên một đối
tượng tham chiếu là một instance của lớp con của Geometry.
Các lớp con của Geometry có những dạng sau:
1. Non-indexed vertex-based Geometry (mỗi khi đối tượng quan sát
được dựng các đỉnh của nó chỉ được sử dụng một lần)
2. Indexed vertex-based Geometry (mỗi khi đối tượng quan sát được
dựng các đỉnh của nó được sử dụng nhiều lần)
Các đối tượng quan sát khác (Các lớp Geometry, Text3D, và
CompressedGeometry)
Phần này chỉ nói về 2 dạng trên. Cây thừa kế được hiển thị dưới hình 2-10
http://tailieuhay.com 276
Lập trình đồ họa trên Java 2D và 3D
2.5.1 GeometryArray Class
Như cái tên của lớp này cho bạn hình dung lớp con này của Geometry
được sử dụng để định nghĩa điểm đường và hình đa giác điền đầy. Những
thành phần nguyên tố dựa trên điểm này là lớp con của của lớp trừu tượng
GeometryArray, chỉ ra một mảng chứa các dữ liệu về đỉnh. Ví dụ như
một đối tượng dùng để chỉ một tam giác, 3 thành phần được định nghĩa,
mỗi thành phần cho mỗi đỉnh. Với mỗi thành phần của mảng này duy trì
một vị trí tọa độ cho đỉnh của nó (có thể định nghĩa bằng Point* với dữ
liệu tương tự) . Ngoài định ra tọa độ thì các giá trị này có thể định nghĩa
màu, bề mặt bình thường hoặc texture. Vì vậy những mảng nầy chứa tọa
độ, màu, bề mặt thường, và texture, dưới dạng dữ liệu mảng.
Có 3 bước trong vòng đời của một đối tượng GeometryArray
1. Tạo một đối tượng rỗng
2. Điền đầy đối tượng với dữ liệu
3. Đồng hóa (tham chiếu) đối tượng từ (1 hoặc nhiều) đối tượng
Shape3D.
Bước 1: Tạo một đối tượng GeometryArray rỗng
Khi một đối tượng GeometryArray vừa được khởi tạo thì cần thiết
phải định nghĩa 2 thứ
Số đỉnh, hay số thành phần cần thiết
Định dạng của dữ liệu (tọa độ, màu, bề mặt thường, và texture) được
lưu tại mỗi đỉnh. Còn được gọi là “vertex format” (định dạng đỉnh).
GeometryArray Constructor
GeometryArray(int vertexCount, int vertexFormat)
Hàm tạo này tạo đối tượng GeometryArray rỗng với những số đỉnh và
định dạng đỉnh cho trước. Một trong những cờ riêng là các bitwise “OR”
http://tailieuhay.com 277
Lập trình đồ họa trên Java 2D và 3D
hợp với nhau để mô tả dữ liệu mỗi đỉnh. Những giá trị cờ để định dạng
các đỉnh là:
COORDINATES: Chỉ ra mảng các đỉnh chứa tọa độ. Bit này buộc phải
lập.
NORMALS: Chỉ ra mảng đỉnh chứa bề mặt thường.
COLOR_3: Chỉ ra mảng đỉnh chứa màu (không có thành phần trong suốt)
COLOR_4: Chỉ ra mảng đỉnh chứa màu (có thành phần trong suốt)
TEXTURE_COORDINATE_2: Chỉ ra mảng đỉnh chứa 2D texture
coordinates.
TEXTURE_COORDINATE_3: Chỉ ra mảng đỉnh chứa 3D texture
coordinates.
Với mỗi cờ định dạng được thiết lâp sẽ có một mảng tương ứng tạo trong
đối tượng GeometryArray. Mỗi mảng này là số đỉnh (vertexCount) về
kích cỡ.
Vì lớp GeometryArray là lớp trừu tượng nên ta chỉ gọi phương thức
thiết lập cho lớp con của nó như LineArray.
Chú ý lớp Axis trong AxisApp.java là khác với lớp Axis chúng ta tự
định nghĩa trong ví dụ này
Bước 2: Điền đầy dữ liệu vào đối tượng GeometryArray rỗng
Sau khi khởi tạo đối tượng GeometryArray, đăng kí dữ liệu cho
mảng tương ứng với tạo định dạng của các đỉnh. Có thể làm việc này trên
mỗi đỉnh hoặc sử dụng mảng để đăng kí dữ liệu cho nhiều đỉnh chỉ với
một lời gọi phương thức . Các phương thức sẵn có sau:
GeometryArray Methods (partial list)
http://tailieuhay.com 278
Lập trình đồ họa trên Java 2D và 3D
GeometryArray là lớp trừu tượng cho PointArray, LineArray,
TriangleArray, QuadArray,
GeometryStripArray, và IndexedGeometryArray.
void setCoordinate(int index, float coordinate[])
void setCoordinate(int index, double coordinate[])
void setCoordinate(int index, Point* coordinate)
Lập tọa độ tương ứng với đỉnh với mỗi đỉnh được định nghĩa là một chỉ
mục cho đối tượng này. void setCoordinates(int index, float
coordinates[])
void setCoordinates(int index, double coordinates[])
void setCoordinates(int index, Point* coordinates[])
Lập các tọa độ tương ứng với đỉnh với các đỉnh được định nghĩa là chỉ
mục cho đối tượng này.
void setColor(int index, float color[])
void setColor(int index, byte color[])
void setColor(int index, Color* color)
Lập màu tương ứng với đỉnh với mỗi đỉnh được định nghĩa là một chỉ
mục cho đối tượng này. void setColors(int index, float colors[])
void setColors(int index, byte colors[])
void setColors(int index, Color* colors[])
Lập các màu tương ứng với các đỉnh ,với mỗi đỉnh được định nghĩa là
một chỉ mục cho đối tượng này.
void setNormal(int index, float normal[])
void setNormal(int index, Vector* normal)
Lập trực giao tương ứng với mỗi đỉnh tại vị trí chỉ mục được chỉ ra cho
đối tượng này.
void setNormals(int index, float normals[])
void setNormals(int index, Vector* normals[])
http://tailieuhay.com 279
Lập trình đồ họa trên Java 2D và 3D
Lập các trực giao tương ứng với các đỉnh tại vị trí chỉ mục được chỉ ra
cho đối tượng này.
void setTextureCoordinate(int texCoordSet, int index, float texCoord[])
void setTextureCoordinate(int texCoordSet, int index, TexCoord*
coordinate)
Lập texture coordinate ứng với mỗi đỉnh tại vị trí chỉ mục cho trước cho
một tập texture coordinate của đối tượng.
GeometryArray Methods (partial list, continued)
void setTextureCoordinates(int texCoordSet, int index, <new in 1.2>
float texCoords[])
void setTextureCoordinates(int texCoordSet, int index, <new in 1.2>
TexCoord* texCoords[])
Lập các texture coordinate ứng với các đỉnh tại vị trí chỉ mục cho trước
cho một tập texture coordinate của đối tượng.
void setInitialVertexIndex(int initialVertexIndex) <new in 1.2>
Lập chỉ mục cho đỉnh ban đầu với đối tượng GeometryArray. Cho phép
một vài đỉnh có thể bỏ qua trong việc dựng hình, và các hoạt động khác.
void setValidVertexCount(int validVertexCount) <new in 1.2>
Lạp các giá trị tính toán đỉnh đúng cho đối tượng GeometryArray.
Cho phép một vài dữ liệu đỉnh có thể bỏ qua khi dựng hình, chọn lọc và
các hoạt động khác.
Đoạn mã 2-5 chỉ ra trường hợp sử dụng phương thức của
GeometryArray để lưu giữ tạo độ và giá trị màu trong mảng LineArray.
Đối tượng trục X chỉ gọi phương thức setCoordinate() để lưu trữ dữ liệu
tọa độ. Đối tượng trục Y gọi cả 2 phương thức setColor() và
setCoordinate() để nạp giá trị màu RGB và giá trị tọa độ. Đối tượng trục
Z thì gọi 10 lần phương thức setCoordinate() cho mỗi đỉnh và gọi
setColors() một lần để nạp cho cả 10 đỉnh với 1 phương thức.
http://tailieuhay.com 280
Lập trình đồ họa trên Java 2D và 3D
// //////////////////////////////////////
////
//
// create axis subgraph
//
public Axis() {
axisBG = new BranchGroup();
// create line for X axis
LineArray axisXLines = new
LineArray(2, LineArray.COORDINATES);
axisBG.addChild(new
Shape3D(axisXLines));
axisXLines.setCoordinate(0, new
Point3f(-1.0f, 0.0f, 0.0f));
axisXLines.setCoordinate(1, new
Point3f(1.0f, 0.0f, 0.0f));
Color3f red = new Color3f(1.0f,
0.0f, 0.0f);
Color3f green = new Color3f(0.0f,
1.0f, 0.0f);
Color3f blue = new Color3f(0.0f,
0.0f, 1.0f);
// create line for Y axis
http://tailieuhay.com 281
Lập trình đồ họa trên Java 2D và 3D
LineArray axisYLines = new
LineArray(2, LineArray.COORDINATES
| LineArray.COLOR_3);
axisBG.addChild(new
Shape3D(axisYLines));
axisYLines.setCoordinate(0, new
Point3f(0.0f, -1.0f, 0.0f));
axisYLines.setCoordinate(1, new
Point3f(0.0f, 1.0f, 0.0f));
axisYLines.setColor(0, green);
axisYLines.setColor(1, blue);
// create line for Z axis
Point3f z1 = new Point3f(0.0f, 0.0f,
-1.0f);
Point3f z2 = new Point3f(0.0f, 0.0f,
1.0f);
LineArray axisZLines = new
LineArray(10, LineArray.COORDINATES
| LineArray.COLOR_3);
axisBG.addChild(new
Shape3D(axisZLines));
axisZLines.setCoordinate(0, z1);
axisZLines.setCoordinate(1, z2);
axisZLines.setCoordinate(2, z2);
http://tailieuhay.com 282
Lập trình đồ họa trên Java 2D và 3D
axisZLines.setCoordinate(3, new
Point3f(0.1f, 0.1f, 0.9f));
axisZLines.setCoordinate(4, z2);
axisZLines.setCoordinate(5, new
Point3f(-0.1f, 0.1f, 0.9f));
axisZLines.setCoordinate(6, z2);
axisZLines.setCoordinate(7, new
Point3f(0.1f, -0.1f, 0.9f));
axisZLines.setCoordinate(8, z2);
axisZLines.setCoordinate(9, new
Point3f(-0.1f, -0.1f, 0.9f));
Color3f colors[] = new Color3f[9];
colors[0] = new Color3f(0.0f, 1.0f,
1.0f);
for (int v = 0; v < 9; v++) {
colors[v] = red;
}
axisZLines.setColors(1, colors);
} // end of axis constructor
Màu mặc định cho các đỉnh của một đối tượng mảng
GeometryArray là trắng, nếu cả COLOR_3 và COLOR_4 không được
định nghĩa. Khi các đường hoặc đa giác đầy được dựng với các màu khác
nhau tại mỗi đỉnh thì các màu sẽ mịn dần giữa các đỉnh sử dụng phép
đánh bóng Gouraud.
http://tailieuhay.com 283
Lập trình đồ họa trên Java 2D và 3D
Bước 3: Tạo đối tượng Shape3D tham chiếu đến đối tượng
GeometryArray
Đoạn mã dưới đây chỉ ra cách làm thế nào để đối tượng Shape3D
tham chiếu đến đối tượng GeometryArray. Đối tượng Shape3D được
thêm vào một BranchGroup sẽ được thêm vào ở nơi nào đó trên đồ thị
khung cảnh. (Shape3D là lớp con của Node, vì thế Shape3D có thể thêm
vào thành con của một đồ thị khung cảnh )
Đồ thị khung cảnh được chỉ ra ở dưới đây:
2.5.2 Subclasses of GeometryArray
Như đã nói ở phần trên do GeometryArray là lớp trừu tượng là lớp
cha của rất nhiều lớp con hữu dụng, chẳng hạn như LineArray. Hình 1-2
cho thấy cây thừa kế đối với lớp GeometryArray và các lớp con của nó.
Lí do tồn tại của các lớp con này là làm sao để trình dựng hình của Java
3D có thể quyết định dựng đối với các đỉnh của các lớp đó.
http://tailieuhay.com 284
Lập trình đồ họa trên Java 2D và 3D
Hình 2-13 chỉ ra một ví du về các lớp con của GeometryArray gồm:
PointArray, LineArray, TriangleArray, và QuadArray (các lớp này
không phải là lớp con của GeometryStripArray). Trong hình này, các
tập bên trái nhất của các đỉnh chỉ ra 3 điểm đỉnh dựng thành 6 điểm, 3
đường, hoặc 2 tam giác. Hình thứ 4 chỉ ra 4 đỉnh định nghĩa một tứ giác.
Chú ý rằng các định này không dùng chung: mỗi đường hoặc một đa giác
đầy được dựng độc lập với nhau.
GeometryArray Subclass Constructors
Tạo một đối tượng rỗng với số đỉnh và định dạng đỉnh cho trước.
PointArray(int vertexCount, int vertexFormat)
LineArray(int vertexCount, int vertexFormat)
TriangleArray(int vertexCount, int vertexFormat)
QuadArray(int vertexCount, int vertexFormat)
http://tailieuhay.com 285
Lập trình đồ họa trên Java 2D và 3D
Để tìm hiểu cách sử dụng hàm tạo và phương thức xem lại đoạn mã 2-
4 và 2-5,2-6 sử dụng đối tượng LineArray. Nếu bạn đang dựng một hình
tứ giác cẩn thận với các đỉnh có thể tạo thành hình lõm, tự cắt nhau hoặc
không phẳng. Nếu xảy ra, chúng không thể dựng đúng được.
2.5.3 Subclasses of GeometryStripArray
Phần trước mô tả 4 lớp con của GeometryArray, không cho phép sử
dụng lại các đỉnh, tuy nhiên có một vài trường hợp ta cần sử dụng lại các
đỉnh, để cho kết quả dựng hình tốt hơn.
Lớp GeometryStripArray là lớp trừu tượng từ đó mỗi thực thể hình
học cơ bản (để ghép tạo đường và bề mặt ) thừa kế.
GeometryStripArray là lớp cha của LineStripArray,
TriangleStripArray và TriangleFanArray. Ta có hình 2-14 chỉ ra một
instance của một dạng các đỉnh được sử dụng lại.
Lớp GeometryStripArray có hàm tạo khác với lớp GeometryArray.
Hàm tạo của nó có 3 tham số, một mảng cách đỉnh tính trên mỗi mảnh
cho phép một đối tượng có thể duy trì nhiều mảnh.
GeometryStripArray có 2 phương thức thường sử dụng đến là
getNumStrips() và getStripVertexCounts().
GeometryStripArray Subclass Constructors
http://tailieuhay.com 286
Lập trình đồ họa trên Java 2D và 3D
Tạo một đối tượng rỗng với giá trị các đỉnh và định dạng các đỉnh và một
mảng tính toán các đỉnh qua các mảnh. Định dạng là một hay nhiều các
bit cờ “OR” để mô tả cho mỗi dữ liệu đỉnh. Định dạng các cờ là giống
nhau như đã định nghĩa trong lớp GeometryArray. Nhiều mảnh cùng
một lúc cũng được hỗ trợ. Tổng các tính toán đỉnh cho tất cả các mảnh
phải bằng với tổng số các đỉnh
LineStripArray(int vtxCount, int vertexFormat, int stripVertexCounts[])
TriangleStripArray(int vtxCount, int vertexFormat, int
stripVertexCounts[])
TriangleFanArray(int vtxCount, int vertexFormat, int
stripVertexCounts[])
Chú ý rằng Java 3D không hỗ trợ các hình cơ bản đầy với nhiều hơn 4
mặt. Người lập trình phải có trách nhiệm trong việc sử dụng kĩ thuật tách
để tách hình phức tạp ra thành nhiều các đối tượng của Java 3D như mảng
tam giác hoặc hình quạt.
Triangulator Class
Package: com.sun.j3d.utils.Geometry
Sử dụng để chuyển các đa giác hình học không có dạng tam giác về các
tam giác để có thể dựng hình bằng Java 3D. Các đa giác phải là lồi, cùng
nằm trên một mặt phẳng các cạnh không giao nhau.
Triangulator Constructor Summary
Triangulator()
Tạo một đối tượng tam giác.
Triangulator Method Summary
void triangulate(GeometryInfo ginfo)
http://tailieuhay.com 287
Lập trình đồ họa trên Java 2D và 3D
Chương trình con này chuyển đối tượng GeometryInfo từ dạng cơ bản
POLYGON_ARRAY thành dạng TRIANGLE_ARRAY sử dụng kĩ thuật
tách đa giác
Tham số:
ginfo - com.sun.j3d.utils.Geometry.GeometryInfo to be triangulated.
Ví dụ về cách sử dụng: TRIANGLE_ARRAY
Triangulator tr = new Triangulator();
tr.triangulate(ginfo); // ginfo contains the Geometry
shape.setGeometry(ginfo.getGeometryArray()); // shape is a Shape3D
Yo-yo Code Demonstrates TriangleFanArray
Đối tượng Yoyo trong chương trình YoyoApp.java schỉ ra cách sử dụng
đối tượng TriangleFanArray để mô hình hóa con yo-yo
Hình 2-15 chỉ 3 hình dựng của TriangleFanArray.
Trong đoạn mã 2-7, phương thức yoyoGeometry()tạo và trả về đối tượng
TriangleFanArray mong muốn.
http://tailieuhay.com 288
Lập trình đồ họa trên Java 2D và 3D
Dòng 15-18 tính toán tâm điểm cho 4 hình nón. Mỗi hình nón có 18 đỉnh
được tính toán ở dòng 20-28. Dòng 30-32 tạo một đối tượng
TriangleFanArray và dòng 34 là nơi để tính toán dữ liệu tọa độ (từ dòng
15-28) để lưu đối tượng
1. private Geometry yoyoGeometry() {
2.
3. TriangleFanArray tfa;
4. int N = 17;
5. int totalN = 4*(N+1);
6. Point3f coords[] = new Point3f[totalN];
7. int stripCounts[] = {N+1, N+1, N+1, N+1};
8. float r = 0.6f;
9. float w = 0.4f;
10. int n;
11. double a;
12. float x, y;
13.
14. // set the central points for four triangle fan strips
15. coords[0*(N+1)] = new Point3f(0.0f, 0.0f, w);
16. coords[1*(N+1)] = new Point3f(0.0f, 0.0f, 0.0f);
17. coords[2*(N+1)] = new Point3f(0.0f, 0.0f, 0.0f);
18. coords[3*(N+1)] = new Point3f(0.0f, 0.0f, -w);
19.
20. for (a = 0,n = 0; n < N; a = 2.0*Math.PI/(N-1) * ++n){
21. x = (float) (r * Math.cos(a));
22. y = (float) (r * Math.sin(a));
23.
24. coords[0*(N+1)+N-n] = new Point3f(x, y, w);
25. coords[1*(N+1)+n+1] = new Point3f(x, y, w);
http://tailieuhay.com 289
Lập trình đồ họa trên Java 2D và 3D
26. coords[2*(N+1)+N-n] = new Point3f(x, y, -w);
27. coords[3*(N+1)+n+1] = new Point3f(x, y, -w);
28. }
29.
30. tfa = new TriangleFanArray (totalN,
31. TriangleFanArray.COORDINATES,
32. stripCounts);
33.
34. tfa.setCoordinates(0, coords);
35.
36. return tfa;
37.} // end of method yoyoGeometry in class Yoyo
Code Fragment 2-7 yoyoGeometry() Method Creates TriangleFanArray
Object
Hình yo-yo trắng mới chỉ là điểm khởi đầu. Hình 2-16 chỉ ra một đối
tượng tương tự nhưng màu đã được thay đổi ở mỗi đỉnh. Phương thức
được yoyoGeometry()thay đổi. Dòng 23 qua 26, 36 tới 39, và dòng 46
chỉ định màu cho mỗi đỉnh.
1. private Geometry yoyoGeometry() {
2.
3. TriangleFanArray tfa;
4. int N = 17;
5. int totalN = 4*(N+1);
6. Point3f coords[] = new Point3f[totalN];
7. Color3f colors[] = new Color3f[totalN];
8. Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
http://tailieuhay.com 290
Lập trình đồ họa trên Java 2D và 3D
9. Color3f yellow = new Color3f(0.7f, 0.5f, 0.0f);
10. int stripCounts[] = {N+1, N+1, N+1, N+1};
11. float r = 0.6f;
12. float w = 0.4f;
13. int n;
14. double a;
15. float x, y;
16.
17. // set the central points for four triangle fan strips
18. coords[0*(N+1)] = new Point3f(0.0f, 0.0f, w);
19. coords[1*(N+1)] = new Point3f(0.0f, 0.0f, 0.0f);
20. coords[2*(N+1)] = new Point3f(0.0f, 0.0f, 0.0f);
21. coords[3*(N+1)] = new Point3f(0.0f, 0.0f, -w);
22.
23. colors[0*(N+1)] = red;
24. colors[1*(N+1)] = yellow;
25. colors[2*(N+1)] = yellow;
26. colors[3*(N+1)] = red;
27.
28. for(a = 0,n = 0; n < N; a = 2.0*Math.PI/(N-1) * ++n){
29. x = (float) (r * Math.cos(a));
30. y = (float) (r * Math.sin(a));
31. coords[0*(N+1)+n+1] = new Point3f(x, y, w);
32. coords[1*(N+1)+N-n] = new Point3f(x, y, w);
33. coords[2*(N+1)+n+1] = new Point3f(x, y, -w);
34. coords[3*(N+1)+N-n] = new Point3f(x, y, -w);
35.
36. colors[0*(N+1)+N-n] = red;
37. colors[1*(N+1)+n+1] = yellow;
http://tailieuhay.com 291
Lập trình đồ họa trên Java 2D và 3D
38. colors[2*(N+1)+N-n] = yellow;
39. colors[3*(N+1)+n+1] = red;
40. }
41. tfa = new TriangleFanArray (totalN,
42. TriangleFanArray.COORDINATES|TriangleFanArray.COLOR_3,
43. stripCounts);
44.
45. tfa.setCoordinates(0, coords);
46. tfa.setColors(0,colors);
47.
48. return tfa;
49. } // end of method yoyoGeometry in class Yoyo
Code Fragment 2-8 Modified yoyoGeometry() Method with Added
Colors
http://tailieuhay.com 292
Lập trình đồ họa trên Java 2D và 3D
2.5.4 Subclasses of IndexedGeometryArray
Các phần trước mô tả các lớp con của GeometryArray, cho thấy chỉ
lớp GeometryStripArray có thêm quyền hạn sử dụng lại các đỉnh. Ví dụ
để định nghĩa một hình lập phương mỗi đỉnh trong 8 đình của nó phải
được sử dụng bởi 3 hình vuông. Trong trường hợp xấu nhất chúng ta phải
định nghĩa 24 đỉnh mặc dù chỉ 8 đỉnh là đủ.
Đối tượng IndexedGeometryArray cung cấp một cấp bậc khác sao
cho có thể tránh việc sử dụng thừa. Với những mảng này cũng chứa tạo
độ, màu sắc, bề mặt thường và tạo độ bề mặt.
Tuy nhiên đối tượng IndexedGeometryArray cũng cần thêm các
mảng phụ gọi là mảng chỉ số chứa các chỉ mục đến mảng dữ liệu. Mảng
chỉ mục này có nhiều tham chiếu đến các đỉnh tương tự trong cùng một
mảng dữ liệu, từ đó cho phép sử dụng lại hiệu quả rõ ràng. Chúng ta có
thể xen ví dụ dưới đây.
Các lớp con của IndexedGeometryArray song song với các lớp con
của lớp GeometryArray. Cây thừa kế được vẽ dưới hình 2-18
http://tailieuhay.com 293
Lập trình đồ họa trên Java 2D và 3D
Hàm tạo cho IndexedGeometryArray,
IndexedGeometryStripArray cùng các lớp con của chúng dưới đây.
IndexedGeometryArray and Subclasses Constructors
Tạo một đối tượng rỗng với số đỉnh và định dạng đỉnh cho trước và số các
chỉ mục trong mảng này.
IndexedGeometryArray(int vertexCount, int vertexFormat, int
indexCount)
IndexedPointArray(int vertexCount, int vertexFormat, int indexCount)
IndexedLineArray(int vertexCount, int vertexFormat, int indexCount)
IndexedTriangleArray(int vertexCount, int vertexFormat, int indexCount)
IndexedQuadArray(int vertexCount, int vertexFormat, int indexCount)
IndexedGeometryStripArray and Subclasses Constructors
Tạo một đối tượng rỗng với số đỉnh và định dạng đỉnh cho trước và số các
chỉ mục trong mảng này và một mảng các tổng số các đỉnh mỗi mảnh.
IndexedGeometryStripArray(int vc, int vf, int ic, int
stripVertexCounts[])
IndexedLineStripArray(int vc, int vf, int ic, int stripVertexCounts[])
http://tailieuhay.com 294
Lập trình đồ họa trên Java 2D và 3D
IndexedTriangleStripArray(int vc, int vf, int ic, int stripVertexCounts[])
IndexedTriangleFanArray(int vc, int vf, int ic, int stripVertexCounts[])
Các phương thức của chúng cho đưới dây:
IndexedGeometryArray Methods (partial list)
void setCoordinateIndex(int index, int coordinateIndex)
Tạo các chỉ mục tọa độ tương ứng với các đỉnh tại vị trí chỉ mục cho đối
tượng
void setCoordinateIndices(int index, int coordinateIndices[])
Tạo các chỉ mục các tọa độ tương ứng với các đỉnh tại vị trí chỉ mục cho
đối tượng
void setColorIndex(int index, int colorIndex)
Lập chỉ mục màu tương ứng với đỉnh tại vị trí chỉ mục đã cho với đối
tượng.
void setColorIndices(int index, int colorIndices[])
Lập các chỉ mục màu tương ứng với các đỉnh tại vị trí chỉ mục đã cho với
đối tượng.
void setNormalIndex(int index, int normalIndex)
Lập chỉ mục bình thường tương ứng với đỉnh tại chỉ mục định trước cho
đối tượng.
void setNormalIndices(int index, int normalIndices[])
Lập các chỉ mục bình thường tương ứng với các đỉnh tại chỉ mục định
trước cho đối tượng.
void setTextureCoordinateIndex(int texCoordSet, int index, <new in 1.2>
int texCoordIndex)
Lập chỉ mục toạ độ tương ứng với đỉnh tại chỉ mục định trước cho đối
tượng.
http://tailieuhay.com 295
Lập trình đồ họa trên Java 2D và 3D
void setTextureCoordinateIndices(int texCoordSet, int index,
int texCoordIndices[])
Lập các chỉ mục toạ độ tương ứng với các đỉnh tại chỉ mục định trước cho
đối tượng.
2.5.5 Axis.java is an Example of IndexedGeometryArray
Ví dụ Axis về IndexedGeometryArray ta có định nghĩa 18 đỉnh và
30 chỉ mục cho 15 đường. Như vậy có 5 đường cho mỗi trục.
2.6 Appearance and Attributes
Đối tượng Shape3D có thể tham chiếu đến cả đối tượng Geometry và
Apperance. Như đã thảo nói ở phía trên trong phần 2.5, đối tượng
Geometry chỉ ra thông tin của mối đỉnh với một đốt tượng quan sát.
Thông tin mỗi đỉnh này có thể chỉ định ra màu của đối tượng. Dữ liệu
trong đối tượng Geometry thường không đủ để mô tả bề ngoài của một
bối tượng. Trong trường hợp đó rất cần thiết đối tượng Apperance.
Một đối tượng Appearance không chứa dữ liệu mô tả đối tượng quan sát
mà nó biết nơi nào có dữ liệu đó, do đó cách làm của nó là tham chiếu
đến một vài đối tượng khác như lớp con của NodeComponent .
http://tailieuhay.com 296
Lập trình đồ họa trên Java 2D và 3D
Một đối tượng Appearance có thể tham chiếu đến thuộc tính một vài đối
tượng lớp khác như:
PointAttributes
LineAttributes
PolygonAttributes
ColoringAttributes
TransparencyAttributes
RenderingAttributes
Material
TextureAttributes
Texture
TexCoordGeneration
Sáu thuộc tính được đề cập đến trong tài liệu này còn lại dành cho
chương 6 và chương 7.
Một đối tượng Appearance với các thuộc tính của đối tượng khác mà
nó tham chiếu đến gọi là một gói giao diện. Để tham chiếu đến nó dựa
trên phương thức với một cái tên chính xác. Ví dụ như tham chiếu đến đối
tượng ColoringAttributes nó sử dụng phương thức
Appearance.setColoringAttributes().
Trên đồ thị khung cảnh
http://tailieuhay.com 297
Lập trình đồ họa trên Java 2D và 3D
2.6.1 Appearance NodeComponent
Appearance Constructor
Hàm tạo này tạo đối tượng Appearance với mọi thành phần chiếu nhận
giá trị null. Các giá trị mặc định có thể đoán được: điểm và đoạn thẳng
được vẽ với kích thước và độ dài 1 pixel và không có có khử răng cưa,
màu mặc định là màu trắng, khả năng xuyên qua vô hiệu hóa.
Appearance()
2.6.2 Sharing NodeComponent Objects
Việc tham chiếu đến một vài đối tượng là hợp lệ và cũng cần thiết vì
thế nên chia sẻ cùng các đối tượng NodeComponent. Ví dụ trong hình 2-
21 2 đối tượng Shape3D chia sẻ cùng thành phần LineAttributes.
Việc chia sẽ này giúp cho việc dựng hình nhanh hơn, hiệu quả càng
cao.
http://tailieuhay.com 298
Lập trình đồ họa trên Java 2D và 3D
Tuy nhiên cần chú ý rằng một node không được có nhiều hơn một cha từ
đó NodeComponent có thể chia sẻ hay tham chiếu đến bởi nhiều đối
tượng khác.
2.6.3 Attribute Classes
PointAttributes
Đối tượng PointAttributes quản lí việc mỗi điểm cơ bản được dựng
hình như thế nào. Mặc định một đỉnh được dựng như một điểm, bạn có
thể dùng setPointSize() để làm cho điểm đó to ra tuy nhiên mặc định một
điểm to sẽ trông như một hình vuông, trừ phi bạn dùng
setPointAntialiasingEnable(). Lúc đó điểm vuông được làm tròn đi.
PointAttributes Constructors
PointAttributes()
Tạo một đối tượng thành phần và mô tả kích thước 1 pixel không dùng
khử răng cưa
PointAttributes(float pointSize, boolean state)
Tạo một đối tượng thành phần và mô tả kích thước 1 pixel dùng khử răng
cưa
PointAttributes Methods
void setPointSize(float pointSize)
Mô tả kích thước pixel của các điểm
void setPointAntialiasingEnable(boolean state)
Thiết lập hoặc bỏ thiết lập chống răng cưa. Thường làm nếu pointSize >=
1 pixel.
http://tailieuhay.com 299
Lập trình đồ họa trên Java 2D và 3D
LineAttributes
Đối tượng này thay đổi cách dựng các đường cơ bản theo 3 cách. Mặc
định đường được vẽ là nét liền, với độ rộng 1pixle không chống răng cửa.
Bạn có thể thay đổi điều này bằng cách sử dụng các phương thức
setLinePattern(), setLineWidth(), và setLineAntialiasingEnable().
Mẫu đường thẳng do người dùng tự định nghĩa
Một mẫu thường dược định nghĩa bằng một mặt nạ mẫu và một thành
phần quy mô.
Một giá trị 16 bit định nghĩa một mặt nạ mẫu. Mỗi bit trong 16 bit giá
trị định nghĩa khi nào 1 pixel trong mẫu được bật hay tắt (1/0). Sau khi cả
16 mẫu đều được sử dụng, thì mẫu được lặp lại. Bit 0 tương ứng với pixel
đầu tiên trong mẫu.
Ví dụ một mặt nạ của 0x00ff (0b0000000011111111) định nghĩa 8 pixel
mở sau đó là 8 pixel đóng.
Nhớ rằng,bit phóng đại bé nhất được sử dụng đầu tiên khi vẽ, nên
mẫu bit được đọc từ phải sang trái. Mặt nạ mẫu giá trị 0x0101 định nghĩa
một mẫu lặp của một pixel mở và 7pixel tắt. Mẫu này được lặp lại nhiều
lần tùy theo yêu cầu, mẫu khởi động lại trước mỗi đường mới của một
mảnh.
Các mẫu có thể mở rộng đến 240 pixel sử dụng nhân tố quy mô. Ví dụ
như quy mô của 3 x với một mặt nạ mẫu 0x001f tương đương với sản
sinh ra mẫu với 15 pixel mở theo bởi 33 pixel đóng. Khoảng cách đúng là
[1,15],giá trị bên ngoài khoảng này là không chấp nhận được.
LineAttributes Constructors
LineAttributes()
Tạo một đối tượng thành phần mô tả độ rộng 1 pixel, một đường thẳng
liền nét không khử răng cưa.
LineAttributes(float pointSize, int linePattern, boolean state)
http://tailieuhay.com 300
Lập trình đồ họa trên Java 2D và 3D
Tạo một đối tượng thành phần mô tả độ rộng 1 pixel cho một đường
thẳng, mẫu dùng để vẽ, có khử răng cưa.
LineAttributes Methods
void setLineWidth(float lineWidth)
Mô tả độ rộng pixel cho đường thẳng
void setLinePattern(int linePattern)
linePattern là một trong số các hằng sau:
PATTERN_SOLID (the default),
PATTERN_DASH, PATTERN_DOT, PATTERN_DASH_DOT, or
PATTERN_USER_DEFINED.
Mô tả làm sao một pixel của một đường được điền vào.
void setLineAntialiasingEnable(boolean state)
Bỏ hay có chống răng cưa với đường thẳng
void setPatternMask(int mask) <new in 1.2>
Lập một mặt nạ mẫu với một giá trị đặc biệt
void setPatternScaleFactor(int scaleFactor) <new in 1.2>
Sets the line pattern scale factor to the specified value.
Line Attributes Line Patterns
PATTERN_SOLID solid lines (no pattern). This is the default.
PATTERN_DASH dashed lines; ideally, a repeating pattern of 8 pixels
on and 8 pixels off.
PATTERN_DOT dotted lines; ideally, a repeating pattern of 1 pixel on
and 7 pixels off.
http://tailieuhay.com 301
Lập trình đồ họa trên Java 2D và 3D
PATTERN_DASH_DOT dashed-dotted lines; ideally, a repeating
pattern of 7 pixels on, 4 pixels
off, 1 pixel on, and 4 pixels off.
PATTERN_USER_DEFINED lines with a user-defined line pattern.
See "User-defined Line Patterns,"above.
PolygonAttributes
PolygonAttributes chi phối việc dựng hình của các thành phần cơ
bản đa giác theo 3 cách: đa giác bị phân tách như thế nào, nếu nó được
chọn lọc và khi nào thì độ sâu bù được chấp nhận. Mặc định các đa giác
đều là đa giác lồi tuy nhiên khi đa giác bị tách thì đa giác được vẽ lại
thành các khung (đường) hoặc chỉ các điểm tại các đỉnh. Phương thức
setCullFace() dùng để loại bỏ các đa giác đã được dựng. Nếu phương
thức này thiết lập hoặc CULL_FRONT hoặc CULL_BACK thì một nửa
số đa giác không được dựng.
Tùy theo sự hiệu quả của hệ thống dựng hình mà các đỉnh được dựng
cả là các dây khung và các đa giác lồi luôn được phân tách với giá trị độ
sâu chính xác. Kết quả là các đa giác và các dây khung có thể được dựng
ở độ sâu khác nhau, gây ra hiện tượng đường khâu. Hiện tương stitching
này là do độ sâu khác nhau nên các dây khung xuất hiện lúc ẩn lúc hiện
trên đa giác. Với 2 thuộc tính PolygonOffset và PolygonOffsetFactor về
giá trị độ sâu cho phép đa giác lồi có thể hướng khửu tay về phía khung
hình ảnh. setBackFaceNormalFlip()được sử dụng để dựng một đa giác lồi
sáng với cả 2 mặt của đa giác đều mờ đi.
PolygonAttributes Constructors
PolygonAttributes()
http://tailieuhay.com 302
Lập trình đồ họa trên Java 2D và 3D
Tạo đối tượng thành phần với giá trị mặc định của đa giác lồi không có
cắt bề mặt không có rìa đa giác.
PolygonAttributes(int polygonMode, int cullFace, float
polygonOffset)
Tạo đối tượng thành phần với giá trị cho trước của giác lồi
PolygonAttributes(int polygonMode, int cullFace, float
polygonOffset,
boolean backFaceNormalFlip)
Tạo đối tượng thành phần giống như các hàm tạo phía trước nhưng cũng
cho phép chỉ ra mặt phía trước và phía sau của đa giác như thế nào
PolygonAttributes(int polygonMode, int cullFace, float
polygonOffset, boolean backFaceNormalFlip, float
polygonOffsetFactor) <new in 1.2>
Tạo đối tượng PolygonAttributes với giá trị cho trước.
PolygonAttributes Methods
void setCullFace(int cullFace)
cullFace là CULL_FRONT, CULL_BACK, or CULL_NONE. Cull
(không dựng) trước mặt và mặt sau của các đa giác hoặc không tách đa
giác nào.
void setPolygonMode(int polygonMode)
polygonMode là: POLYGON_POINT, POLYGON_LINE, or
POLYGON_FILL. Dựng polygons trên points, lines, or filled polygons
(mặc định).
void setPolygonOffset(float polygonOffset)
polygonOffset là screen-space offset thêm vào để hiệu chỉnh giá trị độ sâu
của polygon primitives.
http://tailieuhay.com 303
Lập trình đồ họa trên Java 2D và 3D
void setPolygonOffsetFactor(float polygonOffsetFactor) <new in 1.2>
Lập polygon offset factor với giá trị cho trước.
void setBackFaceNormalFlip(boolean backFaceNormalFlip)
trong đó backFaceNormalFlip xác định khi nào đỉnh bình thường hoặc
mặt sau của đa giác cần khuất sáng. Khi cờ này được lập giá trị true mặt
sau bỏ lựa chọn mặt sau.
ColoringAttributes
Thuộc tính ColoringAttributes điều khiển chuyện tô màu. Phương
thức setColor() lập một màu bên trong trong đó tùy trường hợp mà để
màu đó vào. Thêm vao đó setShadeModel() xác định khi nào có khi cần
thêm ngang một màu vào.
ColoringAttributes Constructors
ColoringAttributes()
Tạo đối tượng thành phần sử sụng màu trắng cho màu bên trong và
SHADE_GOURAUD là mô hình đánh bóng.
ColoringAttributes(Color3f color, int shadeModel)
ColoringAttributes(float red, float green, float blue, int shadeModel)
shadeModel là một trong SHADE_GOURAUD, SHADE_FLAT,
FASTEST, or NICEST.
(trong hầu hết trường hợp, FASTEST là SHADE_FLAT, và NICEST là
SHADE_GOURAUD.)
ColoringAttributes Methods
void setColor(Color3f color)
void setColor(float red, float green, float blue)
cả 2 phương thức đều định nghĩa màu bên trong
void setShadeModel(int shadeModel)
http://tailieuhay.com 304
Lập trình đồ họa trên Java 2D và 3D
shadeModel là một trong các hằng: SHADE_GOURAUD,
SHADE_FLAT, FASTEST,
or NICEST.
TransparencyAttributes
Thuộc tính này quản lí độ trong suốt của bất cứ hình cơ bản nào.
setTransparency() định nghĩa giá trị trong suốt (bằng 1 là trong suốt hoàn
toàn, bằng 0.0 là không trong suốt)
TransparencyAttributes Constructors
TransparencyAttributes()
Tạo đối tượng thành phần với độ trong suốt lập ở chế độ NONE.
TransparencyAttributes(int tMode, float tVal)
Trong đó tMode là một trong những BLENDED, SCREEN_DOOR,
FASTEST, NICEST, hoặc NONE, và tVal định nghĩa tính mờ của đối
tượng (0.0 không trong suốt và 1.0, trong suốt hoàn toàn).
TransparencyAttributes(int tMode, float tVal, int srcBlendFunction,
int dstBlendFunction) <new in 1.2>
Tạo một đối tượng TransparencyAttributes với giá trị định trước
TransparencyAttributes Methods
void setTransparency(float tVal)
tVal định nghĩa tính mờ của đối tượng (0.0 không trong suốt và 1.0, trong
suốt hoàn toàn).
void setTransparencyMode(int tMode)
http://tailieuhay.com 305
Lập trình đồ họa trên Java 2D và 3D
tMode (one of BLENDED, SCREEN_DOOR, FASTEST, NICEST, or
NONE) chỉ ra nếu
có hoạt động làm trong suốt
void setDstBlendFunction(int blendFunction) <new in 1.2>
Lập địa chỉ chức năng pha trộn được sử dụng để trộn độ trong suốt và
chống răng cưa.
void setSrcBlendFunction(int blendFunction) <new in 1.2>
Lập tài nguyen hàm trộng sử dụng để trộn độ trong suốt và chống răng
cưa.
RenderingAttributes
RenderingAttributes điều khiển 2 hoạt động dựng hình trên từng
pixel: kiểm định độ sâu đệm, và kiểm tra alpha.
Hoạt động quét (Geometry) xác định xem việc dựng hình pixel ảnh
hướng đến màn ảnh thế nào. Mặc định là bỏ chọn Geometry thường được
sử dụng trong hầu hết các trường hợp
Độ sâu đệm là tập hợp các giá trị độ sâu của những pixel được dựng. Nó
được dùng đề xác định pixel được nhìn thấy hay bị khuất để chúng có thể
được dựng. Độ sâu đệm sử dụng khác khi dựng đối mờ và trong suốt. Kết
quả là đối tượng trong suốt không cập nhập giá trị độ sâu đêm không bình
thường. Có thể vô hiệu hóa hoặc dùng tính năng này đối với một đối
tượng thành phần RenderingAttributes. Việc vô hiệu hóa đảm bảo đối
tượng luôn luôn nhìn thấy, tuy nhiên mặc định là để nó enable.
RenderingAttributes Constructors
RenderingAttributes()
Tạo một đối tượng thành phần định nghĩa việc dựng trên pixel với việc
kích hoạt kiểm tra độ sâu đệm và vô hiệu hóa tính năng kiểm tra alpha.
http://tailieuhay.com 306
Lập trình đồ họa trên Java 2D và 3D
RenderingAttributes(boolean depthBufferEnable, boolean
depthBufferWriteEnable, float alphaTestValue, int
alphaTestFunction)
Trong đó depthBufferEnable bật tắt so sánh độ sâu đệm (kiểm tra độ sâu),
depthBufferWriteEnable bật và tắt để ghi vào depth buffer,
alphaTestValue được sử dụng để kiểm tra. Đối với các nguồn alpha đi vào
, and alphaTestFunction là một trong những ALWAYS, NEVER,
EQUAL, NOT_EQUAL, LESS, LESS_OR_EQUAL, GREATER, hoặc
GREATER_OR_EQUAL, chỉ rõ loại alpha test nào được kích hoạt. Tạo
một đối tượng thành phần định nghĩa việc dựng trên pixel cho so sanh độ
sâu đệm và kiểm tra alpha.
RenderingAttributes(boolean depthBufferEnable, boolean
depthBufferWriteEnable, float alphaTestValue, int
alphaTestFunction,
boolean visible, boolean ignoreVertexColors,
boolean GeometryOpEnable, int GeometryOp) <new in 1.2>
Tạo một đối tượng RenderingAttributes với giá trị cho trước.
RenderingAttributes Methods
void setDepthBufferEnable(boolean state)
turns on and off the depth buffer testing.
void setDepthBufferWriteEnable(boolean state)
turns on and off writing to the depth buffer.
void setAlphaTestValue(float value)
specifies the value to be used for testing against incoming source alpha
values.
void setAlphaTestFunction(int function)
http://tailieuhay.com 307
Lập trình đồ họa trên Java 2D và 3D
where function is one of ALWAYS, NEVER, EQUAL, NOT_EQUAL,
LESS, LESS_OR_EQUAL,
GREATER, or GREATER_OR_EQUAL, which denotes what type of
alpha test is active. If function is
ALWAYS (the default), then the alpha test is effectively disabled.
void setDepthBufferEnable(boolean state) <new in 1.2>
Enables or disables depth buffer mode for this RenderingAttributes
component object.
void setDepthBufferWriteEnable(boolean state) <new in 1.2>
Enables or disables writing the depth buffer for this object.
void setIgnoreVertexColors(boolean ignoreVertexColors) <new in
1.2>
Sets a flag that indicates whether vertex colors are ignored for this
RenderingAttributes object.
void setGeometryOp(int GeometryOp) <new in 1.2>
Sets the Geometry operation function for this RenderingAttributes
component object.
void setGeometryOpEnable(boolean GeometryOpEnable) <new in
1.2>
Sets the GeometryOp enable flag for this RenderingAttributes
component object.
void setVisible(boolean visible) <new in 1.2>
Sets the visibility flag for this RenderingAttributes component object.
Appearance Attribute Defaults
Hàm tạo Appearance khởi tạo đối tượng Appearance với các thuộc
tính tham chiếu đến các giá trị null. Bảng 2-1 là danh sách các giá trị mặc
định cho những thuộc tính tham chiếu đến giá trị null.
Attributes Class Parameter Default Value
http://tailieuhay.com 308
Lập trình đồ họa trên Java 2D và 3D
ColoringAttributes color
shade model
white (1, 1, 1)
SHADE_GOURAUD
LineAttributes line width
line pattern
line antialiasing enable
1.0
PATTERN_SOLID
false
PointAttributes point size
point antialiasing enable
1.0
false
PolygonAttributes cull face
backFaceNormalFlip
polygon mode
polygonOffset
polygonOffsetFactor
CULL_BACK
false
POLYGON_FILL
0.0
0.0
RenderingAttributes depthBufferEnable
depthBufferWriteEnable
alphaTestFunction
alphaTestValue
visible
ignoreVertexColors
GeometryOpEnable
GeometryOp
true
true
ALWAYS
0.0
true
false
false
ROP_COPY
TextureAttributes textureMode
textureBlendColor
transform
perspectiveCorrectionMod
e
REPLACE
black (0, 0, 0, 0)
identity
NICEST
null
http://tailieuhay.com 309
Lập trình đồ họa trên Java 2D và 3D
textureColorTable
TransparencyAttributes transparencyMode
transparencyValue
srcBlendFunction
dstBlendFunction
NONE
0.0
SRC_BLEND_ALPHA
BLEND_ONE_MINUS_ALPHA
2.6.4 Example: Back Face Culling
Đa giác có 2 mặt. Với nhiều đối tượng quan sát không chỉ một mặt
của đa giác cần được dựng. Để giảm công việc tính toán cần thiết phải
dựng bề mặt của đa diện, hệ thống dựng hình có thể chọn lọc những mặt
không cần thiết. Bề mặt trước của một đối tượng có thể là mặt cho các
đỉnh được định nghĩa theo thứ tự ngược chiều kim đồng hồ.
TwistStripApp.java tạo một đối tượng dải xoắn và quay nó quanh trục
y.
Khi dải xoắn quay các phần của nó xem như biến mất tuy nhiên
những mẩu biến mất có thể dễ dàng thấy ở hình 2-22. Thực tế chương
trình định nghĩa 2 đối tượng quan sát với cùng một hình. Một đối tượng
được dựng dưới dạng khung dây còn đối tượng còn lại dựng với bề mặt
liền. Qua đó khi quay chúng ta có thể quan sát được như vậy.
http://tailieuhay.com 310
Lập trình đồ họa trên Java 2D và 3D
Lí do có mất các đa giác là chế độ chọn lọc không chỉ ra, vì thế nó để
mặc định là CULL_BACK. Các tam giác của bề mặt biến mất khi phần
lưng của nó (phần sau) đối mặt với màn ảnh. Tính năng này cho phép hệ
thống dựng hình tránh không phải dựng phần bề mặt tam giác vốn không
cần thiết.
T uy nhiên trong một số trường hợp việc chọn lọc lại gây vấn đề, như
trong ví dụ TwistStripApp. Vấn đề có một cách giải quyết đơn giản đó là
tắt bỏ chế độ chọn lọc. Như đoạn mã trong hình 2-10:
public class TwistStripApp extends Applet {
// //////////////////////////////////////////
/////
//
// create Twist visual object
//
public class Twist extends Shape3D {
http://tailieuhay.com 311
Lập trình đồ họa trên Java 2D và 3D
// //////////////////////////////////////
////
//
// create twist subgraph
//
public Twist() {
this.setGeometry(createGeometry());
this.setAppearance(createAppearance());
} // end of twist constructor
Geometry createGeometry() {
TriangleStripArray twistStrip;
Color3f blue = new Color3f(0.0f,
0.0f, 1.0f);
// create triangle strip for twist
int N = 80;
int stripCounts[] = { N };
twistStrip = new TriangleStripArray(
N,
TriangleStripArray.COORDINATES |
TriangleStripArray.COLOR_3,
stripCounts);
double a;
http://tailieuhay.com 312
Lập trình đồ họa trên Java 2D và 3D
int v;
for (v = 0, a = 0.0; v < N; v += 2,
a = v * 2.0 * Math.PI / (N - 2)) {
twistStrip.setCoordinate(v, new
Point3d(0.7 * Math.sin(a) + 0.2
* Math.cos(a), 0.3 *
Math.sin(a), 0.7 * Math.cos(a)
+ 0.2 * Math.cos(a)));
twistStrip.setCoordinate(v + 1,
new Point3d(0.7 * Math.sin(a)
- 0.2 * Math.cos(a),
-0.3 * Math.sin(a), 0.7
* Math.cos(a) - 0.2 *
Math.cos(a)));
twistStrip.setColor(v, blue);
twistStrip.setColor(v + 1,
blue);
}
return twistStrip;
}
// create Appearance for Twist Strip
//
// this method creates the default
Appearance for the
// twist strip. The commented line of
code containting
http://tailieuhay.com 313
Lập trình đồ họa trên Java 2D và 3D
// the setCullFace will fix the problem
of half of the
// Twisted Strip disappearing.
Appearance createAppearance() {
Appearance twistAppear = new
Appearance();
PolygonAttributes polyAttrib = new
PolygonAttributes();
//
polyAttrib.setCullFace(PolygonAttributes.CULL_NON
E);
twistAppear.setPolygonAttributes(polyAttrib);
return twistAppear;
}
} // end of class Twist
// //////////////////////////////////////////
/////
//
// create scene graph branch group
//
public BranchGroup createSceneGraph() {
http://tailieuhay.com 314
Lập trình đồ họa trên Java 2D và 3D
BranchGroup contentRoot = new
BranchGroup();
// Create the transform group node and
initialize it to the
// identity. Add it to the root of the
subgraph.
TransformGroup objSpin = new
TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSF
ORM_WRITE);
contentRoot.addChild(objSpin);
Shape3D twist = new Twist();
objSpin.addChild(twist);
// Duplicate the twist strip geometry and
set the
// appearance of the new Shape3D object
to line mode
// without culling.
// Add the POLYGON_FILLED and
POLYGON_LINE strips
// in the scene graph at the same point.
// This will show the triangles of the
original Mobius strip that
// are clipped. The PolygonOffset is set
to prevent stitching.
http://tailieuhay.com 315
Lập trình đồ họa trên Java 2D và 3D
PolygonAttributes polyAttrib = new
PolygonAttributes();
polyAttrib.setCullFace(PolygonAttributes.CULL_NON
E);
polyAttrib.setPolygonMode(PolygonAttributes.POLYG
ON_LINE);
polyAttrib.setPolygonOffset(0.001f);
Appearance polyAppear = new Appearance();
polyAppear.setPolygonAttributes(polyAttrib);
objSpin.addChild(new
Shape3D(twist.getGeometry(), polyAppear));
Alpha rotationAlpha = new Alpha(-1,
16000);
RotationInterpolator rotator = new
RotationInterpolator(rotationAlpha,
objSpin);
// a bounding sphere specifies a region a
behavior is active
// create a sphere centered at the origin
with radius of 1
BoundingSphere bounds = new
BoundingSphere();
http://tailieuhay.com 316
Lập trình đồ họa trên Java 2D và 3D
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
// make background white
Background background = new
Background(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(bounds);
contentRoot.addChild(background);
// Let Java 3D perform optimizations on
this scene graph.
contentRoot.compile();
return contentRoot;
} // end of CreateSceneGraph method of
TwistStripApp
// Create a simple scene and attach it to the
virtual universe
public TwistStripApp() {
setLayout(new BorderLayout());
Canvas3D canvas3D = new Canvas3D(null);
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
// SimpleUniverse is a Convenience
Utility class
http://tailieuhay.com 317
Lập trình đồ họa trên Java 2D và 3D
SimpleUniverse simpleU = new
SimpleUniverse(canvas3D);
// This will move the ViewPlatform back a
bit so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalViewingTra
nsform();
simpleU.addBranchGraph(scene);
} // end of TwistStripApp constructor
// The following method allows this to be run
as an application
public static void main(String[] args) {
System.out.println("TwistStripApp - Java
3D API version 1.1");
System.out.print("See \"Getting Started
with the Java 3D API\"");
System.out.println(" (section 2.6)");
System.out.println("This program
demonstrates back face culling.");
System.out.print("In this program two
visual objects rotate, ");
http://tailieuhay.com 318
Lập trình đồ họa trên Java 2D và 3D
System.out.println("one wireframe and one
solid surface.");
System.out.print("The wire frame is
visible only when components");
System.out.println(" of the surface are
culled.");
Frame frame = new MainFrame(new
TwistStripApp(), 256, 256);
} // end of main method of TwistStripApp
} // end of class TwistStripApp
Trong hình 2-23 việc vô hiệu hóa chọn lọc bề mặt rõ ràng đã điền đầy
vùng bị vỡ. Bây giờ thì tất cả các đa giác đều được dựng dù hướng quay
của nó là gì chăng nữa.
http://tailieuhay.com 319
Lập trình đồ họa trên Java 2D và 3D
Phần mặt phía trước của một đa giác là mặt dùng để các đỉnh xuất
hiện theo chiều quay ngược kim đồng hồ. Điều này thường liên quan đến
“luật tay phải”. Luật này dùng để xác định phần mặt trước của một dải
hình học (chẳng hạn dải tam giác hoặc dải hình vuông thay thế cho mỗi
thành phần trong dải. Hình 2-24 chỉ ra một ví dụ sử dụng luật tay phải)
2.7 Bounds and Scope
Bound định nghĩa một không gian, một vùng cho mỗi nút. Bounds
được định nghĩa các đối tượng như BoundingSphere, BoundingBox,
BoundingPolytope. Để tiếp tục với ví dụ ánh sáng , mỗi nguồn sáng định
nghĩa một vùng ảnh hưởng gọi là vùng biên giới quét . Nếu bất kì thành
phần nào của một đối tượng quan sát giao với luồng sáng thì đối tượng sẽ
bị ảnh hưởng bởi luồng sáng
Phần về Bounds được đặt ở phần 1.9 mô tả mỗi đối tượng hành vi có
một vùng riêng. Một hành vi chỉ được kích hoạt khi biên giới của nó giao
với phần nhìn.
Scope chỉ ra một nhóm các đối tượng đồ thị khung cảnh bằng vị trí của
chúng trong đồ thị khung cảnh. Đặc biệt một Scope là một tập các đối
tượng Group (chừng hạn BranchGroup). Một node có thể chỉ ra các đối
http://tailieuhay.com 320
Lập trình đồ họa trên Java 2D và 3D
tượng đồ thị khung cảnh khác nhau khi chúng ảnh hưởng bởi một tầm
quan sát.
Trong khi Bounds và scope cung cấp các tính năng khác nhau nhưng
chúng lai hoạt động theo những cách khác nhau. Một vùng biên giới độc
lập với vị trí của một đối tượng trong đồ thị khung cảnh. Trong khi đó
một phạm vi độc lập với đối tượng quan sát trong môi trường ảo.Chúng
được sử dụng trong nhiều ứng dụng, thêm vào đó ánh sáng và các hành vi
được sử dụng, như sương mù, âm thanh sẽ được nói phần sau của chương
này, đối với các nút AlternativeAppearance.
2.7.1 Bounds Node Components
Một đối tượng biên giới Bound được tham chiếu đến bởi các đối
tượng cần định nghĩa biên giới biên giới cho phép người lập trình đa dạng
hóa các hành động và bề mặt hoặc âm thanh trong một vung đất ảo.
Bound cũng cho phép hệ thông dựng hình của Java 3D hoạt động hiệu
quả hơn.
Các vùng biên giới được định nghĩa băng một số lớp. Bound là lớp
trừu tượng là lớp cơ sở cho các lớp biên giới. Đối tượng Bound định
nghĩa các vùng lồi kín, được sử dụng trong rất nhiều tương tác và chọn
lọc, 3 lớp mở rộng của nó là BoundingBox, BoundingPolytope, và
BoundingSphere
Khi lựa chọn một đối tượng Bound không phụ thuộc vào chi tiết của
ứng dụng, nhớ rằng những hoạt động nhỏ lẻ khác nhau trong một biên
giới sẽ được tính toán trong vùng giao nhau. BoundingSphere là dễ nhất
trong khi đó BoundingPolytope là khó nhất. Nếu bạn có rất nhiều đối
tượng Bound đang sử dụng, những hoạt động nhỏ cũng có thể thêm vào
và gây ra khác biệt rõ ràng đến toàn bộ hiệu năng của ứng dụng.
Cuối cùng phải nhớ rằng với các vùng biên giới nhỏ thì hành động càng
ít, và nên làm như vậy khi tạo các vùng biên giới.
http://tailieuhay.com 321
Lập trình đồ họa trên Java 2D và 3D
Bounds Method Summary (partial list)
Bounds là lớp trừu tượng, do đó các phương thức liệt kê dưới đây là tất
cả các phương thức trừu tượng và cụ thể của BoundingBox,
BoundingPolytope, và BoundingSphere
Bounds closestIntersection(Bounds[] boundsObjects)
Tìm đối tượng trong biên giới gần nhất mà giao với vùng biên giới này.
void combine(Bounds boundsObject)
Kết nối đối tượng bị bao này với đối tượng bao. Ta có 2 phương thức sau.
boolean equals(java.lang.Object Bounds)
Chỉ ra khi nào đối tượng bao này tương đương với đối tượng bao khác.
boolean intersect(Bounds boundsObject)
Kiểm tra sự giao nhau giữa các đối tượng bao.
boolean isEmpty()
Tests whether the Bounds is empty.
Kiểm tra khi nào các biên giới bao bị rỗng.
void set(Bounds boundsObject)
Lập giá trị cho đối tượng bao.
void transform(Transform3D trans)
Biến đổi đối tượng được bao dựa trên ma trận đưa ra.
BoundingSphere
BoundingSphere Constructor Summary (partial list)
BoundingSphere()
Tạo và định giá trị cho một BoundingSphere với bán kính bằng 1 tại 0 0 0
BoundingSphere(Point3d center, double radius)
Tạo và định giá trị cho một BoundingSphere với bán kính và tâm cho
trước
http://tailieuhay.com 322
Lập trình đồ họa trên Java 2D và 3D
BoundingSphere(Bounds boundsObject)
Tạo và định giá trị cho một BoundingSphere từ đối tượng cho trước.
BoundingSphere(Bounds[] boundsObjects)
Tạo và định giá trị cho một BoundingSphere từ một mảng các đối tượng
bao
BoundingSphere Method Summary (partial list)
void setCenter(Point3d center)
Lập vị trí của vùng bao cầu từ một điểm
void setRadius(double r)
Lập bán kính của hình cầu bao.
BoundingBox
BoundingBox Constructor Summary
Lớp này định nghĩa một hình hộp bao thẳng trục được sử dung cho vùng
bao.
BoundingBox()
Thiết lập và khởi tạo một hình hộp bao kích thước 2 tâm ở gốc.
BoundingBox(Point3d lower, Point3d upper)
Thiết lập và khởi tạo một hình hộp bao biết trước điểm thấp điểm cao trên
x,y, z.
BoundingBox(Bounds boundsObject)
Thiết lập một hình hộp bao từ một hình sẵn có.
BoundingBox(Bounds[] Bounds)
Lập một hình hộp bao với một mảng các đối tượng bao.
http://tailieuhay.com 323
Lập trình đồ họa trên Java 2D và 3D
BoundingBox Method Summary (partial list)
void setLower(double xmin, double ymin, double zmin)
Sets the lower corner of this bounding Box.
Lập góc dưới của hình hộp bao.
void setLower(Point3d p1)
Lập góc dưới của hình hộp bao.
void setUpper(double xmax, double ymax, double zmax)
Lập góc trên của hình hộp bao.
void setUpper(Point3d p1)
Lập góc trên của hình hộp bao.
BoundingPolytope
Một đối tượng BoundingPolytope định nghĩa một vùng đa diện sử
dụng phép giao giữa 4 hoặc hơn một nửa không gian. Một nửa không gian
là một vùng không gian bao quanh một mặt qua một mặt phẳng. Kết quả
là địng nghĩa BoundingPolytope dựa vào danh sách các mặt phẳng mà
tạo nên một vùng đóng.
BoundingPolytope Constructor Summary
BoundingPolytope()
Tạo một BoundingPolytope định nghĩa nó dựa trên tập 6 mặt phẳng
giống như hình lập phương
-1 <= x, y, z <= 1.
BoundingPolytope(Vector4d[] planes)
Tạo một BoundingPolytope sử dụng các mặt cho trước.
BoundingPolytope(Bounds boundsObject)
Tạo một BoundingPolytope ngoại tiếp một mặt bao cho trước.
BoundingPolytope(Bounds[] boundsObjects)
http://tailieuhay.com 324
Lập trình đồ họa trên Java 2D và 3D
Tạo một BoundingPolytope vây quanh một mảng các bao.
BoundingPolytope Method Summary (partial list)
int getNumPlanes()
Trả về số mặt phẳng của đối tượng BoundingPolytope.
void getPlanes(Vector4d[] planes)
Trả về giới hạn của các mặt phẳng cho bao đa diện này.
void setPlanes(Vector4d[] planes)
Lập các mặt phẳng cho bao này.
2.7.2 BoundingLeafa Node
Các biện giới bình thường sử dụng một đối tượng bao để chỉ ra một
vùng được bao quanh. Kết quả trong đồ thị khung cảnh là đối tượng
Bound di chuyển với đối tượng tham chiếu đến nó. Điều này là tố cho
nhiều ứng dụng tuy nhiên có một vài trường hợp lại cần vùng bao di
chuyển độc lập với đối tượng sử dụng vùng bao
Ví dụ như nếu một thế giớibao gồm nguồn sáng cố định chiếu sáng
vào đối tượng đang di chuyển thì vùng biên giới của ánh sáng phải bao
gồm cả đối tượng di chuyển. Một cách để nắm bắt điều này là làm cho
vùng bao rộng đủ để chứa tất cả những nơi mà đối tượng di chuyển đến.
Đây không phải là câu trả lời tốt nhất cho mọi trường hợp. Một cách giải
quyết tốt hơn là sử dụng BoundingLeafa. Đặt trên đồ thị khung cảnh với
đối tượng quan sát đối tượng BoundingLeafa di chuyển với đối tượng
quan sát và độc lập với nguồn sáng. Hình 2-25 chỉ ra một đồ thị khung
cảnh với một nguồn sáng sử dụng BoundingLeafa.
http://tailieuhay.com 325
Lập trình đồ họa trên Java 2D và 3D
Khi các ứng dụng cho BoundingLeafa bao gồm ApplicationBounds
của đối tượng Background, SchedulingBounds của Behaviors, và
InfluencingBounds của Lights, không gây cảm giác lặp lại thông tin trên
cả vùng.
Một trong những ứng dụng khá hay của đối tượng BoundingLeafa là
đặt một BoundingLeafa trên viewPlatform. BoundingLeafa này có thể
sử dụng liên tục trên một vùng bao cho các hành vi hoặc luôn luôn chấp
nhận các ứng dụng bao như nền hoặc sương mù.Ví dụ trong đoạn mã 2-11
sử dụng nguyên tắc đó.
Dòng 2,3,4 tạo đối tượng BoundingLeafa, và PlatformGeometry,
đồng thời làm cho đối tượng BoundingLeafa trở thành con của
PlatformGeometry. Đối tượng PlatformGeometry được thêm vào
nhánh hình thức của đồ thị khung cảnh ở dòng 6.
http://tailieuhay.com 326
Lập trình đồ họa trên Java 2D và 3D
BoundingLeafa Class
Các phi tham số của hàm tạo cho BoundingLeafa tạo một đơn vị
hình cầu bao.
BoundingLeafa Constructor Summary
The BoundingLeafa node defines a bounding region object that can be
referenced by other nodes to define a region of influence, an activation
region, or a scheduling region.
Nút BoundingLeafa dùng để định nghĩa một đối tượng vùng bao có thể
được tham chiếu đến bằng các nút khác nahu để định nghĩa một vùng ảnh
hưởng, một vùng kích hoạt hoặc một vùng danh mục.
BoundingLeafa()
Tạo một nút BoundingLeafa với một đối tương đơn vị hình cầu
BoundingLeafa(Bounds region)
Tạo một nút BoundingLeafa với vùng định trước.
BoundingLeafa Method Summary
Bounds getRegion()
Nhật vùng BoundingLeafa.
void setRegion(Bounds region)
Sets this BoundingLeafa node's bounding region.
Lập vùng bao của nút BoundingLeafa.
2.7.3 Scope
Như đã giới thiệu ở phía trên, định nghĩa một scope (tầm quan sát) là
một cách để giới hạn ứng dựng hay ảnh hưởng của một nút. Nút định
nghĩa một phạm vi quan sát có thể ảnh hưởng tới đối tượng của của đồ thị
con có gốc tại đối tượng Group. Khi không có một phạm vi quan sát cho
một nút ta gọi nút đó có phạm vi quan sát toàn cầu. Điều đó có nghĩa là
http://tailieuhay.com 327
Lập trình đồ họa trên Java 2D và 3D
nút đó có thể quan sát hoàn toàn trong môi trường ảo và chỉ bị giới hạn
bởi môi trường ảo.
Một vài nút cho phép chỉ ra cả vùng biên giới và phạm vi quan sát
nhưng việc chỉ định một phạm vi quan sát không thể thay thế cho một
vùng biên giới. Đối với một nút có một hiệu ứng trên một đối tượng đối
tượng cần phải có cả biên giới lẫn phạm vi quan sát. Một nút không có
phạm vị sẽ không ảnh hưởng được các đối tượng khác.
Một phạm vi quan sát dùng để giới hạn ứng dụng của một nút khi sử
dụng mình vùng bao sẽ rất khó khăn hoặc không thể làm. Việc gọi lại một
vùng bao để khi một thứ gì đó ứng dựng trên thế giới ảo. Có thể hiểu rằng
khi sử dụng một vùng bao để phân biệt giữa các đối tượng mà nằm gần
nhau là rất khó khăn. Thực tế, cũng có những trường hợp sử dụng được .
Nếu 2 đối tượng quan sát chạm hoặc chồng lên nhau và một đối tượng có
thể bao gồm vùng bao hoặc là đối tượng kia. Hiện tượng này không
thường xảy ra như ví dụ dưới đây.
Một khung cảnh chứa một ngọn đèn và một vài đối tượng quan sát
trên bàn. Ngọn đèn có một bóng, vì thế không phải tất cả các đối tượng sẽ
được chiếu sáng bởi chiếc đèn này. Nếu chỉ sử dụng vùng bao sẽ rất khó
để chỉ ra ứng dụng ánh sáng đúng đắn khi đèn tắt và bật giữa các đối
tượng gần nhau.
Định nghĩa phạm vi giới hạn cho nguồn sáng dễ dàng hơn điều khiển ánh
sáng trong khung cảnh. Đồ thị khung cảnh trong hình 2-26 là một giải
pháp. Đồ thị này chia ra các đối tượng được chiếu sáng và không được
chiếu sáng thành 2 nhánh của đồ thị khung cảnh. Chỉ định các nhóm được
chiếu sáng bao gồm cả đối tượng được rọi sán. Thường thì không cần
thiết phải tổ chức một đồ thị khung cảnh xung quanh vùng quan sát.
http://tailieuhay.com 328
Lập trình đồ họa trên Java 2D và 3D
2.8 Hình học nâng cao
Java 3D API phiên bản 1.2 đưa ra 2 mở rộng lớn đối với các lớp sử
dụng các hình học. Thứ nhất cho nhiều hình học trở thành các nút thành
phần của một nút Shape3D. Tính năng này cho phép dựng hình hiệu quả
hơn.
Một tính năng khác là cho phép dữ liệu hình học có thể tham chiếu
bằng đối tượng hình học thay vì phải sao chép. Việc sao chép dữ liệu chỉ
thực hiện trong các phiên bản trước của 1.2 . Việc sao chép dữ liệu làm
mất thời gian và công sức, sử dụng việc tham chiếu trực tiếp tăng hiệu
quả nhiều chương trình.
2.8.1 Multiple Geometries in a Single Shape3D
Chương 1 giới thiệu về lớp Shape3D phần 2.2.1 giới thiệu Shape3D
với định nghĩa của đối tượng quan sát và chỉ ra cách sử dụng cơ bản của
đối tượng Shape3D. Phiên bản 1.2 thêm rất nhiều phương thức tới lớp
http://tailieuhay.com 329
Lập trình đồ họa trên Java 2D và 3D
Shape3D cho phép đối tượng Shape3D có thể tham chiếu đến nhiều đối
tượng thành phần hình học. Tính năng mới này giảm thiểu số lượng đối
tượng trong đồ thị khung cảnh.
Trong AxisApp.java giới thiệu trong phần 2.5.1 sử dụng 3 đối tượng
LineArraty để vẽ các đường đại diện cho 3 trục tọa độ trong không gian,
ngoài ra trong chương trình có 3 đối tượng Shape3D tương đương với 3
đối tượng hình học. Tuy nhiên trong ví dụ AxisApp2.java có sử dụng 1
đối tượng Shape3D, nó tham chiếu đến nhiều đối tượng thành phần hình
học khác.Xem hình 2-27
Như trong đoạn mã 2-12 có thể thấy ta chỉ tạo một đối tượng
Shape3D nhưng có thể tham chiếu đến 3 đối tượng thành phần hình học.
Shape3D Geometry Equivalence Classes
Nút là Shape3D chứa một danh sách 1 hoặc nhiều đối tượng thành phần
hình học và một đối tượng thành phần giao diện. Danh sách đối tượng
hình học có thể tương đương với các lớp và có cùng kiểu với các lớp hình
học cơ bản. Sự cân bằng thể hiện đươi đây:
Point GeometryArray: [Indexed]PointArray
Line GeometryArray: [Indexed]{LineArray, LineStripArray}
Polygon GeometryArray: [Indexed]{TriangleArray, TriangleStripArray,
TriangleFanArray,
QuadArray}
http://tailieuhay.com 330
Lập trình đồ họa trên Java 2D và 3D
CompressedGeometry
Geometry
Text3D
Với sự hạn chế của danh sách đối tượng Shape3D tới một lớp hình học
tương đương cho thấy sự cải tiến này có vẻ không có gì là cải tiến. Một
lần nữa 3 đối tượng lineArray định nghĩa hình cho hoặc AxisApp có thể
thay thế bằng một đối tượng và một đối tượng Shape3D.
Shape3D Method Summary (partial list, see Section 2.2.1)
void addGeometry(Geometry Geometry) <new in 1.2>
Gắn đối tượng hình học tới danh sách của nút Shape3D gồm các thành
phần hình học
java.util.Enumeration getAllGeometries() <new in 1.2>
Trả về liệt kê danh sách các thành phần hình học.
Geometry getGeometry(int index) <new in 1.2>
Lấy các thành phần hình học tại vị trí index trong danh sách.
void insertGeometry(Geometry Geometry, int index) <new in 1.2>
Chèn thêm một thành phần hình học vào danh sách tại vị chí chỉ mục cho
trước.
int numGeometries() <new in 1.2>
Trả về số thành phần hình học trong danh sách.
void removeGeometry(int index) <new in 1.2>
Loại bỏ thành phần hình học tại vị trí chỉ mục cho trước trong danh sách.
void setGeometry(Geometry Geometry, int index) <new in 1.2>
Thay thế thành phần hình học tại vị trí chỉ mục cho trước trong danh sách
với một thành phần khác.
http://tailieuhay.com 331
Lập trình đồ họa trên Java 2D và 3D
2.8.2 GeometryArray
Trong việc xây dựng hình các bước là tạo một đối tượng hình học, rồi
đăng kí giá trị cho nó để định nghĩa dữ liệu hình học (tạo độ, màu ...) .
Với phiên bản 1.2 cho phép lời gọi BY_REFERENCE thay thế cho việc
sao chép dữ liệu hình học. Việc này khi ở phiên bản cũ là đối tượng sao
chép GeometryArray được khởi tạo có một mảng private lưu giữ toàn bộ
dữ liệu này bên trong đối tượng GeometryArray. Sau đó khi dữ liệu hình
học được đăng kí với GeometryArray nó được sao chép vào mảng này.
Khi đối tượng GeometryArray BY_REFERENCE được tạo người dùng
tạo một mảng hình học và quản lí mảng này với dữ liệu hình học. Và vì
thế không có mảng bên trong đối tượng hình học.
Vậy khi nào cần sử dụng BY_REFERENCE, có 2 lí do sử dụng nó là:
1. Nếu dữ liệu hình học là động
2. Nếu dữ liệu hình học cần sử dụng nhiều bộ nhớ
Lí do lớn nhất để chọn phương pháp này là dữ liệu có thể thay đổi
thậm chí đối tượng đang sống hoặc được dịch. Cách thay đổi hình chính
là thay đối dữ liệu của nó, cách khác là phân chia mảng sử dụng bởi đối
tượng hình học.
Những gợi ý và cảnh báo khi sử dụng BY_REFERENCE
Nếu sử dụng BY_REFERENCE, sử dụng phương thức set*RefFloat là tốt
hơn cả. Ví dụ, sử dụng setCoordRefFloat()thay vì setCoordRef3f()sử
dụng mảng số thực cho phép truy cập trực tiếp hơn là sử dụng một mảng
các đối tượng. Một mảng các đối tượng trong Java 3D luôn luôn lưu trữ
các tham chiếu hơn là giá trị thực vì chỉ các mảng có kiểu dữ liệu như
thực mới lưu dữ liệu.
Nhớ rằng khi sử dụng BY_REFERENCE phương thức sử dụng khác với
khi không sử dụng nó. Người lập trình phải có trách nhiệm đảm bảo cho
kiểu dữ liệu đúng đắns.
http://tailieuhay.com 332
Lập trình đồ họa trên Java 2D và 3D
Ví dụ GeometryArray BY_REFERENCE
Sử dụng BY_REFERENCE Geometry với GeometryArray cho đối
tượng hình học tĩnh không khó hơn sao chép Geometry. Trong đoạn ma
2-13 được lấy từ chương trình TwistByRefApp.java, sử dụng tham chiếu
đến dữ liệu hình học thay vì cách cũ, trong trường hợp này tạo độ và màu
được người dùng tạo thành 2 mảng coord và color.
Việc dùng được thực hiện theo các bước sauL
• Khai báo mảng để giữ các dữ liệu hình học
• Tạo đối tượng GeometryArray mong muốn bằng tùy chọn định
dạng đỉnh BY_REFERENCE. Trong trường hợp này đối tượng
GeometryArray là một mảng TriangleStripArray.
• Điền đầy giá trị cho mảng TriangleStripArray
Tham chiếu đến dữliệu người dùng với đối tượng GeometryArray.
Thứ tự của các bước có thể thay đổi khi mảng sử dụng được khai báo
trước khi chúng được tham chiếu hoặc điền giá trị và đối tượng
GeometryArray được tạo trước khi mảng được tham chiếu.
// //////////////////////////////////////////
/////
//
// create scene graph branch group
//
public BranchGroup createSceneGraph() {
BranchGroup contentRoot = new
BranchGroup();
http://tailieuhay.com 333
Lập trình đồ họa trên Java 2D và 3D
// Create the transform group node and
initialize it to the
// identity. Add it to the root of the
subgraph.
TransformGroup objSpin = new
TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSF
ORM_WRITE);
contentRoot.addChild(objSpin);
Shape3D twist = new Twist();
objSpin.addChild(twist);
// Duplicate the twist strip geometry and
set the
// appearance of the new Shape3D object
to line mode
// without culling.
// Add the POLYGON_FILLED and
POLYGON_LINE strips
// in the scene graph at the same point.
// This will show the triangles of the
original Mobius strip that
// are clipped. The PolygonOffset is set
to prevent stitching.
PolygonAttributes polyAttrib = new
PolygonAttributes();
http://tailieuhay.com 334
Lập trình đồ họa trên Java 2D và 3D
polyAttrib.setCullFace(PolygonAttributes.CULL_NON
E);
polyAttrib.setPolygonMode(PolygonAttributes.POLYG
ON_LINE);
polyAttrib.setPolygonOffset(0.001f);
Appearance polyAppear = new Appearance();
polyAppear.setPolygonAttributes(polyAttrib);
objSpin.addChild(new
Shape3D(twist.getGeometry(), polyAppear));
Alpha rotationAlpha = new Alpha(-1,
16000);
RotationInterpolator rotator = new
RotationInterpolator(rotationAlpha,
objSpin);
// a bounding sphere specifies a region a
behavior is active
// create a sphere centered at the origin
with radius of 1
BoundingSphere bounds = new
BoundingSphere();
rotator.setSchedulingBounds(bounds);
objSpin.addChild(rotator);
http://tailieuhay.com 335
Lập trình đồ họa trên Java 2D và 3D
// make background white
Background background = new
Background(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(bounds);
contentRoot.addChild(background);
// Let Java 3D perform optimizations on
this scene graph.
contentRoot.compile();
return contentRoot;
} // end of CreateSceneGraph method of
TwistStripApp
GeometryArray
Lớp GeometryArray là lớp cơ sở của nhiều lớp hình học khác. Vì thế
nó định nghĩa rất nhiều phương thức cho việc quản lí dữ liệu.Để sử dụng
tham chiếu hình học,lập bit BY_REFERENCE trong trường định dạng
đỉnh trong hàm tạo của đối tượng GeometryArray.
GeometryArray Methods for Referencing Geometry Data (partial
list)
This collection of methods set the references to Geometry data in user
arrays. In each case, the method will throw an exception if the data mode
for this Geometry array object is not BY_REFERENCE. In some cases
the data mode must also be INTERLEAVED, in other cases the data
mode must not be INTERLEAVED.
Đây là các phương thức dùng để tham chiếu đến dữ liệu hình học trên
mảng sử dụng. Trong mỗi trường hợp phương thức sẽ đưa ra ngoại lệ nếu
http://tailieuhay.com 336
Lập trình đồ họa trên Java 2D và 3D
chế độ dữ liệu không chọn là BY_REFERENCE, trong một số trường hợp
chế độ dữ liệu có thể là INTERLEAVED, trong một số trường hợp không
được phép là INTERLEAVED.
void setColorRef*(Color*[] colors) <new in 1.2>
Sets the color array reference to the specified Color* (Color3b, Color3f,
Color4b, or Color4f) array.
void setColorRefByte(byte[] colors) <new in 1.2>
Sets the byte color array reference to the specified array.
void setColorRefFloat(float[] colors) <new in 1.2>
Sets the float color array reference to the specified array.
void setCoordRef*(Point*[] coords) <new in 1.2>
Sets the coordinate array reference to the specified Point* (Point3d,
Point3f) array.
void setCoordRefDouble(double[] coords) <new in 1.2>
Sets the double coordinate array reference to the specified array.
void setCoordRefFloat(float[] coords) <new in 1.2>
Sets the float coordinate array reference to the specified array.
void setInterleavedVertices(float[] vertexData) <new in 1.2>
Sets the interleaved vertices array reference to the specified array.
void setNormalRef3f(Vector3f[] normals) <new in 1.2>
Sets the Vector3f normal array reference to the specified array.
void setNormalRefFloat(float[] normals) <new in 1.2>
Sets the float normal array reference to the specified array.
void setTexCoordRef*(int texCoordSet, TexCoord*[] texCoords)
<new in 1.2>
Sets the texture coordinate array reference for the specified texture
coordinate set to the specified
TexCoord* (TexCoord2f, TexCoord3f) array.
http://tailieuhay.com 337
Lập trình đồ họa trên Java 2D và 3D
void setTexCoordRefFloat(int texCoordSet, float[] texCoords) <new
in 1.2>
Sets the float texture coordinate array reference for the specified texture
coordinate set to the specified array.
Một cách đơn giản để thay đổi hình học sử dụng BY_REFERENCE là
thay đối số giá trị sử dụng trong một mảng. Dưới đây là các phương thức
để thay đối giá trị dữ liệu hình học. Tất nhiên nó chỉ có tác dụng nếu chế
độ BY_REFERENCE. Các phương thức này chỉ được cho phép hoạt
động trên các đối tượng đang sống hoặc đang dịch khi khả năng
ALLOW_REF_DATA_WRITE được lập.
GeometryArray Methods for Setting Initial Location of Referenced
Geometry Data (partial list)
void setInitialColorIndex(int initialColorIndex) <new in 1.2>
Sets the initial color index for this GeometryArray object. This method
is easily confused with the
setInitialVetrexIndex method which is used when the Geometry is not
BY_REFERENCE.
void setInitialCoordIndex(int initialCoordIndex) <new in 1.2>
Sets the initial coordinate index for this GeometryArray object.
void setInitialNormalIndex(int initialNormalIndex) <new in 1.2>
Sets the initial normal index for this GeometryArray object.
void setInitialTexCoordIndex(int texCoordSet, <new in 1.2>
int initialTexCoordIndex)
Sets the initial texture coordinate index for the specified texture
coordinate set for this GeometryArray object.
http://tailieuhay.com 338
Lập trình đồ họa trên Java 2D và 3D
GeometryArray Capabilites
BY_REFERENCE <new in 1.2>
Specifies the position, color, normal, and texture coordinate data for this
object are accessed by reference
INTERLEAVED <new in 1.2>
Specifies that the position, color, normal, and texture coordinate data for
this GeometryArray are
accessed via a single interleaved, floating-point array reference. This is
only used in by-reference
Geometry mode.
ALLOW_COUNT_READ | WRITE <new in 1.2>
allow write access to the count or initial index information for this object
ALLOW_REF_DATA_READ <new in 1.2>
allow read access to the Geometry data reference information; only used
in by-reference Geometry mode
ALLOW_REF_DATA_WRITE <new in 1.2>
allow write access to the Geometry data reference information for this
object. It also enables writing the referenced data itself, via the
GeometryUpdater interface. This is only used in by-reference Geometry
mode.
Dữ liệu hình học trong bất cứ mảng nào được tham chiếu đến bởi một
đối tượng GeometryArray sống hoặc đang được dịch có thể thay đổi
thông qua phương thức updateData của nó. Các ứng dụng đều phải quan
tâm tránh để vi phạm luật này.
http://tailieuhay.com 339
Lập trình đồ họa trên Java 2D và 3D
updateData method of GeometryArray
public void updateData(GeometryUpdater updater) <new in 1.2>
Cập nhật mảng dữ liệu được truy cập thông qua tham chiếu. Phương thức
gọi updateData của đối tượng GeometryUpdater để đồng bộ cập nhật với
dữ liệu đỉnh được tham chiếu bởi đối tượng GeometryArray.
2.8.4 AlternateAppearance <new in 1.2>
Như đã thấy trong phần 2.6.1 đối tượng Shape3D có thể có một tham
chiếu đến nút thành phành Appearance. Gói giao diện này định nghĩa các
thuộc tính quan sát của đối tượng Shape3D. Xem hình 2-20 và 2-37.
Phần 2.6.2 mô tả làm thế nào có thể chia sẻ một gói giao diện giữa các đối
tượng Shape3D.
Một AlternateAppearance cho phép người phát triển ứng dụng có
thể phát triển các phương thức thay thế cho việc chia sẻ một gói giao diện
giữa các đối tượng Shape3D. Nó là một cách thay thế cho việc chia sẻ gói
giao diện – đưa ra cách dễ dàng hơn để tạm thời thay đổi giao diện. Có 3
cách. Thứ nhất đối tượng phải nằm trên trên vùng bao của
AlternateAppearance. Thứ 2 phải có một giới hạn quan sát trên ứng
dụng của nó. Thứ 3 chỉ những đối tượng quan sát cho phép giao diện của
nó được ghi đề đưa ra cho AlternateAppearance
Sử dụng AlternativeAppearance Node
Để sử dụng AlternateAppearance đầu tiện phải tạo gói giao diện để
sử dụng phép thay thế và tham chiếu đến gói giao diện bằng đối tượng
AlternativeAppearance. Sau đso lập vùng ảnh hưởng thông qua đối tượng
Bounds hoặc BoundingLeafa. Tạo một phạm vi quan sát cho
AlternateAppearance theo ý mình. Đừng quên thêm
AlternateAppearance vào đồ thị khung cảnh, lập cờ
appearanceOverrideEnable trên đối tượng Shape3D.
http://tailieuhay.com 340
Lập trình đồ họa trên Java 2D và 3D
Shape3D setAppearanceOverrideEnable() Method
void setAppearanceOverrideEnable(boolean flag) <new in 1.2>
Lập cờ chỉ ra khi nào một giao diện của một nút được ghi đè bằng một nút
AlternativeAppearance. Phương thức này có thể gọi khi đối tượng đang
sống hoặc dịch tùy theo khả năng nó được lập thế nào.
Shape3D Capabilities (partial list, see Section 2.2.1)
ALLOW_APPEARANCE_OVERRIDE_READ | WRITE <new in
1.2>
cho phép truy cập đọc/ghi tới cờ appearanceOverrideEnable
AlternativeAppearance Class <new in 1.2>
Các phần dưới là danh sách hàm tao cho lớp AlternateAppearance
AlternateAppearance Constructor Summary
AlternateAppearance() <new in 1.2>
Khởi tạo một nút AlternateAppearance với các tham số mặc định:
Appearance, scope,
influencingBounds, và influencingBoundingLeaf = null
AlternateAppearance(Appearance Appearance) <new in 1.2>
Tạo một nút AlternateAppearance với giao diện cho trước.
AlternateAppearance Method Summary (partial list)
void addScope(Group scope) <new in 1.2>
Gắn một nút Group cho trước tới danh sách nút AlternateAppearance
của phạm vi quan sát.
http://tailieuhay.com 341
Lập trình đồ họa trên Java 2D và 3D
java.util.Enumeration getAllScopes() <new in 1.2>
Trả về bảng liệt kê danh sách nút AlternateAppearance của phạm vi
quan sát.
void insertScope(Group scope, int index) <new in 1.2>
Chèn vào một nút Group cho trước vào danh sách tại chỉ số cho trước.
int numScopes() <new in 1.2>
Trả về số nút trong danh sách.
void removeScope(int index) <new in 1.2>
Loại bỏ nút tại vị trí cho trước trong danh sách.
void setAppearance(Appearance Appearance) <new in 1.2>
Lập giao diện cho nút AlternateAppearance
void setInfluencingBoundingLeaf(BoundingLeafa region) <new in
1.2>
Sets the AlternateAppearance's influencing region to the specified
bounding leaf.
Lập vùng ảnh hưởng của AlternateAppearance tới lá bao cho trước.
void setInfluencingBounds(Bounds region) <new in 1.2>
Lập vùng ảnh hưởng của AlternateAppearance tới vùng bao cho trước.
void setScope(Group scope, int index) <new in 1.2>
Thay thế vị trí của nút tại vị trí chỉ mục trong danh sách với một nút
Group cho trước.
Những khả năng của lớp AlternateAppearance
AlternativeAppearance Capabilities
ALLOW_APPEARANCE_READ | WRITE allow read (write) access
to its Appearance information
ALLOW_INFLUENCING_BOUNDS_READ | WRITE allow read
(write) access to its influencing Bounds and bounding leaf information
http://tailieuhay.com 342
Lập trình đồ họa trên Java 2D và 3D
ALLOW_SCOPE_READ | WRITE allow read (write) access to its
scope information at runtime
2.9 Clipping – Cắt xén
Chủ đề của Clipping không thực sự là việc tạo hình nhưng một trong
những nhân tố ảnh hưởng đến hình ảnh trong như thế nào. Ví dụ khi môt
hình mở rộng đến vùng biên nên nó bị cắt đi vì thế một số hình không
xem được. Cắt xén là một chủ đề phức tạp, phần này đưa ra các vấn đề cơ
bản nhất trong việc cắt hình .
2.9.1 View Defines a Frustum
Trong chương 1 giới thiệu về hệ tọa độ ảo và mô tả vị trí của mắt liên
quan đến nó. Trong một số trường hợp bạn sẽ bắt gặp hoàn cảnh mà một
đối tượng quan sát không được dựng hình. Lí do thì có rất nhiều, ngoài
đối tượng có thể nằm ngoài vùng frustum (hình cụt). Vùng này là nơi
đối tượng quan sát và các phần của đối tượng quan sát khác được hiển thị.
Hình 2-29 sẽ đưa ra cho bạn định nghĩa rõ hơn về vùng frustum.
Chú ý rằng mặt phẳng cắt phía trước(front clipping plane) nằm đằng
sau màn ảnh(image plate). Điều này là không hợp lệ nhưng nó cũng
không được khuyến khích.
http://tailieuhay.com 343
Lập trình đồ họa trên Java 2D và 3D
Phần chóp cụt này được định nghĩa thông vị trí mắt nhìn và 2 mặt
phẳng cắt trước và sau. Giá trị mặt định tương đối hợp lí tuy nhiên người
lập trình có thể thay đổi khoảng cách này.
Nên để
(back clip distance) / (front clip distance) < 3000.
Tuy nhiên thực thế tỉ lệ này thường là từ 100 đến 1000 là hợp lí nhất.
View Methods for Adjusting the Frustum (partial list)
Đối tương View trong phần đồ thị hình thức của đồ thị khung cảnh Java
3D định nghĩa rất nhiều tham số về hình ảnh. Dưới đây là một trong số
đó.
void setBackClipDistance(double distance)
Lập khoảng cách mặt cắt sau với mô hình quan sát, khoảng cách này phải
lớn hơn với khoảng cách của mặt trước.
void setFrontClipDistance(double distance)
Lập khoảng cách mặt cắt trước với mô hình quan sát, khoảng cách này
phải lớn hơn 0.0 và nhỏ hơn khoảng cách sau.
void setFieldOfView(double fieldOfView)
Lập trường ngang mô hình quan sát dạng radians.
http://tailieuhay.com 344
Lập trình đồ họa trên Java 2D và 3D
2.9.2 Clip Node
Như đã nói ở phía trên khoảng cách của hình chóp cụt có thể thay đổi.
Nút cắt là một đối tượng thực hiện điều này. Mỗi Clip định nghĩa một
vùng ứng dụng chỉ ra một đối tượng vùng bao hoặc lá bao. Khi vùng bao
này giao với khu vực quan sát .khoảng cách mặt sau của đối tượng Clip
được sử dụng để dựng. mặt trước định nghĩa bởi đối tượng View không
ảnh hưởng.
Việc sử dụng Clip làm tăng tốc độ xử lí đặc biệt trong những khung
cảnh phức tạp.
Dưới đây là danh sách các hàm tạo và phương thức:
Clip Constructor Summary
Clip()
Tạo một Clip Node với tham số mặc định : backDistance = 100,
ApplicationBounds và applicationBoundingLeaf = null
Clip(double backDistance)
Tạo một Clip node với tham số backDistance
Clip Method Summary
void setApplicationBoundingLeaf(BoundingLeafa region)
Lập vùng ứng dụng cắt tới đối tượng bao lá.
void setApplicationBounds(Bounds region)
Lập vùng ứng dụng cắt tới đối tượng bao.
void setBackDistance(double backDistance)
Lập khoảng cách sau với giá trị cho trước.
http://tailieuhay.com 345
Lập trình đồ họa trên Java 2D và 3D
Clip Field Summary
ALLOW_APPLICATION_BOUNDS_READ | WRITE allow read
(write) access to its application Bounds and bounding leaf at runtime.
ALLOW_BACK_DISTANCE_READ | WRITE allow read (write)
access to its back distance at runtime.
Nút ModelClip có thể cắt đối tượng quan sát ra theo nhiều cách. Một
đối tượng ModelClip định nghĩa một tập 6 mặt cắt với hướng tùy ý trong
hệ tọa độ cơ bản. Mặt cắt định nghĩa một nửa không gian cho những đỉnh
được lựa chọn để dựng. Khi giữa các nửa mặt cắt có giao nhau chúng
định nghĩa một vùng mà các điểm trong đó không được dựng, dù chúng ở
trong hình chóp cụt nhìn thấy. Ảnh hưởng này của nút ModelClip được
điều khiển thông qua các vùng được mô tả trước dựa trên ảnh hưởng và
tầm quan sát.
2.9.4 ModelClip Example
Các bước sử dụng ModelClip
• Thiết lập vùng ảnh hưởng cho đối tượng ModelClip
• Chọn hoặc bỏ chọn các mặt cắt tùy theo ý mình
• Lập hướng và vị trí cho mặt phẳng để sử dụng.
• Thêm đối tượng ModelClip vào đồ thị khung cảnh
Mặc dù không thực hiện trong ví dụ này nhưng ModelClip có thể định
nghĩa một phạm vi quan sát.
http://tailieuhay.com 346
Lập trình đồ họa trên Java 2D và 3D
Nhớ rằng luôn luôn có 6 mặt phẳng trong đối tượng ModelClip. Kết
quả là mảng Vertor4d được sử dụng trong hàm tạo phải có kich thước 6.
ModelClip Constructor Summary
ModelClip() <new in 1.2>
Tạo một nút ModelClip với tham số mặc định.
ModelClip(Vector4d[] planes) <new in 1.2>
Tạo một nút ModelClip với mặt cho trước.
ModelClip(Vector4d[] planes, boolean[] enables) <new in 1.2>
Tạo một nút ModelClip với mặt cho trước và có thiết lập các cờ.
ModelClip Method Summary (partial list)
void addScope(Group scope) <new in 1.2>
Appends the specified Group node to this ModelClip node's list of scopes.
void insertScope(Group scope, int index) <new in 1.2>
Inserts the specified Group node into this ModelClip node's list of scopes
at the specified index.
int numScopes() <new in 1.2>
Returns the number of nodes in this ModelClip node's list of scopes.
void removeScope(int index) <new in 1.2>
http://tailieuhay.com 347
Lập trình đồ họa trên Java 2D và 3D
Removes the node at the specified index from this ModelClip node's list
of scopes.
void setEnable(int planeNum, boolean enable) <new in 1.2>
Sets the specified enable flag of this ModelClip node.
void setEnables(boolean[] enables) <new in 1.2>
Sets the per-plane enable flags of this ModelClip node to the specified
values.
void setInfluencingBoundingLeaf(BoundingLeafa region) <new in
1.2>
Set the ModelClip node's influencing region to the specified bounding
leaf.
void setInfluencingBounds(Bounds region) <new in 1.2>
Set the ModelClip node's influencing region to the specified Bounds.
void setPlane(int planeNum, Vector4d plane) <new in 1.2>
Sets the specified clipping plane of this ModelClip node.
void setPlanes(Vector4d[] planes) <new in 1.2>
Sets the clipping planes of this ModelClip node to the specified planes.
void setScope(Group scope, int index) <new in 1.2>
Replaces the node at the specified index in this ModelClip node's list of
scopes with the specified Group
node.
ModelClip Field Summary
ALLOW_ENABLE_READ | WRITE allow read (write) access to its
enable flags at runtime
ALLOW_INFLUENCING_BOUNDS_READ | WRITE allow read
(write) access to its influencing Bounds and bounding leaf at runtime
http://tailieuhay.com 348
Lập trình đồ họa trên Java 2D và 3D
ALLOW_PLANE_READ | WRITE allow read (write) access to its
planes at runtime
ALLOW_SCOPE_READ | WRITE allow read (write) access to its
scope information at
runtime
http://tailieuhay.com 349
Lập trình đồ họa trên Java 2D và 3D
CHƯƠNG 3
TẠO NỘI DUNG
3.1 Nội dung chính
Trong các chương trước chúng ta đã tìm hiểu cách tạo ra những đối
tượng trực quan bằng các phương pháp đơn giản. Bằng các phương
pháp này công việc lập trình trơ nên buốn tẻ. Trong chương này chúng
ta sẽ xem xét một phưong pháp khác để tạo ra các đối tượng trực quan.
Trong mục 3.2 sẽ giới thiệu lớp GeometryInfo, lớp tiện ích này cung
cấp khả năng tự động hóa trong việc tạo ra các đối tượng trực quan.
Lớp GeometryInfo cũng với các lớp Triangulator, Stripifier, và
NormalGeneration cho phep ta tạo ra cá đối tượng trực quan như là
các đa giác hình học. Các lớp này chuyển đổi đa giác thành tam giác,
và tinh chỉnh các đa giác này.
Mục 3.3 giới thiệu lớp Loader. Lớp này có khả năng tạo ra các dối
tượng trực quan Java3D từ các tệp được tạo bởi các phần mềm 3D. Cụ
thể lớp Loader có thể đọc các file VRML, Lightwave, AutoCad và các
định dạng file 3D khác…Một đặc điểm quan trọng là ta có thể viết các
lớp Loader riêng để phục vụ cho nhu cầu sử dụng.
http://tailieuhay.com 350
Lập trình đồ họa trên Java 2D và 3D
Các mục tiếp theo chúng ta sẽ xem xét các kỹ thuật khởi tạo nội dung.
3.1.1 GeometryInfo
Thông thường để vẽ một hình một đối tượng hình học bất kỳ, chúng ta
phải tự làm hoàn toàn và việc code sẽ rất vất vả và nhàm chán. Sử
dụng lớp GeometryInfo công việc sẽ trở nen dễ dàng và thuận tiên
hơn. Khi bắt đầu vẽ một đối tượng hình học, chúng ta sẽ xác định một
đa giác bất kỳ phù hợp với dối tượng đó. Đa giác này có thể là đa giác
lõm, không phẳng … Đối tượng GeometryInfo và các lớp khác sẽ
chuyển các đa giác này thành các tam giác nhỏ hơn, từ đó Java3D có
thể render (tô_chát) .
Để nâng cao hiệu năng của hệ thống chúng ta có thể sử dụng đối tượng
Stripifier để chai các tam giác thành các tam giác rời nhau. Nếu chúng
ta muốn tạo bóng cho đối tượng hình học, ta sử dụng NormalGenerator
để tính toán các vector bề mặt của đối tượng hình học.
3.2.1 Một ví dụ đơn giản về GeometryInfo
Trong phần này chúng ta sẽ xem xét các khởi tạo và sử dụng đối
tượng GeometryInfo. Để khởi tạo một đối tượng GeometryInfo,
chúg ta cần chỉ rõ loại geometry cần dùng: POLYGON_ARRAY,
QUAD_ARRAY, TRIANGLE_ARRAY,
http://tailieuhay.com 351
Lập trình đồ họa trên Java 2D và 3D
TRIANGLE_FAN_ARRAY và TRAINGLE_STRIP_ARRAY. Khi
khởi tọa chúng ta phải chỉ ra coordinate và strip counts.
Chúng ta xét đoạn code dưới đây.
GeometryInfo gi = new
GeometryInfo(GeometryInfo.POLYGON_ARRAY);
gi.setCoordinates(coordinateData);
gi.setStripCounts(stripCounts);
Triangulator tr = new Triangulator();
tr.triangulate(gi);
NormalGenerator ng = new NormalGenerator();
ng.generateNormals(gi);
Stripifier st = new Stripifier();
st.stripify(gi);
Shape3D part = new Shape3D();
part.setAppearance(appearance);
part.setGeometry(gi.getGeometryArray());
- Khởi tạo đối tượng GeometryInfo và thiết lập các thông số cân
thiết (coordinate, stripcounts).
- Sau khi tạo ra đối tượng GeometryInfo, chúng ta có thể sử
dụng các lớp tiện ích khác như NormalGenerator, Triangulator
… bằng cách truyền tham số là đối tượng GeometryInfo.
-
3.2.2 Sử dụng GeometryInfo
Một số chú ý khi sử dụng đối tượng GeometryInfo. Nếu sử dụng
cả NormalGenerator và Stripifier thì ta phải sử dụng NormalGenerator
trước. Normalgenerator và Stripifier đều chỉ sự dụng với các tam giác chỉ
http://tailieuhay.com 352
Lập trình đồ họa trên Java 2D và 3D
mục. Khi sử dụng những lớp tiện ích này, chúng ta không cần quan tâm
đến kiểu của GeometryInfo(POLYGON_ARRAY, QUAD_ARRAY,
STRIP_ARRAY… ), khi đó các dữ liệu này được chuyển đổi thành các
tam giác chỉ mục. Sau khi thực hiện các tam giác chỉ mục này được gắn
liền lại với nhau. Tuy nhiên các thành phần khác của dối tượng
GeometryInfo sẽ bị thay đổi.
3.2.3 Một số lớp thông dụng có liên quan đến GeometryInfo
Trong phần này chúng ta sẽ xem xét kỹ hơn một số lớp thông dụng
nằm trong gói
com.sun.j3d.util.geometry.
http://tailieuhay.com 353
Lập trình đồ họa trên Java 2D và 3D
Lớp GeometryInfo có một hàm tạo duy nhất, khi khởi tạo một đối
tượng cần chỉ rõ kiểu của đối tượng Gemetry và hệ trục tọa độ tương
ứng.
Hàm tạo GeometryInfo
Gói: com.sun.j3d.utils.geometry
Lớp cha: java..lang.Object
Sử dụng: Chúng ta muốn chuyển các đối tượng hình học cho đối tượng
GeometryInfo để có thể dùng các lớp tiện ích khác. Khi chúng ta chuyển
đối tượng hình học cần thể hiện cho đối tượng GeometryInfo, các lớp
tiện ích sẽ sử dụng các dữ liệu trong đối tượng GeometryInfo để thực
hiện các yêu cấu của chúng ta.
GeometryInfo(int primitive)
Giá trị của primitive:
POLYGON_ARRAY : Đa giác, các đa giác 2 chiều,3 chiều(đa
diện)
QUAD_ARRAY : Tứ diện
TRIANGLE_ARRAY : Tam giác
TRIANGLE_FAN_ARRAY : Mảng StripCounts cho biết số đỉnh
tương với mỗi tam giác rời
http://tailieuhay.com 354
Lập trình đồ họa trên Java 2D và 3D
TRIANGLE_STRIP_ARRAY : Mảng StripCounts cho biết số đỉnh tương
với mỗi tam giác rời
Lớp GeometryInfo chứ nhiều phương thức, trong đó có các phương
thức theíet lập hay lây thông tin về hệ trục toạ độ, mầu sắc, chỉ mục,
các dữ liệu bề mặt.
Các phưong thức của lớp GeometryInfo
void recomputeIndices()
Thực hiện lại việc sắo xếo để đảm bảo các thông tin kết nối là chính xác.
Gọi hàm này khi các thông tin về hệ trục tọa dộ không chính xác
void reverse()
Đảo ngược thứ tự của tất cả các danh sách
void setColorIndices(int[] colorIndices)
void setColors(Color3f[] colors)
Đặt mảng mầu sắc
void setColors(Color4f[] colors)
Đặt mảng mầu sắc.
void setContourCounts(int[] contourCounts)
Đặt danh sách mầu viền
void setCoordinateIndices(int[] coordinateIndices)
Thiết lập mảng tỷ lệ của hệ trục tọa độ.
void setCoordinates(Point3f[] coordinates)
Thiết lập mảng của hệ trục tọa độ.
void setCoordinates(Point3d[] coordinates)
Thiết lập mảng của hệ trục tọa độ.
void setNormalIndices(int[] normalIndices)
http://tailieuhay.com 355
Lập trình đồ họa trên Java 2D và 3D
Thiết lập mảng các chú dẫn.
void setNormals(Vector3f[] normals)
void setNormals(float[] normals)
void setStripCounts(int[] stripCounts)
void setTextureCoordinateIndices(int[] texCoordIndices)
void setTextureCoordinates(Point2f[] texCoords)
Cách sử dụng các lớp tiện ích khác cũng như sử dụng với lớp
GeometryInfo. Sau đây chúg ta sẽ lần lượt xem xét hàm tạovà phương
thức của các lớp Triangulator, Stripifier và NormalGenerator. Đây
cũng chính là thứ tự khi chúng ta làm việc với POLYGON_ARRAY.
Trong đó lớp Triangulator chỉ làm việc với đối tượng hình học kiểu
POLYGON_ARRAY.
http://tailieuhay.com 356
Lập trình đồ họa trên Java 2D và 3D
Hàm tạo lớp Triangulator nhằm tạo ra đối tượng tam giác.
Triangulator Constructor Summary
Gói: com.sun.j3d.utils.geometry
Lớp cha: java.lang.Object
Triangulator()
Hàm tạo lớp Triangulator
Triangulator Method Summary
void triangulate(GeometryInfo gi)
Phươn thức chuyển đổi một đối tượng GeometryInfo tùe kiểu nguyên
thuỷ là POLYGON_ARRAY sang kiểu nguyên thuỷ kiểu
TRIANGLE_ARRY.
Hàm tạo lớp Stripifier nhằm tạo ra một đối tượng stripification
Stripifier Constructor Summary
Gói: com.sun.j3d.utils.geometry
Lớp cha: java.lang.Object
Lớp Stripfier có tiện ích đổi kiểu dũ liệu nguyên thuỷ của một đối tượng
GeometryInfo sang kiểu Triangle Strips. Để cho kết quả tốt Normal
Generation phải được thực hiệntrước khi quá trình tách nhỏ đối tượng
hình học.
Stripifier()
Hàm tạo
Pương thức của lớp Stripifier
void stripify(GeometryInfo gi)
http://tailieuhay.com 357
Lập trình đồ họa trên Java 2D và 3D
Chuyển GeometryInfo có chứa đối tượng GeometryInfo vào mảng
Triangle Strips.
Lớp NormalGenerator có hai hàm tạo. Hàm tạo thứ nhất tạo ra đối
tượng NormalGenerator với góc gấp có giá trị mặc định. Hàm tạo thứ
hai cho phép thiết lập giá trị cho crease angle.
NormalGenerator Constructor Summary
Gói: com.sun.j3d.utils.geometry
Lớp cha: java.lang.Object
NormalGenerator()
Khởi tạo một NormalGenerator với góc gập mặc định (0.76794 radians,
or 44°).
NormalGenerator(double radians)
Khởi tạo một NormalGenerator với góc gập có giá trị là tham số đầu vào.
Các Phương thức NormalGenerator
void generateNormals(GeometryInfo geom)
double getCreaseAngle()
Lấy giá trị góc gập
void setCreaseAngle(double radians)
Thiết lập góc gập
Các phương thức của lớp NormalGenerator : một phương thức thiết
lập, một phương thức lấy giá trị crease angle …
Loaders
Một lớp Leader đọc các file 3D và tạo ra cácm đối tượng của Java3D
với nội dung cảu file được đưa vào. Sau đó đối tượng 3D này có thể
http://tailieuhay.com 358
Lập trình đồ họa trên Java 2D và 3D
được sử dụng như các đối tuwọng khác của Java3D. Gói
com.sun.j3d.leaders cung cấp các phương thức load các file 3D từ các
chuwong trình ứng dụng khác vào trong chuwong trình Java3D.
Trên thực tế ngày cáng có nhiều các định dạng file 3D từ các ứng dụng
khác nhau, công việc để load các file này không phải là công việc của
Java3D hay của gói loaders, ma chỉ có phần giao diện dùng cho kỹ
thuật loading được đưa vào.
Một ví dụ đơn giản sử dụng leader.
Để load vào nội dung một file, chúng ta không nhất thiết phải sử dụng
một lớp tiện ích để load file đó. Ta sử dụng lớp loader với các bước
như sau:
• Tìm một loader
• Import lớp loader ứng với dịnh dạng fie tương ứng
• Import những lớp cần thiết
• Định nghĩa một biến khung cảnh
• Tạo một đối tượng loader
• Load nội dung của file trong khối catch, và gán kết quả đọc được
cho biến khung cảnh
• Chèn đối tuwọng khung cảnh vào trong miền khung cảnh
Ta có thể xem xét một ứng dụng mẫu của lớp ObjectFile trong
jdk1.2/demo/java3d/ObjLoad.
Class ObjectFile
Gói: com.sun.j3d.loaders
Thực thi: Loader
http://tailieuhay.com 359
Lập trình đồ họa trên Java 2D và 3D
Lớp ObjectFile thực thi giao diện Loader với file có định dạng
WaveFront.obj, một định dạng chuẩn của file 3D đuwọc tạo ra bằng phần
mêm WaveFront Advanced Víualizer.
Chúng ta xem xét một ví dụ được thực hiện theo các bước đã nói ở
trên.
Chúng ta có thể thấy các bược 1,2..6 trong ví dụ trên đèu được hiện
theo trình tự các bước ta phân tích.
Các loader phổ biến
Trong Java3D chúng ta có thể tìm thây rất nhiều lớp Loader. Ta có
bảng danh sach cụ thể dưới đây.
File Mô tả
3DS 3D-StudioCOB Caligari trueSpaceDEM Digital Elevation Map
DXFAutoCAD Drawing Interchange
FileIOB Imagine
LWS Lightwave Scene Format
NFF WorldToolKit NFF Format
OBJ Wavefront
PDB Protein Data Bank
PLAY PLAY
SLD Solid World
VRT Superscape VRT
VTK Visual Toolkit
http://tailieuhay.com 360
Lập trình đồ họa trên Java 2D và 3D
WRLVirtual Reality Modeling
language
3.3.3 Giao diện của gói Loader và lớp cơ sở
Để load được các file 3D trong một ứng dụng Java, chuwong trình
của chúng ta phải sử dụng đến đối tượng loader và đối tượng scene.
Đối tượng loader đọc, phân tích, và tạo ra phần thể hiện của Java 3D
cho nội dung file 3D đó. Đối tượng scene lưu lại scene graph được
tạo ra từ loader. Chúng ta có thể load được nhiều scene từ nhiều file
3D, bằng các sử dụng cùng một đối tượng loader tạo ra nhiều đối
tượng scene. Trong một chương trình Java3D chúng ta có thể load
được nhiều file định dạng khác nhau bằng các sử dụng các loader
thích hợp.
Sau đây chúng ta sẽ xem xét cụ thể các interface có trong gói
com.sun.j3d.loaders. Một lớp loader thực thi loader interface và sử
dụng một lớp thích hợp để thực thi scene interface.
com.sun.j3d.loaders Interface Summary
Loader The Loader interface is used to specify the location and elements
of a file format to load.
Scene The Scene interface is a set of methods used to extract Java 3D
scene graph information from a file
loader utility.
Trong đó gói com.sun.j3d.loaders còn cung cấp các lớp cơ sở để thực
thi những interface này.
http://tailieuhay.com 361
Lập trình đồ họa trên Java 2D và 3D
com.sun.j3d.loaders Class Summary
LoaderBase Lớp này thực thi giao diện Loadẻ và thêm vào các hàm tạo.
Lớp đuợc thiết kế để chúng ta có thể thừ kế nếu muốn xây dựng các
loader.
SceneBase Lớp SceneBase thực thi giao diện Scene và việc thừa kế lớp
SceneBase giúp cho chúng ta dễ dàng sử dụng được các phương thức đã
xây dựng
Các phương thức được định nghĩa trong interface, còn phần thực thi
nằm trong các lớp loader mà người lập trình sử dụng.
Interface Loader Method Summary
Gói: com.sun.j3d.loaders
Giao diện Loader được sử dụng để chỉ rõ ra vị trí và các thành phần của
một định dạng file cần load. Phần giao diện này cung cấp cho lớp Loader
các định dạng file khác nhau. Giao diện Scene sẽ được thực thi để cung
cấp cho người dùng những giao diện phù hợp để lấp dữ liệu từ các file.
Scene load(java.io.Reader reader)
Phương thức lấy ra thành phần Reader và trả về một đối tượng scenecó
chứa khung cảnh.
Scene load(java.lang.String fileName)
Phương thức lấy ra nội dung của một file từ tên file, và trả về một đối
tượng scene có chứa khung cảnh
Scene load(java.net.URL url)
Phương thức lấy ra nội dung của một file từ URL, và trả về một đối tượng
scene có chứa khung cảnh
void setBasePath(java.lang.String pathName)
Phương thức này thiiết lập đường dẫn cơ sở cho các file được dùng trong
phương thức load(String)
http://tailieuhay.com 362
Lập trình đồ họa trên Java 2D và 3D
void setBaseUrl(java.net.URL url)
Phương thức này thiiết lập đường dẫn cơ sở cho các file được dùng trong
phương thức load(URL)
void setFlags(int flags)
Phương thức thiết lập cờ load
LOAD_ALL Cho phép load toàn bộ các đối tượng vào khung cảnh.
LOAD_BACKGROUND_NODES Cờ cho phép load các đối tượng
backgrround vào khung cảnh.
LOAD_BEHAVIOR_NODES Cờ cho phép load các hành vi vào trong
khung cảnh.
LOAD_FOG_NODES Cờ cho phép load sương mù vào trong khung
cảnh.
LOAD_LIGHT_NODES Cờ cho phép load đối tượng ánh sáng vào
trong khung cảnh.
LOAD_SOUND_NODES Cờ cho phép load đối tượng âm thanh vào
trong khung cảnh..
LOAD_VIEW_GROUPS Cờ cho phép load đối tượng view (camera)
vào trong khung cảnh...
Lớp loader cơ sở cung cấp phần thực thi với mỗi phương thức load
(gồm 3 phương thức) được định nghĩa trong các loader interface.
Lớp Loader thực hiện phần thực thi 2 hàm tạo.
LoaderBase Constructor Summary
Gói: com.sun.j3d.loaders
Thực thi: Loader
Lớp Loader thực thi giao diện loader.
LoaderBase()
Khởi tạo đối tượng Loader với cá giái trị mặc định
http://tailieuhay.com 363
Lập trình đồ họa trên Java 2D và 3D
LoaderBase(int flags)
Khởi tạo đối tượng Loader với các cờ chỉ định
Khi chúng ta viết một lớp loader mới, chúng ta có thể thừa kế lại lớp
loader cơ sở trong gói com.sun.j3d.loaders và sử dụng lớp SceneBase
trong cùng gói này.
Trong quá trình viết một loader mới chúng ta cần xem xét việc thừa
kế lớp SceneBase hoặc thực thi interface Scene một cách trục tiếp.
Lớp ScaneBase có chức năng lưu trũ và nhận dữ liệu được tạo ra bởi
lớp Loader trong quá trình đọc file. Các phương thức thực hiện việc
lưu trữ (được cung cấp bởi những người viết ra Loader) có tên dạng
add* . Các phương thức thu nhận dữ liệu (được người sử dụng lớp
loader gọi ra) có tên dạng get*.
Khi thừa kế lớp loader cơ sở, công việc chú yếu của chúng ta là viết
các phương thức để nhận ra format của file. Mỗi phương thức này
tạo ra các thành phần scene graph tương ứng và lưu các dữ liệu này
trong đối tượng scene.
SceneBase Constructor Summary
Gói: com.sun.j3d.loaders
Thực thi giao diện Scene
Lớp SceneBase thực thi giao diện Scene.
SceneBase()
Khởi tạo một đối tượng SceneBasse
SceneBase Method Summary (partial list: loader users' methods)
Background[] getBackgroundNodes()
Behavior[] getBehaviorNodes()
java.lang.String getDescription()
http://tailieuhay.com 364
Lập trình đồ họa trên Java 2D và 3D
Fog[] getFogNodes()
float[] getHorizontalFOVs()
Light[] getLightNodes()
java.util.Hashtable getNamedObjects()
BranchGroup getSceneGroup()
Sound[] getSoundNodes()
TransformGroup[] getViewGroups()
Qua những điểm trên ta có thể xây dựng được loader cho nhu cầu cảu
mình. Phần tiếp theo ta sẽ đi vào chi tiết việc viết một loader.
Viết một loader
Công việc viết một loader là một công việc phức tạp và không phải
người lập trình Java 3D nào cũng phải viết. Tuy nhiên việc nghiên cứu
cách viết, làm việc cảu một Loader sẽ giúp chúng ta hiểu rõ hơn khi
nào thì sử dụng loader, hiểu cách sử dụng GeometryInfo, hiểu được
việc thực thi của ObjectLoader.
Công việc của một loader
Ngoài nhiệm vụ chính là đọc nội dung một file đồ hoạ, tạo ra một đối
tuợng scene graph thể hiện cho nội dung của file được load, lớp loader
còn có các chức năng khác.
• Tính toán bề mặt thông thường của các đa giác.
• Thể hiện đối tượng đồ họa tại nguyên gốc
• Chỉnh tỷ lệ của đối tượng hình học một cách thích hợp, tương ứng
1-1 trên mỗi trục
• Làm mịn đối tượng hình học
http://tailieuhay.com 365
Lập trình đồ họa trên Java 2D và 3D
• Thể hiện đối tượng hình học một cách hiệu quả bằng việc phân
nhỏ thành nhiều phần, hoặc sử dụng LOD.
Tuy nhiên không phải bất cứ loader nào cũng phải thực hiện đầy đủ
các chức năng trên. Nhiệm vụ chủ yếu của nó là tạo ra đối tướng
hình học tương ứng với nội dung file được load vào.
Hàm tạo lớp Loader
Trong phần này chúng ta sẽ xem xét việc tao ra một đối tuwọng
loader từ hàm tạo của lớp loader đã xaay dựng. Nhìn chung việc
xây dựng một lớp loader đồi hỏi những kiến thức liên quan đến
định dạng của file cần load và phần luồng stream trong Java.
Có nhiều cách tiếp caạn trong việc xây dựng một loader. Tuy nhiên
để có thể tận dụng được sự hỗ trợ của Java3D, chúng ta có thể dùng
các lớp SceneBase và LoaderBase (đã trình bày ở các chương
trước). Một loader được xây dựng trên các lớp này có khả năng
chọn được phần dữ liệu của file được sử dụng trong ứng dụng. Đó
là cách tiếp cận chuẩn cho việc xây dựng một loader.
Một khía cạnh khó khăn nữa là khi xây dựng một loader chúng ta
phải quan tâm đến format của file, có loại file đơn giản, có loại file
phức tạp, có những file còn có sự liên quan đến các file cấu hình
khác như file quy địng scene graph description.
Sử dụng khái niệm Layer, việc xây dựng lớp loader trở nên dễ dàng
hơn. Số lượng các layer lại phụ thuộc nhiều vào format của file cần
load. Sau đây chúng ta xem xét tập các layer đơn giản.
Layer/leve
l
Chức năng
Tokenizer Chuyển các ký tự thành các
http://tailieuhay.com 366
Lập trình đồ họa trên Java 2D và 3D
token
Đối tượng Chuyển các token hình ảnh
của file thành các đối tượng
đồ hoạ (geometry, lights,
textures… )Scene Chuyển danh sách các đối
tựong scene graph vào tong
khung cảnh đồ hoạFile Liên quan đến các file hay
các URL cần mở
• Tokenizer
Đây là tầng thấp nhất của loader trong việc xử lý các file đồ hoạ.
Tần này có nhiệm vụ chia nhỏ nội dung cảu file thành phần nhỏ
hơn, gọi là các token. Lấy ví dụ một token có thể là một số, một
từ, hay một ký tự đơn.
• Đối tượng
Tầng object có nhiệm vụ tạo ra các đối tượng đồ họa từ các
token được tạo ra theo nội dung của file. Một vài đối tượng có
thể là đối tượng đỉnh, đa giác, ánh sáng, kết cấu hay bất cứ đối
tượng khung cảnh nào trong Java3D. Những object này là các
thành phàn của một khung cảnh
• Scene
Là tập hợp các đối tượng hình học.Thông thường tầng scene
trong Java3D đơn giản. Trừ truờng hợp ngoại lệ khi nó lớp
loader có nhiệm vụ load một tệp đại diện cho một khung cảnh
đồ họa. Ví dụ như file theo định dạng Open Inventor và OOGL
List.
• File
http://tailieuhay.com 367
Lập trình đồ họa trên Java 2D và 3D
File có chứa nội dung cần được load.
Viết một File Loader đơn giản
Trong phần này chúng ta sẽ xem xét cụ thể hơn việc xây dựng một
loader đơn giản. Việc dầu tiên là chúng ta cần xác định định dạng
file mà loader của chúng ta sẽ load. Thông thường chúng ta sẽ chọn
lự một họ các file co định dạng tương đương, ví dụ như họ OOGL
(Object Oriented Graphics Library)
Định dạng QUAD
Bước đầu tiên để viết một Loader là biết được định dạng của file.
Trong phần này chúng ta sẽ xem xét qua về cấu trúc file QUAD,
các chi tiết cụ thể sẽ trình bày ở phần 4. Trong phần 4 chúng ta sẽ
xem xét những vấn đề :
Đa số các file OOGL đều có định dạng ASCII tự do- có các
khoảng trắng, trông, tab, dòng mới… giữa các phần tử (số, ký
tự…). Các phần comment được bắt đầu sau dấu # .
Định dạng QUAD thuộc loại định dạng OOGL. Định dạng QUAD
mô tả một tập hợp các bộ quad. Một file dạng QUAD là một tập
hợp 4*n đỉnh, trong đó n là số các bộ quad.
Ví dụ duới đây cho thấy noọi dung một file QUAD. File này chứa
thông tin về một hình vuông trên hệ không gian 3 chiều, với thành
phần z của hình vuông bằng 0, hình vuông này nằm trên mặt phẳng
Oxy.
http://tailieuhay.com 368
Lập trình đồ họa trên Java 2D và 3D
Cấu trúc của một ile QUAD nói chung là phứuc tạp hơn nhiều so
với ví dụ trên, tuy nhiên mục đích của chúng ta là tìm hiểu cách
viết một loader đơn giản nên ta dựa trên file QUAD đơn giản. Cấu
trúc chung của file QUAD được mô tả kỹ hơn trong phần 4.
Trong bảng dưới đâu đưa ra danh sách các lớp và mối quan hệ giữa
chúng để ta có thể xây dựng một lớp loader.
Tầng/Lớp Thực thi
tokenizer QuadFileParser
Object SimpleQuadObject chứa
QuadFileParserscene SimpleQuadScene thừa kế
lớp SimpleQuadObjectfile SimpleQuadFileLoader
thừa kế lớp
SimpleQuadScene thực thi
lớp Loaderapplication SimpleQuadLoad chứa lớp
SimpleQuadFileLoaderTrong các phần tiếp theo chúng ta sẽ xem xét kỹ hơn ácc lớp này,
thành phần và hoạt động của nó tỏng một ứng dụn loader.
Tầng Tokenizer(Quản lý các phần tử)
Bước đầu tiên để xây dựng một loader là xây dựng tokenizer. Điều
này được thực hiện bằng cách chúng ta thừa kế lớp tiện ích
StreamTokenizer. Lớp này đọc vào luồng các ký tự và chuyển đổi
nó thành tập các phần tử. Trong ví dụ này, chúng ta xây dựng lớp
QuadFileParser thừ kế lớp StreamTokenizer.
Các phương thức trong lớp QuadFileParser
http://tailieuhay.com 369
Lập trình đồ họa trên Java 2D và 3D
Phương thức Nhiệm vụ/hoạt động
Void setup() Chỉ ra các tham số cho tokenizer,
hàm này được gọi trong hàm tạoboolean getToken() Phương thức lấy ra token tiếp theo,
phương thức sử dụng hàm
nextToken()của lớp
StreamTokenizerVoid printToken() In giá trị của các token ra
System.out, dùng trng quá trình gỡ
lỗiQuadFileParser(Reade
r r)
Hàm tạo gọi phương thức setup và
liên kết các token với đối tượng
reader.
Những sự thay đổi mở rộng chủ yếu nằm trong phương thức setup.
Những sự thay đổi này bao gồm:
• Định nghĩa những ký tự đặc biệt, dấu xuống dòng, dấu
comment.
class QuadFileParser extends StreamTokenizer {
// setup
// Sets up StreamTokenizer for reading OOGL file formats.
void setup()
{
resetSyntax();
// EOL chars are insignificant in QUAD file
eolIsSignificant(false);
wordChars('A','z');
// have StreamTokenizer parse numbers (makes double-precision)
http://tailieuhay.com 370
Lập trình đồ họa trên Java 2D và 3D
parseNumbers();
// Comments begin with # to end of line
commentChar('#');
// Whitespace characters delineate words and numbers
// blanks, tabs, and newlines are whitespace in OOGL
whitespaceChars('\t', '\r'); // ht, lf, ff, vt, cr
whitespaceChars(' ', ' '); // space
} // End of setup
/* getToken
* Gets the next token from the stream. Puts one of the four
* constants (TT_WORD, TT_NUMBER, TT_EOL, or TT_EOF) and the
token
* value into ttype token object.
* The value of this method is in the catching of exceptions in this
* central location.
*/
boolean getToken()
{
int t;
boolean done = false;
try {
t = nextToken();
}
catch (IOException e) {
System.err.println(
"IO error on line " + lineno() + ": " + e.getMessage());
return false;
}
return true;
http://tailieuhay.com 371
Lập trình đồ họa trên Java 2D và 3D
} // End of getToken
// QuadFileParser constructor
QuadFileParser(Reader r)
{
super(r);
setup();
} // end of QuadFileParser
} // End of file QuadFileParser.java
Ta có thể thấy những thay đổi trong các phương thức getToekn(),
printToken() .. là không đáng kể. Như vậy ta đã hoàn thành việc
viết lớp QuadFileLoader, tiếp theo chung sta chuyển lên tầng trên,
tầng object.
Thực hiện tầng Object
Nhiệm vụ của tầng Object là chuyển những token được cung cấp
bởi tầng tokenizer sang các đối tượng hình học.Tỏng ví dụ của
chúng ta thì điều này là đơn giản bời vì chúng ta chỉ có một đối
tượng hình học duy nhất là tứ diện. Tuy nhiên chúng ta gặp phải
một khó khăn trong việc xác định số lượng đối tượng hình học
được cung cấp.
Các phương thức trong lớp SimpleQuadObject
Phương thức Nhiệm vụ
Boolean
readVertex(QuadFileParser st)
Đọc đỉnh, mỗi đỉnh bao gồm
tọa độ x,y,z hay các thông
tin khác về mầu sắc, bề
mặt… Boolean
readQuad(QuadFileParser st)
Đọc các tú diện bằng cách
đọc các đỉnh từ file QUAD
http://tailieuhay.com 372
Lập trình đồ họa trên Java 2D và 3D
Void
readQuadFile(QuadFileParserst)
Đọc file QUAD xác nhận
các thẻ trong file, xác định
tập các đỉnh và đọc ra cá tứ
diện(tứ giác)
Nhiệm vụ của tầng này là đọc ra các đối tượng hình học từ tập hợp
các token. Trong trường hợp này các đối tượng hình học là các
đỉnh. Tập các đỉnh này được lưu trữ trong một đối tượng ArrayList.
Sử dụng ArrayList chó phép việc thay đổi kích thước cảu mảng tạo
thời gian thực hiện. Tại tầng Scene, đối tượng kiểu ArrayList được
chuyển đổi sang một Array và sau đó là sang đối tượng hình học.
Chúng ta xem xét phần code chủ yếu trong tầng Object. Toàn bộ
phần code đầy đủ nằm trong example.jar.
import QuadFileParser;
// many other imports omitted in tutorial text
public class SimpleQuadObject
{
protected int flags;
protected int fileType = 0; // what properties vertices have
// constants for indicating file type
protected static final int COORDINATE =
GeometryArray.COORDINATES;
// lists of points are read from the .quad file into this //array. . .
protected ArrayList coordList; // Holds Point3f
/**
* readVertex reads one vertex's coordinate data
*/
boolean readVertex(QuadFileParser st)
{
http://tailieuhay.com 373
Lập trình đồ họa trên Java 2D và 3D
Point3f p = new Point3f();
st.getToken();
if(st.ttype == st.TT_EOF)
return false; // reached end of file
p.x = (float)st.nval;
st.getToken();
p.y = (float)st.nval;
st.getToken();
p.z = (float)st.nval;
// Add this vertex to the array
coordList.add(p);
return true;
} // End of readVertex
/**
* readQuad reads four vertices of the correct type (which in this
* version is always just coordinate data).
*/
boolean readQuad(QuadFileParser st)
{
int v;
boolean result = false;
for(v=0; v < 4; v++)
result = readVertex(st);
return result;
} // End of readQuad
/*
* readFile
*
* Read the model data from the file.
http://tailieuhay.com 374
Lập trình đồ họa trên Java 2D và 3D
*/
void readQuadFile(QuadFileParser st)
{
// verify file type
st.getToken();
if(st.sval.equals("QUAD") || st.sval.equals("POLY"))
fileType = COORDINATE;
else
throw new ParsingErrorException("bad file type: "+st.sval);
// read vertices
while (readQuad(st);
} // End of readFile
} // End of class SimpleQuadObject
// End of file SimpleQuadObject.java
Nếu trong chúng ta có các thông tin đi kèm với mỗi đỉnh như mầu
săc, chữ .. các thông tin này cũng được luwu trong một ArrayList.
Những thông tin thêm vào này cũng đựoc chuyển sang mảng thích
hợp trong tầng scene.
Đây là tầng thực hiện chủ yếu công việc của một loader. Tiếp đén
là tầng Scene, tầng khung cảnh
Thực hiện tầng Scene
Tầng scene thực thi bởi lớp SimpleQuadScene.
Các phương thưc lớp SimpleQuadScene
Phương thức Nhiệm vụSceneBase makeScene() Nhận dữ liệu từ một ArrayList do
tầng dưới đưa lên, tạo ra các đối
tượng hình học tương ứng và đưa
http://tailieuhay.com 375
Lập trình đồ họa trên Java 2D và 3D
vào khung cảnh đồ họa
Point3f[]
objectToPoint3fArray(ArrayList
in)
Chuyển đổi một ArrayList thành
một mảng Point3f, dùng phương
thức makeScene()để tạo ra các đối
tượng hình họcScene load(Reader reader) 1.Khởi tạo a một đối tượng
QuadFileParser
2.Gọi QuadFileLoad(scene)
3.Gọi makeScene()
class SimpleQuadScene extends SimpleQuadObject
2. {
3. // coordList is converted to an arrays for creating geometry
4. //
5. private Point3f coordArray[] = null;
6.
7. private Point3f[] objectToPoint3fArray(ArrayList inList)
8. {
9. Point3f outList[] = new Point3f[inList.size()];
10.
11. for (int i = 0 ; i < inList.size() ; i++) {
12. outList[i] = (Point3f)inList.get(i);
13. }
14. return outList;
15. } // End of objectToPoint3fArray
16.
http://tailieuhay.com 376
Lập trình đồ họa trên Java 2D và 3D
17.
18. private SceneBase makeScene()
19. {
20. // Create Scene to pass back
21. SceneBase scene = new SceneBase();
22. BranchGroup group = new BranchGroup();
23. scene.setSceneGroup(group);
24.
25. // the model will be one Shape3D
26. Shape3D shape = new Shape3D();
27.
28. coordArray = objectToPoint3fArray(coordList);
29.
30. QuadArray qa = new QuadArray(coordArray.length, fileType);
31. qa.setCoordinates(0, coordArray);
32.
33. // Put geometry into Shape3d
34. shape.setGeometry(qa);
35.
36. group.addChild(shape);
37. scene.addNamedObject("no name", shape);
38.
39. return scene;
40. } // end of makeScene
41.
42. public Scene load(Reader reader) throws FileNotFoundException,
43. IncorrectFormatException,
44. ParsingErrorException
45. {
http://tailieuhay.com 377
Lập trình đồ họa trên Java 2D và 3D
46. // QuadFileParser does lexical analysis
47. QuadFileParser st = new QuadFileParser(reader);
48.
49. coordList = new ArrayList();
50.
51. readQuadFile(st);
52.
53. return makeScene();
54. } // End of load(Reader)
55. } // End of class SimpleQuadScene
56. // End of file SimpleQuadScene.java
Thực hiện tầng File
Tầng này có nhiệm vụ thực hiện việc giao tiếp với File. Đa số phần
code của tầng này cũng tươn tự như ở tầng Object. Lớp
SimpleQuadFileLoader thừa kế lớp SimpleQuandScene và thực thi
giao diện Loader.
Xây dựng một Loader hoàn chỉnh
Trong thực tế có rất nhiều thông tin chi tiết trong file QUAD mà
loader đơn giản mà chúng ta vừa xây dựng không đáp ứng dược. Ví
dụ như những ký hiệu khoa học trong một file QUAD, các thông
tin về mầu săc… Lớp StreamTokenizer chúng ta xây dựng chưa
đáp ứng nhu cầu đó.
Một file QUAD cso thể chứa những thông tin về bề mặt, mầu sắc ..
của mỗi đỉnh, mỗi đối tượng. Để nhận được các thông tin này
chúng ta cần thay đổi tầng Object và tầng scene.
http://tailieuhay.com 378
Lập trình đồ họa trên Java 2D và 3D
Một file QUAD có thể bao gồm nội dung của một file khác. Điều
này làm tăng sự phức tạp của loader và đói hỏi việc thay đổi code
tại tất cả các tầng.
Một loader phức tập hơn có thể nhận ra và load được một họ các
định dạng file, ví dụ như LightWave loader.
Text2D
Có hai cách để thực hiện việc them chữ vào trong khung hình
Java3D. Cách thứ nhất là sử dụng lớp Text2D, cách thứ hai là sử
dụng Text3D. Sự khác nhau ở chỗ, lớp Text2D thực hiện các dòng
chữ trong không gian 2 chiều còn Text3D thực hiện trong không
gian 3 chiều.
Đối tượng Text2D là các đa giác vuông trong đó các chữ được coi
như là phần bề mặt. Đối tuwọng Text3D là những đối tượng hình
học trong không gian 3 chiều.
Là một lớp con của lớp Shpae3D, thể hiện của lớp Text2D có thể là
con của đối tượng group. Để thêm vào dòng chữ 2D trong Java3D
chúng ta cần tạo ra đói tượng Text2D sau đó thêm nó vào không
gian đồ hoạ.
Đối tượng Text2D được thực hiện sử dụng một đa giác và một
texture.
http://tailieuhay.com 379
Lập trình đồ họa trên Java 2D và 3D
3.5.1 Ví dụ Text2D đơn giản
Trong ví dụ dưới đây chúng ta xem xét việc tạo ra một dối tượng
Text2D đơn giản. Bao gồmg bước tạo ra đối tượng Text2D và bước
tiếp hteo là thêm đối tượng này vào không gian đồ họa.
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.Font;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Text2D;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
// Text2DApp renders a single Text2D object.
public class Text2DApp extends Applet {
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
// Create a Text2D leaf node, add it to the scene graph.
Text2D text2D = new Text2D("2D text is a textured polygon",
new Color3f(0.9f, 1.0f, 1.0f),
"Helvetica", 18, Font.ITALIC));
objRoot.addChild(text2D);
3.5.2 Lớp Text2D
Lớp Text2D là lớp tiện ích thừ kế từ lớp Shape3D.
http://tailieuhay.com 380
Lập trình đồ họa trên Java 2D và 3D
Hàm tạo lớp Text2D.
Text2D Constructor Summary
Gói: com.sun.j3d.utils.geometry
Lớp Text2D tạo ra một khung chữ nhật được ánh xạ đến phàn nội dung
text, hiẹn thị nội dung text được gửi bởi nguời dùng. Kích thước của
khung chữ nhạt được xác định phụ thuộc vào font được sử dụng(tham số
của hàm tạo). Kêt quả của đối tượng Shape3D trong suốt ngoại trừ hình
chữ nhật chứa nội dung text được đặt tại vị trí (0,0,0) kéo dài theo chiều
dương trục x, trực y
Text2D(java.lang.String text, Color3f color, java.lang.String
fontName,
int fontSize, int fontStyle)
Trong hàm tạo Text2D ta có thể thay đổi tỷ lệ kích thứoc của đối
tuwọng dòng chữ hiện ra so với kích thước điểm cố định.
Text2D Method Summary
void setRectangleScaleFactor(float newScaleFactor)
http://tailieuhay.com 381
Lập trình đồ họa trên Java 2D và 3D
Đặt giá trị tỷ lệ được sử dụng trong việc chuyển đổi chiều rộng/chiều dài
của hình ảnh sang chiểu rộng/chiều cao tương ứng trong không gian đồ
họa bắt đầu bằng thừa số 1/256
void setString(java.lang.String text) <new in 1.2>
Thiết lập giá trị dùng chữ hiện thị cho đối tượng Text2D
Text3D
Trong phần này chúng ta tìm hiểu vấn đề làm việc với lớp Text3D.
Khởi tạo một đối tượng Text3D bao gồm nhiều công việc hơn trong
đối Text2D. trước hết đối tượng Text3D được tạo ra bằng cách sử
dụng đối tượng hình học. Bước đầu tiên chúng ta phải tạo ra đối
tượng Font3D bao gồm các thuộc tính bề mặt, kích thứoc và kích
cỡ của font. Lớp Text3D là lớp con của lớp Geometry, nên đối
tuwọng text3D là một đối tượng NodeComponent được tham chiếu
bởi một hay nhiều đối tuwọng Shape3D.
Các bước tạo ra đối tượng Text3D
• Tạo mới đối tượng Font3D từ AWTFont
• Tạo mới đối tượng Text3D sử dụng đối tượng Font3D, ta có
thể chỉ định diểm tham chiếu tuỳ chọn
• Tham chiếu đói tượng Shape3D, và thêm ào không gian đồ
hoạ
Một ví dụ Text3D
Các bước tạo ra và sử dụng đối tuwọng Text3D được minh hoạ
trong ví dụ sau. Trong đó đối tuwọng Font3D tạo ra với thuộc tính
kiểu bề mặt là “Helvetica”, font chữ là 10. Sau đó chúng ta tạo ra
đối tượng Text3D tham chiếu đến một điểm trong không gian đồ
họa.
http://tailieuhay.com 382
Lập trình đồ họa trên Java 2D và 3D
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.Font;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
// Text3DApp renders a single Text3D object.
public class Text3DApp extends Applet {
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
Font3D font3d = new Font3D(new Font("Helvetica", Font.PLAIN, 10),
new FontExtrusion());
Text3D textGeom = new Text3D(font3d, new String("3DText"),
new Point3f(-2.0f, 0.0f, 0.0f));
Shape3D textShape = new Shape3D(textGeom);
objRoot.addChild(textShape);
Chúng ta xem hình dưới đây.
http://tailieuhay.com 383
Lập trình đồ họa trên Java 2D và 3D
Để tạo ra chiều sâu (thể hiện bằng vùng mầu ghi) chúng ta sử dụng
các đối tượng Material và đối tuwọng DirectionLight.
Ta có thể “chiếu sáng” đối tượng Text3D theo nhiều hướng khác
nhau. Để có thể chiếu nhiêug hướng khác nhau chúng ta sử dụng
lớp Material.
Mỗi đối tượng Text3D có một điểm tham chiếu. Điểm tham chiếu
là sự kết hợp của path và alignment của đối tượng Text3D.
Trong bảng dưới đây cho ta minh họa về sự kết hợp này.
Những lớp liên quan để tạo ra đối tượng Text3D
Trong phần này chúng ta xem xét những lớp có liên quan để tạo ra
đối tượng Text3D.
http://tailieuhay.com 384
Lập trình đồ họa trên Java 2D và 3D
Lớp Text3D bao gồm nhiều hàm tạo. Cho phép ta tạo ra đối tuwọn
Text3D một cách linh hoạt.
Text3D Constructor Summary
A Text3D object is a text string that has been converted to 3D geometry.
The Font3D object determines the
appearance of the Text3D NodeComponent object. Each Text3D object
has a position - a reference point placing the
Text3D object. The 3D text can be placed around this position using
different alignments and paths.
Một đối tượng Text3D là một xâu ký tự được chuyển đổi sang hình học
3D. Đối tượng Font3D xác định bề ngoài của đối tượng Text3D
NodeComponent
Text3D()
Tạo ra đối tượng Text3D. Các giá trị mặc định:
appropriate, are:
font 3D null
string null
position (0,0,0)
alignment ALIGN_FIRST
path PATH_RIGHT
character spacing 0.0
http://tailieuhay.com 385
Lập trình đồ họa trên Java 2D và 3D
Text3D(Font3D font3D)
Tạo ra đối tượng Text3D với đối tượng Font3D đã xác định
Text3D(Font3D font3D, String string)
Tạo ra đối tượng Text3D với đối tượng Font3D đã xác định và nội dung
của xâu ký tự cần hiển thị
Text3D(Font3D font3D, String string, Point3f position)
Tạo ra đối tượng Text3D với cá tham số đối tượng Font3D, xâu ký tự, tọa
độ của điểm tham chiếu. Mặc định điểm tham chiếu nằm về phía bên
dưoiứ cùng bên trái của chữ cần hiển thị
Text3D(Font3D font3D, String string, Point3f position,
int alignment, int path)
ALIGN_CENTER Căn lề giữa.
ALIGN_FIRST alignment: ký tự đầu tiên của dòng chữ được đặt tịa
điểm tham chiếu.
ALIGN_LAST alignment: ký tự cuối cùng của dòng chữ được đặt tại
điểm tham chiếu..
Xem thêm ví dụ ở bảng trên.
Những phương thức của lớp Text3D, gồm những phương thức để
thiết lập các thuộc tính của đối tượng Text3D (setXXX), những
phương thức lấy giá trị các tuộc tính của đối tượng
Text3D(getXXX).
Text3D Method Summary
void setAlignment(int alignment)
Đặt canh lề cho đối tượng Text3D NodeComponent
void setCharacterSpacing(float characterSpacing)
http://tailieuhay.com 386
Lập trình đồ họa trên Java 2D và 3D
Đặt ký tự dấu cách khi tạo ra đối tượng Text3D
void setFont3D(Font3D font3d)
Thiết lậo đối tượng Font3D được sử dụng bởi đối tượng Text3D
NodeComponent
void setPath(int path)
Đặt đường dẫn của node
void setPosition(Point3f position)
Đặt điểm tham chiếu của node
void setString(java.lang.String string)
Copies the character string from the supplied parameter into the Text3D
node.
Copy xâu ký tự từ tham só đầu vào cho đối tượng Text3D node.
Các chế độ của đối tượng Text3D.
Text3D Capabilities Summary
ALLOW_ALIGNMENT_READ | WRITE Cho phép đọc ghi giá trị xâu
ký tự.
ALLOW_BOUNDING_BOX_READ
ALLOW_CHARACTER_SPACING_READ | WRITE Cho phép đọc
ghi các ký tự dấu cách.
ALLOW_FONT3D_READ | WRITE cho phép đọc ghi thông tin các
thành phần Font3D
ALLOW_PATH_READ | WRITE Cho phép đọc ghi giá trị xâu đường
dẫn.
ALLOW_POSITION_READ | WRITE Cho phép đọc ghi giá trị vị trí
của xâu
http://tailieuhay.com 387
Lập trình đồ họa trên Java 2D và 3D
ALLOW_STRING_READ | WRITE Cho phép dọc ghi đối tượng xâu
ký tự..
Mỗi đối tượng Text3D được tạo ra từ một đối tượng Font3D. Một
đối tượng Font3D có thể được dùng để tạo ra nhiều đối tượng
Text3D khác nhau. Một đối tượng Font3D lưu các thông tin về bề
dầy hình học của đối tượng Text3D. Đối tuwonjg Font3D được thu
hồi tự động (garbage collected) mà không ảnh hưởng đến đối tượng
Text3D sử dụng chúng.
Font3D Constructor Summary
Lớp cha: java.lang.Object
Một đối tượng Font3D bao gồm Java 2D Font và chiều sâu.
Font3D(java.awt.Font font, FontExtrusion extrudePath)
Font3D(java.awt.Font font, double tessellationTolerance,
FontExtrusion extrudePath) <new in 1.2>
ALLOW_PATH_READ | WRITE Cho phép đọc ghi giá trị đường dẫn.
ALLOW_POSITION_READ | WRITE Cho phép đọc ghi giá trị vị trí.
ALLOW_STRING_READ | WRITE Cho phép đọc ghi đối tượng xau
ký tự.
Lớp Font3D không có những phương thức set* cụ thể, việc thiết
lập các thuộc tính của đối tượng Font3D được thực hiện trong hàm
tạo. Dưới đây là các phương thức get*.
Font3D Method Summary
void getBoundingBox(int glyphCode, BoundingBox bounds)
java.awt.Font getFont()
Returns the Java 2D Font used to create this Font3D object.
Trả về đối tượng Java2D Font được sử dụng để tạo ra đối tượng Font3D
http://tailieuhay.com 388
Lập trình đồ họa trên Java 2D và 3D
void getFontExtrusion(FontExtrusion extrudePath)
Copies the FontExtrusion object used to create this Font3D object into the
specified parameter.
Thiết lập giá trị đối tượng FontExtrusion sử dụng để tạo ra đối tượng
Font3D bằng giá trị cảu tham số đầu vào. double
getTessellationTolerance() <new in 1.2>
Lớp Font được sử dụng trong việc tạ ra đối tượng Font3D. Ta mô tả
một hàm tạo lớp Font, các hàm tạo còn lại có thể xem thêm trong
javadoc.
Font Constructor Summary (partial list)
Gói: java.awt
public Font(String name, int style, int size)
Hàm tạo mới một đối tượng Font với tham số tên Font, kiểu, kích cỡ
name - the typeface name. Có thể là ten logic hoặc ten typeface. Một tên
logic cần phải là mộ trong các gía trị:
Dialog, DialogInput, Monospaced, Serif, SansSerif, or Symbol.
style -
Tham số kiểu có thể alf mộ trong các kiểu: BOLD, ITALIC …
size - Cỡ Font.
Hàm tạo lớp FontExtrusion
FontExtrusion Constructor Summary
Lớp cha: java.lang.Object
The FontExtrusion object is used to describe the extrusion path for a
Font3D object. The extrusion path is used in
conjunction with a Font2D object. The extrusion path defines the edge
contour of 3D text. This contour is
http://tailieuhay.com 389
Lập trình đồ họa trên Java 2D và 3D
perpendicular to the face of the text. The extrusion has its origin at the
edge of the glyph with 1.0 being the height of
the tallest glyph. Contour must be monotonic in x. User is responsible for
data sanity and must make sure that
extrusionShape does not cause intersection of adjacent glyphs or within
single glyph. The output is undefined for
extrusions that cause intersections.
FontExtrusion()
Hàm tạo với giá trị mặc định
FontExtrusion(java.awt.Shape extrusionShape)
Hàm tạo đối tượng FontExtrusion với đối số shape truyền vào và
tolerance = 0.01
FontExtrusion(java.awt.Shape extrusionShape, <new in 1.2>
double tessellationTolerance)
http://tailieuhay.com 390
Lập trình đồ họa trên Java 2D và 3D
Các phương thức lớp FontExtrusion
FontExtrusion Method Summary
java.awt.Shape getExtrusionShape()
Gets the FontExtrusion's shape parameter.
void setExtrusionShape(java.awt.Shape extrusionShape)
Sets the FontExtrusion's shape parameter.
double getTessellationTolerance() <new in 1.2>
Return the tessellation tolerance with which this FontExtrusion object was
created.
Nền không gian đồ họa
Một cách mặc định, mầu nền của không gian đồ họa là mầu đen sẫm.
Tuy nhiên Java3D cung cấp cho chúng ta khả năng thay đổi nền của
không gian đồ họa, ta có thể lựa chọn mầu sắc, ảnh, các đối tượng hình
học hay kết hợp các thành phần này lại để tạo thành nền của không
gian đồ họa.
Các bước tạo ra nnè của không gian đồ họa:
• Khởi tạo một đối tượng background mới chỉ định mầu sắc hoặc
một hình ảnh nào đó.
• Thêm vào một đối tượng hình học (tùy chọn)
• Cung cấp một Application Boundary hoặc một BoundingLeaf
• Thêm đối tượng background vào không gian đồ họa
Một ví dụ background
Như ta đã trình bày ở phần trước. Một dói tuợng background có thể là
một mầu cụ thể, một hình ảnh hay thậm chí môt đối tượng hình học.
http://tailieuhay.com 391
Lập trình đồ họa trên Java 2D và 3D
tỏng ví dụ đầu tiên chúng ta sẽ xem xét đối tượng backgrond là mầu
trắng, ví dụ thứ hai ta thêm một đối tượng hinh học vào background.
Ví dụ background là mầu nền
Background backg = new Background(1.0f, 1.0f, 1.0f);
//
backg.setApplicationBounds(BoundingSphere());
contentRoot.addChild(backg);
Ví dụ background là đối tượng hình học
Background backg = new Background(); //black background
backg.setGeometry(createBackGraph()); // add BranchGroup
of background
backg.setApplicationBounds(new BoundingSphere(new
Point3d(), 100.0));
objRoot.addChild(backg);
Phương thức createBackGraph() bao gồm việc tạo ra đối tượng hình
học làm nền. Phương thức này trả về đối tượng BranchGroup. Ta có
thể xem một ví dụ hoàn chinh BackgroundApp.java trong thư mục
examples/easyContent.
Lớp Background
Trong phần này chúng ta xem xét cụ thể thành phần và họat dộng của
lớp background
Lớp background thừa kế lớp Leaf, một thể hiện của lớp background là
thành phần con thuộc đối tượng Group
http://tailieuhay.com 392
Lập trình đồ họa trên Java 2D và 3D
Background có nhiều hàm tạo. Tham số trong hàm tọa cho biêt mầu
sắc hoặc hình ảnh cho background.
Hàm tạo của lớp Background
Background Constructor Summary
The Background leaf node defines either a solid background color or a
background image that is used to fill the
window at the beginning of each new frame. It optionally allows
background geometry to be referenced.
Background geometry must be pre-tessellated onto a unit sphere and is
drawn at infinity. It also specifies an
application region in which this background is active.
Background()
Constructs a Background node with a default color (black).
Background(Color3f color)
Constructs a Background node with the specified color.
Background(float r, float g, float b)
Constructs a Background node with the specified color.
Background(ImageComponent2D image)
Constructs a Background node with the specified image.
Các phương thức trong lớp background
http://tailieuhay.com 393
Lập trình đồ họa trên Java 2D và 3D
Background Method Summary
void setApplicationBoundingLeaf(BoundingLeaf region)
Set the Background's application region to the specified bounding leaf.
void setApplicationBounds(Bounds region)
Set the Background's application region to the specified bounds.
void setColor(Color3f color)
Sets the background color to the specified color.
void setColor(float r, float g, float b)
Sets the background color to the specified color.
void setGeometry(BranchGroup branch)
Sets the background geometry to the specified BranchGroup node.
void setImage(ImageComponent2D image)
Sets the background image to the specified image.
Các tham số cáu hình khác của đối tượng Background
Background Capabilities Summary
ALLOW_APPLICATION_BOUNDS_READ | WRITE allow read
(write) access to its application bounds
ALLOW_COLOR_READ | WRITE allow read (write) access to its
color
ALLOW_GEOMETRY_READ | WRITE allow read (write) access to
its background geometry
ALLOW_IMAGE_READ | WRITE allow read (write) access to its
image
3.8 Dữ liệu người dùng:
Các đối tượng SceneGraphObject có thể tham chiếu đến bất cứ đối
tượng nào như là các dữ liệu người dùng. Danh sách lớp con của lớp
http://tailieuhay.com 394
Lập trình đồ họa trên Java 2D và 3D
SceneGraphObject gòm có: Appearance, Background, Behaviour,
BranchGroup, Geometry, Lights, Shape3D và TransformGroup.
Lấy ví dụ, một ứng dụng có thể có nhiều đối tượng có khả năng tương
tác, di chuyển. Mỗi đối tượng có thể có thể chứa những dữ liệu dạng
text trong đối tượng dữ liệu người dùng.
Các phương thức lớp SceneGraphObject
SceneGraphObject Methods (Partial List - User Data Methods)
SceneGraphObject is a common superclass for all scene graph component
objects. This includes Node, Geometry,
Appearance, etc.
java.lang.Object getUserData()
Retrieves the userData field from this scene graph object.
void setUserData(java.lang.Object userData)
Sets the userData field associated with this scene graph object.
http://tailieuhay.com 395
Lập trình đồ họa trên Java 2D và 3D
CHƯƠNG 4
TƯƠNG TÁC
Trong chúng ta sẽ tìm hiểu về các vấn đề sau:
• Tìm hiểu lớp Behaviour, lớp cơ sở cho việc thực hiện tương tác và
xây dựng hoạt hình
• Xây dựng một lớp Behaviour
• Phối hợp các đối tượng Behaviour vào trong thế giới ảo để thực
hiện tưong tác
• Sử dụng lớp tiện ích xử lý bàn phím
• Sử dụng lớp tiến ích xử lý chuột
• Sử lớp lớp tiệc ích picking
Trong các chương trước chúng ta đa xem xét việc lập trình Java3D mọt
cách hoàn toàn tĩnh. Tuy nhiên điều thú vị cảu Java3D còn nằm ở vịec lập
trình tương tác và hoạt hình.
Tương tác là khi các hình ảnh thay đổi phản ứng lại hành động cảu người
dùng. Hoạt hình là những thay đổi của hình ảnh mà không cần sự tương
tác trực tiếp của con người. Trong Java3D, cả tương tác và hoạt hình đều
sử dụng lớp Behaviour. Chúng ta sẽ xem xét lớp này chi tiét hơn trong
các mục chủa chuwong này.
http://tailieuhay.com 396
Lập trình đồ họa trên Java 2D và 3D
4.1 Hành vi: Cơ sở của tương tác và hoạt hình
Cả tưong tác và hạot hình đều sử dụng đối tượng Behaviour. Lớp
Behaviour là một lớp cơ sở trừu tượng, cung cấp các kỹ thuật để thay đổi
đồ thị khung cảnh. Lớp Behaviour và các lớp dẫn xuất, liên kết với phần
mã của người phát triển cung cấp nhằm làm thay đổi hình ảnh, âm thanh
trong không gian ảo. Đối tượng Behaviour trong một đồ thị khung cảnh
có nhiệm vụ thây đổi đồ thị khung cảnh, hay phản ứng lại các kích thích.
Một kích thích, hay tác động có thể là việc ấn một phím, di chuyển chuột,
sự va chạm giữa các đối tượng… Những tác động này có thẻ thêm vào
các đối tượng trong đồ thị khung cảnh hay loại bỏ cá đối tượng trong đồ
thị khung cảnh, thay đổi thuộc tính của đối tượng, sắp lại lại các đối
tượng …
4.1.1 Ứng dụng của hành vi
Trong bảng dưới đây chúng ta sẽ liệt kê những khả năng có thể của
lớp Behaviour, liệt kê nhưng tác nhân từ cột bên trái xuống phỉa dưới, và
những thay đổi nằm trên dòng đầu. Chúng ta chỉ liệt ke những khả năng
đơn giản cảu Behaviour chứ không liệt kê đầy đủ tất cả các khả năng có
thể của Behaviour. Một vài sự kết hợp giữ các tác nhân và các thay đổi
chỉ có ý nghĩa trong những trường hợp đặc biệ, chúng ta gọi là ứng dụng
cụ thể.
Tác nhân TransformGroup Geometry SceneGraph Vie w
Người
dùng
Tương tác Ứng dụng cụ
thể
Ứng dụng
cụ thể
Di
chuyển
Sự va
chạm
Đối tượng trực
quan thay đổi
Đối tượng
trực quan
Đối tượng
xuất hiện
Thể
hiện
http://tailieuhay.com 397
Lập trình đồ họa trên Java 2D và 3D
hướng hay vị trí thay đổi bề
noài trong
các va chạm
trong các va
chạm
những
thay đổi
trong va
chạm
Thời
gian
Hoạt hình Hoạt hình Hoạt hình Hoạt
hìnhKhung
nhìn
Bảng Tần các chi
tiết
(LOD)
Ứng dụng
cụ thể
Ứng
dụng cụ
thể
Bảmg trên chúng ta chỉ liệt kê những truờn hợp đơn giản những khả
năng của lớp Behaviour. Picking được thực thi sử dụng các hành vi
nhưng không được liệ kê ở trên.
Nhưng sự vật ngoài tự nhiên, như một cái cây, bao gồm một số lượng
rất lơn các đối tượng hình học được thể hiện một cách chính xác như la,
cành .Một phương pháp khác được sử dụng là sử dụng kết cấu đa giác
thay cho các đối tượng hình học.
Kỹ thuật trên (texture polygon) thương được gọi là billboard
approach. Điều này là hợp lý và đúng đắn khi một hành vi được sử dụng
tự động định hướng textured polygon trực giao với khung nhìn, trong đó
chỉ có bè mặt cảu kết cấu đa diện được nhìn thấy. Hành vi định hướnggọi
là billboard behavior.
Hướng tiếp cận billboard thực sự hiệu quả khi đối tượng được biểu
diễn bởi texture có khoảng cách xa vì vậy các phần độc lập khác của đối
tượng trực quan được biểu diễn bởi texture sẽ khó khăn. Lấy ví dụ biểu
diễn một cái cây, nếu khung nhìn là rất xa không đủ khả năng nhìn một
cách rõ ràng và nổi bật cành cây, khi đó sẽ là rất vô lý và phí phạm khi
tốn bộ nhớ và công việc xử lý để biể diên tưng chiếc lá. Kỹ thuật này
http://tailieuhay.com 398
Lập trình đồ họa trên Java 2D và 3D
được khuyến khích sử dụng trong các ứng dụng yêu cầu thể hiện các đối
tượng trực quan ở khoảng cách xa.
Hành vi LOD (level of detail) c ó nh ững ứng dụng liên quan. Với
LOD, các đối tượng trực quan được biểu diễn bởi rất nhiều đối tượng trực
quan khác nhỏ hơn, chi tiết hơn. Khi khung nhìn (viewer) càng gần các
chi tiết được thể hiẹn càng rõ và khi khung nhìn ở xa, các đối tượng trực
quan được biểu diễn ít chi tiết hơn. Behaviour LOD tự động chuyển đổi
các chế độ trình diễn dựa vào khoảng cách giữa đối tượng với viewer.
Cả billboard và LOD đều tương ứng với các lớp dẫn xuất từ lớp
Behaviour
4.1.2 Tổng quan lớp Behaviour
Trong bảng 4-1, chỉ rõ sự chuyên môn hoá của Behaviour trong
Java3D API và các gói tiện ích. Trong phần này chúng ta sẽ lân lượt xem
xét từng lớp trong bảng 4-1.
4.2 Cơ bản về hành vi
Như đã đề cập trong các phần trước, lớp Behaviour được sủ dụng
nhiều trong các ứng dụng Java3D theo nhiều cách khác nhau.Việc tìm
hiểu hoạt đọng và lập trình với lớp Behaviour là điều rất quan trọng.
Trong mục này chúng ta sẽ tìm hiểu lớp Behaviour, đưa ra cách thức để
tạo ra một lớp Behaviour của riêng mình và một ví sử dụng lớp
Behaviour.
http://tailieuhay.com 399
Lập trình đồ họa trên Java 2D và 3D
Sơ đồ các lớp con của lớp Behaviour
4.2.1 Viết một lớp Behaviour
Trong phần này chúng ta sẽ tìm hiểu cách viết một lớp
Behaviour.Mechanics của Behaviours
Một lớp Behaviour thực thi quá trình khởi tạo và phương thức
processStimulus của lớp cơ sở trừu tượng Behaviour. Ngoài ra một lớp
Behaviour tự xây dựng cũng có ít nhất một àhm tạo và có các phương
thức khác của riêng nó.
Các Behaviour thông qua các đối tượng đồ hoạ, sẽ hành động trong
một đồ thị khung cảnh nhằm tác động đến hành vi. Đối tượng Behaviour
cần một tham chiếu đến đối tượng có sự thay đổi, để nó có khả năng tạo
ra những hành vi thay đổi.
Trong hàm tạo, có thể thiết lập tham chiếu đến đối tượng trong sự
thay đổi. Nếu không, tỏng một phương thức khác cảu lớp Behaviour tự
xây dựng phải chứa những thông tin này, quá trình tham chiếu phải được
thực hiện tại thời điểm đồ thị khung cảnh được tạo ra.
http://tailieuhay.com 400
Lập trình đồ họa trên Java 2D và 3D
Quá trình khởi tạo được gọi đến khi đồ thị khung cảnh chứa lớp
Behaviour được tạo ra.
Phương thức khởi tạo có trách nhiêm cài đặt những trigger ban đầu để
bắt các sự kiện của Behaviour và cái đặt những điều kiện ban đầu cho
các dữ liệu tĩnh của đối tượng Behaviour.
Các triggger thực chất là các đối tượng WakeupCondition (các điệu
kiến thức dậy), hay là sự kết hợp của các WakeupCondition . Phương
thức processStimulus được gọi khi các trigger được kích hoạt. Phương
thức processStimulus có trach nhiệm bắt và xử lý các sự kiện xảy ra.
Nhiều sự kiện có thể có thể được mã hoá trong một đối tượng
WakeupCondition (nhiều loại kích hoạt của bàn phím có thể được mã
hoá trong WakeupOnAWTEvent), nó bao gồm cả việc giải mã các sự
kiện.
Phương thức processStimulus phản xạ lại các tác nhân, thường là sự
thay đổi của các đối tượng, trong những điều kiện thích hợp, thiết lập lại
các trigger.
Tiếp theo chúng ta xem xét các bước để viết một lớp Behaviour cho
riêng mình.
Viết hàm tạo, chứa tham chiếu đến đối tượng trong sự thay đổi
Viết đè hàm khởi tạo public void initialization(),chỉ định các tiêu
chuẩn kích hoạt ban đầu (trigger)
Viết đè hàm public void processStimulus(), giải mã điều kiện xảy ra
hành động của trigger, reset lại trigger nếu cần thiết.
Các bước trên là các thức chúng ta tạo ra các lớp Behaviour đơn gaỉn,
những Behaviour phức tạp đòi hỏi phải lập trình xử lý nhiều bước hơn.
Chúng ta xem xét ví dụ dưới đây, được thực hiện theo các bước đã
nêu ở trên
Ví dụ xây dựng lớp Behaviour : SimpleBehaviour
http://tailieuhay.com 401
Lập trình đồ họa trên Java 2D và 3D
Trong ví dụ dưới đây chúng ta xây dựng một lớp Behaviour thực hiện
một hành vi đơn giản, làm quay một số thứ dưới sự điều khiển banừg bàn
phím. Để xây dựng một lớp Behaviour như vậy, chúng ta cần một tham
chiếu đến một TransformGroup (đối tượng chứa, chịu sự thay đổi) và
một biến góc nghiêng. Dưới sự kích hoạt của bàn phím, goc nghiêng sẽ
thay đổi và góc nghiêng của TransformGroup được thiết lập bằng với
giá trị mới của góc nghiêng này. Khi đó việc quay đối tượng
TransformGroup không còn là vấn đề khó khăn nữa.
Để tạo ra lớp Behaviour này, chúng ta chỉ cần lập trình theo các
buwóc đã nêu ở trên. Hàm tạo sẽ chứa tham chiếu đến đối tượng
TransformGroup của sự thay đổi. Phương thức initialization thiết lập cá
thông số trigger ban đầu theo sự kiện WakeOnAWTEvent sự kiện, và
thiết lập góc nghiêng bằng 0. Như đã đề cập ở phần trên, tác nhân của một
Behaviour được coi như một đối tượng WakeupCondition . Trong phần
4.3 chngs ta sẽ xem xét lớp WakeupCondition . Phương thức
processStimulus sẽ giải mã phím bấm đẻ có thể xác định được phím hay
tổ hợp phím nào được ấn. Phương thức processStimulus thuwòng xuyên
tăng biến góc nghiêng lên, từ đó ta có thể điều chỉnh sự thay đổi cảu đối
tượng TransformGroup một cách thích hợp. Công việc cuối cùng của
phương thức processStimulus là thiết lập lại các trigger.
Trong ví dụ này, trigger luôn luôn được thiết lập lại dưới tác động của
phím bấm. Behaviour có thể thay đổi các trigger của mình thạm chí trong
suốt thời gian hoạt đọng cảu Behaviour để thay đổi các hành vi.
Trong ví dụ dưới đây gói java.awt.event dùng để xử lý tương tác với
bàn phím. Gói java.util.enumeration cần thiết để giải mã đối tượng
WakeuponCondition
http://tailieuhay.com 402
Lập trình đồ họa trên Java 2D và 3D
// SimpleBehaviorApp renders a single, rotated
cube.
public class SimpleBehaviorApp extends Applet {
public class SimpleBehavior extends Behavior
{
private TransformGroup targetTG;
private Transform3D rotation = new
Transform3D();
private double angle = 0.0;
// create SimpleBehavior - set TG object
of change
SimpleBehavior(TransformGroup targetTG) {
this.targetTG = targetTG;
}
// initialize the Behavior
// set initial wakeup condition
// called when behavior becomes live
public void initialize() {
// set initial wakeup condition
this.wakeupOn(new
WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
}
// called by Java 3D when appropriate
stimulus occurs
http://tailieuhay.com 403
Lập trình đồ họa trên Java 2D và 3D
public void processStimulus(Enumeration
criteria) {
// do what is necessary in response
to stimulus
angle += 0.1;
rotation.rotY(angle);
targetTG.setTransform(rotation);
this.wakeupOn(new
WakeupOnAWTEvent(KeyEvent.KEY_PRESSED));
}
}
}// end of class SimpleBehavior
Lớp SimpleBehaviourApp chỉ thực hiẹn những chức năng chính cần
thiết của một Behaviour đơn giản. Chungs ta có thể phát triển thêm các
chức năng phong phú hơn, ví dụ ta có thể xet góc quay của trục quay có
thể được thay đổi bởi các phương thức của lớp.
Một điểm để phát triển nâng cấp là khắc phục hiẹn tượng tràn của góc
nghiêng.
Những sai lầm trong việc viết một lớp Behaviour
• Quên việc thiết lập và reset lại Behaviour trigger
• Không trả về từ phương thức của lớp Behaviour
Một điều hiển nhiên là nếu không thiết lạp trigger thì hành vi sẽ không thể
thực hiện được. Ngoài ra trigger cũng càn phải được reset trước khi hành
động tiếp theo lặp lại.
Khi cả hai phương thức initilization và processStimulus được gọi bởi
hệ thống Java3D, các hàm này phải trả về để cho phép việc tô trát được
tiếp tục. Lấy ví dụ, khi hành vi quay tròn được gọi, góc quay và đối tượng
TransformGroup cần được cập nhật một cách định kỳ.
http://tailieuhay.com 404
Lập trình đồ họa trên Java 2D và 3D
4.2.2 Sử dụng một lớp Behaviour
Trong phần này chúng ta sẽ tìm hiểu việc thêm vào hành vi cảu đối
tượng trong chương trình.
Bước dầu tiên để thêm vào hành vi bao gồm việc chắc chắn đồ thị
khung cảnh có sự dự trũ cho hành vi. Ví dụ, để sử dụng được lớp
SimpleBehaviourApp trong phần trên , trong đồ thị khung cảnh phải có
chứa đối tượng TransformGroup được chuẩn bị để quay. Rất nhiều
Behaviour chỉ cần một đối tượng TransformGroup, trong khi đó đồ thị
khung cảnh đòi hỏi một Behaviour là ứng dụng và Behaviour phụ thuộc.
Thiết lập sự hỗ trợ cảu một Behaviour, một thể hiện của lớp
Behaviour phải được thêm vào đồ thị khung cảnh.Trong thực tế một đối
tượng Behaviour không phải là một phần của đồ thị khung cảnh và sẽ trở
thành “rác” và được dọn dẹp bởi garbage collection.
Bước cuối cùng để thêm vào một Behaviour là cung cấp một khung
lịch cho Behaviour. Để nâng cấp làm việc hiệu quả hơn, Java3D sử dụng
khung lịch để thực hiện execution culling.Bhv ch ỉ tr ở n ên active khi
khung lịch của nó giao với sự hoạt động của ViewPlatform. Chỉ có những
Behaviour đã active mới có kảh năng nhạn được các tác nhân kích thích.
Trong trường hợp đó, các tác nhân có thể bị một số Behaviour bỏ
qua.Người lập trình cần quản lý sự chọn lọc trong suốt quá trình chọn lựa
lịch của các Behaviour.
Các bước sử dụng một Behaviour
1.Chuẩn bị đồ thị khung cảnh
2.Them Behaviour vào đồ thị khung cảnh, tham chiếu dến đối
tượng cần chuyển động, thay đổi
3.Xác định một khung lịch (SchedulingBoundingLeaf)
4.Đọc và ghi các khả năng cho đối tượng đích
http://tailieuhay.com 405
Lập trình đồ họa trên Java 2D và 3D
Ví dụ dưới đây mô tả các bước sử dụng một Behaviour như đã trình
bày ở trên
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
TransformGroup objRotate = new
TransformGroup();
objRotate.setCapability(TransformGroup.ALLOW_TRAN
SFORM_WRITE);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
SimpleBehavior myRotationBehavior = new
SimpleBehavior(objRotate);
myRotationBehavior.setSchedulingBounds(new
BoundingSphere());
objRoot.addChild(myRotationBehavior);
// Let Java 3D perform optimizations on
this scene graph.
objRoot.compile();
return objRoot;
}
http://tailieuhay.com 406
Lập trình đồ họa trên Java 2D và 3D
Hình trên mô tả mối quan hệ giữa đối tượng Behaviour và đối tượng
chịu sự thay đổi. đối tượng TransformGroup. Ví dụ của chúng ta nhằm
thực hiện quay một ColorCube, nhưng lớp Behaviour không chỉ giưoi
hạn như vậy , ta có thẻ quay bất kỳ đối tượng nào là con của đối tượng
TransformGroup. Ví dụ trên chỉ có ý dịnh là điểm khởi đầu cho quá tnhf
làm việc vói Behaviour, chứ không có ý định thực hiện những khả năng
có thể của Behaviour.
Những sai lầm trong việc sử dụng đối tượng Behaviour
Trong ba bước sử dụng lớp Behaviour , hai bước thuwòng gây nhàm
lẫn sai sót:
• Không chỉ định khung lịch
• Không thêm đối tượng Behaviour vào trong đồ thị khung cảnh
Một điều chú ý là chúng ta nên chú ý hạn chế việc tạo lịch cho mỗi đối
tượng Behaviour càng ít càng tốt để đảm bảo cho hiệu năng của toàn hệ
thống.
Đặt đối tượng Behaviour vào đồ thị khung cảnh
Behaviour có thể được thêm vào bất cứ đau trong đồ thị khung cảnh.
Tiêu chí lựa chọn vị trí thêm đối tượng Behaviour vào đồ thị khung cảnh
phụ thuộc vào các yếu tố: hiệu quả của vịec đặt lịch, bảo trì code.
Trong đồ thị khung cảnh tạo bởi SimpleBehaviourApp, đối tượng
SimpleBehaviour và đối tượng ColorCube khong nằm trong cùng một hệ
tọa độ địa phương.
http://tailieuhay.com 407
Lập trình đồ họa trên Java 2D và 3D
Đối tượng TransformGroup chí có tác dụng quay đối tượng
ColorCube vì vậy khung lịch của di myRotationBehaviour luôn đính kèm
đối tượng ColorCube cho phép việc tương tác với đối tượng ColorCube
khi nó visible. Dù sao, nều đối tượng TransformGroup được dùng để
biêc dịch đối tượng ColorCube, khi dó đối tượng ColorCube có thể bị
dịch chuyển ra ngoài của khung nhìn. Khi đối tượng bound nằm trong đồ
thị khung cảnh cùng với đối tượng Behaviour, người dùng có thể có khả
năng tiếp tục biên dịch đối tượng đó.
Miễn là sự kích hoạt quả view vẫn giao với kung lịch của đối tượng
Behaviour, lúc đó đối tượng Behaviour vẫn còn active.
Chúng ta có thể tương tác với đối tượng trực quan không nằm trong
view.Vấn đề là nếu như lúc đo view thay đổi và không còn giao với
khung kế hoạch của của đối tượng Behaviour , khi đó đối tượng
Behaviour là không active. Như vậy khi đó đối tượng chúng ta muốn
tương tác có thể vẫn anừm trng view nhưng không active. Có hai giải
pháp cho vấn đề này. Một là chúng ta thay đổi đồ thị khung cảnh để vẫn
giữ được khung lịch của đối tượng Behaviour với đối tượng trực quan.
Điều này có thẻ thực hiện được trọn vẹn theo hình dưới đây. Phương
pháp thứ hai là sử dụng đối tượng BoundingLeaf cho khung lịch. Chúng
ta sẽ xem xét lớp BoundingLeaf này trong phần 3.7
http://tailieuhay.com 408
Lập trình đồ họa trên Java 2D và 3D
Những chú ý khi xây dựng lớp Behaviour
Điều cần chú ý khi viết một Behaviour là hiệu năng của hệ thống.
Một Behaviour không tốt sẽ làm giảm hiẹu năng của quá trình tô
trát.chức năng. Một điều cần chú ý khi viết mọt Behaviour là: memory
burnvà những trigger điều kiện không cần thiết.
‘Memory burn’ là thuật ngữ dùng để chỉ việc tạo ra những đối tượng
không cần thiết tỏng Java. Việc sử dụng bộ nhớ quá mức ,sẽ ảnh huwòng
đến quá trình garbage collection và quá trình ô trát sẽ bị dưng lại. Các
phương thức của lớp Behaviour thuwòng gây ra vấn đề ‘memmory burn’.
Ví dụ như đoạn mã tỏng 4-1, phương thức processStimulus sử dụng toán
tử new trong qu á tr ình g ọi wakeupOn. i ều n ày khi ến cho m ột đối
tượng mới được tạo ra mỗi khi phương thức này được gọi, đối tượng này
trở thành ‘rác’ mỗi lần Behaviour được kích hoạt.
Tuy nhiên việc xác định và tránh xảy ra ‘memmory burn’ thường khá
dễ dàng.
Ví dụ trong đoạn code 4-3, thay bằng việc khởi tạo một đối tượng mới,
chúng ta sẽ sử dụng lại đối tượng cũ. Trong phần này chúng ta xem xét
kảh năng để thiết lập các điều kiện trigger nhằm kích hoạc các Behaviour
trong mỗi khung của quá trình tô trát. Nếu như không có tác nhân gì kích
hoạt Behaviour, sẽ là không cần thiết nếu chúng ta gọi đến phương thức
processStimulus.
4.2.3 Các hàm API trong lớp Behaviour
Trong phần này chúng ta sẽ tìm hiểu chi tiết về các hàm API của lớp
Behaviour.
Là một lớp cơ sở trừu tượng, lớp Behaviour càn được thừa kế trước khi
khởi tạo một đối tượng Behaviour.
http://tailieuhay.com 409
Lập trình đồ họa trên Java 2D và 3D
Trong gói tiện ích của Java3D có sằn rất nhiều các lớp Behaviour. Đó
là các lớp con của Leaf, thể hiện của một lớp thừa kế lớp Behaviour là
con của một nhóm trong đồ thị khung cảnh.
Các phương thức processStimulus và initialization cung cấp một gao
diện để chúng Java3D có thể hợp tác các Behaviours trong không gian
ảo. Các phương thức khác của lớp Behaviour đọc trình bày trong bảng
dưới đây. Phương thức wakeOn được dùng trong hai phương thức
initialization và processStimulus để thiết lập trigger cho Behaviour.Tham
số đầu vào của phương thức này là đối tượng WakeupCondition . Lớp
WakeupCondition và các lớp liên quan sẽ được trình bày trong phần
4.3.
Phương thức postId cho phép một Behaviour có thể giao tiếp với các
phương thức khác. Mộ trong những điều kiện wakeup là
WakeupOnBehaviorPost. Đối tượng Behaviour có thể sử dụng phương
thức postId để tạo ra sự cộng tác với điều kiện WakeupOnBehaviorPost
thích hợp. Chúng ta xem xem xét lớp akeupOnBehaviorPost chi tiết hơn
trong mục 4-16.
http://tailieuhay.com 410
Lập trình đồ họa trên Java 2D và 3D
Phương thức setEnable chung cấp một cách thức để vô hiệu hoá một
Behaviour thậm chí ngay cả khi bounds làm cho nó active. Giá trị mặc
định là true (đối tượng Behaviour được enable)
Một đối tượng Behaviour chỉ active khi khung đặt lịch của nó giao
với quá tình họat động của view.Tỏng một không gian ảo, chúng ta có thẻ
có nhiều view, một Behaviour có thể được active bởi nhiều view.
Phương thức getView rất hiệu quả với Behaviour dựa trên thông tin
của mỗi View (BillBoard, LOD..) và đối với những Behaviour nói chung
chung. Phương thức này trả về tham chiếu tới đối tượng View chính hiện
đang được kết hợp với Behaviour đó. Chúng ta không có phương thức
setView.
Đối tượng View chính được định nghĩa là đối tượng View đầu tiên
đọc gắn kèm với ViewPlatform, nếu chúng ta có nhiều View active.
Vì vậy một hành vi Billboard pahỉ hướng tới view chính, trong trường
hợp có nhiều view trong cùng một đồ thị khung cảnh.
Các hàm API của ViewPlatform
Các Behaviour chỉ active (có khả năng kích hoạt được) chỉ khi khung
lịch của nó giao với quá trình hoạt động của ViewPlatform .
Behavior Method Summary
Behavior is an abstract class that contains the framework for all
behavioral components in Java 3D.
View getView()
Returns the primary view associated with this behavior.
void initialize()
Initialize this behavior.
void postId(int postId)
Post the specified Id.
void processStimulus(java.util.Enumeration criteria)
http://tailieuhay.com 411
Lập trình đồ họa trên Java 2D và 3D
Process a stimulus meant for this behavior.
void setEnable(boolean state)
Enables or disables this Behavior.
void setSchedulingBoundingLeaf(BoundingLeaf region)
Set the Behavior's scheduling region to the specified bounding leaf.
void setSchedulingBounds(Bounds region)
Set the Behavior's scheduling region to the specified bounds.
void wakeupOn(WakeupCondition criteria)
ViewPlatform Method Summary (partial list)
These methods of the ViewPlatform class get and set the activation
volume (sphere) radius. Default activation radius
= 62.
float getActivationRadius()
Get the ViewPlatform's activation radius.
void setActivationRadius(float activationRadius)
Set the ViewPlatform's activation radius which defines an activation
volume around the view platform.
4.3 Điều kiện kích hoạt: Cách kích hoạt các hành vi
Những active Behaviour được kích hoạt bởi sự kiện của một hay
nhiều tác nhân kích hoạt. tác nhân kích hoạt. Tác nhân wakeup cho một
Behaviour được xác định sử dụng lớp con của lớp WakeupCondition .
Lớp cơ sở trừu tượng, là cơ sở của tất cả các lớp wakeup trong
Java3D. Có 5 lớp thừa kế lớp WakeupCondition , một trong số dó là lớp
cơ sở trừu tượng WakeupCriterion, các lớp còn lại kết hợp nhiềU điều
kiện wakeup trong một điều kiện wakeup duy nhất.
http://tailieuhay.com 412
Lập trình đồ họa trên Java 2D và 3D
Một điều kiện wakeup của một đối tượng Behaviour được xác định
như là sự kết hợp của các điều khiện khác sử dụng lớp kết hợp wakeup
thích hợp. Phần tiếp theo chúng ta mô tả lớp WakeupCondition và các
lớp con của nó.
4.3.1 Điều kiện kích hoạt
Lớp WakeupCondition cung cấp hai phương thức.Phương thức đầu
tiên, allElements, trả về danh sách liệt kê các tác nhân wakeup của đối
tượng WakeupCondition . Phương thức còn lại, triggeredElements, li ệt
k ê nh ững t ác nh ân wakeup có thể kích hoạt Behaviour. Phương thức
này có thể rất hữu hiệu trong phương thức processStimulus.
WakeupCondition Method Summary
The WakeupCondition abstract class is the base for all wakeup classes.
It provides the following two methods.
Enumeration allElements()
http://tailieuhay.com 413
Lập trình đồ họa trên Java 2D và 3D
Returns an enumeration of all WakeupCriterion objects in this
Condition.
Enumeration triggeredElements()
Returns an enumeration of all triggered WakeupCriterion objects in this
Condition.
4.3.2 WakeupCriterion
WakeupCriterion là phương thức trừu tượng cho phép 14 quy định
lớp tác nhân wakeup. WakeupCondition chỉ cung cấp một phương thức
duy nhất: hasTriggered. Chúng ta không cần thiết phải sử dụng phương
thức này, vì phương thức triggeredElements của lớp WakeupCondition
thực hiện điều này hộ chúng ta.
WakeupCriterion Method Summary
boolean hasTriggered()
Returns true if this criterion triggered the wakeup.
4.3.3 Quy định lớp WakeupCriterion
Trong bảng 4-2 đưa ra quy định 14 lớp WakeupCriterion. Những
lớp này được sự dụng để xác định những điều kiện wakup cho đối tượng
Behaviour. Thể hiện của những lớp này được sử dụng một cách độc lập
hay trong việc sử dụng kết hợp các điều kiện wakeup trong các lớp đã
nói trong mục trước.
Chúng ta sẽ xem xét chi tiết các lớp này trong ngay sau đây. CÓ
những lớp chỉ gồm những hàm API đơn giản, lớp WakeupOnActivation
chỉ có một hàm tạo duy nhất. Tham số khung lịch của các điều kiện
wakeup được chỉ định trong đối tượng Behaviour tương ứng.
http://tailieuhay.com 414
Lập trình đồ họa trên Java 2D và 3D
Những chú ý xung quanh WakeupCriterion
Một số lớp WakeupCriterion được kích hoạt ngay trong “first
detection” của một sự kiện. Đều này có nghĩa là tác nhân sẽ chỉ một lần
kích hoạt bởi sự kiện. Ví dụ đối tượng WakeupOnActivation sẽ kích hoạt
sự giao nhau giữa quá trình vận động của ViewPlatform và vùng kung
lịch của đối tượng Behaviour. Khi sự giao nhau này vần còn,
WakeupCondition sẽ không kích hoạt thêm một nào nữa. ĐIều tương tự
cũng đúng với một dãy các frame sau đó cho đến khi Java3D nhận biết
được sự thay đổi quá trình giao nhau, thì WakeupCondition mới có thể
kích hoạt lần tiếp theo.
Ta có những lớp WakeupCriterion theo từn cặp (Entry/Exit hay
Activation/ Deactivation). Những nhân tố này chỉ kích hoạt một cách xen
kẽ giữa tunừg cặp Entry hoặc Activation.
WakeupOnActivation
Nếu khung lịch giao với quá trình active của ViewPlatform trong một
thời gian đủ ngắn thì rất có thể là nó không được nhận ra. Khi đó cả
Acivation và Deactivation đều khong được kích hoạt. trong những trường
hợp như vậy, Behaviour sẽ không trở nên active.
WakeupOnActivation Constructor Summary
extends: WakeupCriterion
Class specifying a wakeup on first detection of a ViewPlatform's
activation volume intersection with this object's
scheduling region. WakeupOnActivation is paired with
WakeupOnDeactivation which appears on page 4-21.
WakeupOnActivation()
Constructs a new WakeupOnActivation criterion.
WakeupOnAWTEvent
http://tailieuhay.com 415
Lập trình đồ họa trên Java 2D và 3D
Nhiều lớp WakeupCriterion thực hiện kích hoạt trong những hàm
tạo và các phương thức một cách phụ thuộc.
Ví dụ WakeupOnAWTEvent có 2 hàm tạo và một phương thức. Hàm
tạo cho phép xác định các sự kiện AWT nhất định bằng cách sử dụng các
hằn của lớp AWT. Phương thức còn lại trả về mảng các sự kiện AWT liên
tục nhau được kích hoạt bởi trigger/
WakeupOnAWTEvent Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một Behaviour được kích hoạt bởi một sự kiên AWT
WakeupOnAWTEvent(int AWTId)
Khởi tạo một đối tượng WakeupOnAWTEvent mới, trong đó AWTId là
một trong các hằng số
KeyEvent.KEY_TYPED,
KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED,
MouseEvent.MOUSE_CLICKED,
MouseEvent.MOUSE_PRESSED, MouseEvent.MOUSE_RELEASED,
MouseEvent.MOUSE_MOVED,
MouseEvent.MOUSE_DRAGGED, or one of many other event values.
WakeupOnAWTEvent(long eventMask)
Khởi tạo một đối tượng WakeupOnAWTEvent sử dụng ORed
EVENT_MASK,và AWT EVENT_MASK với các giá trị:
: KEY_EVENT_MASK, MOUSE_EVENT_MASK,
MOUSE_MOTION_EVENT_MASK, hoặc các giá trị khác.
WakeupOnAWTEvent Method Summary
AWTEvent[] getAWTEvent()
http://tailieuhay.com 416
Lập trình đồ họa trên Java 2D và 3D
Trả vể một mảng các sự kiên AWT liên tiếp, những sự kiện kích hoạt lớp
WakeupOnAWTEvent .
WakeupOnBehaviorPost
Lớp WakeupOnBehaviorPost cùng với phương thức the postID của
lớp Behavior cung cấp một kỹ thuật qua đó một hành vi có thể được thực
hiện.Một đối tượng Behavior có thể post đưa ra một giá tri ID (kiểu số
nguyên). Các Behaviour khác có thể xác định được điều kiện kích hoạt
của nó, sử dụng ID của một Behaviour xác định. Điều này cho phép
chúng ta có thể tạo ra một Behaviour mở cửa ra vào, và một Behaviour
khác đóng cửa. Với cách thức như vậy ngay cả những Behaviour phức
tạp chúng ta có thể xây dựng một cách tương tự như vây, kết hợp
Behaviour với post ID.
WakeupOnBehaviorPost Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một Behaviour được kích hoạt khi một đối tượng
Behaviour khác đưa ra một sự kiện
WakeupOnBehaviorPost(Behavior behavior, int postId)
Khởi tạo một đối tượng WakeupOnBehaviorPost
Do WakeupCondition có thể chứa nhiều đối tượng
WakeupCriterion, bao gồm nhiều hơn 1 WakeupOnBehaviorPost,
phương thức để xác định rõ các triggering post caàn thiết cho sự kiện
trigger.
http://tailieuhay.com 417
Lập trình đồ họa trên Java 2D và 3D
WakeupOnBehaviorPost Method Summary
Behavior getBehavior()
Trả về Behaviour xác định được thiết lập trong hàm tạo của đối tượng
int getPostId()
Nhận postId xác định của WakeupCriterion
Behavior getTriggeringBehavior()
Trả về behavior được kích hoạt bằng tác nhân.
int getTriggeringPostId()
Trả về thông tin postId kích hoạt Behaviour
Đoạn code dưới đây của một chuwong trình đơn giản sử dụng
Behaviour posting để hợp tác các Behaviour. Ví dụ mở và đóng cửa ra
vào. Ứng dụng bao gồm một lớp: OpenBehaviour, và đaọn code tạo ra
hai đối tượng Behaviour. Đối tượng thứ hai là thể hiện của
CloseBehaviour, hoàn toàn giốnh hệt OpenBehaviour. Trong lớp
CloseBehaviour, điều kiện tráo đổi trong phương thức initialization (và
Behaviour ngược lại được thực hiện)
public class OpenBehavior extends Behavior {
private TransformGroup targetTG;
private WakeupCriterion
pairPostCondition;
private WakeupCriterion wakeupNextFrame;
private WakeupCriterion
AWTEventCondition;
http://tailieuhay.com 418
Lập trình đồ họa trên Java 2D và 3D
private Transform3D t3D = new
Transform3D();
private Matrix3d rotMat = new Matrix3d();
private double doorAngle;
OpenBehavior(TransformGroup targetTG) {
this.targetTG = targetTG;
AWTEventCondition = new
WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
wakeupNextFrame = new
WakeupOnElapsedFrames(0);
}
public void
setBehaviorObjectPartner(Behavior behaviorObject)
{
pairPostCondition = new
WakeupOnBehaviorPost(behaviorObject, 1);
}
public void initialize() {
this.wakeupOn(AWTEventCondition);
doorAngle = 0.0;
}
http://tailieuhay.com 419
Lập trình đồ họa trên Java 2D và 3D
public void processStimulus(Enumeration
criteria) {
if
(criteria.nextElement().equals(pairPostCondition)
) {
System.out.println("ready to
open door");
this.wakeupOn(AWTEventCondition);
doorAngle = 0.0f;
} else { // could be KeyPress or
nextFrame, in either case: open
if (doorAngle < 1.6) {
doorAngle += 0.1;
if (doorAngle > 1.6)
doorAngle = 1.6;
// get rotation and scale
portion of transform
targetTG.getTransform(t3D);
t3D.getRotationScale(rotMat);
// set y-axis rotation to
doorAngle
// (clobber any previous y-
rotation, x and z scale)
rotMat.m00 =
Math.cos(doorAngle);
rotMat.m22 = rotMat.m00;
http://tailieuhay.com 420
Lập trình đồ họa trên Java 2D và 3D
rotMat.m02 =
Math.sin(doorAngle);
rotMat.m20 = -rotMat.m02;
t3D.setRotation(rotMat);
targetTG.setTransform(t3D);
this.wakeupOn(wakeupNextFrame);
} else { // finished opening
door, signal other behavior
System.out.println("door is
open");
this.wakeupOn(pairPostCondition);
postId(1);
}
}
}
} // end of class OpenBehavior
Code 4-4: Sử dụng lớp OpenBehaviour và CloseBehaviour
Đối tượng của hai lớp này sẽ thay phiên nhau phản hồi với tác nhân
phím bấm.Đối tượng open behavior sẽ trả lời lại kích hoạt phím bấm đầu
tiên đồng thời nó đánh dấu cho đối tượng close Behaviour biết và thiết
lập điều kiện trigger của nó để có thể đựoc đối tượng close Behaviour
nhân biêt.Đối tượng open behavior mở cửa để trả lời lại tác nhân phím
bấm.Đối tượng close behavior thiết lập trigger của nó như là một phím
bấm để trả lời lại tín hiệu từ đối tượng open Behaviour
http://tailieuhay.com 421
Lập trình đồ họa trên Java 2D và 3D
Phím bấm tiếp theo kích hoạt đối tượng close. Đối tượng close lúc đo
sẽ thực hiện chức năng tương tự đối tượng open : gửi đến một tín hiệu và
thiết lập lại điều kiện kích hoạt của chính nó.
Đối tượng close đóng cửa để trả lời sự kiện bấm phím. Tiếp đó phím
bấm tiếp theo cũng được thực hiện tương tự. WakeupOnCollisionEntry
Java3D có khả năng tự động nhận ra sự va chạm giữa các đối tượng trong
không gian ảo. Java3D cung cấp 3 lớp WakeupCondition để xử lý sự va
chạm của các đối tượng:
• WakeupOnCollisionEntry,
• WakeupOnCollisionMovement,
• WakeupOnCollisionExit.
Một WakeupOnCollisionEntry sẽ đựoc kích hoạt khi một đối tượng
lần đầu va chạm. Sau đó WakeupOnCollisionMovement sẽ được kích
hoạt trong khi hai đối tượng trong va chạm
Cuối cùng một đối tượng WakeupOnCollisionExit sẽ kích hoạt khi va
chạm kết thúc Java3D chỉ có thẻ quản lý được một va chạm của một đối
tượng tại một thời điểm. Những va chạm diễn ra trong khoảng thời gian
rất ngắn cũng không được nhận biêt. Một cách hợp lý, CollisionEntry và
CollisionExit đều không đựoc kích hoạt. Quá trình nhạn biết va chạm
Collision detectiontrong thực tế diễn ra rất phức tạp.Dù sao tron tài liệu
này chúng ta không đi sâu vào collision detection, có thể tham kahỏ thêm
trong Java3D API specification.
Hàm tạo WakeupOnCollisionEntry
Thừa kế: WakeupCriterion
Lớp xác định va chạm đầu tiên của một đối tượng xác định với một đối
tượng khác trong đồ thị khung cảnh.
WakeupOnCollisionEntry(Bounds armingBounds)
http://tailieuhay.com 422
Lập trình đồ họa trên Java 2D và 3D
Tạo một đối tượng WakeupOnCollisionEntry mới.
WakeupOnCollisionEntry(Node armingNode)
Tạo một đối tượng WakeupOnCollisionEntry mới.
WakeupOnCollisionEntry(Node armingNode, int speedHint)
Tạo một đối tượng WakeupOnCollisionEntry mới trong đó speedHint
nhận một trong các giá trị: USE_BOUNDSvà USE_GEOMETRY
WakeupOnCollisionEntry(SceneGraphPath armingPath)
Tạo một đối tượng WakeupOnCollisionEntry mới với giá trị speed hint là
USE_BOUNDS WakeupOnCollisionEntry(SceneGraphPath
armingPath, int speedHint)
Tạo một đối tượng WakeupOnCollisionEntry mới với giá trị speed hint là
USE_BOUNDS hoặc USE_GEOMETRY.
WakeupOnCollisionExit
WakeupOnCollisionExit Constructor Summary
Thừa kế WakeupCriterion
Lớp xác định khi một đối tượng xác định kết thúc va chạm với các đối
tượng khác trong đồ thị khung cảnh
WakeupOnCollisionExit(Bounds armingBounds)
Hàm tạo với tham số Bound
WakeupOnCollisionExit(Node armingNode)
Hàm tạo với tham số armingNode
WakeupOnCollisionExit(Node armingNode, int speedHint)
Hàm tạo với tham số armingNode,speedHine
WakeupOnCollisionExit(SceneGraphPath armingPath)
Hàm tạo với tham sốarmingPath
http://tailieuhay.com 423
Lập trình đồ họa trên Java 2D và 3D
WakeupOnCollisionExit(SceneGraphPath armingPath, int
speedHint)
Hàm tạo với tham số armingPath, speedHint
WakeupOnCollisionExit Method Summary
Bounds getArmingBounds()
Trả về đối tượng Bound được sử dụng trong việc xác địng va chạm
SceneGraphPath getArmingPath()
Trả về đường dẫn dùng trong va chạm xác định
Bounds getTriggeringBounds()
Trả về đối tượng Bounds gây ra va chạm
SceneGraphPath getTriggeringPath()
Trả về đường dẫn mô tả đối tượng gây ra va chạm
WakeupOnCollisionMovement
WakeupOnCollisionMovement Constructor Summary
Thừ kế: WakeupCriterion
Lớp xác định khi đối tượng xác định di chuyển trong va chạm với một đối
tượng khác trong không gian ảo
WakeupOnCollisionMovement(Bounds armingBounds)
Hàm tạo WakeupOnCollisionMovement
WakeupOnCollisionMovement(Node armingNode)
Hàm tạo WakeupOnCollisionMovement
WakeupOnCollisionMovement(Node armingNode, int speedHint)
Hàm tạo WakeupOnCollisionMovement trong đó speedHint nhận giá trị:
http://tailieuhay.com 424
Lập trình đồ họa trên Java 2D và 3D
USE_BOUNDS hoặc USE_GEOMETRY
WakeupOnCollisionMovement(SceneGraphPath armingPath)
Hàm tạo WakeupOnCollisionMovement.
WakeupOnCollisionMovement(SceneGraphPath armingPath, int
speedHint)
Hàm tạo WakeupOnCollisionMovement, trong đó speedHint nhận một
trong hai giá trị: USE_BOUNDS hoặc USE_GEOMETRY
WakeupOnCollisionMovement Method Summary
Bounds getArmingBounds()
Trả về đối tượng bounds đựợc sử dụng trong collision condition.
SceneGraphPath getArmingPath()
Trả về đương dẫn đựoc sủ dụng trong collision condition.
Bounds getTriggeringBounds()
Trả về đối tượng Bounds gây ra va chạm
SceneGraphPath getTriggeringPath()
Trả về đường dẫn gây ra va chạm.
WakeupOnDeactivation
WakeupOnDeactivation Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định va chạm đầu tiên khi quá trình hoạt động củ ViewPlatform
không còn giao với khung lịch của đối tượng
WakeupOnDeactivation()
Hàm tạo đối tượng WakeupOnDeactivation
http://tailieuhay.com 425
Lập trình đồ họa trên Java 2D và 3D
WakeupOnElapsedFrames
Đối tượng WakeupOnElapsedFrames được sử dụng để kích hoạt một
đối tượng active sau một số lượng frame nhất đinh trôi qua.
WakeupOnElapsedFrames Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một kích hoạt sau một ố lượng frame nhất định
WakeupOnElapsedFrames(int frameCount)
Hàm tạo WakeupOnElapsedFrames.
frameCount - Số luwọng các frames mà Java 3D vẽ ra trước khi kích hoạt
một đối tượng Behaviour; giá trị n cho biết sao n frame Behaviour sẽ
đuợc kích hoạt. giá trị 0 cho biết Behaviour sẽ đựoc kích hoạt ngay sau
frame hiện thời.
WakeupOnElapsedFrames(int frameCount, boolean passive) <new in
1.2>
Hàm tạo WakeupOnElapsedFrames với tham số frameCount và tham số
passive
passive - cờ chỉ dẫn cho biết khi nào Behaviour trở nên bị động, một
Behaviour chủ động sẽ làm cho hệ thống phải chạy một cách liêc tục khi
một Behaviour bị động nó cho phép các sự kiện khác gây ra frame đuợc
chạy.
WakeupOnElapsedFrames Method Summary
int getElapsedFrameCount()
Trả về số lương các frameCount
boolean isPassive() <new in 1.2>
Trả về trạng thái của cờ bị động.
http://tailieuhay.com 426
Lập trình đồ họa trên Java 2D và 3D
WakeupOnElapsedTime
Java 3D không thể bảo đảm thời gian chính xác của trigger cho một tiêu
chuẩn WakeupOnElapsedTime.
WakeupOnElapsedTime Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một wakeup sau một khoang thời gian (ms) trôi qua.
WakeupOnElapsedTime(long milliseconds)
Hàm tạo đối tượng WakeupOnElapsedTime
WakeupOnElapsedTime Method Summary
long getElapsedFrameTime()
Trả về thời gian trôi qua của WakeupCriterion
WakeupOnSensorEntry
Trong Java 3D, bất kỹ thiết bị input nào (ngoại trừ chuột và bàn phím)
đều là một sensor Mỗi sensor có một hotspot được xác định trong hệ
thốnh của sensor. Sự giao nhau giữa hotspt cảu môt sensor với một region
có thể được nhận biết bởi lớp WakeupOnSensorEntry và
WakeupOnSensorExit.
WakeupOnSensorEntry Constructor Summary
Thừ kế: WakeupCriterion
Lớp xác định một wakeup trong giai đaọn đầu tiên nhận biết sự giao nhau
giưa một sensor nào đó với một boundary xác định
WakeupOnSensorEntry(Bounds region)
http://tailieuhay.com 427
Lập trình đồ họa trên Java 2D và 3D
Hàm tạo đối tượng WakeupOnEntry.
WakeupOnSensorEntry Method Summary
Bounds getBounds()
Trả về bound của đối tượng xác định.
Sensor getTriggeringSensor() <new in 1.2>
Trả về đối tượng sensor gây ra wakeup.
WakeupOnSensorExit
WakeupOnSensorExit Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một wakeup trong giai đoạn nhận biết đầu tiên khi không
còn sự giao nhau giữa một đối tượng sensor trước đó với một boundary
xác định.
WakeupOnSensorExit(Bounds region)
Hàm tạo đối tượng WakeupOnExit .
WakeupOnSensorExit Method Summary
Bounds getBounds()
Trả về bound của đối tượng xác định.
Sensor getTriggeringSensor() <new in 1.2>
Trả về đối tượng Sensor gây ra wakeup.
WakeupOnTransformChange
http://tailieuhay.com 428
Lập trình đồ họa trên Java 2D và 3D
WakeupOnTransformChange rất hiệu quả trong việc nhận biết thay
đổi vị trí hay hướng của các đối tượng trực quan trong đồ thị khung cảnh.
Lớp này sử dụng phương thức postId để tạo ra các Behaviour hợp tác.
Điều này đặc biệt hiệu quả khi chúng ta muốn hợp tác với một Behaviour
đã được xây dựng trước đó.
WakeupOnTransformChange Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một wakeup khi một đối tượng transform trong một nhóm
TransformGroup xác định thay đổi.
WakeupOnTransformChange(TransformGroup node)
Hàm tạo đối tượng WakeupOnTransformChange.
WakeupOnTransformChange Method Summary
TransformGroup getTransformGroup()
Trả về node TransformGroup sử dụng trong WakeupCriterion
WakeupOnViewPlatformEntry
Quá trình nhận biết sự giao nhau của ViewPlatform với một region xác
định có thể được thực hiện bởi lớp WakeupOnViewPlatfomEntry và lớp
WakeupOnViewPlatformExit.
WakeupOnViewPlatformEntry Constructor Summary
Thừa kế: WakeupCriterion
Lớp xác định một wakeup trong lần đầu tiên giao nhau của ViewPlatform
với một boundary xác định.
WakeupOnViewPlatformEntry(Bounds region)
Hàm tạo đối tượng WakeupOnEntry.
http://tailieuhay.com 429
Lập trình đồ họa trên Java 2D và 3D
WakeupOnViewPlatformEntry Method Summary
Bounds getBounds()
Trả về bound của đối tượng xác định
WakeupOnViewPlatformExit
WakeupOnViewPlatformExit Constructor Summary
Thừa kế : WakeupCriterion
Lớp xác định một wakeup trong lần đầu tiên khi ViewPlatform không còn
giao nhau với đối tượng boundary xác định
WakeupOnViewPlatformExit(Bounds region)
Hàm tạo đối tượng WakeupOnExit
WakeupOnViewPlatformExit Method Summary
Bounds getBounds()
Trả về bound của đối tượng xác định
4.3.4 Thành phần của WakeupCondition
Nhiều đối tượng WakeupCriterion có thể được kết hợp gắn với một
WakeupCondition sử dụng 4 lớp được giới thiệu trong phần sau. Hai
lớp đầu tiên được gắn liền vào một WakeupCondition từ một tập
WakeupCriterion mọt cách vật lý.Lớp thứ ba và lớp thư tư cho phép kết
http://tailieuhay.com 430
Lập trình đồ họa trên Java 2D và 3D
hợp các thể hiện của hai lớp đầu tiên thành một đối tượng
WakeupCondition phức tạp.
WakeupAnd Constructor Summary
extends: WakeupCondition
Class specifying any number of wakeup criterion logically ANDed
together.
WakeupAnd(WakeupCriterion[] conditions)
Constructs a new WakeupAnd condition.
WakeupOr Constructor Summary
extends: WakeupCondition
Class specifying any number of wakeup criterion logically ORed
together.
WakeupAnd(WakeupCriterion[] conditions)
Constructs a new WakeupOr condition.
WakeupAndOfOrs Constructor Summary
extends: WakeupCondition
Class specifying any number of WakeupOr condition logically ANDed
together.
WakeupAndOfOrs(WakeupOr[] conditions)
Constructs a new WakeupAndOfOrs condition..
WakeupOrOfAnds Constructor Summary
http://tailieuhay.com 431
Lập trình đồ họa trên Java 2D và 3D
extends: WakeupCondition
Class specifying any number of WakeupAnd condition logically ORed
together.
WakeupOrsOfAnds(WakeupAnd[] conditions)
Constructs a new WakeupOrOfAnds condition.
4.4 Lớp Behaviour tiện ích xử lý bàn phím
Chúng ta đã xem xét viewer với vị trí và góc không đổi. Thay đổi
viewer là một khả năng quan trọng trong rất nhiều ứng dụng 3D. Java3D
cung cấp khả năng thay đổi vị trí, hướng của viewer. Trong hình dưới đây
chúng ta có thể thấy nền transform. Nếu như transform thay đổi, ảnh
huwỏng tới dịch chuyển hoặc định hướng lại hoặc của viewer. Từ quan
điểm này chúng ta có thể thấy thiết kế cơ bản của tương tác bàn phím: ta
có một đối tượng Behaviour thay đổi nền view để đáp lại tác động của
phím bấm.
Đây chính cách mà là lớp tiện ích Java3D làm việc. trong phần còn lại
chúng ta xem xét việc sử dụng lớp tương tác với bàn phím.
http://tailieuhay.com 432
Lập trình đồ họa trên Java 2D và 3D
Cách dịch chuyển trong SimpleUniverse
Lớp SimpleUniverse và các lớp liên quan cung cấp một sự kết hợp để
nhận được đối tượng ViewPlatformTransform object. Từ đó chúng ta
có thể di chuyển SimpleUniverse. Đặcbiệt đaọn cod dưới đây nhận được
ViewPlatformTransform từ một đối tượng SimpleUniverse
TransformGroup vpt =
su.getViewingPlatform().getViewPlatformTransform ();
4.4.1 Một ví dụ đơn giản
Ví dụ KeyNavigatorApp sau đây nằm trong thư mục
examples/Interaction
Trong chương trình này chúng ta có thể thấy được các bước thực hiện bao
gồm cả việc sử dụng lớp KeyNavigatorBehavior giống như việc sử dụng
các lớp Behaviour khác.
1. Tạo ra đối tượng KeyNavigatorBehaviour ,thiết lập transform
group
2. Thêm đối tượng KeyNavigatorBehavior vào đồ thị khung cảnh
3. Cung cấp một gới hạn (hoặc BoundingLeaf) cho đối tượng
KeyNavigatorBehavior
public BranchGroup
createSceneGraph(SimpleUniverse su) {
// Create the root of the branch graph
TransformGroup vpTrans = null;
BranchGroup objRoot = new BranchGroup();
objRoot.addChild(createLand());
// create other scene graph content
http://tailieuhay.com 433
Lập trình đồ họa trên Java 2D và 3D
vpTrans =
su.getViewingPlatform().getViewPlatformTransform
();
translate.set( 0.0f, 0.3f, 0.0f); // 3
meter elevation
T3D.setTranslation(translate); // set as
translation
vpTrans.setTransform(T3D); // used for
initial position
KeyNavigatorBehavior keyNavBeh = new
KeyNavigatorBehavior(vpTrans);
keyNavBeh.setSchedulingBounds(new
BoundingSphere(new Point3d(),1000.0));
objRoot.addChild(keyNavBeh);
// Let Java 3D perform optimizations on
this scene graph.
objRoot.compile();
return objRoot;
}
Theo công thức các bước đã trình bày ở trên, trong phương thức
createSceneGraph đòi hỏi việc truy cập vào nhóm ViewPlatform
transform.Quá trình thực thi này truyền đối tượng SimpleUniverse vào
phương thức createSceneGraph làm cho nó trở nên active để có thể truy
cập vào các nhành view khác của SimpleUniverse, như
PlatformGeometry, ViewerAvatar, hoặc thêm một đối tượng
BoundingLeaf vào nhánh view.
Dòng 13-15 khởi tạo vị trí ban đầu của viewer. Trong trường hợp
này , đối tượng viewer được chuyển tới vị trí 0.3 meters nằm trên vị trí
http://tailieuhay.com 434
Lập trình đồ họa trên Java 2D và 3D
ban đầu của thế giới ảo. Đầy chỉ là vị trí ban đầu và chúng ta có thẻ thay
đổi vị trí và góc của viewer sau này.
// The following allows this to be run as an
application
// as well as an applet
public KeyNavigatorApp() {
setLayout(new BorderLayout());
Canvas3D canvas3D = new Canvas3D(null);
add("Center", canvas3D);
// SimpleUniverse is a Convenience
Utility class
SimpleUniverse simpleU = new
SimpleUniverse(canvas3D);
BranchGroup scene =
createSceneGraph(simpleU);
simpleU.addBranchGraph(scene);
} // end of KeyNavigatorApp (constructor)
Cách xây dựng ứng dụng chung của một Behavior
Như bất kỳ đối tượng Behaviour khác, KeyNavigatorBehaviour
chỉ active khi khung lịch của nó giao nhau với giai đoạn active của một
ViewPlatform.
4.4.2 Lớp KeyNavigatorBehaviour và KeyNavigator
http://tailieuhay.com 435
Lập trình đồ họa trên Java 2D và 3D
Lớp tiệc ích tương tác bàn phím thực thi hai lớp. Trong thời gian chạy
chương trình có hai đối tượng. Đối tượng đầu tiên là đối tượng
KeyNavigatorBehavior, đối tượng thứ hai là KeyNavigator. Lớp thứ hai
không cần thiết phải trình bày trong tài liẹu này. Đối tượng
KeyNavigatorBehavior thực hiện hầu hết tất cả các hàm chức năng
truyền thống của mọt lớp Behaviour, ngoài việc nó gọi đến đối tượng
KeyNavigator để thực hiện phương thức perform the
processStimulus.Lớp KeyNavigator nhận sự kiện AWTEvent và chuyển
các sự kiện thành từng các phím bấm riêng biệt.Bảng dưới đây 4-3 chỉ ra
tác dụng của từng phím bấm riêng biệt. Lớp KeyNavigator thực thi sự
vận động nhanh chóng.
KeyNavigatorBehavior Constructor Summary
Gói: com.sun.j3d.utils.behaviors.keyboard
Thừa kế : Behavior
Lớp là một behavior đơn giản that gọi đến KeyNavigator để thay đổi bề
ngoài view platform
KeyNavigatorBehavior(TransformGroup targetTG)
Hàm tạo một node key navigator behavior mới có tác dụng trên nhóm
transform xác định
KeyNavigatorBehavior Method Summary
void initialize()
Hàm đè phương thức khởi tạo của lớp Behavior để thiết lập thông số
wakeupvoid processStmulus(java.util.Enumeration criteria)
Hàm đè phương thức processStimulus của lớp Behavior để quản lý sự
kiện
http://tailieuhay.com 436
Lập trình đồ họa trên Java 2D và 3D
4.5 Lớp tiện ích tương tác với chuột
Gói tiện ích Behaviour (com.sun.j3d.utils.behaviors.mouse) chứa
những lớp Behaviour tỏng đó quản lý việc tương tác với chuột. Bao gồm
các lớp để chuyển dịch, phóng to/nhỏ và điều khiển quay các đối tượng
trực quan theo sự di chuyển của chuột.
Bảng 4-4 tổng hợp lại 3 Behaviour xác định của trong việc tương tác
với chuột the. Trong gói còn có chứa lớp cơ sở trừu tượng
MouseBehavior class và giao diện MouseCallback . Lớp cơ sở trừu
tượng và giao diện được sử dụng để tạo ra các Behaviour xác định của
con chuột.
4.5.1 Sử dụng lớp MouseBehaviour
Sử dụng lớp mouse Behaviour cũng tương tự như ki sử dụng ácc
lứop Behaviour khác.
Các bước khi sử dụng lớp mouse Behaviour
1.Cung cấp khả năng đọc và ghi cho đối tượng đích transform group
2. Khởi toạ một đối tượng MouseBehavior
3. Thiết lập đối tượng đích đến transform group
4. Cung cấp một giứoi hạn (or BoundingLeaf) cho đối tượng
MouseBehavior
5. Thêm đối tượng MouseBehavior vào đồ thị khung cảnh
Figure 4-10 Recipe for Using Mouse Behavior Classes
Tuy nhiên các bước trên là kô bắt buộc phải thực hiện đầy đủ. Bước 2
và bước 3 có thể cung thực hiện trong một hàm tạo. ví dụ dưới đây giới
http://tailieuhay.com 437
Lập trình đồ họa trên Java 2D và 3D
thiệu phương thức createSceneGraph từ ví dụ MouseRotateApp. Đồ thị
khung cảnh chứa đối tượng ColorCube. Người dùng có thể quay đối
tượng ColorCube sử dụng chuột và cả đối tượng MouseRotate trong đồ
thị khung cảnh
// MouseRotateApp renders a single,
interactively rotatable cube.
public class MouseRotateApp extends Applet {
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
TransformGroup objRotate = new
TransformGroup();
objRotate.setCapability(TransformGroup.ALLOW_TRAN
SFORM_WRITE);
objRotate.setCapability(TransformGroup.ALLOW_TRAN
SFORM_READ);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
objRoot.addChild(new Axis());
http://tailieuhay.com 438
Lập trình đồ họa trên Java 2D và 3D
MouseRotate myMouseRotate = new
MouseRotate();
myMouseRotate.setTransformGroup(objRotate);
myMouseRotate.setSchedulingBounds(new
BoundingSphere());
objRoot.addChild(myMouseRotate);
// Let Java 3D perform optimizations on
this scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
MouseRotateApp
// Create a simple scene and attach it to the
virtual universe
public MouseRotateApp() {
setLayout(new BorderLayout());
Canvas3D canvas3D = new Canvas3D(null);
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
// SimpleUniverse is a Convenience
Utility class
http://tailieuhay.com 439
Lập trình đồ họa trên Java 2D và 3D
SimpleUniverse simpleU = new
SimpleUniverse(canvas3D);
// This will move the ViewPlatform back a
bit so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalViewingTra
nsform();
simpleU.addBranchGraph(scene);
} // end of MouseRotateApp (constructor)
// The following allows this to be run as an
application
// as well as an applet
public static void main(String[] args) {
System.out
.print("MouseRotateApp.java \n-
a demonstration of using the MouseRotate ");
System.out
.println("utility behavior class
to provide interaction in a Java 3D scene.");
System.out
.println("Hold the mouse button
while moving the mouse to make the cube
rotate.");
http://tailieuhay.com 440
Lập trình đồ họa trên Java 2D và 3D
System.out
.println("This is a simple
example progam from The Java 3D API Tutorial.");
System.out.println("The Java 3D Tutorial
is available on the web at:");
System.out
.println("http://java.sun.com/pr
oducts/java-media/3D/collateral");
Frame frame = new MainFrame(new
MouseRotateApp(), 256, 256);
} // end of main (method of MouseRotateApp)
} // end of class MouseRotateApp
Code Fragment 4-7 Using the MouseRotate Utility Class
Chương trình cho kết qủa:
http://tailieuhay.com 441
Lập trình đồ họa trên Java 2D và 3D
Một cách tương tự chúng ta có thể làm việc với hai lớp mouse
Behaviour còn lại. Trong thực técả ba lớp này đều có thể dùng chung
trong một ứng dụng tác động cùn vào một đối tượng trực quan Chúng ta
cũng chỉ cần một đối tượng TransformGroup chung có cả 3 đối tượng
mouse behaviors. Trong ví dụ tiếp theo chúng ta xem xét các thức hai
mouse Behaviour cùng hành động trong một thế giới ảo. Ví dụ
MouseRotate2App tạo ra một đồ thị khung cảnh với hai đối tượng
ColorCube nằm gần nhau.Mỗi đối tượng ColorCubes gắn liền với một đối
tượng MouseRotate.
Khi cả hai đối tượng mouse behavior cùng active, lúc đo người dùng
click và di chuyển chuột, cả hai đối tượng ColorCubes cùng quay.
Nếu chúng ta không muốn cả hai đối tượng cùng quay, ta có hai giải
pháp
• Thay đổi vị trí viewer hay thay đổi khung lịch của Behaviour sao
cho chỉ có một Behaviour đuwọc active
• Sử dụng kỹ thuật picking cách ly Behaviour. Ký thuật picking
được xem xét trong phần 4.6
Trong phần 4.6 chúng sẽ sử dụng các lớp thích hợp để có thể kết hợp
các mouse Behaviour với picking cho phép người dùng tương tác với
từng đối tượng trực quan tại một thời điểm.
4.5.2 Mouse Behaviour Foundation
Các phương thức mouse Behaviour xác định (MouseRotate,
MouseTranslate, và MouseZoom) là mở rộng của lớp cơ sỏ trưừ tượng
MouseBehavior và thực thi giao diện MouseCallback .
Lớp cơ sở trừu tượng Mouse Behavior
http://tailieuhay.com 442
Lập trình đồ họa trên Java 2D và 3D
Lớp cơ sở trừu tượng được giới thiệu sau đây khi chúng ta muốn thừa
kế nó đê viết các lớp mouse Behaviour của rieng mình.
MouseBehavior Method Summary
Lớp cơ sở cho tất cả các thao tác chuột mouse
void initialize()
Khởi tạo behavior.
void processMouseEvent(java.awt.event.MouseEvent evt)
kiểm soat các sự kiện chuột.
void processStimulus(java.util.Enumeration criteria)
Tất cả các thao tác chuột phải thực thi phương thức này của lớp
Behaviour void setTransformGroup(TransformGroup
TransformGroup)
Thiết lập TransformGroup đích cho Behaviour
void wakeup()
Gọi đến phương thức wakeup.
MouseCallback Interface
Một lớp thực thi giao diện này cung cấp phương thức
transformChanged, phương thức này sẽ được gọi khi đối tượng đich
transform thay đổi theo một cách thức xác định. cả 3 lớp mouse
Behaviour đều phải thực thi giao diện này. Chúng ta cũng có thể viết đè
phương thức transformChanged của một trong số các lớp kia để xác định
phương thức được gọi khi đối tượng transform thay đổi
Các phương thức Interface MouseBehaviorCallback
Gói: com.sun.j3d.utils.behaviors.mouse
void transformChanged(int type, Transform3D transform)
http://tailieuhay.com 443
Lập trình đồ họa trên Java 2D và 3D
Lớp thực thi giao diện này đựơc dăng ký với một trong số các
MouseBehaviors sẽ được gọi mỗi khi Behaviour cập nhật transform.
Giá trị của type: MouseCallback.ROTATE,
MouseCallback.TRANSLATE, hoặc MouseCallback.ZOOM.
4.5.3 Các lớp MouseBehaviour
Mouse Rotate
Một đồ thị khung cảnh có chưa một đối tượng MouseRotate cho phép
nguời dùng quay đối tượng truqj quan. Chúng ta sẽ xem chi tiết trong các
ví dụ MouseRotateApp,
MouseRotate2App, và MouseBehaviorApp.
Hàm tạo MouseRotate Constructor
Gói: com.sun.j3d.utils.behaviors.mouse
Thừa kế : MouseBehavior
MouseRotate là một Behaviour cho phép người dùng điều khiẻn việc
quay đối tượng thông qua chuột. Để sử dụng lớp này, trước hết tạo ra một
transform group mà hành động quay này tác động vào. người dùng có thẻ
quay bất cứ đối tượng con nào của nhóm TransformGroup.
MouseRotate()
Hàm tạo một mouse rotate behavior mặc định.
MouseRotate(TransformGroup TransformGroup)
Hàm tạo một mouse rotate behavior gắn với TransformGroup
MouseRotate(int flags)
Khởi tạo một mouse behavior với cờ, giái trị của cờ:
MouseBehavior.INVERT_INPUT Cho phép đảo ngược đầu vào.
http://tailieuhay.com 444
Lập trình đồ họa trên Java 2D và 3D
MouseBehavior.MANUAL_WAKEUP Cho phép gọi Behaviour một
cách chủ động
Tổng hợp phương thức MouseRotate
void setFactor(double factor)
void setFactor(double xFactor, double yFactor)
void setupCallback(MouseBehaviorCallback callback)
Phương thức transformChanged trong lớp callback sẽ đựoc gọi tự động
mỗi khi transform được cập nhật
void transformChanged(Transform3D transform)
Chúng ta có thẻ chông hàm, khi đó hàm mới sẽ được gọi mỗi khi
Behaviour cập nhật transform
MouseTranslate
Cho phép người dùng di chuyển đối tượng trực quan trong một mặt
phẳng song song với mặt phẳng xác định trong không gian ảo. Xem ví dụ
MouseBehaviorApp.
MouseTranslate Constructor Summary
Gói : com.sun.j3d.utils.behaviors.mouse
Thừa kế : MouseBehavior
MouseTranslate là một đối tượng Behaviour cho phép người dùng điều
khiển sự chuyển động theo (X/Y) của một đối tượng bằn các sự dụng
chuột phải
MouseTranslate()
Khởi tạo một Behaviour dịch chuyển mặc định
MouseTranslate(TransformGroup TransformGroup)
Khởi tạo một Behaviour dịch chuyển với tham số TransformGroup
http://tailieuhay.com 445
Lập trình đồ họa trên Java 2D và 3D
MouseTranslate(int flags)
Khởi tạo một Behaviour dịch chuyển với tham số cờ. Cờ nhận một trong
các giá trị:
MouseBehavior.INVERT_INPUT Cho phép đảo ngược đầu vào.
MouseBehavior.MANUAL_WAKEUP Cho phép gọi Behaviour một
cách chủ động
MouseTranslate Method Summary
void setFactor(double factor)
void setFactor(double xFactor, double yFactor)
void setupCallback(MouseBehaviorCallback callback)
Phương thức transformChanged trong lớp callback sẽ đựoc gọi tự động
mỗi khi transform được cập nhật
void transformChanged(Transform3D transform)
Chúng ta có thẻ chông hàm, khi đó hàm mới sẽ được gọi mỗi khi
Behaviour cập nhật transform
MouseZoom
Cho phép người dùng di chuyển đối tượng trực quan trong một mặt
phẳng trực giao với .Xem them ví dụ MouseBehaviorApp.
Hàm tạo MouseZoom
Gói: com.sun.j3d.utils.behaviors.mouse
Thừa kế : MouseBehavior
MouseZoom là một đối tượng behavior cho phép người dùng thay đổi vị
trí của đối tượng truqjc uan theo trục Z bằn nút giữ của chuột.
MouseZoom()
Tạo ra đối tượng mouse zoom behavior mặc định.
http://tailieuhay.com 446
Lập trình đồ họa trên Java 2D và 3D
MouseZoom(TransformGroup TransformGroup)
Tạo ra đối tượng mouse zoom behavior với tham số transform group.
MouseZoom(int flags)
Khởi tạo một zoom Behaviour với tham số cờ. Cờ nhận một trong các giá
trị:
MouseBehavior.INVERT_INPUT Cho phép đảo ngược đầu vào.
MouseBehavior.MANUAL_WAKEUP Cho phép gọi Behaviour một
cách chủ động
MouseZoom Method Summary
void setFactor(double factor)
void setupCallback(MouseBehaviorCallback callback)
void transformChanged(Transform3D transform)
Chúng ta có thẻ chông hàm, khi đó hàm mới sẽ được gọi mỗi khi
Behaviour cập nhật transform
4.5.4 Mouse Navigation
Trong số các hàm tạo của ba lớp mouse Behaviour đều có tham số
flag.Khi cờ có giá trị MouseBehavior.INVERT_INPUTS đối tượng
mouse Behaviour đảo ngược lại thứ tự của input. Nhờ vậy ta các lớp
mouse Behaviour có thể dùng để điều khiển chuyển hướng.Xem ví dụ
MouseNavigatorApp.
Đoạn code trong 4-8 trình bày phương thức createSceneGraph. Đối tượng
TransformGroup đích của mỗi đối tượng the mouse behavior objects là
ViewPlatform transform. Đối tượng SimpleUniverse là tham số truyền
http://tailieuhay.com 447
Lập trình đồ họa trên Java 2D và 3D
cho phương thức createSceneGraph vì vậy đối tượng ViewPlatform có thể
được truy cập.
public BranchGroup
createSceneGraph(SimpleUniverse su) {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
TransformGroup vpTrans = null;
BoundingSphere mouseBounds = null;
vpTrans =
su.getViewingPlatform().getViewPlatformTransform(
);
objRoot.addChild(new ColorCube(0.4));
objRoot.addChild(new Axis());
mouseBounds = new BoundingSphere(new
Point3d(), 1000.0);
MouseRotate myMouseRotate = new
MouseRotate(MouseBehavior.INVERT_INPUT);
myMouseRotate.setTransformGroup(vpTrans);
myMouseRotate.setSchedulingBounds(mouseBo
unds);
objRoot.addChild(myMouseRotate);
http://tailieuhay.com 448
Lập trình đồ họa trên Java 2D và 3D
MouseTranslate myMouseTranslate = new
MouseTranslate(MouseBehavior.INVERT_INPUT);
myMouseTranslate.setTransformGroup(vpTran
s);
myMouseTranslate.setSchedulingBounds(mous
eBounds);
objRoot.addChild(myMouseTranslate);
MouseZoom myMouseZoom = new
MouseZoom(MouseBehavior.INVERT_INPUT);
myMouseZoom.setTransformGroup(vpTrans);
myMouseZoom.setSchedulingBounds(mouseBoun
ds);
objRoot.addChild(myMouseZoom);
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
MouseNavigatorApp
Kết quả cho ta là:
http://tailieuhay.com 449
Lập trình đồ họa trên Java 2D và 3D
4.6 Picking Object
Trong ví dụ MouseRotate2App, cả hai đối tượng ColorCube đều quay
khi gặp tác động của guời dùng. Trong ví dụ đó cả hai đối tượng đều chưa
có thể quay một cách đọc lập.Kỹ thuật picking cho phép chúng ta tương
tác với từng đối tượng trực quan trong đồ thị khung cảnh .
Picking được thực thi bởi một Behaviour, dưới sự kích hoạt của sự kiện
click chuột. Để picking một đối tượng, người dùng di chuyển chuột vào
đối tượng trực quan và click chuột. Đối tượng behavior được kích hoạt
bởi sự kiện click chuột và thực hiện picking. Một ray là một tia đựoc
chiếu từ vị trí con trỏ chuột song song với projected.
Sự giao nhau của ray với đối tượng trong không gian ảo được tính toán .
Đối tượng trực quan giao cắt với mặt phẳng khung hình gần nhất được
clựa chọn để giao cắt.
http://tailieuhay.com 450
Lập trình đồ họa trên Java 2D và 3D
Một pick ray trong không gian ảo
Một cách tổng thể, quá trình giao cắt không thực hiện trực tiếp trên
đối tượng được lựa chọn, mà làm việc với đối tượng chuyển hướng đồ thị
khung cảnh đến đối tượng. Lấy ví dụ để picking một đối tượng
ColorCube object để điều khiển quay , đối tượng ColorCube không bị
trực tiếp điều khiển mà thay vào đó là đối tượng TransformGroup nằm
trên đối tượng ColorCube trong cùng path đến đối tượng ColorCube. Nói
một cách khác nếu công việc picking kựa chọn đối tượng trực quan nhằm
thay đổi mầu sắc của đối tượng,khi đó đối tượng trực quan phải được tác
động một cách trực tiếp.
Việc xác định chính xác đối tượng được xử lý không phải là một công
việc đơn giản. Nếu chúng ta cần quay một đối tượng hìn lập phương 6
mặt , mỗi mặt là một đối tượng Shape3D đọc lập được sapư xếp bởi 6 đối
tượng TransformGroup , khi đó đối tượng hình lập phương sẽ cần phải
giao cắt trực tiếp chứ không phải là đối tượng TransformGroup
Việc quay đối tượng hình lập phương bằng việc tương tác đến đối
tượng TransformGroup, là con của đối tượng BranchGroup trong đồ thị
khung cảnh .
http://tailieuhay.com 451
Lập trình đồ họa trên Java 2D và 3D
Việc tính toán quá trình giao cắt là rất “tốn kém”. Vì vậy, picking đòi
hỏi khả năng tính toán cao và làm tăng độ phức tạp của đồ thị khung
cảnh. trong Java3D cung cấp cho chúng ta những cách khác nhau để giới
hạn số lượng tính toán phải thực hiẹn trong picking. Một cách quan trọng
là sử dụng khẳ năng và thuộc tính các node của đồ thị khung cảnh.
Một node trong đồ thị khung cảnh có phương thức setPickable()đặt là
false khi đó đối tượng node này và tất cả các đối tượng con của nó đều
không thể picking Bởi vậy, những node không được xem xét đến khi tính
toán giao cắt.
Một đặc điểm khác của lớp Node là khả năng
ENABLE_PICK_REPORTING. Khả năng này chỉ áp dụng với một nhóm
node.
Node Method (partial list)
Thừa kế : SceneGraphObject
Lớp con: Group, Leaf
Lớp Node là một lớp cơ sở trừu tượng cho tất cả các Group và Leaf
Nodes.Nó cung cấp một khung thông dụng trong việc xây dựng một
http://tailieuhay.com 452
Lập trình đồ họa trên Java 2D và 3D
Java3D đồ thị khung cảnh., như specifically bounding volumes, picking
và khả năng nhận biết collision
void setBounds(Bounds bounds)
Thiết lập một đối tượng hình học bao quanh một node.
void setBoundsAutoCompute(boolean autoCompute)
Bật tắt chế độ tự động tính toán tự động đối tượng hình học bao quanh mộ
setPickable(boolean pickable)
Đặt chế độ pick, nếu là true đối tượng Node này có thẻ pick, ngựoc lại đối
tượng Node và các con của nó đều không thể pick được
Node Capabilities Summary (partial list)
ENABLE_PICK_REPORTING
Chỉ định Node có thể được thông báo trong SceneGraphPath nếu như quá
trìh pick được thực hiện. Khả năng này chỉ có thẻ đuwọc định rõ cho các
Group node, nó không áp dụng cho các node lá.Giá trị mặc định là false.
ALLOW_BOUNDS_READ | WRITE
Chỉ định Node được đọc/ghi đẻ truy cập các thông tin vào khung của nó.
ALLOW_PICKABLE_READ | WRITE
Một cách khác để người lập trình có thể giảm thiểu việc tính toán
trong qú trình picking là sử dụng thử nghiệm giao cắt của khung bao
quanh thay vì việc sử dụng giao cắt của các đối tượng hình học. Rất nhìeu
lớp có các hàm tạo và phương thức nhận tham số đầu vào
USE_BOUNDS hoặc USE_GEOMETRY. Quyết định sử dụng khung
baop quanh rõ ràng đã đem lại hiệu quả hơn nhiều (trong việc tính toán)
đối với hầu hết vì vậy hiệu năng của chương trình tăng rõ rệt. Tuy nhiên
http://tailieuhay.com 453
Lập trình đồ họa trên Java 2D và 3D
phương án này thực tế không phải lúc nào cũng tỏ ra hiệu quả và thực
hiện đuợc.
Một kỹ thuật thứ 3 để giảm những tính toán phức tạp trong quá trình
picking la giới hạn phạm vi picking với những phần có liên quan trong đồ
thị khung cảnh.
4.6.1 Using Picking Utility Classes
Có hai cách tiếp cận trong quá tình sử dụng picking của java3D: sử
dụng đối tượng của lớp picking, hoặc tạo ra lớp picking mới và sử dụng
thể hiện của nó . Gói picking bao gồm các lớp để pick/rotate,
pick/translate, và pick/zoom . Mỗi lớp picking sử dụng một phím chuột
khác nhau để thực hiện quá trình điều khiển đối tượng với đầy đủ khả
năng của các lớp picking trong cùng một ứng dụng.
Trong phần này chúng ta giới thiệu các lớp tiện ích
PickRotateBehavior, PickTranslateBehavior, và PickZoomBehavior.
Trong phần tiếp theo 4.6.2 chúng ta giới thiệu các lớp hay sử dụng trong
việc tạo ra các lớp picking mới.
Do mỗi đối tượng picking behavior object có khả năng thực hiện với
bất kỳ đối tượng đồ thị khung cảnh, vì vậy chỉ cần một đối tượng picking
behavior đẻ cung cấp khả năng picking Đoạn code dưới đây mô tả công
việc cần thiết đẻ sử dụng các lớp picking behavior trong một chương trình
Java 3D
PickRotateBehavior behavior = new PickRotateBehavior(root,
canvas, bounds);
root.addChild(behavior);
http://tailieuhay.com 454
Lập trình đồ họa trên Java 2D và 3D
Đối tượng behavior sẽ quản lí bất cứ sưk kiện picking nào diễn ra
trong đồ thị khung cảnh (nằm dưới root) và xử lí các thao tác kéo thả
chuột.
Các bứoc sử dụng lớp picking
1. Khởi tạo đồ thị khung cảnh
2. Khởi tạo đối tượng picking behavior với root, canvas, và bounds
xác định.
3. Thêm đối tượng behavior vào đồ thị khung cảnh.
4. Bật chức năng thích hợp cho đối tượng đồ thị khung cảnh
Những sai sót hặygp phải khi sử dụng đối tượng Picking
Sử dụng lớp picking behavior có thể dẫn đến các sai lầm hay gặp phải
như khi lập trình với lớp behavior. Vấn đề thường gặp là: quên không bao
gồm các đối tượng behavior trong đồ thị khung cảnh, và không thiết lập
khung thích hợp cho đối tượng behavior
Chương trình ví dụ MousePickApp.
Đoạn code dưới đây trình bầy phương thức createSceneGraph của lớp
MousePickApp. Chương trình sử dụng đối tượng PickRotate object để
cung cấp quá trình tuơng tác. Đoạn code dưới đây tuân thủ các bước đã
trình bày ở trên.
public BranchGroup createSceneGraph(Canvas3D
canvas) {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
TransformGroup objRotate = null;
http://tailieuhay.com 455
Lập trình đồ họa trên Java 2D và 3D
PickRotateBehavior pickRotate = null;
Transform3D transform = new
Transform3D();
BoundingSphere behaveBounds = new
BoundingSphere();
// create ColorCube and
PickRotateBehavior objects
transform.setTranslation(new Vector3f(-
0.6f, 0.0f, -0.6f));
objRotate = new
TransformGroup(transform);
objRotate.setCapability(TransformGroup.AL
LOW_TRANSFORM_WRITE);
objRotate.setCapability(TransformGroup.AL
LOW_TRANSFORM_READ);
objRotate.setCapability(TransformGroup.EN
ABLE_PICK_REPORTING);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
pickRotate = new
PickRotateBehavior(objRoot, canvas,
behaveBounds);
objRoot.addChild(pickRotate);
// add a second ColorCube object to the
scene graph
http://tailieuhay.com 456
Lập trình đồ họa trên Java 2D và 3D
transform.setTranslation(new
Vector3f( 0.6f, 0.0f, -0.6f));
objRotate = new
TransformGroup(transform);
objRotate.setCapability(TransformGroup.AL
LOW_TRANSFORM_WRITE);
objRotate.setCapability(TransformGroup.AL
LOW_TRANSFORM_READ);
objRotate.setCapability(TransformGroup.EN
ABLE_PICK_REPORTING);
objRoot.addChild(objRotate);
objRotate.addChild(new ColorCube(0.4));
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
MousePickApp
http://tailieuhay.com 457
Lập trình đồ họa trên Java 2D và 3D
Đoạn code trên cũng tuơng tự với ví dụ MouseRotate2App, tuy nhiên
vẫn khác nhua trong một số trường hợp. Điều khác biệt chủ yếu là ứng
dụng trên chỉ sử dụng một đối tượng behavior trong khi ứng dụng
MouseRotate2App sử dụng h2 đối tượng behavior – cho mỗi đối tượng
trực quan.
Ngoài ra chức năng của các behavior cũng rất khác nhau. Ứng dụng của
chúng ta chô phép người dùng pick một đối tượng để tương tác, trong khi
ứng dụng MouseRotate2App làm quay cả hai đối tượng.
4.6.2 Các hàm API cơ bản trong các lớp Picking
Về cơ bản có 3 'levels' picking classes được cung cấp trong Java 3D.
Các hàm Java 3D API cơ bản cung cấp các hàm chức năng ở tầng dưới
cùng. Gói tiện ích picking cung cấp nhưng lớp picking behavior chung,
phù hợp và dễ dàng thay đổi. Gói tiệc ích picking cũng cung cấp các lớp
behavior có thể sử dụng trực tiếp trong chuwong trình Java3D.
Những lớp nhân cơ bản bao gồm lớp PickShape và lớp
SceneGraphPath, và các phương thức của BranchGroup và Locale.Những
http://tailieuhay.com 458
Lập trình đồ họa trên Java 2D và 3D
lớp này cung cấp những kỹ thuật để xác định hưng hình đựoc sử dụng
trong việc tương tác với các đối tượng trừu tượng. trong phần này chúng
ta giứoi thiệu các hàm API của các lớp : PickShape and SceneGraphPath.
Những lớp tiệc ích picking xác định sủ dụng các lớp chung để thực
thi một picking behavior xác định.
PickShape classes
Lớp cơ sở trừu tượng chỉ cung cấp một cách trừu tượng 5 lớp con:
PickBounds, PickRay, PickSegment, PickPoint, và PickCone.
Thông thường , đối tượng hình học, là đích của picking, sẽ xác định
sử dụng đối tượng pick shapes nào.Đối với các hình có dạng đa giác bất
cứ pick shape nào cũng thỏa mãn được nhiệm vụ này. Tuy nhiên có sự
khác nhau về hiêu năng sử dung giữa các lớp này.
Sơ đồ phả hệ PickShape
PickShape
Lớp con: PickBounds, PickRay, PickSegment, PickPoint, and PickCone
PickBounds
Đối tượng PickBounds thể hiện mọt khung cho pick testing.
http://tailieuhay.com 459
Lập trình đồ họa trên Java 2D và 3D
PickBounds Constructor Summary
Thừa kế: PickShape
Một khung để cung cấp cho phương thức BranchGroup Locale pick.
PickBounds()
Hàm tạo Pickbounds
PickBounds(Bounds boundsObject)
Hàm tạo với tham số bound.
PickBounds Method Summary
Bounds get()
Trả về đối tượng bound từ đối tượng PickBounds.
void set(Bounds boundsObject)
Thiết lập boundsObject trong đối tượng PickBounds.
PickPoint
Đối tượng PickPoint thể hiẹn cho điểm picking. Là lớp con của lớp
PickShape, đối tượng PickPoint có thể được sử dụng với BranchGroup
and Locale pick testing
PickPoint Constructor Summary
Thừa kế : PickShape
Một điểm cung câp cho phương thức pick của BranchGroup và Locale
PickPoint()
Hàm tọa đối tượng PickPoint tại (0, 0, 0).
PickPoint(Point3d location)
Hàm tọa PickPoint với tham số location.
http://tailieuhay.com 460
Lập trình đồ họa trên Java 2D và 3D
PickPoint Method Summary
void set(Point3d location)
Thiết lập giá trị vị trí của PickPoint.
PickRay
Đối tượng PickRay thể hiện một ray trong picking.
PickRay Constructor Summary
Thừa kế : PickShape
Đối tượng PickRay là một gói gọn các ray để truyền vào cho phương thức
picking trong lớp BranchGroup và Locale
PickRay()
Hàm tạo với giá trị mặc định (0, 0, 0).
PickRay(Point3d origin, Vector3d direction)
Hàm tạo với tham số hướng.
PickRay Method Summary
void set(Point3d origin, Vector3d direction)
Thiết lập một tia đến một điểm từ vị trí với tham số tọa đọ và hướng.
PickSegment
Đối tượng PickSegment biểu diễn một đoạn thẳng (defined by two
points) để picking.
Lớp con lớp PickShape, đối tượng PickSegment được sử dụng với
phương thức pick testing của BranchGroup và Locale
http://tailieuhay.com 461
Lập trình đồ họa trên Java 2D và 3D
PickSegment Constructor Summary
Thừa kế : PickShape
PickSegment()
Hàm tạo PickSegment.
PickSegment(Point3d start, Point3d end)
Hàm tạo PickSegment tham số điểm đầu điểm cuối.
PickSegment Method Summary
void set(Point3d start, Point3d end)
Thiết lạp một PickSegment tham số điểm đầu điẻm cuối.
PickCone
PickCone lớp mới trong API phiên bản 1.2. Lớp PickCone là lớp cơ
sở trừu tượng với tất cả các khung hình nón. Khung hình nón sử dụng
hiệu quả khi picking giữa các đối tượng hình học.
Gồ hai lớp con: PickConeRay và PickConeSegment. Điểm khác biệt
giữa chúng là độ dài. PickConeRay là một hình nón với độ dài is a cone
of vô tận length trong khi PickConeSegment có độ dài giới hạn.
Đối tượng PickConeRay đựoc xác định ởi một điểm ban đầu và
hướng. Đối tượng PickConeSegment được định nghĩa hai điểm xác định
cả độ dài và huwosng của hình nón.
PickCone Method Summary
void getDirection(Vector3d direction) <new in 1.2>
http://tailieuhay.com 462
Lập trình đồ họa trên Java 2D và 3D
Trả về hướng của đối tượng PickCone
void getOrigin(Point3d origin) <new in 1.2>
double getSpreadAngle() <new in 1.2>
Trả về góc rộng của đối tượng PickCone.PickConeRay <new in 1.2>
PickConeRay Constructor Summary
Thừa kế PickCone
PickConeRay() <new in 1.2>
Hàm tạo PickConeRay.
PickConeRay(Point3d origin, Vector3d direction, <new in 1.2>
double spreadAngle)
Hàm tạo PickConeRay.
PickConeRay Method Summary
void set(Point3d origin, Vector3d direction, double spreadAngle)
Phương thức thiết lập các tham số của đối tượng PickCone
PickConeSegment <new in 1.2>
PickConeSegment Constructor Summary
Thừa kế : PickCone
PickConeSegment() <new in 1.2>
PickConeSegment(Point3d origin, Point3d end, double spreadAngle)
<new in 1.2>
PickConeSegment Method Summary
void getEnd(Point3d end) <new in 1.2>
http://tailieuhay.com 463
Lập trình đồ họa trên Java 2D và 3D
Trả về điểm cuối của đối tượng PickConeSegment. Điểm đầu đuwojc
nhận từ phương thức của lớp cha.
void set(Point3d origin, Point3d end, double spreadAngle) <new in
1.2>
PickCylinder <new in 1.2>
Lớp PickCylinder và lớp con của nó cũng tưong tự như lớp PickCone
và các lớp con của PickCone. Lớp PickCone là lớp cơ sở trừu tượng của
hai lớp: PickCylinderRay và PickCylinderSegment.
PickCylinder Method Summary
void getDirection(Vector3d direction) <new in 1.2>
Trả về hướng của đối tượng PickCylinder.
void getOrigin(Point3d origin) <new in 1.2>
Trả về điểm khởi đầu của đối tượng cylinder.
double getRadius() <new in 1.2>
Trả về goc ban đầu của đối tượng cylinder
PickCylinderRay <new in 1.2>
PickCylinderRay Constructor Summary
Thừa kế : PickCylinder
PickCylinderRay() <new in 1.2>
http://tailieuhay.com 464
Lập trình đồ họa trên Java 2D và 3D
Hàm tạo PickCylinderRay. Sử dụng phương thức set(Point3d, Vector3d
double) đẻ thiết lập các giá trị của htuộc tính
PickCylinderRay(Point3d origin, Vector3d direction, <new in 1.2>
double radius)
Hàm tạo với tham số điểm ban đầu và hứong.
PickCylinderRay Method Summary
void set(Point3d origin, Vector3d direction, double radius) <new in
1.2>
Phương thức thiết lập giá trị cho các thuộc tính của đối tượng
PickCylinderRay.
PickCylinderSegment <new in 1.2>
PickCylinderSegment Constructor Summary
Thừa kế : PickCylinder
PickCylinderSegment() <new in 1.2>
Hàm tạo PickCylinderSegment.
PickCylinderSegment(Point3d origin, Point3d end, double radius)
<new in 1.2>
PickCylinderRay Method Summary
void getEnd(Point3d end) <new in 1.2>
Trả về điểm cuối đối tượng PickCylinderSegment.
void set(Point3d origin, Point3d end, double radius) <new in 1.2>
SceneGraphPath
http://tailieuhay.com 465
Lập trình đồ họa trên Java 2D và 3D
Lớp SceneGraphPath được sử dụng trong hầu hết các ứng dụng
picking.Điều này là do quá trình picking thuwongf xuyên bao gồm quá
trình tìm đừong đi trong đồ thị khung cảnh có chứa đối tượng cần tương
tác. Một đối tượng SceneGraphPath thể hiện một đường đi trong đồ thị
khung cảnh.
SceneGraphPath Method Summary (partial list)
boolean equals(java.lang.Object o1)
Trả về true nếu đối tượng o1 có kiêu SceneGraphPath và các dữ liệu
thành phần của đối tượng o1 tương ứng bằng với các thành phần dữ liệu
của đối tượng SceneGraphPath và néu giá trị của transforms cũng bằng
nhau
Transform3D getTransform()
Trả về bản copy của transform gắn liền với đối tượng SceneGraphPath;
trả về null nếu không có transform.
int hashCode()
boolean isSamePath(SceneGraphPath testPath)
Xác định hai đối tượng đại diện cho cùng một đường đi hay không.
int nodeCount()
Trả về số node của đừong đi.
void set(SceneGraphPath newPath)
void setLocale(Locale newLocale)
Thiết lập đường đi là đường đi từ đối tượng Locale đến một đối tượng
Locale.xác định
void setNode(int index, Node newNode)
void setNodes(Node[] nodes)
void setObject(Node object)
http://tailieuhay.com 466
Lập trình đồ họa trên Java 2D và 3D
void setTransform(Transform3D trans)
java.lang.String toString()
Các phương thức picking của BranchGroup và Local Picking
Đây là tầng thấp nhất trong việc tính toán picking được cung cấp
trong Java 3D API.
BranchGroup and Locale picking methods for use with PickShape
SceneGraphPath[] pickAll(PickShape pickShape)
Trả về mảng tham chiếu các node nằm duới BranchGroup,có thể pick và
có giao cắt với đối tượng PickShape.
SceneGraphPath[] pickAllSorted(PickShape pickShape)
Trả về một mảng các có thứ tự tham chiếu đến các thành phần có thể pick
đựoc và có giao cắt với đối tượng pickShape. Phần tử [0] tham chiếu đến
thành phần nằm gần đối tượng PickShape nhất
SceneGraphPath pickClosest(PickShape pickShape)
SceneGraphPath pickAny(PickShape pickShape)
4.6.3 Các lớp picking
Những lớp picking nói chung được dùng hiệu quả trong việc tạo ra
các picking behavior . Các lớp : PickMouseBehavior, PickObject,và
PickCallback.
PickMouseBehavior Class
Lớp cơ sở cung cấp các phương thức picking behavior.Lớp này còn
rất hiệu quả trong việc xây dựung các picking class sau này bằng việc
thừa kế nó.
PickMouseBehavior Method Summary
http://tailieuhay.com 467
Lập trình đồ họa trên Java 2D và 3D
Gói : com.sun.j3d.utils.behaviors.picking
Thừa kế : Behavior
void initialize()
Phương thức này cần được viết đè để cung cấp các trạng thái ban đầu và
các đièu kiện trigger ban đầu.
void processStimulus(java.util.Enumeration criteria)
void updateScene(int xpos, int ypos)
PickObject Class
Lớp PickObject cung cấp các phương thức xác định đối tượng nào
đựoc chọn bởi hành động pick của người dùng.
PickObject Constructor Summary
Gói: com.sun.j3d.utils.behaviors.picking
Thừa kế : java.lang.Object
PickObject(Canvas3D c, BranchGroup root)
Hàm tạo PickObject.
PickObject Method Summary (partial list)
Lớp PickObject có nhiều phương thức đẻ tính toán sự giao cắt của một
đối tượng pickRay với đối tượng đồ thị khung cảnh..
PickShape generatePickRay(int xpos, int ypos)
Khởi tạo một đối tượng PickRay bắt đầu từ vị trí của viewer và trỏ tới
điểm xác địnhtheo huwonsg xác định.
PickObject Method Summary (partial list - continued)
http://tailieuhay.com 468
Lập trình đồ họa trên Java 2D và 3D
SceneGraphPath[] pickAll(int xpos, int ypos)
Trả về một mảng tham chiếu tất cả các thành phần nằm dưới
BranchGroup có giao cắt với một ray bắt đầu từ vị trí viewer và trỏ tới
khung hình theo hướng và đỉem tới xác định
SceneGraphPath[] pickAllSorted(int xpos, int ypos)
Tương tự phương thức trên nhưng mảng trả vè được sắp xếp theo thứ tự.
SceneGraphPath pickAny(int xpos, int ypos)
Trả về tham chiếu đến một đối tượng nằm dưới BranchGroup có giao cắt
với một ray bắt đầu từ vị trí viewer và trỏ tới khung hình theo hướng và
đỉem tới xác định
SceneGraphPath pickClosest(int xpos, int ypos)
Node pickNode(SceneGraphPath sgPath, int node_types)
Trả về một đối tượng Node có kiểu xác định và có chưa đối tượng
SceneGraphPath xác định giá trị của kiểu node:
PickObject.BRANCH_GROUP,
PickObject.GROUP, PickObject.LINK, PickObject.MORPH,
PickObject.PRIMITIVE,
PickObject.SHAPE3D, PickObject.SWITCH,
PickObject.TRANSFORM_GROUP.
Node pickNode(SceneGraphPath sgPath, int node_types, int
occurrence)
PickingCallback Interface
Giao diện PickingCallback cung cấp một khng làm việc để thừa kế
một lớp picking đã có trước.
Interface PickingCallback Method Summary
http://tailieuhay.com 469
Lập trình đồ họa trên Java 2D và 3D
Gói: com.sun.j3d.utils.behaviors.picking
void transformChanged(int type, TransformGroup tg)
Lớp Intersect
Lớp cung cấp các phương thức để kiểm tra việc qiao cắt của một đối
tượng PickShape (core class) với một đối tượng geometry primitives.
Intersect Constructor Summary
Gói: com.sun.j3d.utils.behaviors.picking
Thừa kế : java.lang.Object
Intersect()
Hàm tạo Intersect.
Intersect Method Summary (partial list)
boolean pointAndLine(PickPoint point, Point3d[] coordinates, int
index)
Trả về true nếu như đối tượng PickPoint và đối tượng Line giao nhau.
Lien đuợc xác định bởi tham số đầu vào.
boolean pointAndPoint(PickPoint point, Point3d pnt)
Tra về true néu đối tượng PickPoint và đối tượng Point3d giao cắt nhau.
boolean rayAndLine(PickRay ray, Point3d[] coordinates, int index,
double[] dist)
boolean rayAndPoint(PickRay ray, Point3d pnt, double[] dist)
boolean rayAndQuad(PickRay ray, Point3d[] coordinates, int index,
double[] dist)
boolean rayAndTriangle(PickRay ray, Point3d[] coordinates, int
index,
http://tailieuhay.com 470
Lập trình đồ họa trên Java 2D và 3D
double[] dist)
boolean segmentAndLine(PickSegment segment, Point3d[]
coordinates, int index,
double[] dist)
Intersect Method Summary (partial list - continued)
boolean segmentAndPoint(PickSegment segment, Point3d pnt,
double[] dist)
boolean segmentAndQuad(PickSegment segment, Point3d[]
coordinates, int index,
double[] dist)
boolean segmentAndTriangle(PickSegment segment, Point3d[]
coordinates,
int index, double[] dist)
4.6.4 Các lớp Picking Behavior
Gói com.sun.j3d.utils.behaviors.picking cung cấp các lớp
PickRotateBehavior
Lớp PickRotateBehavior cho phép người dùng tưong tác pick và
rotate đối tượng trực quan.
PickRotateBehavior Constructor Summary
Gói: com.sun.j3d.utils.behaviors.picking
Thừa kế : PickMouseBehavior
Thực this: PickingCallback
PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds)
http://tailieuhay.com 471
Lập trình đồ họa trên Java 2D và 3D
PickRotateBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds,
int pickMode)
Giáptrị PickMode : PickObject.USE_BOUNDS hay
PickObject.USE_GEOMETRY. Note: If pickMode is set
to PickObject.USE_GEOMETRY, all geometry objects in the scene
graph intended to be available for picking
must have their ALLOW_INTERSECT bit set.
PickRotateBehavior Method Summary
void setPickMode(int pickMode)
Thiết lập giá trị pickMode: nhạn một trong các giá trị
PickObject.USE_BOUNDS hay
PickObject.USE_GEOMETRY.
void setupCallback(PickingCallback callback)
void transformChanged(int type, Transform3D transform)
void updateScene(int xpos, int ypos)
PickTranslateBehavior
Lớp PickTranslateBehavior cho phép người dung tương tác pick và
translate đối tượng trực quan. Một thể hiện của lớp
PickTranslateBehavior có thể đuợc sử dụng kết hợp với các đối tượng
tcủa các lớp picking khác.
PickTranslateBehavior Constructor Summary
Gói : com.sun.j3d.utils.behaviors.picking
Thừa kế : PickMouseBehavior
http://tailieuhay.com 472
Lập trình đồ họa trên Java 2D và 3D
Thực thi: PickingCallback
PickTranslateBehavior(BranchGroup root, Canvas3D canvas,
Bounds bounds)
Khởi tạo hành vi pick/translate chờ sự kiện từ chuột trong đồ thị khung
cảnh
PickTranslateBehavior(BranchGroup root, Canvas3D canvas,
Bounds bounds,
int pickMode)
PickTranslateBehavior Method Summary
void setPickMode(int pickMode)
Thiết lạp giá trị thành phần pickMode
void setupCallback(PickingCallback callback)
Đăng kí lớp callback được gọi mỗi khi đối tượng được kích họat.
void transformChanged(int type, Transform3D transform)
void updateScene(int xpos, int ypos)
PickZoomBehavior
Lớp PickZoomBehavior cho phép người dung tương tác pick và zoom
đối tượng trực quan. Một thể hiện của lớp PickZoomBehavior có thể đuợc
sử dụng kết hợp với các đối tượng tcủa các lớp picking khác.
PickZoomBehavior Constructor Summary
Gói: com.sun.j3d.utils.behaviors.picking
Thừa kế : PickMouseBehavior
Thực thi: PickingCallback
http://tailieuhay.com 473
Lập trình đồ họa trên Java 2D và 3D
PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds)
Khởi tạo hành vi pick/zoom chờ sự kiện từ chuột trong đồ thị khung cảnh
PickZoomBehavior(BranchGroup root, Canvas3D canvas, Bounds
bounds,
int pickMode)
PickZoomBehavior Method Summary
void setPickMode(int pickMode)
Thiết lạp giá trị thành phần pickMode .
void setupCallback(PickingCallback callback)
Đăng kí lớp callback được gọi mỗi khi đối tượng được kích họat.
void transformChanged(int type, Transform3D transform)
Phương thức Callback từ lớp MouseZoom.
void updateScene(int xpos, int ypos)
Cập nhật khung cảnh .
CHƯƠNG 5
Hoạt Hình
http://tailieuhay.com 474
Lập trình đồ họa trên Java 2D và 3D
Trong chương này, chúng tôi sẽ trình bày các vấn đề cơ bản sau:
• Sử dụng các lớp Alpha và Interpolator để thêm các hoạt ảnh
đơn giản
• Sử dụng các lớp LOD và Billboard để giảm khối lượng tính
toán khi tạo các hoạt ảnh
• Sử dụng đối tượng Morph với các đối tượng hành vi tùy chỉnh
để tạo hoạt ảnh từ các khung hình chính
• Tạo đối tượng hình học động để tạo Behavior hiệu chỉnh dữ liệu
BY_REFERENCE.
Trong thế giới ảo, có rất nhiều đối tượng trực quan thay đổi độc lập với
hành động của con người. Ví như một chiếc đồng hồ ảo chẳng hạn, nó có
thể hoạt động mà không cần tương tác của người dùng. Chiếc đồng hồ
chính là một ví dụ về hoạt ảnh. Vậy hoạt ảnh là những thay đổi xảy ra
trong vũ trụ ảo mà không có tương tác trực tiếp của con người. Ngược lại,
những thay đổi xảy ra trong vũ trụ ảo mà là kết quả trực tiếp của hành
động người dùng thì được gọi là tương tác (chúng ta đã xét trong chương
4).
http://tailieuhay.com 475
Lập trình đồ họa trên Java 2D và 3D
Animation - Hoạt hình:
Tương tự như phần tương tác, hoạt ảnh trong Java 3D cũng được cài
đặt nhờ sử dụng đối tượng Behavior (hành vi). Bất cứ hoạt ảnh nào cũng
có thể tạo ra được với các đối tượng hành vi. Tuy nhiên, Java 3D API
cung cấp một tập các lớp cho phép tạo hoạt ảnh mà không phải tạo một
lớp mới. Các lớp này đều kế thừa lớp Behavior.
Java 3D cung cấp một tập các lớp hoạt ảnh có vai trò như những bộ
nội suy (Interpolator ). Đối tượng Interpolator cùng với một đối tượng
Alpha điều khiển một vài thông số của đối tượng đồ thị khung cảnh để
tạo ra hoạt ảnh dựa thời gian. Đối tượng Alpha cung cấp cơ chế định thời
gian. Chi tiết về hai lớp đối tượng này sẽ được bàn đến trong mục 5.2.
Một tập các lớp hoạt ảnh khác trong Java 3D tạo hoạt ảnh cho các đối
tượng trực quan nhờ đáp ứng sự thay đổi về khung nhìn. Tập các lớp này
(bao gồm: lớp OrientedShape3D, các lớp hành vi Billboard và Level Of
Detail (LOD )) không được điều khiển bởi các khoảng thời gian mà bởi
vị trí và hướng của khung nhìn. Hai lớp hành vi sẽ được xét kĩ hơn trong
các mục 5.3 và 5.5
Một vài lớp hoạt ảnh không kế thừa từ lớp Behavior như:
OrientedShape3D và Morph . Mục 5.4 sẽ trình bày về OrientedShape3D,
lớp hoạt ảnh được đưa vào Java 3D API từ phiên bản v1.2 như một sự
thay thế cho hành vi Billboard trong các phiên bản trước đó. Mục 5.6
trình bày về Morph , lớp hoạt ảnh được sử dụng cả trong các ứng dụng
hoạt ảnh và nội suy.
http://tailieuhay.com 476
Lập trình đồ họa trên Java 2D và 3D
Hình 5-1. Sơ đồ phân cấp các lớp hoạt ảnh kế thừa Behavior
Đối tượng Interpolator và Alpha với hoạt ảnh dựa thời gian
Đối tượng Alpha sinh ra một giá trị nằm trong khoảng từ 0 đến 1 tùy
thuộc vào thời gian và các tham số của đối tượng Alpha. Thực thể nội suy
(Interpolator ) là các đối tượng hành vi tùy chỉnh sử dụng một đối tượng
Alpha để sinh hoạt ảnh cho các đối tượng trực quan. Nội suy bao gồm sự
thay đổi vị trí, hướng, độ lớn, màu sắc hoặc độ trong suốt của đối tượng.
Các hành vi nội suy có thể được cài đặt bằng cách tạo ra một lớp hành vi
tùy chỉnh, tuy nhiên, sử dụng lớp nội suy cho phép tạo hoạt ảnh dễ dàng
hơn nhiều. Trong phần 5.2.3, chúng ta sẽ xét một ví dụ sử dụng lớp nội
suy RotationInterpolator.
Alpha
Đối tượng Alpha sinh ra một giá trị, được gọi là giá trị Alpha, nằm
trong khoảng từ 0.0 và 1.0, kể cả hai đầu mút. Giá trị Alpha thay đổi theo
thời gian như đã định sẵn bởi các tham số của đối tượng Alpha. Với các
bộ giá trị tham số nhất định, tại thời điểm cụ thể, đối tượng Alpha chỉ
sinh ra một giá trị Alpha duy nhất. Biểu diễn bằng đồ thị giá trị Alpha so
với thời gian, chúng ta sẽ được một dạng sóng mà đối tượng Alpha sinh
ra.
Đồ thị dạng sóng của đối tượng Alpha có bốn đoạn: Alpha tăng,
Alpha bằng 1, Alpha giảm và Alpha bằng 0. Bốn đoạn này tạo thành một
http://tailieuhay.com 477
Lập trình đồ họa trên Java 2D và 3D
chu kì của dạng sóng Alpha và tương ứng với bốn tham số của đối tượng
Alpha. Thời gian của một chu kì được xác định bằng một số nguyên, đơn
vị tính là mili giây. Hình 5-2 biểu diễn bốn đoạn của dạng sóng Alpha.
Việc định thời gian của các đối tượng Alpha có liên hệ với thời điểm
khởi động chúng. Thời điểm khởi động của tất cả các đối tượng Alpha
đều được lấy từ thời điểm khởi động hệ thống. Vì thế tuy các đối tượng
Alpha được tạo ra ở các thời điểm khác nhau, nhưng chúng đều có chung
một thời điểm khởi động. Kết quả là, tất cả các đối tượng nội suy mặc dù
dựa trên các đối tượng Alpha khác nhau nhưng đều được đồng bộ hóa.
Dạng sóng của các đối tượng Alpha có thể bắt đầu ở những thời điểm
khác nhau. Chu kì dạng sóng đầu tiên của một đối tượng Alpha có thể bị
trễ do việc sử dụng một trong hai hoặc cả hai tham số: TriggerTime (thời
điểm kích hoạt) và PhaseDelayDuration (thời gian trễ). TriggerTime xác
định khoảng thời gian từ lúc đối tượng Alpha khởi động cho đến khi bắt
đầu hoạt động. Sau khoảng thời gian xác định bởi tham số
PhaseDelayDuration tính từ thời điểm kích hoạt TriggerTime, chu kì của
dạng sóng đầu tiên bắt đầu. Các tham số này được thể hiện trong hình 5-
2.
Dạng sóng của đối tượng Alpha có thể quay vòng một chu kì, tiếp tục
quay vòng với số lần xác định hoặc sẽ quay vòng không dừng. Số chu kì
của sóng xác định bởi tham số loopCount. loopCount dương qui định số
chu kì, loopCount bằng –1 xác định vòng lặp không dừng. Nếu dạng sóng
Alpha quay vòng hơn 1 chu kì, tất cả các giai đoạn trên đều được lặp lại,
ngoại trừ giai đoạn trễ.
http://tailieuhay.com 478
Lập trình đồ họa trên Java 2D và 3D
Hình 5-2. Các giai đoạn của dạng sóng Alpha
Dạng sóng Alpha có thể không sử dụng tất cả bốn giai đoạn trên mà
có thể được tạo thành từ một, hai, ba hoặc bốn giai đoạn. Hình 5-3 biểu
diễn một số dạng sóng tạo bởi một, hai hoặc ba giai đoạn.
Đối tượng Alpha có hai kiểu chỉ định các tập con giai đoạn được sử
dụng. Kiểu INCREASING_ENABLE chỉ định sử dụng các giai đoạn
Alpha tăng và giai đoạn Alpha bằng 1. Kiểu DECREASING_ENABLE
chỉ định sử dụng giai đoạn Alpha giảm và Alpha bằng 0. Kiểu thứ ba là
kết hợp của cả hai kiểu trên, chỉ định sử dụng cả bốn giai đoạn.
Hình 5-3. Một vài dạng sóng cơ sở được tạo với đối tượng Alpha
http://tailieuhay.com 479
Lập trình đồ họa trên Java 2D và 3D
Các đặc tả về kiểu của đối tượng Alpha sẽ vô hiệu các thiết lập tham
số khoảng thời gian. Ví dụ, khi kiểu là INCREASING_INABLE, thì các
tham số DecreasingAlphaDuration, DecreasingAlphaRampDuration và
AlphaAtZeroDuration sẽ bị bỏ qua. Mặc dù bất kì một dạng sóng nào
cũng có thể xây dựng được bằng cách cho khoảng thời gian tồn tại của
các giai đoạn không cần thiết bằng 0, tuy nhiên, việc đặc tả chính xác kiểu
sẽ làm tăng hiệu quả của đối tượng Alpha.
Sử dụng các đối tượng Interpolator và Alpha:
Cách thức sử dụng các đối tượng Interpolator và Alpha rất giống
với cách thức sử dụng đối tượng hành vi. Điểm khác biệt lớn nhất so với
cách sử dụng đối tượng hành vi chính là việc gộp cùng với đối tượng
Alpha.
Công thức sử dụng các đối tượng Interpolator và Alpha có thể tóm
tắt như sau:
1. tạo đối tượng đích với các khả năng thích hợp
2. tạo đối tượng Alpha
3. tạo đối tượng Interpolator tham chiếu đến đến đối tượng
Alpha và đối tượng đích
4. thêm các giới hạn cho đối tượng Interpolator
5. thêm đối tượng Interpolator vào đồ thị khung cảnh
Hình 5-4. Công thức sử dụng các đối tượng Interpolator và Alpha
để tạo hoạt ảnh
Ví dụ sử dụng lớp Alpha và RotationInterpolator:
ClockApp.java là một ví dụ sử dụng lớp RotationInterpolator. Khung
cảnh là mặt một chiếc đồng hồ. Chiếc đồng hồ này được điều khiển quay
http://tailieuhay.com 480
Lập trình đồ họa trên Java 2D và 3D
mỗi phút một lần bởi hai đối tượng RotationInterpolator và Alpha.
Chương trình đầy đủ xin xem phần phụ lục, ở đây chúng tôi chỉ trích rút
một phần để tập trung vào vấn đề chính.
Trong chương trình này, đối tượng đích là một đối tượng
TransformGroup. Yêu cầu đối tượng này phải được thiết lập khả năng
ALLOW_TRANSFORM_WRITE. Các đối tượng Interpolator khác
nhau sẽ hoạt động trên các đối tượng đích khác nhau. Ví dụ, đích của đối
tượng ColorInterpolator là một đối tượng Material. Đối tượng
Interpolator thiết lập giá trị của đối tượng đích dựa vào các giá trị của
đối tượng Alpha và các giá trị do chính nó lưu giữ.
Đối tượng Interpolator định nghĩa điểm kết thúc của hoạt ảnh.
Trong trường hợp của RotationInterpolator, đối tượng này xác định góc
quay bắt đầu và kết thúc. Đối tượng Alpha điều khiển hoạt ảnh tương ứng
với thời gian và cách mà Interpolator dịch chuyển từ điểm này đến một
điểm khác bằng đặc tả các giai đoạn của dạng sóng Alpha.
Ứng dụng này sử dụng thiết lập mặc định cho đối tượng
RotationInterpolator với góc bắt đầu là 0 và góc kết thúc là 2Π (một vòng
quay hoàn chỉnh). Trục quay mặc định là trục y. Đối tượng Alpha được
thiết lập ở chế độ quay không dừng (loopCount = -1) với quãng thời gian
là 1 phút (60.000 mili giây). Hai đối tượng này kết hợp với nhau sẽ làm
cho đối tượng trực quan (đối tượng đích) quay một vòng hoàn chỉnh trong
1 phút. Chu trình này được tiếp diễn và lặp lại ngay lập tức. Kết quả là
chiếc đồng hồ dường như quay không ngừng chứ không phải là quay một
vòng rồi bắt đầu lại một vòng khác.
Đoạn mã sau định nghĩa phương thức createSceneGraph trong chương
trình ClockApp.java. Đoạn mã này được đánh dấu các bước tương ứng
với công thức đưa ra trong hình 5-4.
public BranchGroup createSceneGraph() {
http://tailieuhay.com 481
Lập trình đồ họa trên Java 2D và 3D
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
// create target TransformGroup with
Capabilities
TransformGroup objSpin = new
TransformGroup();
objSpin.setCapability(TransformGroup.ALLO
W_TRANSFORM_WRITE);
// create Alpha that continuously rotates
with a period of 1 minute
Alpha alpha = new Alpha (-1, 60000);
// create rotation about y-axis
RotationInterpolator rotInt = new
RotationInterpolator (alpha, objSpin);
rotInt.setSchedulingBounds(new
BoundingSphere());
objRoot.addChild(objSpin);
objSpin.addChild(new Clock());
objRoot.addChild(rotInt);
Background background = new Background();
background.setColor(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(new
BoundingSphere());
objRoot.addChild(background);
http://tailieuhay.com 482
Lập trình đồ họa trên Java 2D và 3D
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
ClockApp
Hình 5-5 là một cảnh được tạo ra bằng chương trình ClockApp tại 4:30.
Mặt đồng hồ trông bị nghiêng đi là do cả mặt đấy quay theo trục thẳng
đứng.
Làm trơn dạng sóng Alpha
Ngoài khoảng thời gian của 4 giai đoạn như đã trình bày, người lập
trình còn có thể xác định các sườn thoải cho giai đoạn Alpha tăng và
Alpha giảm. Trong đoạn thoải này, giá trị Alpha thay đổi dần dần. Trong
trường hợp lập trình cho vật thể chuyển động, thì cách này cho phép vật
thể chuyển động chậm dần hoặc nhanh dần trông giống thật hơn.
Vì giá trị của đoạn dốc thoải tác động đến cả phần bắt đầu và kết thúc
của giai đoạn, nên đoạn này lớn nhất chỉ bằng một nửa của cả giai đoạn.
http://tailieuhay.com 483
Lập trình đồ họa trên Java 2D và 3D
Hình 5-5. Một cảnh sinh bởi chương trình ClockApp tại 4:30
Hình 5-6 biểu diễn một dạng sóng Alpha được thiết lập cả
Hình 5-6. Làm trơn dạng sóng Alpha
AlphaApp.java (xem phụ lục) là một chương trình ví dụ về tác động
của việc thiết lập IncreasingAlphaRampDuration trên một dạng sóng
Alpha. Sự khác biệt về giá trị sẽ được đánh giá trực quan qua việc quan
sát chuyển động của 3 chiếc ô tô. Cả 3 chiếc này xuất phát tại cùng một
tọa độ x và di chuyển song song với nhau. Chiếc xe trên cùng không có
đoạn giá trị Alpha thoải, chiếc dưới cùng có đoạn thoải với giá trị lớn
nhất (bằng một nửa của giai đoạn Alpha tăng hoặc giảm), còn chiếc ở
http://tailieuhay.com 484
Lập trình đồ họa trên Java 2D và 3D
giữa có đoạn thoải với giá trị bằng một nửa giá trị lớn nhất (tức là bằng ¼
giai đoạn Alpha tăng hoặc giảm). Mỗi xe cần 2 giây để chuyển động qua
khung nhìn.
Time ~ 0.4s Time ~ 0.8s
Time ~ 1.2s Time ~ 1.6s
Hình 5-7. Tác dụng của IncreasingAlphaRampDuration trên một dạng
sóng Alpha
Hình 5-7 biểu diễn 4 cảnh sinh ra từ chương trình AlphaApp. Quan
sát chương trình, chúng ta có thể nhận thấy rằng: ban đầu chiếc xe trên
cùng (không có đoạn thoải) chuyển động nhanh hơn và giữ nguyên tốc
http://tailieuhay.com 485
Lập trình đồ họa trên Java 2D và 3D
độ, hai chiếc phía dưới chuyển động chậm hơn nhưng nhanh dần. Đến
thời điểm 1 giây sau khi khởi động, cả 3 chiếc đều đi được quãng đường
giống nhau. Trong một nửa quãng đường còn lại, vị trí của 3 chiếc xe bị
đảo ngược với chiếc dưới cùng chạy nhanh nhất nhưng chậm dần. Cuối
cùng, khi hết 2 giây, 3 chiếc xe lại bắt kịp nhau.
Alpha API:
Lớp Alpha có vai trò chuyển đổi một giá trị thời gian về một giá trị
Alpha (giá trị nằm trong khoảng từ 0 đến 1, kể cả hai đầu mút). Vì vậy,
có thể nói đối tượng Alpha là một hàm của thời gian, trả về một giá trị
nằm trong đoạn [0, 1]. Ứng dụng thông thường của Alpha là cung cấp giá
trị Alpha cho các hành vi Interpolator .
Các phương thức API của lớp Alpha có thể tùy biến một cách dễ
dàng để sử dụng trong các ứng dụng bằng cách tác động vào các tham số
của chúng. 4 phương thức khởi tạo chủ yếu sau xuất hiện trong hầu hết
các ứng dụng Alpha:
Alpha()
Khởi tạo đối tượng Alpha với mode = INCREASING_ENABLE,
loopCount = -1, increasingAlphaDuration = 1000, tất cả các tham số khác
= 0, ngoại trừ thời gian khởi động: StartTime. StartTime được thiết lập
bằng thời gian khởi động của chương trình.
Alpha(int loopCount, long increasingAlphaDuration)
Khởi tạo đối tượng Alpha với hai tham số loopCount và
increasingAlphaDuration là tùy biến của người dùng, thiết lập chế độ
INCREASING_ENABLE và gán giá trị 0 cho tất cả các tham số còn lại
(ngoại trừ StartTime).
Alpha(int loopCount, long triggerTime,
long phaseDelayDuration, long increasingAlphaDuration,
long increasingAlphaRampDuration,
http://tailieuhay.com 486
Lập trình đồ họa trên Java 2D và 3D
long alphaAtOneDuration)
Khởi tạo đối tượng Alpha ở chế độ INCREASING_ENABLE
Alpha(int loopCount, int mode, long triggerTime,
long phaseDelayDuration, long increasingAlphaDuration, long
increasingAlphaRampDuration,
long alphaAtOneDuration, long decreasingAlphaDuration, long
alphaAtZeroDuration)
Khởi tạo đối tượng Alpha theo các tham số định nghĩa của người dùng.
Lớp Alpha cung cấp rất nhiều các phương thức hữu ích, cho phép
người dùng tuỳ biến các đặc tính của đối tượng Alpha. Chúng tôi liệt kê ở
đây một vài phương thức phổ dụng nhất. Chú ý rằng mỗi phương thức set
(phương thức thiết lập) đều có một phương thức get (không tham số) trả
về một giá trị cùng kiểu với kiểu của tham số có mặt trong phương thức
set tương ứng.
boolean finished()
Kiểm tra xem đối tượng Alpha hiện thời đã kết thúc mọi hoạt động
của nó hay chưa.
void setAlphaAtOneDuration(long alphaAtOneDuration)
Thiết lập thuộc tính alphaAtOneDuration của đối tượng Alpha hiện
thời đến giá trị xác định.
void setAlphaAtZeroDuration(long alphaAtZeroDuration)
Thiết lập giá trị xác định cho thuộc tính alphaAtZeroDuration của đối
tượng Alpha hiện thời.
void setDecreasingAlphaDuration(long decreasingAlphaDuration)
Thiết lập giá trị xác định cho thuộc tính decreasingAlphaDuration của
đối tượng Alpha hiện thời.
void setDecreasingAlphaRampDuration(long
decreasingAlphaRampDuration)
Thiết lập giá trị xác định cho thuộc tính
http://tailieuhay.com 487
Lập trình đồ họa trên Java 2D và 3D
decreasingAlphaRampDuration của đối Alpha tượng hiện thời.
void setIncreasingAlphaDuration(long increasingAlphaDuration)
Thiết lập giá trị xác định cho thuộc tính increasingAlphaDuration của
đối tượng Alpha hiện thời.
void setIncreasingAlphaRampDuration(long
decreasingAlphaRampDuration)
Thiết lập giá trị xác định cho thuộc tính
increasingAlphaRampDuration của đối tượng Alpha hiện thời.
void setLoopCount(int loopCount)
Thiết lập giá trị xác định cho thuộc tính loopCount của đối tượng
Alpha hiện thời.
void setMode(int mode)
Thiết lập chế độ xác định bởi đối số mode cho đối tượng Alpha hiện
thời. mode có thể là INCREASING_ENABLE hoặc
DECREASING_ENABLE, hay là hoặc của hai giá trị.
INCREASING_ENABLE - chỉ định sử dụng giai đoạn 3 và 4
DECREASING_ENABLE - chỉ định sử dụng giai đoạn 1 và 2
void setPhaseDelayDuration(long phaseDelayDuration)
Thiết lập giá trị phaseDelayDuration của đối tượng Alpha hiện thời
bằng giá trị cho trong đối số.
void setStartTime(long startTime)
Thiết lập giá trị startTime của đối tượng Alpha hiện thời bằng giá trị
cho trong đối số. startTime quy định mốc cho mọi tính toán thời gian
tương đối. Giá trị mặc định của startTime là thời điểm khởi động hệ
thống.
void setTriggerTime(long triggerTime)
Thiết lập giá trị triggerTime của đối tượng Alpha hiện thời bằng giá
trị cho trong đối số.
http://tailieuhay.com 488
Lập trình đồ họa trên Java 2D và 3D
float value()
Trả về một giá trị nằm trong đoạn [0, 1] dựa trên thời gian hiện thời và
đối số time-to-Alpha được thiết lập cho đối tượng Alpha đang xét.
float value(long atTime)
Trả về một giá trị nằm trong đoạn [0, 1] dựa trên giá trị atTime và đối
số time-to-Alpha được thiết lập cho đối tượng Alpha đang xét.
Các lớp hành vi Interpolator :
Interpolator là một lớp trừu tượng, kế thừa lớp hành vi Behavior để
cung cấp các phương thức chung cho các lớp con nội suy. Có khoảng hơn
10 lớp con Interpolator cơ bản. Hình 5-8 biểu diễn mối quan hệ của các
lớp Interpolator cơ sở (ô sáng màu) trong Java 3D cùng các gói tiện ích
(ô sẫm màu).
Hình 5-8. Biểu đồ phân cấp lớp đối tượng Interpolator cơ sở trong Java
3D và các tiện ích
Mỗi đối tượng nội suy Interpolator là một đối tượng hành vi
Behavior tùy biến có cơ chế kích hoạt để “đánh thức” mỗi khung ảnh.
Trong phương thức processStimulus, đối tượng Interpolator kiểm tra
giá trị của đối tượng Alpha liên hợp với nó, hiệu chỉnh đối tượng đích
dựa trên các giá trị này rồi xác lập lại cơ chế kích hoạt để “đánh thức”
khung ảnh tiếp theo (trừ phi đối tượng Alpha kết thúc hoạt động). Một
http://tailieuhay.com 489
Lập trình đồ họa trên Java 2D và 3D
vài phương thức này được cung cấp bởi lớp trừu tượng Interpolator , còn
hầu hết các hành vi còn lại được cài đặt trong mỗi lớp Interpolator đơn
lẻ.
Mỗi đối tượng Interpolator chứa 2 giá trị được sử dụng như các
điểm giới hạn cho các hành động được nội suy. Ví dụ, đối tượng nội suy
RotationInterpolator lưu trữ hai góc là giới hạn quay do nó điều khiển.
Với mỗi khung ảnh, đối tượng Interpolator kiểm tra giá trị Alpha của
đối tượng Alpha liên hợp với nó rồi tạo ra các hiệu chỉnh quay thích hợp
cho đối tượng đích TransformGroup của nó. Nếu giá trị Alpha là 0 thì
một trong hai giá trị sẽ được sử dụng; nếu giá trị Alpha là 1, thì giá trị kia
sẽ được sử dụng. Nếu giá trị Alpha nằm trong khoảng từ 0 đến 1, đối
tượng Interpolator sẽ nội suy tuyến tính giữa hai giá trị, dựa trên giá trị
Alpha rồi sử dụng kết quả để điều chỉnh đối tượng đích.
Mô tả chung chung về các đối tượng Interpolator như vậy không
đúng lắm với các lớp SwitchValueInterpolator và PathInterpolator. Đối
tượng SwitchValueInterpolator lựa chọn một nút con trong nhóm các nút
đích Switch, nên trong lớp này, không hề có quá trình nội suy.
Tuy rằng các lớp Interpolator rất giống nhau, chúng cũng mang một
vài chi tiết khác nhau dễ nhận ra. Bảng sau so sánh các đặc điểm khác
nhau của 7 lớp Interpolator cơ bản. Trong các phần sau, chúng ta lần
lượt sẽ đi sâu hơn về 7 lớp này.
lớp Interpolator chức năng kiểu đối tượng đích TrangColorInterpolator thay đổi màu
khuyếch tán của
một đối tượng
Material 5-12
PathInterpolator lớp trừu tượng TransformGroup 5-20PositionInterpolator thay đổi vị trí
của đối tượng
TransformGroup 5-14
RotationInterpolator thay đổi chuyển TransformGroup 5-15
http://tailieuhay.com 490
Lập trình đồ họa trên Java 2D và 3D
động quay
(hướng) của đối
tượngScaleInterpolator thay đổi kích cỡ
của đối tượng
TransformGroup 5-16
SwitchValueInterpolator lựa chọn một
thay đổi (switch)
trong một bộ các
đối tượng
Switch 5-17
TransparencyInterpolator thay đổi mức độ
trong suốt của
đối tượng
TransparencyAttributes 5-19
Bảng 5-1. Tóm tắt các lớp Interpolator cơ bản
Chú ý: PathInterpolator là một lớp trừu tượng, nên không có đối
tượng đích. Tuy nhiên, bất cứ lớp nào thừa kế lớp này đều có đối tượng
đích thuộc kiểu Transformation.
Để hiểu thêm hiệu ứng của các Interpolator này, hãy xem ví dụ
InterpolatorApp.java (chi tiết ở phần phụ lục). Trong chương trình này,
mỗi đối tượng Interpolator được điều khiển bởi một đối tượng Alpha
đơn. Các thay đổi về vị trí, quay, độ lớn, màu sắc, độ trong suốt, và đối
tượng trực quan được tạo ra bởi các đối tượng PositionInterpolator,
RotationInterpolator, ScaleInterpolator, ColorInterpolator,
TransparencyInterpolator, và SwitchValueInterpolator tương ứng.
http://tailieuhay.com 491
Lập trình đồ họa trên Java 2D và 3D
Hình 5-9. InterpolatorApp.java
Mã của chương trình Interpolator.java
package Animation;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.*;
http://tailieuhay.com 492
Lập trình đồ họa trên Java 2D và 3D
import javax.vecmath.*;
// InterpolatorApp renders an
public class InterpolatorApp extends Applet {
Shape3D createCar(float xScale, float yScale,
boolean createNormals,
boolean assignColoring) {
Shape3D car = new Shape3D();
QuadArray carGeom = null;
if (createNormals)
carGeom = new QuadArray(16,
GeometryArray.COORDINATES
|
GeometryArray.NORMALS);
else
carGeom = new QuadArray(16,
GeometryArray.COORDINATES);
carGeom.setCoordinate( 0, new
Point3f(xScale*-0.25f, yScale*0.22f, 0.0f));
carGeom.setCoordinate( 1, new
Point3f(xScale* 0.20f, yScale*0.22f, 0.0f));
carGeom.setCoordinate( 2, new
Point3f(xScale* 0.10f, yScale*0.35f, 0.0f));
http://tailieuhay.com 493
Lập trình đồ họa trên Java 2D và 3D
carGeom.setCoordinate( 3, new
Point3f(xScale*-0.20f, yScale*0.35f, 0.0f));
carGeom.setCoordinate( 4, new
Point3f(xScale*-0.50f, yScale*0.10f, 0.0f));
carGeom.setCoordinate( 5, new
Point3f(xScale* 0.50f, yScale*0.10f, 0.0f));
carGeom.setCoordinate( 6, new
Point3f(xScale* 0.45f, yScale*0.20f, 0.0f));
carGeom.setCoordinate( 7, new
Point3f(xScale*-0.48f, yScale*0.20f, 0.0f));
carGeom.setCoordinate( 8, new
Point3f(xScale*-0.26f, yScale*0.00f, 0.0f));
carGeom.setCoordinate( 9, new
Point3f(xScale*-0.18f, yScale*0.00f, 0.0f));
carGeom.setCoordinate(10, new
Point3f(xScale*-0.16f, yScale*0.12f, 0.0f));
carGeom.setCoordinate(11, new
Point3f(xScale*-0.28f, yScale*0.12f, 0.0f));
carGeom.setCoordinate(12, new
Point3f(xScale* 0.25f, yScale*0.00f, 0.0f));
carGeom.setCoordinate(13, new
Point3f(xScale* 0.33f, yScale*0.00f, 0.0f));
carGeom.setCoordinate(14, new
Point3f(xScale* 0.35f, yScale*0.12f, 0.0f));
carGeom.setCoordinate(15, new
Point3f(xScale* 0.23f, yScale*0.12f, 0.0f));
if (createNormals){
int i;
http://tailieuhay.com 494
Lập trình đồ họa trên Java 2D và 3D
Vector3f normal = new Vector3f(0.6f,
0.6f, 0.8f);
for(i = 0; i < 8; i++)
carGeom.setNormal(i, normal);
normal.set(new Vector3f(0.5f, 0.5f,
0.5f));
for(i = 8; i <16; i++)
carGeom.setNormal(i, normal);
}
if (assignColoring){
ColoringAttributes colorAttrib =
new ColoringAttributes(0.0f,
0.0f, 1.0f, ColoringAttributes.NICEST);
Appearance carAppear = new
Appearance();
carAppear.setColoringAttributes(color
Attrib);
car.setAppearance(carAppear);
}
car.setGeometry(carGeom);
return car;
}
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
Transform3D t3d = new Transform3D();
http://tailieuhay.com 495
Lập trình đồ họa trên Java 2D và 3D
BoundingSphere bounds = new
BoundingSphere();
// create target TransformGroup with
Capabilities
TransformGroup objMove = new
TransformGroup();
objMove.setCapability(TransformGroup.ALLO
W_TRANSFORM_WRITE);
// create target TransformGroup with
Capabilities
TransformGroup objRotate = new
TransformGroup();
objRotate.setCapability(TransformGroup.AL
LOW_TRANSFORM_WRITE);
// create target TransformGroup with
Capabilities
TransformGroup objScale = new
TransformGroup();
objScale.setCapability(TransformGroup.ALL
OW_TRANSFORM_WRITE);
// create target Material with
Capabilities
Material objColor = new Material();
objColor.setCapability(Material.ALLOW_COM
PONENT_WRITE);
http://tailieuhay.com 496
Lập trình đồ họa trên Java 2D và 3D
// create target Transparency with
Capabilities
TransparencyAttributes objTransp = new
TransparencyAttributes();
objTransp.setCapability(TransparencyAttri
butes.ALLOW_VALUE_WRITE);
objTransp.setTransparencyMode(Transparenc
yAttributes.BLENDED);
// create target Switch with Capabilities
Switch objSwitch = new Switch();
objSwitch.setCapability(Switch.ALLOW_SWIT
CH_WRITE);
// create Alpha
Alpha alpha = new Alpha (-1,
Alpha.INCREASING
_ENABLE + Alpha.DECREASING_ENABLE,
0, 0, 2000, 0,
1000, 2000, 0, 1000);
// create position interpolator
PositionInterpolator posInt = new
PositionInterpolator (alpha, objMove);
posInt.setSchedulingBounds(bounds);
posInt.setStartPosition(-1.0f);
// create rotation interpolator
http://tailieuhay.com 497
Lập trình đồ họa trên Java 2D và 3D
RotationInterpolator rotInt = new
RotationInterpolator (alpha, objRotate);
rotInt.setSchedulingBounds(bounds);
// create scale interpolator
ScaleInterpolator scaInt = new
ScaleInterpolator (alpha, objScale);
scaInt.setSchedulingBounds(bounds);
// create color interpolator
ColorInterpolator colInt = new
ColorInterpolator (alpha, objColor);
colInt.setStartColor(new Color3f(1.0f,
0.0f, 0.0f));
colInt.setEndColor(new Color3f(0.0f,
0.0f, 1.0f));
colInt.setSchedulingBounds(bounds);
// create transparency interpolator
TransparencyInterpolator traInt = new
TransparencyInterpolator (alpha, objTransp);
traInt.setSchedulingBounds(bounds);
// create switch value interpolator
SwitchValueInterpolator swiInt = new
SwitchValueInterpolator (alpha, objSwitch);
swiInt.setSchedulingBounds(bounds);
http://tailieuhay.com 498
Lập trình đồ họa trên Java 2D và 3D
t3d.setTranslation(new Vector3f(0.0f,
0.8f, 0.0f));
TransformGroup objMovePos = new
TransformGroup(t3d);
objRoot.addChild(objMovePos);
objMovePos.addChild(objMove);
objMove.addChild(createCar(0.4f, 0.4f,
false, true));
objRoot.addChild(posInt);
t3d.setTranslation(new Vector3f(0.0f,
0.5f, 0.0f));
TransformGroup objRotPos = new
TransformGroup(t3d);
objRoot.addChild(objRotPos);
objRotPos.addChild(objRotate);
objRotate.addChild(createCar(0.4f, 0.4f,
false, true));
objRoot.addChild(rotInt);
t3d.setTranslation(new Vector3f(0.0f,
0.2f, 0.0f));
TransformGroup objScalePos = new
TransformGroup(t3d);
objRoot.addChild(objScalePos);
objScalePos.addChild(objScale);
objScale.addChild(createCar(0.4f, 0.4f,
false, true));
objRoot.addChild(scaInt);
http://tailieuhay.com 499
Lập trình đồ họa trên Java 2D và 3D
t3d.setTranslation(new Vector3f(0.0f,
-0.2f, 0.0f));
TransformGroup objColorPos = new
TransformGroup(t3d);
objRoot.addChild(objColorPos);
Shape3D colorCar = createCar(0.4f, 0.4f,
true, false);
Appearance materialAppear = new
Appearance();
materialAppear.setMaterial(objColor);
colorCar.setAppearance(materialAppear);
objColorPos.addChild(colorCar);
objRoot.addChild(colInt);
t3d.setTranslation(new Vector3f(0.0f,
-0.5f, 0.0f));
TransformGroup objTranspPos = new
TransformGroup(t3d);
objRoot.addChild(objTranspPos);
Shape3D transpCar = createCar(0.4f, 0.4f,
false, true);
Appearance transpAppear =
transpCar.getAppearance();
transpAppear.setTransparencyAttributes(ob
jTransp);
objTranspPos.addChild(transpCar);
objRoot.addChild(traInt);
http://tailieuhay.com 500
Lập trình đồ họa trên Java 2D và 3D
t3d.setTranslation(new Vector3f(0.0f,
-0.8f, 0.0f));
TransformGroup objSwitchPos = new
TransformGroup(t3d);
objRoot.addChild(objSwitchPos);
objSwitch.addChild(createCar(0.4f, 0.4f,
false, true));;
objSwitch.addChild(new ColorCube(0.1f));
objSwitchPos.addChild(objSwitch);
objRoot.addChild(swiInt);
swiInt.setLastChildIndex(2);// since
switch made after interpolator
DirectionalLight lightD1 = new
DirectionalLight();
// lightD1.setDirection(new Vector3f(-0.7f,-
0.7f,0.0f));
lightD1.setInfluencingBounds(bounds);
objRoot.addChild(lightD1);
Background background = new Background();
background.setColor(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(new
BoundingSphere());
objRoot.addChild(background);
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
http://tailieuhay.com 501
Lập trình đồ họa trên Java 2D và 3D
return objRoot;
} // end of CreateSceneGraph method of
InterpolatorApp
// Create a simple scene and attach it to the
virtual universe
public InterpolatorApp() {
setLayout(new BorderLayout());
Canvas3D canvas3D = new Canvas3D(null);
add("Center", canvas3D);
BranchGroup scene = createSceneGraph();
// SimpleUniverse is a Convenience
Utility class
SimpleUniverse simpleU = new
SimpleUniverse(canvas3D);
// This will move the ViewPlatform back a bit
so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalVi
ewingTransform();
simpleU.addBranchGraph(scene);
} // end of InterpolatorApp (constructor)
http://tailieuhay.com 502
Lập trình đồ họa trên Java 2D và 3D
// The following allows this to be run as an
application
// as well as an applet
public static void main(String[] args) {
System.out.print("InterpolatorApp.java
\n- a demonstration of using Interpolator ");
System.out.println("objects to provide
animation in a Java 3D scene.");
System.out.println("This is a simple
example progam from The Java 3D API Tutorial.");
System.out.println("The Java 3D Tutorial
is available on the web at:");
System.out.println("http://java.sun.com/p
roducts/java-media/3D/collateral");
Frame frame = new MainFrame(new
InterpolatorApp(), 256, 256);
} // end of main (method of InterpolatorApp)
} // end of class InterpolatorApp
Những nhầm lẫn thường gặp khi lập trình với Interpolator
Các đối tượng Interpolator là dẫn suất có quan hệ rất gần gũi với
các đối tượng hành vi. Vì vậy, việc sử dụng các đối tượng Interpolator
cũng sẽ phải đối mặt với các lỗi thường gặp như khi sử dụng các đối
tượng hành vi. Thêm vào đó, cũng có các bẫy lỗi khác, chung cho các
Interpolator và các bẫy lỗi riêng cho mỗi Interpolator .
Một nhầm lẫn thường gặp gây ra bởi việc không nhận thấy rằng các
đối tượng Interpolator thay đổi thường xuyên giá trị các đối tượng đích
http://tailieuhay.com 503
Lập trình đồ họa trên Java 2D và 3D
của chúng. Người lập trình có thể nghĩ rằng đối tượng đích
TransformGroup của đối tượng RotationInterpolator có thể được sử dụng
để tịnh tiến đối tượng đó ngoài hoạt động quay mà đối tượng
RotationInterpolator cung cấp. Điều này là hoàn toàn sai. Tập các biến
đổi của đối tượng đích TransformGroup được ghi lại mỗi lần tại khung
ảnh mà đối tượng Alpha hoạt động. Điều này cũng có nghĩa rằng: hai đối
tượng Interpolator không thể có cùng một đối tượng đích.
Một lỗi khác cũng hay xảy ra khi người lập trình quên không thiết lập
các khả năng thích hợp cho đối tượng đích. Kết quả là gây ra lỗi runtime
error.
Core Interpolator API:
Interpolator là một lớp trừu tượng, nó chỉ được sử dụng khi cần tạo
một lớp con mới. Lớp Interpolator chỉ cung cấp duy nhất một hàm cho
người sử dụng các lớp con của nó:
void setAlpha(Alpha Alpha)
Thiết lập đối tượng Alpha cho đối tượng Interpolator hiện hành .
ColorInterpolator
Đối tượng ColorInterpolator có đối tượng đích thuộc kiểu Material.
Interpolator này cho phép thay đổi thành phần màu khuyếch tán của vật
liệu đích. Khả năng này vừa là điểm mạnh lại cũng là điểm hạn chế của
ColorInterpolator. Điểm mạnh thể hiện ở khả năng cho phép nhiều hơn
một đối tượng trực quan dùng chung một đối tượng vật liệu Material. Vì
vậy, một đối tượng ColorInterpolator cùng với một đối tượng đích
Material có thể tác động tới nhiều đối tượng trực quan khác nhau. Hạn
chế ở chỗ các đối tượng trực quan với chất liệu Material NodeComponent
chỉ có thể nhìn thấy khi được chiếu sáng.
Sự nhầm lẫn thường xảy ra ở đây chính là do sự phức tạp trong việc
tạo độ bóng cho hình ảnh. Việc sử dụng ánh sáng trong đồ họa là khá rắc
http://tailieuhay.com 504
Lập trình đồ họa trên Java 2D và 3D
rối, vì vậy nó được trình bày chi tiết trong một chương riêng, chương 6.
Màu sắc của thực thể trực quan là sự kết hợp của 3 thành phần: phản xạ,
khuyếch tán và màu xung quanh. ColorInterpolator chỉ thay đổi một trong
3 thành phần, đó chính là thành phần khuyếch tán.
Một lỗi khác cũng hay xảy ra khi gắn đối tượng đích Material cho đối
tượng Shape3D. Hình 5-10 biểu diễn một phần biểu đồ đồ thị khung cảnh
của đối tượng ColorInterpolator với đối tượng đích Material
NodeComponent.
Hình 5-10. Một phần biểu đồ đồ thị khung cảnh của đối tượng
ColorInterpolator với đối tượng đích Material NodeComponent
Lớp ColorInterpolator có dạng của phương thức get khác với các
Interpolator khác. Phương thức get của ColorInterpolator không phải là
phương thức không tham số.
ColorInterpolator là một hành vi hiệu chỉnh màu khuyếch tán của đối
tượng material đích bằng cách nội suy tuyến tính giữa một cặp màu cho
trước, sử dụng giá trị sinh ra bởi đối tượng Alpha xác định.
Lớp ColorInterpolator có các phương thức khởi tạo sau:
ColorInterpolator(Alpha Alpha, Material target)
Khởi tạo đối tượng Interpolator màu thường với đối tượng đích cho
trước. Giá trị màu nội suy nằm trong khoảng từ màu đen tới màu trắng.
http://tailieuhay.com 505
Lập trình đồ họa trên Java 2D và 3D
ColorInterpolator(Alpha Alpha, Material target,
Color3f startColor, Color3f endColor)
Khởi tạo đối tượng Interpolator màu với đối tượng đích, màu bắt
đầu, màu kết thúc cho trước.
Các phương thức thường dùng khác:
void setEndColor(Color3f color)
Thiết lập thuộc tính endColor cho đối tượng Interpolator hiện thời.
Phương thức get tương ứng: void getEndColor(Color3f color)
void setStartColor(Color3f color)
Thiết lập thuộc tính startColor cho đối tượng Interpolator hiện thời.
Phương thức get tương ứng: void getStartColor(Color3f color)
void setTarget(Material target)
Thiết lập đối tượng thành phần chất liệu (material) đích cho
Interpolator hiện thời
Phương thức get tương ứng: Material getTarget()
PositionInterpolator
Đối tượng PositionInterpolator thay đổi vị trí của đối tượng trực quan
theo một trục tọa độ. Hai điểm dừng sử dụng cho phép nội suy được cho
dưới dạng hai giá trị thực dấu phảy động cùng trục tọa độ tịnh tiến. Trục
tịnh tiến mặc định là trục x.
Các phương thức khởi tạo:
PositionInterpolator(Alpha Alpha, TransformGroup target)
Khởi tạo đối tượng nội suy vị trí Interpolator thường với đối tượng
đích cho trước, trục tịnh tiến mặc định là x, vị trí bắt đầu startPosition là
0.0f, vị trí kết thúc endPosition là 1.0f.
PositionInterpolator(Alpha Alpha, TransformGroup target,
http://tailieuhay.com 506
Lập trình đồ họa trên Java 2D và 3D
Transform3D axisOfTranslation,
float startPosion, float endPosition)
Khởi tạo đối tượng Interpolator vị trí biến đổi thành phần tịnh tiến
của đối tượng TransformGroup đích theo một trục tịnh tiến nhất định.
Các phương thức khác:
void setAxisOfTranslation(Transform3D axisOfTranslation)
Thiết lập trục tịnh tiến cho đối tượng Interpolator hiện thời.
void setEndPosition(float position)
Thiết lập vị trí kết thúc endPosition cho đối tượng Interpolator hiện
thời.
void setStartPosition(float position)
Thiết lập vị trí bắt đầu startPosition cho đối tượng Interpolator hiện
thời.
RotationInterpolator
Đối tượng RotationInterpolator biến đổi hướng quay của đối tượng
trực quan xung quanh một trục. Hai điểm sử dụng trong phép nội suy
được cho dưới dạng hai giá trị góc dấu phảy động và trục quay. Giá trị nội
suy sẽ được sử dụng để sinh chuyển động quay quanh trục quay. Trục
quay mặc định là trục y dương.
Các phương thức khởi tạo:
RotationInterpolator(Alpha Alpha, TransformGroup target)
Khởi tạo đối tượng nội suy quay Interpolator thường với đối tượng
đích cho trước, sử dụng trục quay mặc định (+Y), góc nhỏ nhất là 0.0f,
góc lớn nhất là 2*pi radian.
RotationInterpolator(Alpha Alpha, TransformGroup target,
Transform3D axisOfRotation,
float minimumAngle, float maximumAngle)
Khởi tạo đối tượng Interpolator biến đổi thành phần quay của một
đối tượng transform đích.
http://tailieuhay.com 507
Lập trình đồ họa trên Java 2D và 3D
Các phương thức khác:
void setAxisOfRotation(Transform3D axisOfRotation)
Thiết lập trục quay cho đối tượng Interpolator hiện thời.
void setMaximumAngle(float angle)
Thiết lập giá trị góc lớn nhất maximumAngle theo radian cho đối
tượng Interpolator hiện thời.
void setMinimumAngle(float angle)
Thiết lập giá trị góc nhỏ nhất minimumAngle theo radian cho đối
tượng Interpolator hiện thời.
void setTarget(TransformGroup target)
Thiết lập nút TransformGroup đích cho đối tượng Interpolator hiện
thời.
ScaleInterpolator
Lớp ScaleInterpolator định nghĩa một hành vi biến đổi thành phần tỉ
lệ kích thước (giữ nguyên các tính chất khác) của đối tượng
TransformGroup đích bằng cách nội suy tuyến tính giữa một cặp giá trị tỉ
lệ cho trước (sử dụng giá trị của đối tượng Alpha xác định). Giá trị tỉ lệ
nội suy được sử dụng để sinh ra biến đổi tỉ lệ trong hệ tọa độ địa phương
của đối tượng Interpolator hiện thời.
Các phương thức khởi tạo:
ScaleInterpolator(Alpha Alpha, TransformGroup target)
Khởi tạo đối tượng nội suy tỉ lệ biến đổi nút TransformGroup đích
giữa hai giá trị Alpha xác định, sử dụng đối tượng Alpha và một ma trận
đồng nhất cho trước, với tỉ lệ phóng bé nhất minimum scale = 0.1f và tỉ lệ
phóng lớn nhất maximum scale = 1.0f.
ScaleInterpolator(Alpha Alpha, TransformGroup target,
Transform3D axisOfScale,
float minimumScale, float maximumScale)
http://tailieuhay.com 508
Lập trình đồ họa trên Java 2D và 3D
Khởi tạo đối tượng scaleInterpolator biến đổi thành phần tỉ lệ nút
TransformGroup đích giữa hai giá trị tỉ lệ (minimumScale và
MaximumScale).
Các phương thức khác:
void setAxisOfScale(Transform3D axisOfScale)
Thiết lập biến đổi AxisOfScale cho đối tượng nội suy Interpolator
hiện thời.
void setMaximumScale(float scale)
Thiết lập tỉ lệ phóng lớn nhất maximumScale cho đối tượng
Interpolator hiện thời.
void setMinimumScale(float scale)
Thiết lập tỉ lệ phóng nhỏ nhất minimumScale cho đối tượng
Interpolator hiện thời.
void setTarget(TransformGroup target)
Thiết lập đối tượng TransformGroup cho đối tượng Interpolator
hiện thời.
SwitchValueInterpolator
Đối tượng SwitchValueInterpolator không nội suy giữa các giá trị như
các đối tượng Interpolator khác. Nó chỉ lựa chọn một trong các con của
đối tượng Switch. Giá trị ngưỡng để chuyển tới một con khác được xác
định bằng cách chia đoạn [0.0, 1.0] cho số con mà đối tượng Switch có.
Chú ý rằng, đối tượng Interpolator không tự động cập nhật khi số
con của đối tượng Switch thay đổi. Các giá trị chuyển đổi (switching
value) được xác định ngay khi tạo đối tượng SwitchValueInterpolator.
Nên nếu ban đầu đối tượng Switch không có con, hoặc khi số con của nó
thay đổi sau khi đối tượng Interpolator đã được tạo thì số các con trong
đối tượng Interpolator phải được cập nhật. Điểm thuận lợi khi sử dụng
đối tượng này là người lập trình có thể xác định một tập con các chỉ mục
http://tailieuhay.com 509
Lập trình đồ họa trên Java 2D và 3D
để đối tượng Interpolator sử dụng. Tập con này bị giới hạn bởi tập các
chỉ mục tuần tự.
Các phương thức khởi tạo:
SwitchValueInterpolator(Alpha Alpha, Switch target)
Khởi tạo đối tượng hành vi SwitchValueInterpolator biến đổi chỉ mục
con của nút Switch đích trong khoảng từ 0 đến n-1, trong đó, n là số con
của nút Switch đích.
SwitchValueInterpolator(Alpha Alpha, Switch target,
int firstChildIndex, int lastChildIndex)
Khởi tạo đối tượng hành vi SwitchValueInterpolator biến đổi chỉ mục
con của nút Switch đích giữa hai giá trị firstChildIndex và lastChildIndex
cho trước.
Các phương thức khác:
void setFirstChildIndex(int firstIndex)
Thiết lập chỉ mục con đầu tiên firstChildIndex của đối tượng
Interpolator hiện thời.
void setLastChildIndex(int lastIndex)
Thiết lập chỉ mục con cuối lastChildIndex của đối tượng Interpolator
hiện thời.
void setTarget(Switch target)
Thiết lập đối tượng Switch đích cho đối tượng Interpolator hiện
thời.
Trong các tham số của phương thức khởi tạo SwitchValueInterpolator
có đối tượng Switch. Vậy Switch là gì?
Switch
Lớp Switch kế thừa từ lớp Group và là cha của 0 hay nhiều nhánh con
đồ thị khung cảnh. Đối tượng Switch lựa chọn một trong các con của nó
để biểu diễn. Nó định nghĩa một giá trị lựa chọn (switch value) có thể
http://tailieuhay.com 510
Lập trình đồ họa trên Java 2D và 3D
chọn 1 hoặc chọn 0 hay nhiều con của nó và nhờ sử dụng một mặt nạ để
xác định xem con nào được biểu diễn. Đối tượng Switch có thể sử dụng
độc lập không cần đối tượng Interpolator hay LOD .
Các phương thức khởi tạo:
Switch()
Khởi tạo một nút Switch với các tham số mặc định.
Switch(int whichChild)
Khởi tạo và gán giá trị ban đầu cho một nút Switch sử dụng chỉ mục
lựa chọn con thích hợp.
CHILD_ALL - chỉ thị tất cả các con được biểu diễn
CHILD_MASK - sử dụng mặt nạ childMask (kiểu BitSet) để lựa
chọn con thích hợp
CHILD_NONE - không có con nào được biểu diễn
Switch(int whichChild, java.util.BitSet childMask)
Khởi tạo và gán giá trị đầu cho một nút Switch sử dụng chỉ mục lựa
chọn và mặt nạ cho trước.
Các phương thức khác:
void setChildMask(java.util.BitSet childMask)
Thiết lập mặt nạ lựa chọn con.
void setWhichChild(int child)
Thiết lập chỉ mục lựa chọn con xác định con nào được biểu diễn.
Khả năng có thể thiết lập cho Switch:
ALLOW_SWITCH_READ | WRITE
Chỉ định rằng nút Switch này cho phép đọc lựa chọn nút con, các giá
trị mặt nạ và các con hiện thời của nó.
TransparencyInterpolator
Lớp TransparencyInterpolator định nghĩa đối tượng hành vi biến đổi
mức độ trong suốt của đối tượng đích thuộc lớp TransparencyAttributes
http://tailieuhay.com 511
Lập trình đồ họa trên Java 2D và 3D
bằng cách nội suy tuyến tính giữa một cặp giá trị độ trong suốt cho trước
(sử dụng giá trị sinh bởi đối tượng Alpha cho trước). Nhiều hơn một đối
tượng trực quan có thể chia sẻ một đối tượng TransparencyAttributes, vì
vậy một đối tượng TransparencyAttributes có khả năng tác động cùng lúc
đến nhiều đối tượng trực quan khác nhau. Chú ý rằng các chế độ trong
suốt khác nhau có thể ảnh hưởng đến chất lượng biểu diễn và sự hiện diện
của các đối tượng trực quan.
Các phương thức khởi tạo:
TransparencyInterpolator(Alpha Alpha,
TransparencyAttributes target)
Khởi tạo đối tượng nội suy độ trong suốt với đối tượng đích cho
trước, độ trong suốt tối thiểu là 0.0f và tối đa là 1.0f.
TransparencyInterpolator(Alpha Alpha,
TransparencyAttributes target,
float minimumTransparency,
float maximumTransparency)
Khởi tạo đối tượng nội suy độ trong suốt biến đổi độ trong suốt chất
liệu của đối tượng đích giữa hai giá trị minimumTransparency và
maximumTransparency.
Các phương thức khác:
void setMaximumTransparency(float transparency)
Thiết lập giá trị maximumTransparency cho đối tượng Interpolator
hiện thời.
void setMinimumTransparency(float transparency)
Thiết lập giá trị minimumTransparency cho đối tượng Interpolator
hiện thời.
void setTarget(TransparencyAttributes target)
Thiết lập đối tượng đích TransparencyAttributes cho đối tượng
Interpolator hiện thời.
http://tailieuhay.com 512
Lập trình đồ họa trên Java 2D và 3D
Các lớp đối tượng nội suy đường:
Path Interpolator (nội suy đường) khác với các lớp nội suy khác ở
chỗ, nó có thể chứa hai hay nhiều hơn hai giá trị để nội suy. Path
Interpolator cung cấp các khả năng nội suy vị trí (Position
Interpolation), nội suy quay (Rotation Interpolation); vừa nội suy vị trí,
vừa nội suy quay; hoặc vừa nội suy vị trí, nội suy quay và nội suy tỉ lệ
(Scale Interpolation). Đích của đối tượng nội suy là một đối tượng
TransformGroup, đối tượng này thay đổi vị trí, hướng, và tỉ lệ thích hợp
cho các đối tượng con của nó.
Một đối tượng Path Interpolator chứa một tập các giá trị, hay các
điểm mút, được sử dụng theo từng cặp để nội suy. Giá trị Alpha có vai
trò xác định giá trị hai điểm nào sẽ được sử dụng. Giá trị các điểm này
nằm trong khoảng từ 0.0 tới 1.0, bao gồm cả hai đầu mút, tương ứng với
khoảng giá trị của đối tượng Alpha. Điểm mút đầu tiên phải có giá trị là
0.0, còn điểm mút cuối cùng phải có giá trị là 1.0. Các mút còn lại được
lưu trữ theo trật tự giá trị tăng dần trong đối tượng nội suy đường.
Các giá trị của một điểm mút là tương ứng với các giá trị tham số biến
(ví dụ như vị trí hay góc quay) được sử dụng trong phép nội suy.Với mỗi
điểm mút thì có một giá trị tham số xác định làm đại diện. Điểm mút có
giá trị lớn nhất bằng hoặc nhỏ hơn giá trị Alpha và giá trị của điểm mút
tiếp theo sẽ được sử dụng. Các điểm mút được xác định theo một trật tự,
theo đó, khi giá trị Alpha thay đổi, các điểm mút sẽ được sử dụng theo
từng cặp kề nhau.
Phía bên trái của hình 5-11 biểu diễn các giá trị điểm mút cho một đối
tượng Path Interpolator nội suy vị trí. Với mục đích minh họa, chúng tôi
chỉ xét vị trí trong không gian 2 chiều. Phần giữa của hình ánh xạ vị trí
của đối tượng trực quan với các giá trị Alpha từ 0.0 tới 1.0. Phía bên phải
là các giá trị điểm mút được sử dụng tương ứng với các giá trị Alpha khác
http://tailieuhay.com 513
Lập trình đồ họa trên Java 2D và 3D
nhau của ví dụ này. Kết hợp các giá trị điểm mút và tham số Alpha sẽ xác
định hoạt ảnh.
Hình 5-11. Quan hệ giữa giá trị các điểm mút và giá trị Alpha cho vị
trí trong không gian 2 chiều
Ví dụ sử dụng PathInterpolator
Sử dụng đối tượng nội suy đường tuân theo công thức sử dụng các đối
tượng nội suy khác. Sự khác biệt là ở số lượng biến được sử dụng để khởi
tạo đối tượng nội suy đường. Công thức sử dụng có thể tóm tắt trong hình
sau:
1. tạo đối tượng đích với khả năng thích hợp
2. tạo đối tượng Alpha
3. tạo các mảng điểm mút và các giá trị khác
4. tạo đối tượng nội suy đường tham chiếu đến đối tượng Alpha, đối
tượng đích, và mảng của các giá trị thiết lập
5. thêm danh giới cho đối tượng nội suy
6. thêm đối tượng nội suy đường vào đồ thị khung cảnh
Hình 5-12. Công thức sử dụng đối tượng nội suy đường
Chương trình RotPosPathApp.java sử dụng đối tượng
RotPosPathInterpolator để tạo hoạt ảnh cho một khối hộp ColorCube qua
một tập các giá trị vị trí và quay. Đối tượng RotPosPathInterpolator chứa
tập các giá trị quay (mảng Quat4f), vị trí (mảng Point3f), và các giá trị
điểm mút (mảng giá trị thực). Chi tiết của ví dụ này xin xem thêm phần
phụ lục.
http://tailieuhay.com 514
Lập trình đồ họa trên Java 2D và 3D
public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
Alpha alpha = new Alpha(-1, 10000);
TransformGroup target = new
TransformGroup();
Transform3D axisOfRotPos = new
Transform3D();
float[] knots = {0.0f, 0.1f, 0.2f, 0.3f,
0.4f, 0.6f, 0.8f, 0.9f, 1.0f};
Quat4f[] quats = new Quat4f[9];
Point3f[] positions = new Point3f[9];
target.setCapability(TransformGroup.ALLOW
_TRANSFORM_WRITE);
AxisAngle4f axis = new
AxisAngle4f(1.0f,0.0f,0.0f,0.0f);
axisOfRotPos.set(axis);
quats[0] = new Quat4f(0.0f, 1.0f, 1.0f,
0.0f);
quats[1] = new Quat4f(1.0f, 0.0f, 0.0f,
0.0f);
quats[2] = new Quat4f(0.0f, 1.0f, 0.0f,
0.0f);
http://tailieuhay.com 515
Lập trình đồ họa trên Java 2D và 3D
quats[3] = new Quat4f(0.0f, 1.0f, 1.0f,
0.0f);
quats[4] = new Quat4f(0.0f, 0.0f, 1.0f,
0.0f);
quats[5] = new Quat4f(0.0f, 1.0f, 1.0f,
0.0f);
quats[6] = new Quat4f(1.0f, 1.0f, 0.0f,
0.0f);
quats[7] = new Quat4f(1.0f, 0.0f, 0.0f,
0.0f);
quats[8] = quats[0];
positions[0]= new Point3f( 0.0f, 0.0f,
-1.0f);
positions[1]= new Point3f( 1.0f, -1.0f,
-2.0f);
positions[2]= new Point3f( -1.0f, 1.0f,
-3.0f);
positions[3]= new Point3f( 2.0f, 0.0f,
-4.0f);
positions[4]= new Point3f( -2.0f, -1.0f,
-5.0f);
positions[5]= new Point3f( 3.0f, 1.0f,
-6.0f);
positions[6]= new Point3f( -3.0f, 0.0f,
-7.0f);
positions[7]= new Point3f( 2.0f, -1.0f,
-4.0f);
positions[8]= positions[0];
http://tailieuhay.com 516
Lập trình đồ họa trên Java 2D và 3D
RotPosPathInterpolator rotPosPath = new
RotPosPathInterpolator(
alpha, target, axisOfRotPos,
knots, quats, positions);
rotPosPath.setSchedulingBounds(new
BoundingSphere());
objRoot.addChild(target);
objRoot.addChild(rotPosPath);
target.addChild(new ColorCube(0.4));
Background background = new Background();
background.setColor(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(new
BoundingSphere());
objRoot.addChild(background);
PointArray point_geom = new PointArray(9,
GeometryArray.COORDINATES);
point_geom.setCoordinates(0, positions);
Appearance points_appear = new
Appearance();
ColoringAttributes points_coloring = new
ColoringAttributes();
points_coloring.setColor(1.0f, 0.0f,
0.0f);
http://tailieuhay.com 517
Lập trình đồ họa trên Java 2D và 3D
points_appear.setColoringAttributes(point
s_coloring);
PointAttributes points_points = new
PointAttributes(4.0f, true);
points_appear.setPointAttributes(points_p
oints);
Shape3D points = new Shape3D(point_geom,
points_appear);
objRoot.addChild(points);
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
RotPosPathApp
Đoạn mã trên được trích không toàn vẹn từ phương thức
createSceneGraph trong chương trình RotPosPathApp.java để bạn đọc có
hình dung sơ qua về cách sử dụng một đối tượng nội suy đường:
RotPosPathInterpolator. Các bước thực hiện đã được đánh số từ 1-6 tương
ứng với các bước trong công thức.
Hình 5-13 là một cảnh trong chương trình RotPosPathApp, với các
điểm màu đỏ biểu diễn vị trí của 9 điểm mút. Điểm đầu tiên được dùng 2
lần, nên trong hình, chúng ta chỉ thấy có 8 điểm.
http://tailieuhay.com 518
Lập trình đồ họa trên Java 2D và 3D
Hình 5-13. Một cảnh trong chương trình RotPosPathApp
Khi chương trình RotPosPathApp được thực hiện, khối hộp
ColorCube di chuyển từ vị trí điểm mút này đến vị trí của điểm mút khác,
đồng thời tự quay để đến được các điểm mút khác nhau. Giống như tất cả
các đối tượng nội suy khác, hoạt ảnh kết quả phụ thuộc vào sự kết hợp
giữa các giá trị đối tượng nội suy với các tham số Alpha được sử dụng.
Như đã nói bên trên, lớp PathInterpolator có rất nhiều các lớp con
khác nhau. Ngoài các lớp con trong hạt nhân của Java 3D, còn có một cặp
các lớp liên quan trong gói tiện ích. Lớp TCBPathSplineInterpolator là
một lớp tương tự với lớp PathInterpolator. Lớp này có một lớp con nằm
trong gói tiện ích (tham khảo hình 5-8 để hình dung được quan hệ giữa
các lớp nội suy).
Trong chương trình RotPosPathApp, hoạt ảnh xuất hiện không tự
nhiên chủ yếu là do sự kết hợp vị trí các điểm mút được chọn. Khi khối
hộp ColorCube di chuyển đến mỗi vị trí điểm mút xác định, thì ngay lập
tức chuyển động của nó thay đổi để đến được điểm mút tiếp theo. Di
chuyển như vậy không tự nhiên do trong thế giới thực, chuyển động của
tất cả các vật đều có tính ì nhất định.
http://tailieuhay.com 519
Lập trình đồ họa trên Java 2D và 3D
TCBPathSplineInterpolator là một tiện ích cung cấp các hành vi và
chức năng tương tự lớp PathInterpolator, nhưng làm trơn đường đi của
đối tượng thành một đường cong dựa trên vị trí các điểm mút. Đường
cong này bắt chước chuyển động của đối tượng trong thế giới thực. Trong
chuyển động này, đối tượng trực quan có thể không đi qua toàn bộ hoặc
không hề đi qua bất cứ điểm mút nào. Chương trình ví dụ,
SplineAnim.java, bạn đọc có thể tìm trong đĩa chương trình kèm theo.
PathInterpolator
PathInterpolator là một lớp trừu tượng cung cấp giao diện và chức
năng cơ bản cho các lớp con của nó. Các đối tượng PathInterpolator lưu
trữ các giá trị điểm mút và tính toán chỉ mục của các giá trị này để sử
dụng dựa trên giá trị Alpha và thời gian hiện thời
(currentInterpolationValue). Tham số currentInterpolationValue được tính
toán bằng cách nội suy tuyến tính trong chuỗi các điểm mút đã được định
nghĩa trước (sử dụng giá trị sinh bởi đối tượng Alpha xác định). Điểm
mút đầu tiên phải có giá trị là 0.0 và điểm mút cuối cùng phải có giá trị là
1.0. Điểm mút trung gian với chỉ mục k phải có giá trị lớn hơn giá trị của
bất cứ điểm mút nào có chỉ mục nhỏ hơn k.
Một số phương thức cung cấp bởi lớp PathInterpolator:
int getArrayLengths()
Trả về độ dài của mảng các điểm mút
void setKnot(int index, float knot)
Thiết lập điểm mút tại chỉ mục xác định bởi index cho đối tượng
Interpolator hiện thời.
void setKnots(float [] knots)
Thiết lập (thay thế) tất cả các điểm mút cho đối tượng Interpolator
hiện thời.
http://tailieuhay.com 520
Lập trình đồ họa trên Java 2D và 3D
RotPosPathInterpolator
RotPosPathInterpolator là một lớp đối tượng hành vi, biến đổi thành
phần quay và tịnh tiến của đối tượng đích thuộc lớp TransformGroup
bằng cách nội suy tuyến tính giữa chuỗi các cặp điểm mút/vị trí và điểm
mút/hướng, sử dụng giá trị sinh bởi đối tượng Alpha xác định. Vị trí và
hướng nội suy được sử dụng để sinh một dịch chuyển trong hệ tọa độ địa
phương của đối tượng Interpolator này. Xét về mặt giao diện lập trình
ứng dụng thì phương thức khởi tạo là quan trọng nhất đối với lớp đối
tượng này. Trong phương thức khởi tạo, tất cả các giá trị và đối tượng liên
quan đều phải được xác định. Chú ý rằng mỗi mảng tham số phải có cùng
độ dài trong đối tượng khởi tạo hiện tại và các đối tượng PathInterpolator
khác trong chương trình.
RotPosPathInterpolator(Alpha Alpha, TransformGroup target,
Transform3D axisOfRotPos, float[] knots, Quat4f[] quats,
Point3f[] positions)
Khởi tạo đối tượng Interpolator mới biến đổi chuyển động quay và
tịnh tiến của đối tượng đích TransformGroup.
Một số phương thức cung cấp bởi lớp RotPosPathInterpolator:
void getPositions(Point3f[] positions)
Sao chép các giá trị vị trí của đối tượng Interpolator hiện thời vào
mảng positions. Mảng positions phải đủ lớn để chứa dữ liệu.
void getQuats(Quat4f[] quats)
Sao chép giá trị các quantenion của đối tượng Interpolator hiện thời
vào mảng quats. Mảng quats phải đủ lớn để chứa dữ liệu.
void setAxisOfRotPos(Transform3D axisOfRotPos)
Thiết lập trục của giát trị RotPos cho đối tượng Interpolator hiện
thời.
void setPosition(int index, Point3f position)
http://tailieuhay.com 521
Lập trình đồ họa trên Java 2D và 3D
Thiết lập vị trí tại chỉ mục xác định cho đối tượng Interpolator hiện
thời.
void setQuat(int index, Quat4f quat)
Thiết lập quantenion tại chỉ mục xác định cho đối tượng Interpolator
hiện thời.
void setTarget(TransformGroup target)
Thiết lập đối tượng đích TransformGroup cho đối tượng Interpolator
hiện thời.
Lớp Billboard :
Thuật ngữ “Billboard ” được sử dụng trong đồ họa máy tính để ám
chỉ công nghệ quay tự động một đối tượng trực quan 2 chiều sao cho nó
luôn đối mặt với người quan sát. Sự phát sinh lớp hành vi Billboard xuất
phát từ ý tưởng sử dụng các bề mặt đơn giản thay thế cho cho các hình
khối phức tạp. Hành vi Billboard thông thường được dùng cho mục đích
này, ngoài ra, nó còn được dùng cho các mục đích khác, ví dụ như làm
cho dòng văn bản có thể được nhìn thấy từ mọi góc độ trong môi trường
ảo. Trong Java 3D, công nghệ Billboard được cài đặt bởi một lớp con
của lớp hành vi Behavior, vì vậy, người ta vẫn hay dùng thuật ngữ “hành
vi Billboard ” để chỉ công nghệ này.
Một ví dụ kinh điển sử dụng hành vi behavior là ứng dụng biểu diễn
cây cối dưới dạng hình 2 chiều. Tất nhiên, nếu cái cây chỉ giữ một hướng
cố định thì khi góc nhìn thay đổi, người quan sát sẽ phát hiện ra hình dạng
2 chiều của cây. Nhưng nếu cái cây đó tự định hướng lại sao cho luôn đối
mặt với người quan sát thì nó dường như có dạng 3 chiều. Hiệu quả của
hiệu ứng này càng cao nếu cái cây đó nằm ở hình nền của khung cảnh
hoặc là nằm ở phía đằng xa so với vị trí quan sát.
Billboard làm việc được với hình ảnh cây cối bởi cây cối có dạng
gần giống nhau khi nhìn từ đằng trước, đằng sau hay từ bất cứ góc nhìn
http://tailieuhay.com 522
Lập trình đồ họa trên Java 2D và 3D
nào. Billboard làm cho đối tượng trực quan xuất hiện hoàn toàn giống
nhau từ bất cứ góc nhìn nào, nên nó rất thích hợp sử dụng cùng với ảnh 2
chiều để tạo đối tượng 3 chiều có dạng hình học đối xứng qua trục y như
các tòa nhà hình trụ, tháp nước, hay bất kì đối tượng hình trụ nào. Đối
tượng Billboard còn có thể sử dụng cho các đối tượng 3 chiều không có
dạng đối xứng khi chúng được quan sát từ một khoảng cách đủ lớn để che
dấu dạng 2 chiều.
Hình 5-14 biểu diễn một phần của đồ thị khung cảnh được xây dựng
để sử dụng nút Billboard . Thông thường hai nút TransformGroup được
sử dụng. Nút TransformGroup phía trên được dùng để định vị trí đối
tượng trực quan và có thể là tĩnh. Nút TransformGroup phía dưới được
dùng để định hướng đối tượng và được thao tác bởi đối tượng Billboard .
Chi tiết việc lập trình sẽ được trình bày trong phần dưới đây.
Sử dụng đối tượng Billboard
Việc sử dụng đối tượng Billboard tương tự việc sử dụng đối tượng
Interpolator , ngoại trừ rằng không cần dùng đối tượng Alpha để điều
khiển hoạt ảnh. Hoạt ảnh của đối tượng Billboard được điều khiển bởi vị
trí tương đối của người quan sát trong thế giới ảo. Hình 5-15 biểu diễn
các bước sử dụng Billboard .
Hình 5-14. Biểu đồ đồ thị khung cảnh sử dụng đối tượng Billboard
http://tailieuhay.com 523
Lập trình đồ họa trên Java 2D và 3D
1. tạo đối tượng đích với khả năng ALLOW_TRANSFORM_WRITE
2. tạo đối tượng Billboard tham chiếu đến đối tượng đích
TransformGroup
3. thêm danh giới làm việc cho đối tượng Billboard
4. lắp ghép đồ thị
Hình 5-15. Công thức sử dụng đối tượng Billboard tạo hoạt ảnh
Các lỗi thường gặp khi sử dụng Billboard
Mặc dù việc sử dụng đối tượng Billboard không hề phức tạp, nhưng
cũng có hai lỗi lập trình thường gặp sau. Lỗi thứ nhất xảy ra do đối tượng
đích TransformGroup thiết lập lại hoàn toàn giá trị của nó mỗi khi được
cập nhật. Do đó, đối tượng TransformGroup này không thể sử dụng để
định vị đối tượng trực quan. Nếu dùng đối tượng đích để định vị, hiệu ứng
Billboard vẫn hoạt động, tuy nhiên, trong lần cập nhật quay đầu tiên,
thông tin vị trí của đối tượng đích sẽ bị mất và đối tượng trực quan sẽ
được hiển thị tại vị trí ban đầu.
Nếu đối tượng đích không được thiết lập thuộc tính
ALLOW_TRANSFORM_WRITE khi chương trình được thực thi sẽ phát
sinh lỗi runtime. Nếu danh giới làm việc không được thiết lập hay thiết
lập không chính xác thì đối tượng Billboard sẽ không điều khiển được
đối tượng trực quan. Danh giới làm việc thông thường được xác định bởi
đối tượng BoundingSphere với phạm vi làm việc đủ lớn để bao gồm đối
tượng trực quan.
Có một giới hạn khi sử dụng lớp Billboard : trong các ứng dụng với
nhiều hơn một quan sát, mỗi đối tượng Billboard chỉ điều khiển hoạt ảnh
chính xác cho chỉ một quan sát. Với một vài ứng dụng thì khả năng cung
cấp của Billboard là đảm bảo, còn với các ứng dụng khác, đặc điểm này
là một giới hạn lớn. Java3D API phiên bản 1.2 giới thiệu lớp
OrientedShape3D để vượt qua giới hạn này. Đối tượng OrientedShape3D
cung cấp các chức năng giống với chức năng của đối tượng Billboard
http://tailieuhay.com 524
Lập trình đồ họa trên Java 2D và 3D
nhưng có thêm khả năng xử lý nhiều quan sát cùng một lúc. Billboard
quay quanh một trục hoặc một điểm. Trong trường hợp sử dụng khác, đối
tượng Billboard điều khiển một đối tượng TransformGroup sao cho trục
z dương của đối tượng TransformGroup và các con của nó luôn đối diện
với người quan sát. Do Billboard hướng trục z+ của đối tượng đích về
phía người quan sát nên nó không thể dùng để quay vật thể quanh trục z.
Vì lý do này, nếu một trục quay của đối tượng được xác định là (0, 0, z)
thì đơn giản Billboard không làm gì cả.
Chương trình ví dụ sử dụng Billboard
Chương trình ví dụ BillboardApp tạo một thế giới ảo với cây cối sử
dụng kĩ thuật Billboard . Mặc dù cây cối trong chương trình này được tạo
bởi các hình thô (hình tam giác phẳng) nhưng chúng không hề hiển thị
như các đối tượng 2 chiều.
Hai đối tượng TransformGroup được sử dụng cho mỗi cây trong ví dụ
này. Một đối tượng TransformGroup, TGT, đơn giản chỉ dịch các cây
thành tọa độ vị trí trong ứng dụng. Giá trị của TGT không bị thay đổi
trong thời gian thực thi của ứng dụng. Đối tượng TransformGroup thứ
hai, TGR, điều khiển hoạt động quay của cây. TGR là đối tượng đích của
Billboard .
public BranchGroup
createSceneGraph(SimpleUniverse su) {
// Create the root of the branch graph
TransformGroup vpTrans = null;
BranchGroup objRoot = new BranchGroup();
Vector3f translate = new Vector3f();
http://tailieuhay.com 525
Lập trình đồ họa trên Java 2D và 3D
Transform3D T3D = new Transform3D();
TransformGroup TGT = null;
TransformGroup TGR = null;
Billboard billboard = null;
BoundingSphere bSphere = new
BoundingSphere();
objRoot.addChild(createLand());
SharedGroup share = new SharedGroup();
share.addChild(createTree());
float[][] position = { { 0.0f, 0.0f,
-3.0f }, { 6.0f, 0.0f, 0.0f },
{ 6.0f, 0.0f, 6.0f }, { 3.0f,
0.0f, -10.0f },
{ 13.0f, 0.0f, -30.0f }, {
-13.0f, 0.0f, 30.0f },
{ -13.0f, 0.0f, 23.0f },
{ 13.0f, 0.0f, 3.0f } };
for (int i = 0; i < position.length; i++)
{
translate.set(position[i]);
T3D.setTranslation(translate);
TGT = new TransformGroup(T3D);
TGR = new TransformGroup();
http://tailieuhay.com 526
Lập trình đồ họa trên Java 2D và 3D
TGR.setCapability(TransformGroup.ALLOW_TRANSFORM_
WRITE);
billboard = new Billboard(TGR);
billboard.setSchedulingBounds(bSphere);
//
billboard.setAlignmentMode(Billboard.ROTATE_ABOUT
_POINT);
objRoot.addChild(TGT);
objRoot.addChild(billboard);
TGT.addChild(TGR);
TGR.addChild(new Link(share));
}
vpTrans =
su.getViewingPlatform().getViewPlatformTransform(
);
translate.set(0.0f, 0.3f, 0.0f);
T3D.setTranslation(translate);
vpTrans.setTransform(T3D);
KeyNavigatorBehavior keyNavBeh = new
KeyNavigatorBehavior(vpTrans);
keyNavBeh
.setSchedulingBounds(new
BoundingSphere(new Point3d(), 1000.0));
objRoot.addChild(keyNavBeh);
Background background = new Background();
background.setColor(0.3f, 0.3f, 1.0f);
http://tailieuhay.com 527
Lập trình đồ họa trên Java 2D và 3D
background.setApplicationBounds(new
BoundingSphere());
objRoot.addChild(background);
// Let Java 3D perform optimizations on
this scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
BillboardAppĐoạn mã trên được trích từ phương thức
createSenceGraph của chương trình BillboardApp.java với các kí hiệu
đánh dấu tương ứng với các bước thực hiện được liệt kê trong hình 5-15.
Hình 5-16. Biểu đồ đồ thị sử dụng đối tượng Billboard trong
BillboardApp.java
Hình 5-17 hiển thị một cảnh sinh bởi chương trình ví dụ BillboardApp.
http://tailieuhay.com 528
Lập trình đồ họa trên Java 2D và 3D
Hình 5-17. Một ảnh của BillboardApp với tất cả “cây” 2 chiều đều
hướng về phía người quan sát BillboardApp.java cung cấp
KeyNavigatorBehavior cho phép người dùng di chuyển xung quanh và
quan sát các cây từ các vị trí và hướng nhìn khác nhau. Xin xem lại phần
4.4.2 của chương 4 để biết thêm chi tiết về lớp đối tượng này.
Giao diện lập trình ứng dụng của Billboard (Billboard
API)
Trong ví dụ BillboardApp phía trên, đối tượng Billboard hoạt động
với chế độ mặc định là quay đối tượng trực quan xung quanh trục y. Nên,
nếu các cây trong ví dụ này được quan sát từ phía trên hay từ phía dưới,
dạng 2 chiều của nó sẽ bị lộ.
Một chế độ thay thế là quay đối tượng trực quan quanh một điểm.
Trong chế độ này, hình ảnh 2 chiều được điều khiển quay quanh 1 điểm,
do đó, đối tượng trực quan luôn được quan sát trực diện từ bất cứ vị trí
quan sát nào. Một ứng dụng dễ thấy là biểu diễn mặt trăng hay các vật thể
hình cầu ở khoảng cách xa dưới dạng một hình tròn.
http://tailieuhay.com 529
Lập trình đồ họa trên Java 2D và 3D
Các phương thức khởi tạo của Billboard
Billboard ()
Khởi tạo một Billboard với tham số mặc định: mode =
ROTATE_ABOUT_AXIS, axis = (0, 1, 0).
Billboard (TransformGroup tg)
Khởi tạo một đối tượng Billboard với các tham số mặc định hoạt
động trên đối tượng TransformGroup xác định.
Billboard (TransformGroup tg, int mode, Vector3f axis)
Khởi tạo đối tượng Billboard với trục quay và chế độ hoạt động xác
định điều khiển đối tượng TransformGroup xác định.
Billboard (TransformGroup tg, int mode, Point3f point)
Khởi tạo đối tượng Billboard với tâm quay và chế độ xác định, hoạt
động trên đối tượng đích TransformGroup xác định.
Một vài phương thức khác cung cấp bởi lớp Billboard :
void setAlignmentAxis(Vector3f axis)
Thiết lập trục canh chỉnh.
void setAlignmentAxis(float x, float y, float z)
Thiết lập trục canh chỉnh.
void setAlignmentMode(int mode)
Thiết lập chế độ canh chỉnh, trong đó mode có thể là
ROTATE_ABOUT_AXIS - Chỉ định quay xung quanh một
trục xác định
ROTATE_ABOUT_POINT - Chỉ định quay xung quanh một điểm
xác định và chỉ định rằng trục Y của đối tượng con phải phù hợp với trục
Y của đối tượng được quan sát
void setRotationPoint(Point3f point)
Thiết lập tâm quay
void setRotationPoint(float x, float y, float z)
Thiết lập tâm quay
http://tailieuhay.com 530
Lập trình đồ họa trên Java 2D và 3D
void setTarget(TransformGroup tg)
Thiết lập đối tượng đích TransformGroup cho đối tượng Billboard
hiện thời.
OrientedShape3D
Đối tượng OrientedShape3D được sử dụng để thực hiện các chức
năng giống như đối tượng Billboard trong mục trước. Điểm khác biệt
chủ yếu giữa hai lớp đối tượng như đã được nhắc đến ở phần trên là ở chỗ
OrientedShape3D có khả năng làm việc với nhiều hơn một quan sát còn
Billboard thì không, cũng như khả năng chia sẻ sử dụng chỉ có ở
OrientedShape3D.
Đối tượng OrientedShape3D cũng yêu cầu sử dụng ít mã hơn.
OrientedShape3D không hiệu chỉnh đối tượng đích TransformGroup, mà
để mở khả năng này cho mã chương trình thực hiện. OrientedShape3D
không phải là một đối tượng hành vi do đó, người lập trình cũng không
cần quan tâm đến giới hạn hoạt động.
Với so sánh trên thì dễ thấy OrientedShape3D là sự lựa chọn hiển
nhiên cho các ứng dụng dùng hiệu ứng Billboard . Nguyên nhân duy nhất
để không loại bỏ lớp Billboard khỏi Java3D API chính là khả năng
tương thích ngược với các ứng dụng đang tồn tại.
Đối tượng OrientedShape3D quay xung quanh một trục hoặc một tâm.
Trong cả hai trường hợp, đối tượng OrientedShape3D tự định hướng bản
thân nó sao cho trục z+ của các con của nó luôn đối diện với người quan
sát. Do OrientedShape3D hướng trục z+ của các vật thể về phía người
quan sát, nên không có ý nghĩa gì nếu quay vật thể quanh trục z. Vì lí do
này nên trục quay không được song song với trục z, có nghĩa là, trục quay
không được định nghĩa là (0, 0, z) với bất cứ giá trị nào của z. Nếu một
trục song song với z được chỉ định, OrientedShape3D đơn giản sẽ không
http://tailieuhay.com 531
Lập trình đồ họa trên Java 2D và 3D
làm gì cả. Lúc đó coi như là đối tượng TransformGroup được thiết lập ma
trận đồng nhất.
Không có giới hạn cho giá trị được sử dụng để làm tâm quay. Nếu chế
độ biểu diễn được thiết lập là ROTATE_ABOUT_POINT thì vật thể sẽ
quay xung quanh một điểm xác định.
Giao diện lập trình ứng dụng của OrientedShape3D
Giao diện lập trình ứng dụng của OrientedShape3D là tương tự với
giao diện lập trình của lớp Billboard , ngoài ra, cũng có vài điểm khác
biệt. Sự khác biệt phát sinh chủ yếu do sự khác nhau về cấu trúc phân cấp
lớp đối tượng. OrientedShape3D kế thừa từ lớp Shape3D, trong khi đó,
Billboard lại kế thừa từ Behavior.
Danh sách các phương thức khởi tạo của OrientedShape3D không
nhiều như của lớp Shape. Ví dụ như không có phương thức khởi tạo với
chỉ một tham số Geometry. Trong trường hợp này, các phương thức khởi
tạo không kế thừa lớp cơ sở. Một ứng dụng có thể sử dụng phương thức
khởi tạo không tham số và một vài phương thức khác để tạo ra đối tượng
OrientedShape3D cần thiết.
Các phương thức khởi tạo:
OrientedShape3D()
Khởi tạo đối tượng OrientedShape3D với các tham số mặc định
OrientedShape3D(Geometry geometry, Appearance appearance,
int mode, Point3f point)
Khởi tạo đối tượng OrientedShape3D với thành phần hình học, thành
phần xuất hiện, chế độ và tâm quay xác định.
OrientedShape3D(Geometry geometry, Appearance appearance,
int mode, Vector3f axis)
Khởi tạo đối tượng OrientedShape3D với thành phần hình học, thành
phần xuất hiện, chế độ và trục quay xác định.
http://tailieuhay.com 532
Lập trình đồ họa trên Java 2D và 3D
Một số phương thức khác cung cấp bởi OrientedShape3D:
void setAlignmentAxis(float x, float y, float z)
void setAlignmentAxis(Vector3f axis)
void setAlignmentMode(int mode)
void setRotationPoint(float x, float y, float z)
void setRotationPoint(Point3f point)
Các phương thức này có các tham số và chức năng giống với các phương
thức cùng tên của Billboard . Xem chi tiết ở phần “Giao diện lập trình
ứng dụng của Billboard ”.
Các khả năng có thể thiết lập cho OrientedShape3D:
ALLOW_AXIS_READ | WRITE
Cho phép đọc (ghi) thông tin trục canh chỉnh.
ALLOW_MODE_READ | WRITE
Cho phép đọc (ghi) thông tin chế độ canh chỉnh.
ALLOW_POINT_READ | WRITE
Cho phép đọc (ghi) thông tin tâm quay.
Ví dụ sử dụng OrientedShape3D
Việc sử dụng OrientedShape3D rất dễ dàng, bất cứ chỗ nào sử dụng
đối tượng Shape3D đều có thể thay thế đơn giản bằng đối tượng
OrientedShape3D.
Xét chương trình ví dụ OrientedShape3DApp.java. Ứng dụng này tạo
một phong cảnh ảo với các cây Billboard 2 chiều. Mỗi cây là một con
của một đối tượng OrientedShape3D, đối tượng này tạo hiệu ứng
Billboard cho cây.
1. public BranchGroup createSceneGraph(SimpleUniverse su) {
2. // Create the root of the branch graph
3. BranchGroup objRoot = new BranchGroup();
http://tailieuhay.com 533
Lập trình đồ họa trên Java 2D và 3D
4.
5. Vector3f translate = new Vector3f();
6. Transform3D T3D = new Transform3D();
7. TransformGroup positionTG = null;
8. OrientedShape3D orientedShape3D = null;
9.
10. Geometry treeGeom = createTree();
11.
12. //specify the position of the trees
13. float[][] position = {{ 0.0f, 0.0f, -2.0f},
14. {-13.0f, 0.0f, 23.0f},
15. { 1.0f, 0.0f, -3.5f}};
16.
17. // for the positions in the array create a OS3D
18. for (int i = 0; i < position.length; i++){
19. translate.set(position[i]);
20. T3D.setTranslation(translate);
21. positionTG = new TransformGroup(T3D);
22.
23. orientedShape3D = new OrientedShape3D();
24. orientedShape3D.addGeometry(treeGeom);
25.
26. objRoot.addChild(positionTG);
27. positionTG.addChild(orientedShape3D);
28. }
Đoạn mã trên được trích từ phương thức createSceneGraph của
chương trình OrientedShape3DApp.java. Có thể nhận thấy tính dễ dùng
của OrientedShape3D so với Billboard .
http://tailieuhay.com 534
Lập trình đồ họa trên Java 2D và 3D
Hoạt ảnh mức chi tiết (Level Of Detail Animations)
Mức chi tiết (Level Of Detail – LOD ) là một thuật ngữ chỉ kĩ thuật
biến đổi lượng chi tiết trong một đối tượng trực quan dựa trên một vài giá
trị của thế giới ảo. Ứng dụng thường gặp của kĩ thuật này là thay đổi mức
chi tiết của đối tượng dựa trên khoảng cách đối với người quan sát. Khi
khoảng cách tới đối tượng trực quan càng tăng thì càng ít chi tiết của đối
tượng đó được hiển thị. Do vậy, việc giảm độ phức tạp của đối tượng có
thể không ảnh hưởng đến kết quả hiển thị. Việc giảm bớt lượng chi tiết
của đối tượng khi chúng ở khoảng cách xa so với người quan sát sẽ làm
giảm khối lượng tính toán để tô trát. Nếu kĩ thuật này được áp dụng tốt sẽ
có thể tiết kiệm được đáng kể số lượng công thức tính toán mà vẫn không
làm mất đi nội dung của vật thể.
Lớp DistanceLOD cung cấp đối tượng hành vi LOD dựa trên khoảng
cách của vật thể đối với người quan sát. Một ứng dụng khác của LOD có
thể là thay đổi lượng chi tiết dựa trên tốc độ tô trát (hay tốc độ hiển thị,
được tính bằng số khung hình / giây) để giữ tỉ lệ khung hình là thấp nhất;
tốc độ của vật thể, hay mức độ chi tiết có thể được điều khiển với các
thiết lập của người dùng.
Mỗi đối tượng LOD có một hoặc nhiều hơn các đối tượng Switch
đóng vai trò đối tượng đích. Đối tượng Switch là một nhóm đặc biệt bao
gồm không, một hoặc nhiều hơn các con của chúng trong đồ thị khung
cảnh được dùng để hiển thị. Trong trường hợp sử dụng DistanceLOD,
việc lựa chọn con của đối tượng đích Switch được điều khiển bởi khoảng
cách của đối tượng DistanceLOD đối với người quan sát, dựa trên một tập
các ngưỡng khoảng cách.
Ngưỡng khoảng cách được xác định trong một mảng bắt đầu với
khoảng cách xa nhất, khi đó, con đầu tiên của đối tượng đích sẽ được sử
dụng. Con đầu tiên của đối tượng đích thông thường là đối tượng trực
quan chi tiết nhất. Khi khoảng cách của đối tượng DistanceLOD đối với
http://tailieuhay.com 535
Lập trình đồ họa trên Java 2D và 3D
người quan sát lớn hơn ngưỡng thứ nhất, con thứ hai của đối tượng switch
sẽ được sử dụng. Các ngưỡng khoảng cách sau phải lớn hơn ngưỡng
khoảng cách trước và xác định khoảng cách mà con tiếp theo của đối
tượng đích được sử dụng. Do đó, số lượng con của đối tượng đích là
nhiều hơn số ngưỡng khoảng cách.
Nếu có nhiều hơn một đối tượng Switch được thêm vào với tư cách là
đích của đối tượng LOD , các đối tượng đích Switch sẽ được sử dụng
song song. Có nghĩa là các con của các đối tượng đích Switch có cùng chỉ
mục sẽ được lựa chọn đồng thời. Theo cách làm này, đối tượng trực quan
phức tạp có thể được biểu diễn bởi nhiều đối tượng hình học là con của
các đối tượng Switch khác nhau.
Sử dụng đối tượng DistanceLOD
Việc sử dụng đối tượng DistanceLOD tương tự việc sử dụng đối
tượng nội suy Interpolator , ngoại trừ việc không có đối tượng Alpha
nào cần sử dụng để điều khiển hoạt ảnh. Hoạt ảnh của đối tượng LOD
được điều khiển bởi khoảng cách tương đối của nó đối với người quan sát
trong thế giới ảo, theo cách này, việc sử dụng đối tượng DistanceLOD
giống với việc sử dụng đối tượng Billboard . Sử dụng đối tượng
DistanceLOD cũng cần phải thiết lập các ngưỡng khoảng cách. Hình 5-18
biểu diễn các bước để sử dụng DistanceLOD.
1. tạo các đối tượng Switch đích với khả năng
ALLOW_SWITCH_WRITE
2. tạo danh sách mảng các ngưỡng khoảng cách cho đối tượng
DistanceLOD
3. tạo đối tượng DistanceLOD sử dụng mảng các ngưỡng khoảng
cách
4. thiết lập đối tượng Switch đích cho đối tượng DistanceLOD
http://tailieuhay.com 536
Lập trình đồ họa trên Java 2D và 3D
5. thiết lập giới hạn hoạt động cho đối tượng DistanceLOD
6. “lắp ghép” đồ thị khung cảnh, bao gồm cả việc thêm các con cho
các đối tượng Switch
Hình 5-18. Công thức sử dụng DistanceLOD để tạo hoạt ảnh
Các lỗi thường gặp khi sử dụng LOD
Mặc dù việc sử dụng đối tượng LOD không phải là phức tạp, nhưng
cũng có hai lỗi lập trình thường gặp sau. Lỗi thường xảy ra nhất là không
gộp đối tượng Switch đích vào đồ thị khung cảnh. Thiết lập đối tượng
Switch là đích của đối tượng DistanceLOD không tự động gộp nó vào đồ
thị khung cảnh.
Nếu khả năng ALLOW_SWITCH_WRITE không được thiết lập cho
đối tượng Switch đích thì khi chương trình được thực thi sẽ phát sinh lỗi
runtime. Còn nữa, nếu giới hạn hoạt động không được thiết lập, hoặc thiết
lập không chính xác thì LOD không điều khiển được đối tượng trực
quan. Giới hạn hoạt động thông thường được quy định bởi một đối tượng
BoundingSphere với bán kính đủ lớn để điều khiển được đối tượng trực
quan. Tương tự như các đối tượng hành vi khác, nếu không gộp LOD
vào đồ thị khung cảnh thì chương trình cũng sẽ không báo lỗi.
Có một giới hạn mà lớp LOD không vượt qua được chính là số lượng
quan sát mà chương trình có thể làm việc được. Nếu chương trình có
nhiều hơn một quan sát, LOD chỉ có thể điều khiển hoạt ảnh chính xác
cho chỉ một trong số các quan sát đó.
Ví dụ sử dụng DistanceLOD
Đoạn mã sau được trích từ phương thức createSceneGraph trong
chương trình DistanceLODApp. Chi tiết về chương trình này, xin xem
http://tailieuhay.com 537
Lập trình đồ họa trên Java 2D và 3D
thêm phần phụ lục và đĩa chương trình kèm theo. Đoạn mã này đã được
đánh số tương ứng với các bước trong công thức sử dụng ở hình 5-18.
public BranchGroup createSceneGraph() {
BranchGroup objRoot = new BranchGroup();
BoundingSphere bounds = new
BoundingSphere();
// create target TransformGroup with
Capabilities
TransformGroup objMove = new
TransformGroup();
objMove.setCapability(TransformGroup.ALLO
W_TRANSFORM_WRITE);
// create Alpha
Alpha alpha = new Alpha (-1,
Alpha.INCREASING_ENABLE
+ Alpha.DECREASING_ENABLE,
0, 0, 5000, 1000, 1000,
5000, 1000, 1000);
// specify the axis of translation
AxisAngle4f axisOfTra = new
AxisAngle4f(0.0f,1.0f,0.0f,(float)Math.PI/-2.0f);
Transform3D axisT3D = new Transform3D();
axisT3D.set(axisOfTra);
// create position interpolator
http://tailieuhay.com 538
Lập trình đồ họa trên Java 2D và 3D
PositionInterpolator posInt
= new PositionInterpolator (alpha,
objMove, axisT3D, 0.0f, -35.0f);
posInt.setSchedulingBounds(bounds);
// create DistanceLOD target object
Switch targetSwitch = new Switch();
targetSwitch.setCapability(Switch.ALLOW_S
WITCH_WRITE);
// add visual objects of various levels
of detail to the target switch
Appearance sphereAppearA = new
Appearance();
ColoringAttributes sphereCAa = new
ColoringAttributes();
sphereCAa.setColor(0.1f, 0.8f, 0.1f);
sphereAppearA.setColoringAttributes(spher
eCAa);
Appearance sphereAppearB = new
Appearance();
ColoringAttributes sphereCAb = new
ColoringAttributes();
sphereCAb.setColor(0.8f, 0.1f, 0.1f);
sphereAppearB.setColoringAttributes(spher
eCAb);
http://tailieuhay.com 539
Lập trình đồ họa trên Java 2D và 3D
targetSwitch.addChild(new Sphere(.40f, 0,
25, sphereAppearA));
targetSwitch.addChild(new Sphere(.40f, 0,
15, sphereAppearB));
targetSwitch.addChild(new Sphere(.40f, 0,
10, sphereAppearA));
targetSwitch.addChild(new Sphere(.40f, 0,
4, sphereAppearB));
// create DistanceLOD object
float[] distances = { 5.0f, 10.0f,
20.0f};
DistanceLOD dLOD = new
DistanceLOD(distances, new Point3f());
dLOD.addSwitch(targetSwitch);
dLOD.setSchedulingBounds(bounds);
if((targetSwitch.numChildren()-1) !=
dLOD.numDistances()){
System.out.println("DistanceLOD
not initialized properly");
System.out.println(targetSwitch.n
umChildren());
System.out.println(dLOD.numDistan
ces());
}
// assemble scene graph
http://tailieuhay.com 540
Lập trình đồ họa trên Java 2D và 3D
objRoot.addChild(objMove); // target
TG of position interp to move vo
objRoot.addChild(posInt); // add
position interpolator
objMove.addChild(dLOD); // make
the bounds move with visual object
objMove.addChild(targetSwitch);// must
add target switch to scene graph too
// show a level 3 object up close for
comparison
Transform3D t3d = new Transform3D();
t3d.set(new Vector3f(0.6f, 0.0f, 0.0f));
TransformGroup tga = new
TransformGroup(t3d);
objRoot.addChild(tga);
tga.addChild(new Sphere(.40f, 0, 4,
sphereAppearB));
// show a level 0 object at a distance
for comparison
t3d.set(new Vector3f(-5.0f, 0.0f,
-35.0f));
TransformGroup tgb = new
TransformGroup(t3d);
objRoot.addChild(tgb);
tgb.addChild(new Sphere(.40f, 0, 25,
sphereAppearA));
http://tailieuhay.com 541
Lập trình đồ họa trên Java 2D và 3D
// a white background is better for
printing images in tutorial
Background background = new Background();
background.setColor(1.0f, 1.0f, 1.0f);
background.setApplicationBounds(new
BoundingSphere());
objRoot.addChild(background);
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
DistanceLODApp
Hình 5-19 biểu diễn biểu đồ đồ thị khung cảnh được tạo ra trong ví dụ
trên. Chú ý rằng, đối tượng Switch đích vừa là con của đối tượng
TransformGroup vừa được tham chiếu đến bởi đối tượng DistanceLOD.
Cả hai quan hệ này đều cần được xác lập.
http://tailieuhay.com 542
Lập trình đồ họa trên Java 2D và 3D
Hình 5-19. Một phần biểu đồ đồ thị khung cảnh cho chương trình
DistanceLODApp
Hình 5-20 là hai cảnh được sinh từ chương trình DistanceLODApp.
Mỗi ảnh này có 2 khối cầu tĩnh và một khối cầu dịch chuyển (trong hình
bên phải, khối cầu bên trái nhất đã bị che khuất). Khối cầu dịch chuyển
được biểu diễn bằng một đối tượng DistanceLOD với 4 khối cầu có độ
phức tạp hình học khác nhau. Khối cầu nhỏ màu xanh là khối cầu chi tiết
nhất được sử dụng bởi đối tượng DistanceLOD ở khoảng cách cực đại.
Khối cầu lớn màu đỏ là khối cầu kém chi tiết nhất của đối tượng
DistanceLOD và ở khoảng cách cực tiểu. Hai khối cầu này được hiển thị
để làm mốc so sánh.
Trong chương trình này, đối tượng DistanceLOD được biểu diễn bởi các
khối cầu có màu sắc khác nhau để minh họa quá trình chuyển đổi.
Một đối tượng nội suy vị trí PositionInterpolator được sử dụng để
dịch chuyển đối tượng DistanceLOD theo hướng vuông góc với màn
hình. Khi đối tượng DistanceLOD dịch chuyển ra xa người quan sát, nó
sẽ chuyển đối tượng trực quan để hiển thị. Nếu không sử dụng các khối
http://tailieuhay.com 543
Lập trình đồ họa trên Java 2D và 3D
cầu có màu sắc khác nhau sẽ rất khó khăn để nhận biết khi nào thì đối
tượng trực quan được chuyển.
Hình 5-20. Hai cảnh được sinh ra từ DistanceLODApp.
Giao diện lập trình ứng dụng DistanceLOD API
DistanceLOD định nghĩa một nút đối tượng hành vi LOD dựa
khoảng cách, hoạt động trên một nút nhóm Switch để lựa chọn một trong
số các con của nút Switch đó dựa vào khoảng cách của nút đối tượng
LOD so với người quan sát. Một mảng n giá trị khoảng cách đơn điệu
tăng, được xác định sao cho thành phần đầu tiên distances[0] tương ứng
với mức chi tiết cao nhất và thành phần cuối cùng distances[n-1] tương
ứng với mức chi tiết thấp nhất. Dựa vào khoảng cách thực từ người quan
sát đến nút DistanceLOD, n giá trị khoảng cách [0, n-1] lựa chọn n+1
mức chi tiết [0, n]. Nếu gọi khoảng cách từ người quan sát đến nút LOD
thì phương trình để xác định mức chi tiết (con của nút Switch) được lựa
chọn là:
0 nếu d <= distances[0]
1. i nếu distances[i-1] < d <= distances[i]
2. n nếu d > distances[n-1]
http://tailieuhay.com 544
Lập trình đồ họa trên Java 2D và 3D
Chú ý rằng cả vị trí và mảng các giá trị khoảng cách đều được xác
định trong hệ tọa độ địa phương của nút hiện thời.
Các phương thức khởi tạo:
DistanceLOD()
Khởi tạo và khởi gán cho nút DistanceLOD giá trị mặc định.
DistanceLOD(float[] distances)
Khởi tạo và gán giá trị ban đầu cho nút DistanceLOD với mảng các
giá trị khoảng cách xác định và vị trí mặc định (0, 0, 0).
DistanceLOD(float[] distances, Point3f position)
Khởi tạo và khởi gán cho nút DistanceLOD với mảng các giá trị
khoảng cách và vị trí xác định.
Một số phương thức cung cấp bởi DistanceLOD:
int numDistances()
Trả về số lượng các ngưỡng khoảng cách.
void setDistance(int whichDistance, double distance)
Thiết lập ngưỡng khoảng cách LOD xác định.
void setPosition(Point3f position)
Thiết lập vị trí của nút LOD .
Morph
Các lớp nội suy thay đổi các thuộc tính trực quan khác nhau trong thế
giới ảo. Tuy nhiên, không có lớp nội suy nào cung cấp các khả năng thay
đổi hình dạng hình học của các đối tượng trực quan. Khả năng này do lớp
Morph cung cấp. Đối tượng Morph tạo hình dạng cho một đối tượng
trực quan thông qua việc nội suy từ một tập các đối tượng
GeometryArray. Theo đặc điểm này, lớp Morph giống với các lớp nội
suy. Tuy nhiên, Morph không phải là lớp nội suy, thậm chí, nó còn
không kế thừa lớp hành vi Behavior. Lớp Morph mở rộng từ lớp Node.
http://tailieuhay.com 545
Lập trình đồ họa trên Java 2D và 3D
Trong chương 4, chúng ta đã làm quen với phương thức
processStimulus của đối tượng Behavior để thực hiện các thay đổi đối với
đồ thị khung cảnh thực hay đối với các đối tượng trong đồ thị khung cảnh
thực. Do không có lớp hành vi chuyên biệt sử dụng với đối tượng Morph
, các ứng dụng Morph phải tự xây dựng lớp hành vi riêng. Lớp Morph
được coi như một lớp hoạt ảnh hay lớp tương tác phụ thuộc vào sự mô
phỏng hành vi tương tác với đối tượng Morph .
Đối tượng Morph có thể được sử dụng để biến kim tự tháp thành
hình khối hộp, mèo thành chó, hoặc biến đổi bất kì hình dạng hình học
nào thành một dạng hình học khác. Hạn chế duy nhất là các đối tượng
hình học sử dụng cho việc nội suy phải cùng thuộc một lớp và là lớp con
của lớp GeometryArray, với cùng số lượng các đỉnh. Hạn chế về số lượng
đỉnh không phải là hạn chế lớn của Morph , trong đĩa chương trình kèm
theo, bạn đọc có thể thấy chương trình Pyramid2Cube.java, biến một kìm
tự tháp thành hình hộp.
Đối tượng Morph cũng có thể được sử dụng để tạo hoạt ảnh cho các
đối tượng trực quan (ví dụ: làm cho một người đi lại được, hay làm cho
bàn tay có thể cầm nắm được vật dụng…). Chương trình ví dụ tạo hoạt
ảnh cho bàn tay, Morphing.java cũng có thể tìm thấy trong đĩa chương
trình kèm theo. Chương trình ví dụ thứ 3, làm cho một dạng hình que đi
lại được sẽ được trình bày chi tiết trong phần sau.
Sử dụng đối tượng Morph
Để hiểu được cách sử dụng đối tượng Morph , trước hết, cần phải
biết các thức đối tượng Morph làm việc. Morph không quá phức tạp.
Đối tượng Morph lưu trữ một mảng các đối tượng GeometryArray với
mỗi đối tượng định nghĩa đặc tả hình học hoàn chỉnh cho một đối tượng
trực quan. Các đối tượng GeometryArray có thể được coi như là các
http://tailieuhay.com 546
Lập trình đồ họa trên Java 2D và 3D
khung ảnh chính trong hoạt ảnh, hay chính xác hơn, là các hằng số trong
phương trình tính toán để tạo ra một đối tượng GeometryArray mới.
Ngoài mảng các đối tượng GeometryArray, một đối tượng Morph
còn có một mảng các trọng số, đây chính là các biến số trong phương
trình. Sử dụng các đối tượng GeometryArray cùng với các trọng số, đối
tượng Morph khởi tạo một đối tượng mảng hình học sử dụng giá trị
trọng số trung bình của tọa độ, màu sắc, …cung cấp bởi đối tượng
GeometryArray. Thay đổi các trọng số sẽ làm thay đổi hình dạng hình
học.
1. tạo một mảng các đối tượng GeometryArray
2. tạo một đối tượng Morph với khả năng
ALLOW_WEIGHTS_WRITE
3. lắp ghép đồ thị khung cảnh, bao gồm cả việc thêm các con cho đối
tượng đích Switch
Hình 5-21. Công thức sử dụng đối tượng Morph
Như đã trình bày, sử dụng đối tượng Morph không khó, tuy nhiên,
các bước này đúng cho cả hoạt ảnh và tương tác. Hoạt ảnh và tương tác
được cung cấp thông qua một đối tượng hành vi. Do đó, sử dụng đối
tượng Morph thường có nghĩa là viết một lớp hành vi. Cách viết lớp
hành vi đã được trình bày trong phần 4.2.1, nên ở đây không nói chi tiết.
Tất nhiên, Morph hoàn toàn có thể sử dụng mà không cần đối tượng
hành vi, nhưng nó sẽ không thể tạo ra được hoạt ảnh.
Ví dụ sử dụng Morph
Chương trình Morph này sử dụng một đối tượng hành vi tùy chỉnh
để sinh hoạt ảnh. Bước đầu tiên trong quá trình phát triển sẽ là xây dựng
lớp hành vi này.
http://tailieuhay.com 547
Lập trình đồ họa trên Java 2D và 3D
Trong đối tượng hành vi được sử dụng để tạo hoạt ảnh cho đối tượng
Morph , phương thức processStimlus thay đổi trọng số của đối tượng
Morph . Trong ví dụ này processStimulus thiết lập các giá trị trọng số
dựa vào giá trị Alpha của một đối tượng Alpha. Hoạt động này xảy ra tại
mỗi khung ảnh được tô trát khi điều kiện kích hoạt đã được thỏa mãn.
Đoạn mã sau là đoạn mã xây dựng đối tượng hành vi tùy biến trong
chương trình MorphApp.
public class MorphBehavior extends Behavior{
private Morph targetMorph;
private Alpha alpha;
// the following two members are here for
effciency (no memory burn)
private double[] weights = {0, 0, 0, 0};
private WakeupCondition trigger = new
WakeupOnElapsedFrames(0);
// create MorphBehavior
MorphBehavior(Morph targetMorph, Alpha
alpha){
this.targetMorph = targetMorph;
this.alpha = alpha;
}
public void initialize(){
// set initial wakeup condition
this.wakeupOn(trigger);
}
http://tailieuhay.com 548
Lập trình đồ họa trên Java 2D và 3D
public void processStimulus(Enumeration
criteria){
// don't need to decode event since
there is only one trigger
// do what is necessary
weights[0] = 0;
weights[1] = 0;
weights[2] = 0;
weights[3] = 0;
float alphaValue = 4f * alpha.value()
- 0.00001f;
int alphaIndex = (int) alphaValue;
weights[alphaIndex] = (double)
alphaValue - (double)alphaIndex;
if(alphaIndex < 3)
weights[alphaIndex + 1] = 1.0 -
weights[alphaIndex];
else
weights[0] = 1.0 -
weights[alphaIndex];
targetMorph.setWeights(weights);
// set next wakeup condition
this.wakeupOn(trigger);
}
} // end of class MorphBehavior
http://tailieuhay.com 549
Lập trình đồ họa trên Java 2D và 3D
Lớp MorphBehavior tạo khung hoạt ảnh chính bằng cách sử dụng các
đối tượng GeometryArray hai lần tại một thời điểm theo một quá trình có
tính tuần hoàn. Lớp này thích hợp cho tất cả các hoạt ảnh sử dụng 4
khung ảnh chính và có thể thay đổi dễ dàng để khớp với số lượng khung
ảnh chính khác nhau.
Với lớp hành vi tùy chỉnh vừa viết, mọi việc còn lại chỉ là tạo khung
ảnh chính sử dụng cho hoạt ảnh. Hình 5-22 biểu diễn các hình vẽ tay
được sử dụng làm khung ảnh chính cho chương trình ví dụ. Muốn xây
dựng các khung ảnh đẹp hơn, có thể sử dụng các gói 3D.
Các hình có màu đen trông giống như là hai khung hình chính, mỗi
cái được lặp lại một lần, nhưng thực tế, chúng là bốn khung hình chính
riêng biệt. Sự khác nhau là ở thứ tự các đỉnh được xác định.
Đoạn mã sau được trích từ phương thức createSceneGraph của
chương trình MorphApp.java với các số đánh dấu các bước được chỉ ra
trong hình 5-21. Trong phương thức này, một đối tượng MorphBehavior,
một đối tượng Alpha và một đối tượng Morph được tạo ra, rồi được gộp
vào đồ thị khung cảnh. Các đối tượng khung ảnh chính GeometryArray
được tạo ra bởi một số phương thức khác. Toàn bộ chương trình có thể
tìm thấy trong đĩa chương trình kèm theo.
Hình 5-22. Các hình khung ảnh chính của MorphApp với đường quỹ đạo
của một đỉnh (đường mờ)
public BranchGroup createSceneGraph() {
http://tailieuhay.com 550
Lập trình đồ họa trên Java 2D và 3D
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
Transform3D t3d = new Transform3D();
t3d.set(new Vector3f(0f, -0.5f, 0f));
TransformGroup translate = new
TransformGroup(t3d);
// create GeometryArray[] (array of
GeometryArray objects)
GeometryArray[] geomArray = new
GeometryArray[4];
geomArray[0] = createGeomArray0();
geomArray[1] = createGeomArray1();
geomArray[2] = createGeomArray2();
geomArray[3] = createGeomArray3();
// create morph object
Morph morphObj = new Morph(geomArray);
morphObj.setCapability(Morph.ALLOW_WEIGHT
S_WRITE);
// create alpha object
Alpha alpha = new Alpha(-1, 1, 0, 0,
2000, 100, 0, 0, 0, 0);
// create morph driving behavior
MorphBehavior morphBehav = new
MorphBehavior(morphObj, alpha);
http://tailieuhay.com 551
Lập trình đồ họa trên Java 2D và 3D
morphBehav.setSchedulingBounds(new
BoundingSphere());
//assemble scene graph
objRoot.addChild(translate);
translate.addChild(morphObj);
objRoot.addChild(morphBehav);
Background background = new Background();
background.setColor(1f, 1f, 1f);
background.setApplicationBounds(new
BoundingSphere());
objRoot.addChild(background);
// Let Java 3D perform optimizations on this
scene graph.
objRoot.compile();
return objRoot;
} // end of CreateSceneGraph method of
MorphApp
Một chú ý thú vị rút ra từ ví dụ trên là nhiều hoạt ảnh khác nhau có
thể được tạo ra, sử dụng chính các khung hình chính được xây dựng ở
trên, với các lớp hành vi khác nhau. Hình 5-23 biểu diễn một cảnh sinh ra
bởi Morph3DApp. Trong chương trình này, 3 lớp hành vi khác nhau tạo
hoạt ảnh dựa trên một số hoặc tất cả đối tượng GeometryArray của
MorphApp. Chúng được gọi lần lượt (từ trái qua phải) là “In Place”,
“Tango”, và “Broken”.
http://tailieuhay.com 552
Lập trình đồ họa trên Java 2D và 3D
Hình 5-23. Một cảnh trong chương trình Morph3App
Giao diện lập trình ứng dụng Morph API
Các phương thức khởi tạo:
Morph (GeometryArray[] geometryArrays)
Khởi tạo và khởi gán giá trị cho đối tượng Morph với một mảng đối
tượng GeometryArray xác định và một đối tượng null thuộc kiểu
Appearance.
Morph (GeometryArray[] geometryArrays, Appearance appearance)
Khởi tạo và khởi gán giá trị cho đối tượng Morph với một mảng đối
tượng GeometryArray và một đối tượng Appearance xác định.
Một số phương thức khác cung cấp bởi Morph :
void setAppearance(Appearance appearance)
Thiết lập thành phần hiển thị bề ngoài cho nút Morph .
void setGeometryArrays(GeometryArray[] geometryArrays)
Thiết lập thành phần geometryArrays cho nút Morph .
void setAppearanceOverrideEnable(boolean flag)
Thiết lập cờ để có nút lá AlternateAppearance làm bề ngoài hiển thị
cho nút Morph .
http://tailieuhay.com 553
Lập trình đồ họa trên Java 2D và 3D
void setWeights(double[] weights)
Thiết lập vector trọng số Morph cho nút Morph hiện thời.
Các khả năng có thể thiết lập cho Morph :
ALLOW_APPEARANCE_READ | WRITE
Xác định rằng nút hiện thời cho phép đọc (ghi) thông tin
appearance của nó.
ALLOW_GEOMETRY_ARRAY_READ | WRITE
Xác định rằng nút hiện thời cho phép đọc (ghi) thông tin dạng hình
học của nó.
ALLOW_WEIGHTS_READ | WRITE
Xác định rằng nút hiện thời cho phép đọc (ghi) vector trọng số
Morph của nó.
Giao diện GeometryUpdater
Trong các phần trên, hoạt ảnh được tạo ra chủ yếu bằng cách di
chuyển các khối hình hình học, chứ không thay đổi hay tạo ra hình mới.
Ngoại trừ Morph tạo ra hình nội suy từ các hình cho trước. Java 3D API
giới thiệu giao diện GeometryUpdater, giao diện này cùng với
BY_REFERENCE geometry (chương 2) cho phép thay đổi hình dạng
hình học trong thời gian thực thi chương trình.
Với giao diện GeometryUpdater, người lập trình ứng dụng có thể tạo
ra bất cứ loại hoạt ảnh nào phụ thuộc vào việc thay đổi thông tin về dạng
hình học, kể cả các hoạt ảnh sử dụng kĩ thuật Billboard , level of detail
và Morph . Giao diện GeometryUpdater có tính mềm dẻo cao, cho phép
người lập trình tạo được nhiều hiệu ứng hơn so với các kĩ thuật trên.
Các ứng dụng có thể sử dụng GeometryUpdater bao gồm các kĩ thuật
hoạt ảnh chuẩn như kiến tạo các hệ động, các hệ phân tử; sinh bóng mờ tự
động hay các hiệu ứng đặc biệt như chớp… Do GeometryUpdater cho
http://tailieuhay.com 554
Lập trình đồ họa trên Java 2D và 3D
phép truy cập đến dữ liệu từng đỉnh của đối tượng hình học nên khả năng
tạo hoạt ảnh là không có giới hạn.
Mặc dù có thể hiệu chỉnh dữ liệu đối tượng hình học BY_REFERENCE
mà không cần sử dụng đối tượng GeometryUpdater, nhưng cách làm này
cho kết quả hoặc là không thể dự đoán được hoặc là không ổn định.
Sử dụng GeometryUpdater
Để sử dụng được đối tượng GeometryUpdater cho các ứng dụng hình
học động, trước hết cần tạo đối tượng hình học BY_REFERENCE với các
khả năng thích hợp, tạo một lớp GeometryUpdater và lấy ra một đối
tượng thuộc lớp đó, rồi tạo một lớp hành vi tùy biến và cũng lấy ra một
đối tượng thuộc lớp đó. Công việc này không quá phức tạp như nhìn nhận
ban đầu.
Công việc tạo đối tượng hình học BY_REFERENCE không làm gì
nhiều hơn ngoài việc tạo ra một đối tượng hình học khác. Đối tượng
GeometryUpdater có nhiệm vụ hiệu chỉnh đối tượng hình học khi được
gọi. Đối tượng hành vi lập lịch gọi đối tượng GeometryUpdater trong ứng
dụng.
Chúng ta xem xét qua hai phương thức quan trọng của giao diện
GeometryUpdater. Hai phương thức này có cùng tên là updateData().
Phương thức updateData() thứ nhất phải được cài đặt chi tiết trong lớp
định nghĩa GeometryUpdater trong ứng dụng. Phương thức updateData()
thứ hai là phương thức của GeometryArray, phương thức này sẽ gọi
phương thức được cài đặt trong lớp GeometryUpdater.
void updateData(Geometry geometry)
Cập nhật dữ liệu hình học có thể truy cập bởi tham chiếu.
void updateData(GeometryUpdater updater)
http://tailieuhay.com 555
Lập trình đồ họa trên Java 2D và 3D
Phương thức này gọi phương thức updateData của đối tượng
GeometryUpdater xác định để đồng bộ hóa cập nhật dữ liệu đối tượng
hình học được tham chiếu bởi đối tượng GeometryArray hiện thời.
Chương trình ví dụ hệ thống phân tử đài phun nước sử
dụng GeometryUpdater
Các hệ thống phân tử thông thường được sử dụng để mô hình nước,
khói, pháo hoa và các hiện tượng giống dạng lỏng khác. Trong một hệ
thống phân tử, có hai tham số thiết kế cơ bản: các phân tử sẽ có dạng như
thế nào, vị trí và hướng của nó sẽ được cập nhật ra sao. Các phân tử thông
thường được biểu diễn dưới dạng điểm hoặc đường, tuy nhiên, các dạng
hình học khác cũng có thể được sử dụng. Việc cập nhật chuyển động có
thể mô phỏng được hành vi tự nhiên của các đối tượng (cụ thể hơn là mô
phỏng các định luật vật lý) hay các chuyển động mong muốn khác. Thông
thường, một vài phần của mã chương trình sẽ có thành phần ngẫu nhiên
để tránh cho các phân tử hoạt động hoàn toàn giống nhau.
Trong chương trình ví dụ, các hạt nước được biểu diễn dưới dạng các
đoạn thẳng nhỏ với chuyển động tuân theo các quy luật vật lý (cụ thể là
chúng được gia tốc bởi trọng trường). Mỗi đoạn thẳng được xác định bởi
2 điểm.
Hình 5-24 là một chuỗi các ảnh thu được từ chương trình ví dụ
ParticleApp. Ảnh phía bên trái là đài nước trước khi các phân tử nước
được khởi tạo. Ảnh ở giữa là khi cột “nước” được khởi tạo trong đài
phun. Trong ảnh này, có tất cả khoảng 300 phần tử hoạt động. Hình ngoài
cùng bên phải là ảnh đài phun khi đã hoạt động một khoảng thời gian.
Trong hình này có khoảng 500 phần tử nước hoạt động.
http://tailieuhay.com 556
Lập trình đồ họa trên Java 2D và 3D
Hình 5-24. Chuỗi hình ảnh thu từ chương trình ParticleApp
Trong chương trình ParticleApp.java, cả đài phun được quay quanh
trục để thể hiện tính 3 chiều tự nhiên của hoạt ảnh. Lớp hành vi tuỳ biến
Behavior và lớp GeometryUpdater là các lớp trong của lớp Fountain. Có
thể dùng một vài cách khác để thiết kế hoạt ảnh như trên. Tuy nhiên, sử
dụng các lớp này như là lớp trong sẽ biến Fountain trở thành một đối
tượng đồ hoạ hoạt ảnh hoàn chỉnh. Hơn nữa, do cả hai lớp Behavior và
Geometry đều chỉ được sử dụng cho riêng ứng dụng này, nên chẳng có lí
do gì để cho phép chúng được sử dụng bởi các lớp khác bên ngoài
Fountain.
Các đoạn mã sau tương ứng định nghĩa các đối tượng hình học, hành
vi và geometryUpdater cho ứng dụng ParticleApp. Ba đoạn mã này là
thành phần chính tạo nên hoạt ảnh trong ParticleApp.
Đoạn mã đầu tiên đưa ra định nghĩa cho lớp Fountain. Cụ thể, nó định
nghĩa một vài trường và tạo ra đối tượng hình học được dùng để biểu diễn
nước.
Ba trường (hay 3 thuộc tính) được định nghĩa gần thẻ . Trường
waterLines và baseElevation được sử dụng trong một vài phương thức
khác nhau nên chúng được khai báo là các thuộc tính của lớp Fountain.
waterLines là một tham chiếu đến đối tượng hình học LineArray, đối
tượng hình học của phần tử nước. baseElevation là giá trị toạ độ y của
http://tailieuhay.com 557
Lập trình đồ họa trên Java 2D và 3D
chân đài phun. Trường thuộc tính thứ 3 giữ một tham chiếu đến đối tượng
WaterUpdater được tạo ra tại đây với mục đích là không làm tràn bộ nhớ.
Phương thức thứ nhất của lớp Fountain là createWaterGeometry().
Phương thức này có định nghĩa một biến nguyên N , N là số lượng các
phần tử nước (số các đoạn thẳng của LineArray) được dùng để biểu diễn
nước. Giá trị 1400 được gán cho N trong đoạn mã không có gì đặc biệt
ngoại trừ việc nó làm cho hoạt ảnh trông có vẻ hợp lý hơn. Gần như bất
cứ giá trị nào cũng có thể gán cho N. Càng nhiều phần tử được sử dụng để
tạo hoạt ảnh thì thời gian để xây dựng một khung hình hiển thị càng lớn.
Trong phương thức createWaterGeometry(), đối tượng LineArray
được tạo ra trên dòng mã gán nhãn . Số lượng các đỉnh là N*2, bởi mỗi
phần tử (mỗi đoạn thẳng) cần một đỉnh bắt đầu và một đỉnh kết thúc. Chú
ý rằng định dạng đỉnh bao gồm cả BY_REFERENCE.
Các phần tử nước được tạo hoạt ảnh bằng cách thay đổi giá trị toạ độ
đỉnh cho các đoạn thẳng tương ứng. Việc này chỉ có thể thực hiện được
nếu khả năng thích hợp được thiết lập. Dòng mã dán nhãn đầu tiên thiết
lập khả năng cho phép ghi dữ liệu đỉnh. Khả năng này cần phải được thiết
lập cho bất cứ ứng dụng nào sử dụng GeometryUpdater. Trong hầu hết
các ứng dụng sử dụng GeometryUpdater, khả năng đọc cũng cần phải
được thiết lập. Ứng dụng này đòi hỏi như vậy. Dòng mã dán nhãn thứ 2
có nhiệm vụ thiết lập khả năng đọc dữ liệu giá trị đỉnh.
Phụ thuộc ứng dụng và cách đối tượng GeometryUpdater được thiết
kế, thông tin dạng hình học nhất định ngoài dữ liệu đỉnh có thể cần để
thiết lập đối tượng Geometry. Ví dụ, nếu đối tượng GeometryUpdater
không “biết” được số đỉnh được sử dụng thì giá trị này phải được đọc từ
đối tượng Geometry đã được truyền cho nó. Tất nhiên, thông tin này chỉ
có thể đọc được nếu khả năng thích hợp được thiết lập. Dòng mã tiếp sau
hai dòng mã gán nhãn chịu trách nhiệm thiết lập khả năng đọc số lượng
đỉnh.
http://tailieuhay.com 558
Lập trình đồ họa trên Java 2D và 3D
Các dòng mã còn lại trong đoạn mã sau khởi tạo toạ độ cho N đỉnh. Mỗi
đỉnh được khởi tạo toạ độ (0, baseElevation, 0), do đó ban đầu, không có
phần tử nào được nhìn thấy.
public class Fountain extends BranchGroup {
protected LineArray waterLines = null;
protected float baseElevation = -0.45f;
protected GeometryUpdater geometryUpdater =
new WaterUpdater();
Geometry createWaterGeometry() {
int N = 1400; // number of 'drops'
waterLines = new LineArray(N * 2,
LineArray.COORDINATES
| LineArray.BY_REFERENCE);
waterLines.setCapability(GeometryArray.ALLOW_REF_
DATA_WRITE);
waterLines.setCapability(GeometryArray.ALLOW_REF_
DATA_READ);
http://tailieuhay.com 559
Lập trình đồ họa trên Java 2D và 3D
waterLines.setCapability(GeometryArray.ALLOW_COUN
T_READ);
float[] coordinates = new float[N * 3 *
2];
int p;
for (p = 0; p < N; p += 2) { // for each
particle
coordinates[p * 3 + 0] = 0.0f;
coordinates[p * 3 + 1] =
baseElevation;
coordinates[p * 3 + 2] = 0.0f;
coordinates[p * 3 + 3] = 0.0f;
coordinates[p * 3 + 4] =
baseElevation;
coordinates[p * 3 + 5] = 0.0f;
}
waterLines.setCoordRefFloat(coordinates);
// the following statements would be
redundant
// waterLines.setInitialCoordIndex(0);
// waterLines.setValidVertexCount(N*2);
return waterLines;
}
http://tailieuhay.com 560
Lập trình đồ họa trên Java 2D và 3D
abstract class UpdateWaterBehavior extends
Behavior {
WakeupOnElapsedFrames w = null;
public UpdateWaterBehavior() {
w = new WakeupOnElapsedFrames(0);
}
public void initialize() {
wakeupOn(w);
}
public void processStimulus(Enumeration
critiria) {
waterLines.updateData(geometryUpdater);
wakeupOn(w);
} // end processStimulus
} // end class UpdateWaterBehavior
public class WaterUpdater implements
GeometryUpdater {
Random random;
public WaterUpdater() {
random = new Random();
http://tailieuhay.com 561
Lập trình đồ họa trên Java 2D và 3D
}
public void updateData(Geometry geometry)
{
GeometryArray geometryArray =
(GeometryArray) geometry;
float[] coords =
geometryArray.getCoordRefFloat();
int N =
geometryArray.getValidVertexCount();
int i;
for (i = 0; i < N; i += 2) { // for
each particle
if (coords[i * 3 + 1] >
baseElevation) { // update active
// particles
coords[i * 3 + 0] +=
coords[i * 3 + 0] - coords[i * 3 + 3]; // x1
coords[i * 3 + 1] +=
coords[i * 3 + 1] - coords[i * 3 + 4]
- 0.01f; // y1
coords[i * 3 + 2] +=
coords[i * 3 + 2] - coords[i * 3 + 5]; // z1
coords[i * 3 + 3] =
(coords[i * 3 + 0] + coords[i * 3 + 3]) / 2; //
x2
http://tailieuhay.com 562
Lập trình đồ họa trên Java 2D và 3D
coords[i * 3 + 4] =
(coords[i * 3 + 1] + coords[i * 3 + 4] + 0.01f) /
2;// y2
coords[i * 3 + 5] =
(coords[i * 3 + 2] + coords[i * 3 + 5]) / 2; //
z2
if (coords[i * 3 + 1] <
baseElevation) { // if particle
// below base
coords[i * 3 + 0] =
0.0f; // x1
coords[i * 3 + 1] =
baseElevation; // y1
coords[i * 3 + 2] =
0.0f; // z1
coords[i * 3 + 3] =
0.0f; // x2
coords[i * 3 + 4] =
baseElevation; // y2
coords[i * 3 + 5] =
0.0f; // z2
}
} else { // an inactive particle
if (random.nextFloat() >
0.8) { // randomly start a drop
coords[i * 3 + 0] =
0.03f * (random.nextFloat() - 0.5f); // x1
http://tailieuhay.com 563
Lập trình đồ họa trên Java 2D và 3D
coords[i * 3 + 1] =
0.14f * random.nextFloat()
+
baseElevation; // y1
coords[i * 3 + 2] =
0.03f * (random.nextFloat() - 0.5f); // z1
} // end if
} // end if-else
} // end for loop
}
}
}
Đoạn mã sau định nghĩa lớp UpdateWaterBehavior, một lớp mở rộng
từ lớp Behavior. Đây là đoạn mã dễ nhất trong ứng dụng
GeometryUpdater. Lớp Behavior điều khiển hoạt ảnh bằng cách gọi
phương thức updateGeometry của đối tượng hình học được tạo hoạt ảnh
khi phương thức processStimulus của nó được gọi.
Định nghĩa lớp UpdateWaterBehavior bao gồm trường w – một tham
chiếu đến đối tượng WakeupOnElasedFrames - được sử dụng để kích
hoạt đối tượng hành vi. Đối tượng WakeupOnElasedFrames được tạo
trong phương thức khởi tạo của UpdateWaterBehavior bắt đầu từ dòng
mã được dán nhãn . Phương thức initialize() của lớp
UpdateWaterBehavior, bắt đầu từ dòng mã , thiết lập điều kiện đánh
thức ban đầu cho đối tượng hành vi.
Phương thức processStimulus(), bắt đầu từ dòng mã gán nhãn , định
nghĩa các hành động của đối tượng hành vi đáp ứng lại các sự kiện đánh
thức nó. Trong trường hợp này, phương thức updateData() được gọi và
truyền tham số geometryUpdater cho waterLines.
http://tailieuhay.com 564
Lập trình đồ họa trên Java 2D và 3D
abstract class UpdateWaterBehavior extends
Behavior {
WakeupOnElapsedFrames w = null;
public UpdateWaterBehavior() {
w = new WakeupOnElapsedFrames(0);
}
public void initialize() {
wakeupOn(w);
}
public void processStimulus(Enumeration
critiria) {
waterLines.updateData(geometryUpdater);
wakeupOn(w);
} // end processStimulus
} // end class UpdateWaterBehavior
Đoạn mã sau định nghĩa lớp GeometryUpdater. GeometryUpdater
dịch chuyển các phần tử nước bằng cách thay đổi dữ liệu tọa độ của
chúng.
Lớp GeometryUpdater trong ứng dụng này có một hàm khởi tạo và
một phương thức. Trong hàm khởi tạo, nhãn , một đối tượng Random
được tạo ra để sử dụng trong phương thức thường duy nhất của lớp,
phương thức updateData().
http://tailieuhay.com 565
Lập trình đồ họa trên Java 2D và 3D
Phương thức updateData(), nhãn , tạo hoạt ảnh cho các phần tử
nước. Thông thường, không phải tất cả các phần tử đều hoạt động tại
cùng một thời điểm. Phần tử nào không hoạt động sẽ có tọa độ y trùng với
tọa độ y của chân đài phun (baseElevation). Nếu một phần tử có tọa độ y
bằng với baseElevation, nó được coi là không hoạt động và vì thế, phần tử
này không di chuyển. Ban đầu, tất cả các phần tử nước đều không hoạt
động.
Xét hệ phần tử này một thời gian ngắn sau khi khởi động, khi này, đã
có một vài phần tử hoạt động, số còn lại thì chưa. Mỗi lần updateData()
được gọi, tiến trình hoạt ảnh sẽ thu thập thông tin liên quan về đối tượng
hình học để cập nhật. Trên dòng mã , tham số Geometry được ép kiểu
thành GeometryArray. Trên dòng mã , một tham chiếu đến dữ liệu tọa
độ đỉnh được lấy ra. Dòng thu thập số lượng đỉnh.
Chú ý rằng, ứng dụng này có thể chạy hiệu quả hơn bằng cách tính
toán các thông tin này một lần rồi lưu trữ nó trong các trường của đối
tượng. Tuy nhiên, hiệu quả đạt được cũng chỉ hạn chế và làm cho đoạn
mã không sử dụng lại được. Lớp Geometry này có thể được sử dụng cho
đài phun với các kích thước khác nhau.
Khi đã có những bước chuẩn bị thích hợp, phương thức updateData() xét
mỗi phần tử tại một thời điểm nào đó trong vòng lặp . Với mỗi phần tử
hoạt động (xác định bằng cách so sánh tọa độ y của nó với
baseElevation), chương trình sẽ tính toán chuyển động cong dạng parabol
của nó. Tọa độ đỉnh đầu tiên của một phần tử được gán các giá trị thích
hợp để mô hình chuyển động, sau đó, tọa độ cũ của đỉnh thứ nhất sẽ được
gán cho đỉnh thứ hai.
Câu lệnh if trên dòng kiểm tra xem phần tử đã vượt qua
baseElevation hay chưa. Nếu điều kiện này thỏa mãn, phần tử đó sẽ
ngừng hoạt động bởi chương trình cập nhật giá trị tọa độ cả hai đỉnh của
nó về giá trị ban đầu, giá trị xác định phần tử không hoạt động.
http://tailieuhay.com 566
Lập trình đồ họa trên Java 2D và 3D
Một phần các phần tử không hoạt động, phần else của điều kiện trên dòng
, được ngẫu nhiên khởi tạo bởi điều kiện trên dòng . Trong ví dụ này,
một lượng trung bình khoảng 20% các phần tử không hoạt động sẽ được
khởi tạo.
public class WaterUpdater implements
GeometryUpdater {
Random random;
public WaterUpdater() {
random = new Random();
}
public void updateData(Geometry geometry)
{
GeometryArray geometryArray =
(GeometryArray) geometry;
float[] coords =
geometryArray.getCoordRefFloat();
int N =
geometryArray.getValidVertexCount();
int i;
for (i = 0; i < N; i += 2) { // for
each particle
if (coords[i * 3 + 1] >
baseElevation) { // update active
http://tailieuhay.com 567
Lập trình đồ họa trên Java 2D và 3D
// particles
coords[i * 3 + 0] +=
coords[i * 3 + 0] - coords[i * 3 + 3]; // x1
coords[i * 3 + 1] +=
coords[i * 3 + 1] - coords[i * 3 + 4]
- 0.01f; // y1
coords[i * 3 + 2] +=
coords[i * 3 + 2] - coords[i * 3 + 5]; // z1
coords[i * 3 + 3] =
(coords[i * 3 + 0] + coords[i * 3 + 3]) / 2; //
x2
coords[i * 3 + 4] =
(coords[i * 3 + 1] + coords[i * 3 + 4] + 0.01f) /
2;// y2
coords[i * 3 + 5] =
(coords[i * 3 + 2] + coords[i * 3 + 5]) / 2; //
z2
if (coords[i * 3 + 1] <
baseElevation) { // if particle
// below base
coords[i * 3 + 0] =
0.0f; // x1
coords[i * 3 + 1] =
baseElevation; // y1
coords[i * 3 + 2] =
0.0f; // z1
http://tailieuhay.com 568
Lập trình đồ họa trên Java 2D và 3D
coords[i * 3 + 3] =
0.0f; // x2
coords[i * 3 + 4] =
baseElevation; // y2
coords[i * 3 + 5] =
0.0f; // z2
}
} else { // an inactive particle
if (random.nextFloat() >
0.8) { // randomly start a drop
coords[i * 3 + 0] =
0.03f * (random.nextFloat() - 0.5f); // x1
coords[i * 3 + 1] =
0.14f * random.nextFloat()
+
baseElevation; // y1
coords[i * 3 + 2] =
0.03f * (random.nextFloat() - 0.5f); // z1
} // end if
} // end if-else
} // end for loop
}
}
Cột nước trong hoạt ảnh trông sẽ đẹp hơn nếu các đoạn thẳng biểu
diễn mỗi phần tử loại bỏ được răng cưa. Việc này có thể thực hiện được
bằng cách thêm đối tượng LineAttributes với
setLineAntialiasedEnable(true) vào thành phần Appearance của phần tử
nước. Tuy nhiên, lưu ý rằng, việc làm này có thể phải trả giá bởi tốc độ
xử lý hoạt ảnh.
http://tailieuhay.com 569
Lập trình đồ họa trên Java 2D và 3D
Tài liệu tham khảo
Trong quá trình làm cuốn tutorial về lập trình đồ họa trong Java 2D
& 3D chúng em có tham khảo các tài liệu sau:
1. Slide bài giảng Kĩ thuật đồ họa và hiện thực ảo của ThS.Lê Tấn
Hùng.
2. The Java Tutorial, 2nd Volume. Available online at:
http://java.sun.com/docs/books/tutorial/2d/index.html
3. The 2D Text Tutorial. Available online from the Java Developer
Connection:
http://developer.java.sun.com/developer/onlineTraining/Graphics/2
DText/
3. The Java 2D Sample Programs. Available online at:
http://java.sun.com/products/java-media/2D/samples/index.html
4. The Java 2D Demo. Available from the Java 2D website:
http://java.sun.com/products/java-media/2D/index.html
5. The Java 3D document at:
http://java.sun.com/developer/onlineTraining/java3d/
http://tailieuhay.com 571