Physics education app visualizes Magnetic Field for HoloLens
Any teacher can use this app in your classrooms, and any researcher can use this app to write your paper.
We are very welcome to your contribution for education including porting to other platforms (such as Magic Leap One, Oculus Quest, iPad, Pixel3, and many others).
This code is published to help understanding sessions of HoloLens app development in IT Tech conference which is held once a year by Microsoft Japan.
The reason why I published this open-source app is, because I was one of 17 personal sponsors who have Microsoft MVP Award (The Microsoft Most Valuable Professional award is given by Microsoft to "technology experts who passionately share their knowledge with the community.")
The app executes the Physics calculation of each of 500 compasses on every frame, and the FPS is 58.
Specifically, it does not instantiate it's Shader. It executes Physics calculation in the single Shader. As a result, the load is very light.
Furthermore, the reason why the light weight is needed is explained in next subject "UI / Expression".
As the following codes, the Material is not operated by a Script. Valuables are set in the Shader which accept external valuables. They are assigned directly to the Shader by a Script.
CompassesManagedlySimultaneouslyUpdater.cs
void AssignMagnetPosition()
{
var np = barMagnet01NorthPole.transform.position;
var sp = barMagnet01SouthPole.transform.position;
var nv4 = new Vector4(np.x, np.y, np.z, 0); // Convert to Vector4
var sv4 = new Vector4(sp.x, sp.y, sp.z, 0); // Convert to Vector4
// Set coordinates to Shader of Material of NORTH side of compass
CompassesModel.Instance.MatNorth.SetVector("_NorthPolePos", nv4);
CompassesModel.Instance.MatNorth.SetVector("_SouthPolePos", sv4);
// Set coordinates to Shader of Material of SOUTH side of compass
CompassesModel.Instance.MatSouth.SetVector("_NorthPolePos", nv4);
CompassesModel.Instance.MatSouth.SetVector("_SouthPolePos", sv4);
}
As a result, the Shader is not instantiated and processed as a single Shader. That significantly reduces the calculation load.
As the following codes, Physics calculation is executed in a Shader.
// Define position vector of self (compass) as vecP
float3 vecP;
vecP = IN.worldPos;
// Define position vector of NORTH Pole as vecN
float3 vecN;
vecN.x = _NorthPolePos.x;
vecN.y = _NorthPolePos.y;
vecN.z = _NorthPolePos.z;
// Define position vector of SOUTH Pole as vecS
float3 vecS;
vecS.x = _SouthPolePos.x;
vecS.y = _SouthPolePos.y;
vecS.z = _SouthPolePos.z;
// Define displacement vector from self to bar magnet as vecDisN, vecDisS
float3 vecDisN, vecDisS;
vecDisN = vecP - vecN;
vecDisS = vecP - vecS;
// Get magnetic force vectors from two poles as vecF_N, vecF_S
float3 vecF_N, vecF_S;
vecF_N = vecDisN / pow(length(vecDisN), 3);
vecF_S = -1.0 * vecDisS / pow(length(vecDisS), 3);
// Get resultant magnetic force vector as vecF
float3 vecF;
vecF = vecF_N + vecF_S;
As a result, Physics calculation is completed in GPU. It significantly reduces CPU load. Since the CPU power of HoloLens is very weak, it's important to transfer necessary processes to GPU.
More than 300 people in 5 countries at places including 11 schools were practically taken experience lessons / sessions with this app. Learning tests were taken in 3 schools, and all of them gave questionaires (both quantitative and qualitative). These results made the app experience better, and made the learning efficience and satisfaction degree increase. The devices are as followings:
The followings are lesson / session scenes. Appearance of the app was changing, because we improved step by step.
We were asked by The Physics Education Society of Japan to write a paper about these knowledge. We already posted. The detail is going to be put on the journal. We are going to add the link to the paper on publication.
This is the structure figure of the app.
(Drawn with Qt Visual Graph Editor)
We drew simple original structure figure in order to express both class relations and activity flows.
Rolls of classes against a Prefab is followings:
A beginner developer of HoloLens tends to create classes disorderly.
However, when you distinguish handler, model and controller classes against each Prefab, you can design with good prospect easily.
Email, Homepage, Facebook, Twitter, LinkedIn
本アプリは、「de:code 2019」(マイクロソフト社の開発者をはじめとするITに携わるすべてのエンジニアのための年に一度のテクニカルカンファレンス)において、
「Microsoft MVP アワード」(マイクロソフトの製品やテクノロジーに関する豊富な知識や経験を他者と共有することで、すべてのユーザーが最大限に製品を活用できるよう多大なサポートをおこなったコミュニティのリーダーに、マイクロソフトが感謝の意を表して授与する賞)の受賞者として、
セッション内容をより深く理解し実践するのに役に立つコード「パターンを用い、シンプルな UI を提供する、初心者でもできる HoloLens アプリ開発と Microsoft ストアへの登録方法~実際のソースコードと構成図を見ながら~」という位置づけで公開したものです。
500個の方位磁針の個々の物理計算を毎フレームおこないながら、FPS 58を実現しています。
具体的には、シェーダをインスタンス化せずに、シェーダ内で物理計算をおこなって負荷を大幅に減らしています。
なお、軽量化が必要な理由については次項の「UI・表現」で説明します。
以下のように、マテリアルをスクリプトから操作せずに、シェーダに外部変数を受け取る変数を設定し、スクリプトからマテリアルを介さずにシェーダに直接値を代入しています。
CompassesManagedlySimultaneouslyUpdater.cs
void AssignMagnetPosition()
{
var np = barMagnet01NorthPole.transform.position;
var sp = barMagnet01SouthPole.transform.position;
var nv4 = new Vector4(np.x, np.y, np.z, 0); //Vector4 に変換
var sv4 = new Vector4(sp.x, sp.y, sp.z, 0); //Vector4 に変換
// 方位磁針の N 極側のマテリアルのシェーダに座標をセット
CompassesModel.Instance.MatNorth.SetVector("_NorthPolePos", nv4);
CompassesModel.Instance.MatNorth.SetVector("_SouthPolePos", sv4);
// 方位磁針の S 極側のマテリアルのシェーダに座標をセット
CompassesModel.Instance.MatSouth.SetVector("_NorthPolePos", nv4);
CompassesModel.Instance.MatSouth.SetVector("_SouthPolePos", sv4);
}
これによりシェーダがインスタンス化されず、単一のシェーダとして処理されるため、計算負荷を大幅に減らすことができます。
以下のように、シェーダ内で物理計算を行っています。
// 自身(方位磁針)の位置ベクトルvecPを作成
float3 vecP;
vecP = IN.worldPos;
// N極の位置ベクトルvecNを作成
float3 vecN;
vecN.x = _NorthPolePos.x;
vecN.y = _NorthPolePos.y;
vecN.z = _NorthPolePos.z;
// S極の位置ベクトルvecSを作成
float3 vecS;
vecS.x = _SouthPolePos.x;
vecS.y = _SouthPolePos.y;
vecS.z = _SouthPolePos.z;
// 自身から棒磁石に対する変位ベクトルvecDisN、vecDisSを作成
float3 vecDisN, vecDisS;
vecDisN = vecP - vecN;
vecDisS = vecP - vecS;
// 極からの磁力ベクトルvecF_N, vecF_Sを求める
float3 vecF_N, vecF_S;
vecF_N = vecDisN / pow(length(vecDisN), 3);
vecF_S = -1.0 * vecDisS / pow(length(vecDisS), 3);
// 磁力の合力ベクトルvecFを求める
float3 vecF;
vecF = vecF_N + vecF_S;
これにより、物理計算をGPU内で完結させることができ、CPUへの負荷を大幅に減らすことができます。HoloLensのCPUはとても非力なため、必要な処理をどれだけGPUに回せるかが重要です。
本アプリを用いた授業は、5カ国の10の学校で300人が体験しました。全員のアンケート(定量および定性)を収集し、それらを元に、アプリ体験をより良くし学習効果と満足度を上げるために、以下の工夫をおこないました。
操作が安定していない(例えばフォーカスが外れる、マーカートラッキングがしばしば途切れる)と、体験者は不満を感じます。初めて体験するユーザに対するHoloLensアプリは、極めて簡易な操作方法を提供することが望ましいです。
動作が遅いと、体験者は不満を感じるため、動作を可能な限り速くすることが望ましいです。
シェアリングは高次元の体験を提供することができますが、途中で接続が切れた場合の復旧に時間がかかるため、時間にタイトな授業(40人の場合、3分のロスも許されません)には適しません。
これらの知見については日本物理教育学会から研究報告の執筆を依頼され、すでに投稿しました。学会誌に詳細が掲載される予定です。公開され次第リンクに変えます。
本アプリの構成図です。
クラス関係とアクティビティフローを両方表現するために、シンプルな独自の構成図を描きました。
プレハブに対するクラスの役割は以下の通りです。
HoloLensアプリを作成する際は、最初はどうしても無秩序にプレハブやクラスを作ってしまいがちです。
しかし、プレハブごとにハンドラ、モデル、コントローラクラスを作成すると、見通しの良い設計を手軽におこなうことができます。
Email, Homepage, Facebook, Twitter, LinkedIn
© 2019 Feel Physics® All rights reserved.