Insipred by this question and the corresponding answer I've written a code for full-screen exploration of 3D scenes using standard WASD and mouse look controls. Here it is.
Begin["wasd`"];
prmWORLDWIDTH = 300;
prmVIEWERHEIGHT = 2.5;
prmMOUSESENS = 0.01;
prmKEYSENS = 2;
pos = {-146.2715891902948`, -154.52068004641723`, 2.5`}(*{0.,-200,prmVIEWERHEIGHT}*);
moveDir = {0.6365371822219685`, 0.7712460149971068`, 0.`}(*{0,1,0}*);
viewDir = moveDir;
strafeDir = {0.7712460149971068`, -0.6365371822219685`, 0.`}(*{1,0,0}*);
cube = {Gray, EdgeForm[None],
CapForm[None], Tube[{{-150, -150, 0}, {-50, 0, 0}, {50, 0, 0}}, 20
],
Blue // Lighter,
Translate[
ExampleData[{"Geometry3D", "SpaceShuttle"}, "PolygonObjects"]~
Scale~3, {0, 0, 6}]
};
floor = {
Texture@ExampleData[{"ColorTexture", "GreenMarble"}],
EdgeForm@None,
Polygon[{{-w, -w, 0}, {-w, w, 0}, {w, w, 0}, {w, -w, 0}},
VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]
} /. w -> prmWORLDWIDTH;
rotTrans := Function[x, Evaluate[RotationTransform[x, {0., 0., 1.}]]];
mp0 = MousePosition[];
getMouseOffset := (mousePos = MousePosition[];
{mouseDx, mouseDy} = mousePos - mp0;
mp0 = mousePos;
);
processMouse := (getMouseOffset;
viewDir =
RotationTransform[-prmMOUSESENS mouseDy, strafeDir]@viewDir;
{moveDir, strafeDir, viewDir} =
rotTrans[-prmMOUSESENS mouseDx] /@ {moveDir, strafeDir, viewDir};
);
processKeyboard := Switch[CurrentValue["EventKey"],
"w", pos += prmKEYSENS moveDir,
"s", pos -= prmKEYSENS moveDir,
"a", pos -= prmKEYSENS strafeDir,
"d", pos += prmKEYSENS strafeDir
];
actions = {
"MouseMoved" :> processMouse,
"KeyDown" :> processKeyboard
};
hideMouse[expr_] :=
MouseAppearance[expr, Graphics[{[email protected], Point@{0, 0}}]];
nb = MessageDialog[
Dynamic@EventHandler[
hideMouse@
Style[
Graphics3D[{cube, floor},
ViewVector -> {pos, pos + viewDir},
ViewRange -> {0.1, 300},
Lighting -> "Neutral",
Boxed -> False,
ImageSize -> Full,
Background -> LightBlue,
PlotRangePadding -> 0
],
Selectable -> False,
Editable -> False
],
actions
],
CellMargins -> 0,
ShowCellBracket -> False,
ShowCellLabel -> False,
"TrackCellChangeTimes" -> False,
WindowElements -> {},
WindowFrame -> "Normal",
WindowSize -> Full,
WindowMargins -> Automatic,
WindowTitle -> "WASD"
];
SetOptions[nb, NotebookEventActions -> actions];
End[];
To implement 'pure' full screen look I used this answer.
Though I'm pretty satisfied with the result there are some issues here which require tweaking.
Since mouse offset events are implemented using
MousePosition
it is quite easy to get mouse look stucked (e.g. when you try to turn around). This happens when hidden mouse cursor hits screen borders. So, how to correctly handle mouse offset events?It is impossible to move diagonally because
KeyDown
events do not handle simultaneous keystrokes. Can something be done with this?The duplication of event handlers at the end (
SetOptions[nb, NotebookEventActions -> actions]
) does not seem logical to me, but without itKeyDown
events do not work. Why?hideMouse
hack is what I discussed here. Unfortunately the elegant constructionMouseAppearance[expr, Spacer[0]]
proposed by Mike does not work on v. 8.0.4 and WinXP and Win7.And finally are there any possibilities for speeding this up?
Graphics3D[{ Cylinder[], Sphere[{0, 0, 2}], Line[{{-2, 0, 2}, {2, 0, 2}, {0, 0, 4}, {-2, 0, 2}}], Yellow, Cuboid[{-2, -2, -2}, {2, 2, -1}], }]
For example would it be easy to create a function of the formwasd[gr_]
. I thinking of starting such a question. $\endgroup$