3Dオブジェクトでマウスのイベントを起こす
3Dオブジェクトとマウスカーソルとの関係性を作ります。
ヒエラルキーからchara->Modelを選択。
ADD COMPONENTからScriptを選択し、hotspotのscriptを登録します。
このModelを一つずつ選択する動作は面倒ですが、複数選択して設定を行うこともできます。
hotspotの中身をコードエディターで開きます。
配置された3Dオブジェクトとマウスカーソルとの関係を持たせるにはレイキャストと呼ばれるものを使用します。
レイキャストとは、特定の地点から特定の方向へ直線の線を引き、その線上のどこかでぶつかるものがあるか検知するものです。
ここでのレイキャストは、「マウスがクリックされた時、カメラから見て、3Dオブジェクトとそのマウスカーソルが重なっているか」を取得するような処理を作ります。
ここから以下の処理を追加していきます
- 3Dオブジェクトにレイキャストの線が当たるヒットエリアを作成
- 使用するカメラのEntityとヒットエリアの大きさをAttributesでEditorから設定
- ヒットエリアにマウスホバーしてイベントが取れる
以下のコードをhotspot.jsに書き換えます。
varHotspot=pc.createScript('hotspot');Hotspot.attributes.add("cameraEntity",{type:"entity",title:"Camera Entity"});// カメラのEntityを取得Hotspot.attributes.add("radius",{type:"number",title:"Radius"});// Entityのヒットエリアの範囲を指定Hotspot.prototype.initialize=function(){// initthis.hitArea=newpc.BoundingSphere(this.entity.getPosition(),this.radius);// ヒットエリアを作成。BoundingSphereがentityの境界エリアを作成(Photoshopでいうバウンディングボックス的な)this.ray=newpc.Ray();// cameraからentityへ直進する線のデータを作成。(Rayは光線の意でstart pointからentityまでの距離を測ったりすることが可能)this.directionToCamera=newpc.Vec3();// Vector座標の型を取得this.app.mouse.on(pc.EVENT_MOUSEMOVE,this.onMouseHover,this);// マウスカーソルがホバーした時};Hotspot.prototype.onMouseHover=function(screenPosition){// マウスホバー時this.cameraEntity.camera.screenToWorld(screenPosition.x,screenPosition.y,this.cameraEntity.camera.farClip,this.ray.direction);// ポジションを2Dスクリーンから3D空間へ変換this.ray.origin.copy(this.cameraEntity.getPosition());// レイのオリジナルのポジションにカメラのポジションをコピーthis.ray.direction.sub(this.ray.origin).normalize();// 3次元ベクトルを他の場所から減算し、単位ベクトルに変換if(this.hitArea.intersectsRay(this.ray)){// ヒットエリアとレイが交差した場合console.log("hover");}};
新しくattributesというのが言葉がありますが、これは属性設定ができ、PlayCanvasのEditorからデータを変更することができるようになります。
ここではカメラのEntityの選択と、対象の3Dオブジェクトのヒットエリアの大きさを指定できます。
Hotspot.attributes.add("cameraEntity",{type:"entity",title:"Camera Entity"});// カメラのEntityを取得Hotspot.attributes.add("radius",{type:"number",title:"Radius"});// Entityのヒットエリアの範囲を指定
以下画像のように入力エリアが表示されていない場合は、Editアイコン横のParseで更新され表示されます。
initializeではヒットエリア、レイキャストのRayの設定、マウス移動のイベントを取得しています。
Hotspot.prototype.initialize=function(){this.hitArea=newpc.BoundingSphere(this.entity.getPosition(),this.radius);// ヒットエリアを作成。BoundingSphereがentityの境界エリアを作成(Photoshopでいうバウンディングボックス的な)this.ray=newpc.Ray();// 直進する線のデータを作成。(Rayは光線の意でstart pointからentityまでの距離を測ったりすることが可能)this.app.mouse.on(pc.EVENT_MOUSEMOVE,this.onMouseHover,this);// マウスカーソルがホバーした時};
マウス移動のイベントで3Dオブジェクトとカメラから見てホバーしているかonMouseHoverで取得しています。
Hotspot.prototype.onMouseHover=function(screenPosition){// マウスホバー時this.cameraEntity.camera.screenToWorld(screenPosition.x,screenPosition.y,this.cameraEntity.camera.farClip,this.ray.direction);// ポジションを2Dスクリーンから3D空間へ変換this.ray.origin.copy(this.cameraEntity.getPosition());// レイのオリジナルのポジションにカメラのポジションをコピーthis.ray.direction.sub(this.ray.origin).normalize();// 3次元ベクトルを他の場所から減算し、単位ベクトルに変換if(this.hitArea.intersectsRay(this.ray)){// ヒットエリアとレイが交差した場合console.log("hover");}};
マウス移動のイベントで3Dオブジェクトとカメラから見てホバーしているかonMouseHoverで取得しています。
これでマウスオーバー(ホバー)のイベントを取得できました。
次はクリックのイベントです。
initializeに以下を追加
this.app.mouse.on(pc.EVENT_MOUSEDOWN,this.onMouseDown,this);// クリックが押された時
クリックイベントの左クリックを取得
Hotspot.prototype.onMouseDown=function(event){// クリックが押されている時if(event.button==pc.MOUSEBUTTON_LEFT){// 左クリックが押された時this.doRayCast(event);// レイキャストを呼ぶ}};
クリックしたらレイキャストを走らせる
Hotspot.prototype.doRayCast=function(screenPosition){// レイキャスト処理(ある地点から特定方向に直線で線を引いて、その線上で物体があるか検知する処理)if(this.hitArea.intersectsRay(this.ray)){// ヒットエリアとレイが交差した場合console.log("click!!");}};
Launch画面をリロードしてコンソールから確認ができます。
ここまでのコードは以下になります。(hotspot.js)
varHotspot=pc.createScript('hotspot');// canvasのclickやhoverなどの処理を行うHotspot.attributes.add("cameraEntity",{type:"entity",title:"Camera Entity"});// カメラのentityを取得Hotspot.attributes.add("radius",{type:"number",title:"Radius"});// entityのヒットエリアの範囲を指定Hotspot.prototype.initialize=function(){// initthis.hitArea=newpc.BoundingSphere(this.entity.getPosition(),this.radius);// ヒットエリアを作成。BoundingSphereがentityの境界エリアを作成(Photoshopでいうバウンディングボックス的な)this.ray=newpc.Ray();// cameraからentityへ直進する線のデータを作成。(Rayは光線の意でstart pointからentityまでの距離を測ったりすることが可能)this.directionToCamera=newpc.Vec3();// Vector座標の型を取得this.app.mouse.on(pc.EVENT_MOUSEMOVE,this.onMouseHover,this);// マウスカーソルがホバーした時this.app.mouse.on(pc.EVENT_MOUSEDOWN,this.onMouseDown,this);// クリックが押された時};Hotspot.prototype.doRayCast=function(screenPosition){// レイキャスト処理(ある地点から特定方向に直線で線を引いて、その線上で物体があるか検知する処理)if(this.hitArea.intersectsRay(this.ray)){// ヒットエリアとレイが交差した場合console.log("click!!");}};Hotspot.prototype.onMouseHover=function(screenPosition){// マウスホバー時this.cameraEntity.camera.screenToWorld(screenPosition.x,screenPosition.y,this.cameraEntity.camera.farClip,this.ray.direction);// ポジションを2Dスクリーンから3D空間へ変換this.ray.origin.copy(this.cameraEntity.getPosition());// レイのオリジナルのポジションにカメラのポジションをコピーthis.ray.direction.sub(this.ray.origin).normalize();// 3次元ベクトルを他の場所から減算し、単位ベクトルに変換if(this.hitArea.intersectsRay(this.ray)){// ヒットエリアとレイが交差した場合console.log("hover");}};Hotspot.prototype.onMouseDown=function(event){// クリックが押されている時if(event.button==pc.MOUSEBUTTON_LEFT){// 左クリックが押された時this.doRayCast(event);// レイキャストを呼ぶ}};
次は3Dオブジェクトに応じてHTMLのページを表示させるようにします。