I. Gớới thiệu về VRML
5. The Browser object
Đối tợng Browser là một đối tợng ECMAScript nằm bên trong trình dịch
ECMAScript đợc cung cấp bởi trình duyệt VRML. Tất cả các trình duyệt cần đợc cung cấp đối tợng này. Không may, các script hỗ trợ trong VRML thờng khá mâu thuẫn nhau và nói chung là thờng hỗ trợ không tốt. Điều này là rất đáng tiếc khi các script hỗ trợ đóng vai trò rất quan trọng. Dù vậy, nh tôi đã nói, đối tợng Browser vẫn đợc gắn liền trong bộ dịch ECMAScript của trình duyệt. Đó là đối tợng tĩnh, nghĩa là bạn không phải tạo ra các biến kiểu đối tợng này trớc khi bạn có thể sử dụng các phơng thức của nó. Để sử dụng phơng thức bên trong đối tợng Browser, chỉ cần sử dụng cú pháp sau :
Browser.functionName().
Nó sẽ thực thi các phơng thức tĩnh bên trong đối tợng Browser. Đối tợng Browser đối tợng sử dung rất nhiều. Nó là tài nguyên thông tin của cũng cung cấp một số cách thay đổi thế giới quan của bạn. Trớc hết, chúng ta sẽ xem việc lấy thông tin từ trình duyệt. Bạn hãy nhớ lại ở Script node có 2 trờng đợc gọi là directOutput và mustEvaluate. Chúng khá là quan trọng khi sử dụng Browser, nên tôi sẽ nhắc lại cho các bạn biết chúng có vai trò thế nào.
mustEvaluate – Nếu nó có giá trị là true, thì script sẽ đợc định lợng ngay tức khắc.
Trình duyệt đợc phép ngăn lại quá trình xử lý script nếu có quá trình quan trọng hơn cần thực hiện trớc. MustEvaluate nếu bằng true thì trình duyệt sẽ không có khả năng làm điều này nữa mà phải thực thi script ngay tức khắc.
directOutput – nếu có giá trị true, script có thể ghi trực tiếp tới eventIns và đọc
trực tiếp từ eventOuts của nút mà nó truy cập tới. Bình thờng, script có thể chỉ làm nh vậy khi gửi hoặc nhận sự kiện trong tập các sự kiện bình thờng.
Information Technology
Tập các phơng thức đầu tiên mà chúng ta sẽ xem trong đối tợng Brower là các ph- ơng thức lấy thông tin. Tôi sẽ sắp xếp chúng lại, kèm theo các mô tả ngắn gọn các phơng thức :
Browser.getName()
Đây là phơng thức chỉ trả lại một chuỗi chứa tên của trình duyệt, ví dụ nh
"Cosmo Player". Nó trả về một chuỗi rỗng nếu không có thông tin.It returns
Browser.getVersion()
Phơng thức trả lại chuỗi chứa thông tin về phiên bản của trình duyệt. Nó cũng là chuỗi rỗng nếu không có thông tin gì.
Browser.getWorldURL()
Phơng thức trả lại chuỗi URL hiện tại đang đợc load.
Browser.getCurrentFrameRate()
Trả lại một giá trị tơng đơng với tốc độ load các frame hiện hành (số các hình ảnh trình duyệt thể hiện đợc trên một giây).
Browser.getCurrentSpeed()
Đây cũng là phơng thức trả về một giá trị số, là thời gian bằng tốc độ chuyển động của ngời dùng, liên quan đến hệ thống toạ độ Viewpoint's.
Browser.setDescription(string description) – cần mustEvaluate có giá trị TRUE . đây
là phơng thức thay đổi mô tả hiện tại của trang Web bằng một chuỗi, tơng đơng một tham số.
Browser.loadURL(MFString url, MFString parameter)-cần mustEvaluate có giá
bằng TRUE . Nó load các thông tin mới về từ các file khác. Đối số đầu tiên là danh sách MFString để thử. The chuẩn của VRML, các phần tử của danh sách đợc thử cho đến khi thành công. Đối số thứ 2, parameter, cung cấp thêm các thông số, chẳng hạn cửa sổ TARGET vv..Những tham số bạn hoàn toàn có thể sử dụng cho node Anchor. Thực tế có nhiều công việc làm giống nh Anchor. Nếu trang Web mới đợc load xuống cùng lúc thì trang hiện tại sẽ bị đóng xuống và đợc thay thế bằng nội dung mới.
Browser.replaceWorld(MFNode nodes) - cần mustEvaluate có giá trị bằng
TRUE
Nó thay thế toàn bộ các trang đang load hiện tại bằng các node trong đối tợng MFNode. Phơng thức này sẽ không bào giờ quay lui lại đợc, cũng giống nh các script đang vận hành cũng sẽ đợc thay thế.
Có 2 phơng thức cho phép bạn tạo ra các phần mới của VRML , chúng đợc biết tới nh các phơng thức createVrmlFromX. Chúng là :
Browser.createVrmlFromString(String string)
Browser.createVrmlFromURL(MFString url, SFNode node, String eventIn)
Các phơng thức cho phép ta tạo ra các phần mới của VRML từ các chuỗi hoặc các file. Cả 2 phơng thức tạo ra đối tợng MFNode mới, do đó bạn có thể sử dụng để thêm vào
nhóm các node thông qua addChildren eventIn.Tất cả các node đều có sự kiện eventIn này, vì thế bạn có thể thêm các node con tại bất kỳ nơi nào bạn muốn.
Hai phơng thức làm việc theo các cách không khác nhau là mấy, nh bạn có thể thấy ở định nghĩa của các phơng thức. Tại sao có điều này thì tôi không rõ. Bạn cũng có thể nghĩ chúng làm việc nh nhau, nhng thực tế không phải thế.
createVrmlFromString lấy chuỗi làm tham số và trả lại đối tợng MFNode chứa
VRML từ chuỗi. Chuỗi phải là VRML có giá trị và phải độc lập hoàn toàn. Có nghĩa là nó không thể sử dụng DEFed ngoài chuỗi và cũng nh vậy cho định nghĩa PROTO. Bạn cũng có thể tính đến cả ROUTEs trong chuỗi. Về cơ bản, chuỗi cũng giống nh file VRML và có thể sử dụng các quy định về file cho chuỗi. Ví dụ, nếu chúng ta bên trong một script mà có sự kiện eventOut của MFNode gọi là newChildren, nó sẽ dẫn đến sự kiện
addChildren ở một nhóm các node, chúng ta có thể làm một số việc nh sau
newVRML = 'Shape {';
newVRML += ' appearance Appearance {'; newVRML += ' material Material {'; newVRML += ' diffuseColor 1 0 0'; newVRML += ' }';
newVRML += ' }';
newVRML += ' geometry Box {'; newVRML += ' }';
newVRML += '}';
newChildren = Browser.createVrmlFromString(newVRML);
Chúng sẽ kết hợp thành một chuỗi mà chúng ta cần và sau đó tạo thành MFNode mới từ chuỗi đó. MFNode này ngay lập tức đợc gán cho sự kiện eventOut newChildren, và nó đợc gửi tới nhóm các node. Nút con hiện thời của nhóm đợc thay thế, chỉ một node mới đợc thêm vào.
Còn một phơng thức khác ít phức tạp hơn. createVrmlFromString() làm việc rất đơn giản và linh hoạt. Ngợc lại, , createVrmlFromURL() phức tạp hơn và không linh hoạt bằng. Với phơng thức này, bạn phải cung cấp MFString chứa danh sách các URL để thử thay thế vào tham số đầu tiên trong phơng thức. Các file hoàn toàn phải có giá trị VRML và tuân theo các luật bình thờng. Các node bên trong file sẽ đợc đọc và biến đổi sang node mới cho bạn sử dụng. Sự lúng túng sẽ đến khi bạn thử và gửi MFNode mới tới nhóm các node ở bên ngoài. Phơng thức createVrmlFromString cho bạn đối tợng MFNode đơn giản mà bạn có thể vận dụng một cách linh hoạt và làm những gì bạn muốn. Phơng thức createVrmlFromURL không trả lại bất cứ giá trị nào. Thay vào đó, nó gửi MFNode bằng chính nó, từ bên trong phơng thức. Đó là vai trò của các tham số. Đầu tiên là tham chiếu đến nút bạn muốn thêm các phần mới và thứ hai là tên của MFNode eventIn mà sẽ nhận nút mới. Tôi nghĩ ví dụ sau sẽ nói rõ hơn
} Script {
field SFNode group USE GROUP url "javascript:
function initialize() {
urlString = new MFString('cone.wrl');
Browser.createVrmlFromURL(urlString,group,'addChildren'); }
" }
Nh bạn thấy, các tham số là tên các file đợc dùng, SFNode tham chiếu, tên của các sự kiện eventIn. Phơng thức quản lý mọi thứ khác cho bạn, gửi nút mới vào addChildren eventIn của nhóm. Tôi không chắc chắn tại sao nó lại làm nh vậy, nhng biết chắc có lý do nào đó. Tôi sẽ nói cho các bạn khi nào tôi biết lý do này. Khi lựa chọn bạn có thể bỏ qua phơng thức createVrmlFromURL() và sử dụng phơng thức createVrmlFromString() với nút Inline chứa tên các file bạn muốn thay thế, nh :
newVRML = 'Inline { url "cone.wrl" }';
newChildren = Browser.createVrmlFromString(newVRML);
Nó đa ra chức năng giống nh phơng thức createVrmlFromURL() với việc sử dụng cách của createVrmlFromString(). Cám ơn Eyal Teler cho đề xuất này.
Trở lại công việc hay xem ví dụ sau : #VRML V2.0 utf8
WorldInfo {
title "Floppy's VRML97 Tutorial Example 4.5b" info ["(C) Copyright 2000 Vapour Technology Ltd." "guide@vapourtech.com"] } NavigationInfo { type ["NONE"] } Viewpoint {
description "Default View" position 0 0.5 2
}
translation -0.25 -0.15 0 children [
DEF CUBESENSOR TouchSensor { } Shape { appearance Appearance { material Material { diffuseColor 1 0 0 } } geometry Box { size 0.1 0.1 0.17 } } ] } Transform { translation 0 -0.15 0 children [
DEF SPHERESENSOR TouchSensor { } Shape { appearance Appearance { material Material { diffuseColor 0 1 0 } } geometry Sphere { radius 0.05 } } ] } Transform { translation 0.25 -0.15 0 children [
DEF CONESENSOR TouchSensor { }
Shape { appearance Appearance { material Material { diffuseColor 0 0 1 } } geometry Cone { bottomRadius 0.05 height 0.1 } } ] }
DEF TOP Transform { translation 0 0.5 0 children [ Transform { rotation 1 0 0 1.57 children [ Shape { appearance Appearance { material Material { diffuseColor 0.4 0.4 0.4 } } geometry Box { size 1 1e-8 1 } } ] } ] }
DEF CREATOR Script {
eventIn SFTime cube_touchTime eventIn SFTime sphere_touchTime eventIn SFTime cone_touchTime field SFNode parentNode USE TOP
eventOut MFNode newChildren mustEvaluate TRUE
url "javascript:
function cube_touchTime(value,time) { newVRML = 'Group {';
newVRML += ' children [';
newVRML += ' DEF SENSOR PlaneSensor {'; newVRML += ' maxPosition 0.45 0.45'; newVRML += ' minPosition -0.45 -0.45'; newVRML += ' }';
newVRML += ' DEF OBJECT Transform {'; newVRML += ' children [';
newVRML += ' Shape {';
newVRML += ' appearance Appearance {'; newVRML += ' material Material {'; newVRML += ' diffuseColor 1 0 0'; newVRML += ' }';
newVRML += ' }';
newVRML += ' geometry Box {'; newVRML += ' size 0.1 0.1 0.1'; newVRML += ' }'; newVRML += ' }'; newVRML += ' ]'; newVRML += ' }'; newVRML += ' ]'; newVRML += '}';
newVRML += 'ROUTE SENSOR.translation_changed TO OBJECT.set_translation'; newChildren = Browser.createVrmlFromString(newVRML); } function sphere_touchTime(value,time) { newVRML = 'Group {'; newVRML += ' children [';
newVRML += ' DEF SENSOR PlaneSensor {'; newVRML += ' maxPosition 0.45 0.45'; newVRML += ' minPosition -0.45 -0.45'; newVRML += ' }';
newVRML += ' DEF OBJECT Transform {'; newVRML += ' children [';
newVRML += ' appearance Appearance {'; newVRML += ' material Material {'; newVRML += ' diffuseColor 0 1 0'; newVRML += ' }';
newVRML += ' }';
newVRML += ' geometry Sphere {'; newVRML += ' radius 0.05'; newVRML += ' }'; newVRML += ' }'; newVRML += ' ]'; newVRML += ' }'; newVRML += ' ]'; newVRML += '}';
newVRML += 'ROUTE SENSOR.translation_changed TO OBJECT.set_translation';
newChildren = Browser.createVrmlFromString(newVRML); }
function cone_touchTime(value,time) { urlString = new MFString('cone.wrl');
Browser.createVrmlFromURL(urlString, parentNode, 'addChildren'); }
" }
ROUTE CUBESENSOR.touchTime TO CREATOR.cube_touchTime ROUTE SPHERESENSOR.touchTime TO CREATOR.sphere_touchTime ROUTE CONESENSOR.touchTime TO CREATOR.cone_touchTime ROUTE CREATOR.newChildren TO TOP.addChildren
Tất cả các phơng thức đều đơn giản, tôi sẽ đa ra đây một ví dụ, qua đó bạn có thể thấy hoạt động của chúng. Trong đó sẽ không có cái gì là bạn không hiểu vì tất cả mọi thứ bây giờ đều đã khá quen thuộc. TimeSensor trong ví dụ có vai trò cập nhật bình th- ờng các văn bản hiện ra màn hình.
#VRML V2.0 utf8 WorldInfo {
title "Floppy's VRML97 Tutorial Example 4.5a" info ["(C) Copyright 2000 Vapour Technology Ltd." "guide@vapourtech.com"]
}
NavigationInfo { }
Viewpoint {
description "Default View" } Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } }
geometry DEF TEXT Text { fontStyle FontStyle { size 0.5 justify "MIDDLE" } } }
DEF TIMER TimeSensor { loop TRUE
startTime 0 stopTime -1 cycleInterval 0.1 }
DEF TEXTCREATOR Script { eventIn SFTime ping
eventOut MFString string url "javascript:
function ping(value,time) {
browserString = 'Browser: ' + Browser.getName(); versionString = 'Version: ' + Browser.getVersion();
urlString = 'URL: ' + Browser.getWorldURL(); speedString = 'Speed: ' + Browser.getCurrentSpeed();
frameString = 'Frame Rate: ' + Browser.getCurrentFrameRate() + ' fps'; string = new MFString(browserString, versionString, urlString, speedString, frameString);
} " }
ROUTE TIMER.cycleTime TO TEXTCREATOR.ping ROUTE TEXTCREATOR.string TO TEXT.string
III.Nội dung của bài tập lớn
Trong bài tập lớn này chỳng tụi sẽ tập trung mụ phỏng một toà nhà (lấy mụ hỡnh từ nhà C14_15 DHBKHN) sử dụng ngụn ngữ VRML kốm theo JavaScript.Chương trỡnh này cho phộp người dựng quan sỏt căn nhà từ xa hay ở gần,cú thể tham quan cỏc phũng học(giống như trong thực tế, bao gồm bàn ghế,cửa ra vào,cửa sổ,quạt trần...)
IV.Cỏc đối tượng cơ bản trong bài tập lớn 1,Cửa ra vào Mó VRML cú dạng như sau: SENSOR CylinderSensor { diskAngle 0.78 maxAngle 3 minAngle 0 }
DEF OBJECT Transform { children [
canhcua{ pos 0 0 0} ]
}
ROUTE SENSOR.rotation_changed TO OBJECT.rotation
Như vậy là để xõy dựng cỏnh cửa quay ,ta xõy dựng một cỏnh cửa tĩnh sau đú đưa vào Cylindersensor với điều kiện là tõm của hệ toạ độ di chuyển về cạnh bờn của cỏnh cửa. 2,Cửa kộo Mó VRML cú dạng như sau: Group { children [ Transform { translation 0.4 2.39 0 scale 0.6 1.52 1 children [
DEF SENSOR PlaneSensor { maxPosition 1 0
Ceiling fan
}
DEF SLIDER Transform { rotation 0 1 0 1.57 children [ cuaso{pos 0 0 0} ] } 3,Quạt trần
Quạt trần cú thể quay được nhờ trong quạt cú định nghĩa một nỳt nội suy về hướng, hoạt động theo một TimerSensor
Mó VRML cú dạng như sau: DEF fan Transform {
translation 0 290 200 scale 1.5 1.5 1.5 children [
Inline {url "Fan.wrl"}
DEF gocquay OrientationInterpolator { key[0 0.25 0 5 0.75 1.0] keyValue [0 1 0 0, 0 1 0 1.57, 0 1 0 3.14 , 0 1 0 4.17 0 1 0 6.28] } ] }
DEF ts1 TimeSensor {
cycleInterval 1.3 loop TRUE }
ROUTE fanon.isActive TO scr.turnin ROUTE scr.turnchange TO time.enabled
ROUTE time.fraction_changed TO gocquay.set_fraction ROUTE gocquay.value_changed TO q1.rotation
Quạt cũn được định nghĩa TouchSensor để cú thể bật tắt.Một nỳt định nghĩa TouchSensor để khi ấn vào thỡ nú sẽ bật hay tắt Timerđể quay quạt.
Ngoài ra cũn dựng cỏc hàm javasciript để xỏc định trạng thỏi của quạt đang hay đang tắt ,từ đú sẽ xỏc định quạt quay hay dừng.
4,Bảng kộo
Bảng kộo giảng đường gồm 4 tấm cú thể kộo lờn hay xuống tuỳ theo người sử dụng.Nguyờn tắc xõy dựng bảng tương tự như là cửa kộo.Ta dựng planesensor để cho cỏc tấm bảng dịch chuyển.
5,Ánh sỏng
Đầu tiờn ta xõy dựng cỏc ỏnh sỏng điểm cú dạng như sau: DEF light PointLight {
radius 100 location 0 0 0 color 0 0 0}
Lỳc này ỏnh sỏng chưa cú tỏc động.Sau đú ,ta xõy dựng cỏc hàm để khi tỏc động vào một nỳt gắn với thỡ nguồn sỏng sẽ được kớch hoạt.Hàm đú cú dạng như sau:
eventInSFBoolset_light
eventOut SFColor light_change field SFBool IsOpen FALSE url "javascript: function set_light(val) { if(IsOpen) { light_change[0] = 0; light_change[1] = 0; light_change[2] = 0; } else { light_change[0] = 1; light_change[1] = 1; light_change[2] = 1; } IsOpen = !IsOpen; } }
Ngoài ra ta cũn xõy dựng một hàm java khỏc để xỏc định trạng thỏi của nguồn sỏng để từ đú ta cú thể xỏc định được là khi ấn cụng tắc nguồn sỏng được tắt hay là bật.
6, Ghế
Chiếc ghế đợc xây dựng từ các đối t- ợng hình học cơ bản : hộp, trụ, cầu.
DEF chair Transform { rotation 0 1 0 -1.57
children [ DEF ps1 PlaneSensor { autoOffset TRUE offset 0 0 0 maxPosition 0 0 minPosition -40 0 }
DEF Trenghe Transform { }
DEF Trenghe Transform { children [
DEF Quay CylinderSensor { autoOffset TRUE maxAngle 0 minAngle 1 diskAngle 0.2 enabled TRUE } ]
ROUTE Quay.rotation_changed TO Trenghe.rotation }
]
ROUTE ps1.translation_changed TO chair.translation }
ghế đợc định nghĩa làm hai phần : trên ghế và chân ghế. Phần trên ghế có thể quay quanh trục, cả chiếc ghế có thể di đợc trên một trục nằm ngang.
7,Bàn học:
DEF banhoc Transform { }
DEF ngankeo Transform { rotation 0 1 0 -1.57 translation -2 0 -25 children [ Inline { url "ngankeo.wrl" } ] }
Bàn có các ngăn kéo có thể kéo ra vào.
Trờn đõy là một số đối tượng cơ bản trong VRML, ngoài ra khi xõy dựng nhà C14- 15 thỡ em xõy dựng theo nguyờn tắc cơ bản sau đõy :Đầu tiờn xỏc định toa độ cần đặt tõm để cho việc đặt cỏc phũng vào được một cỏch dễ dàng. Ở đõy ta đặt tõm tại gúc ngoài cựng bờn trỏi của phũng 102. Nguyờn tắc xõydựng cơ bản là : Đầu tiờn ta xõy dựng bộ khung của nú. Sau đú mới xõy dựng cỏc phũng và đặt cỏ phũng vào vị trớ chớnh xỏc.
Khi xõy dựng một phũng dầu tiờn ta xỏc định cỏc đối tượng cơ bản trong phũng là