HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /home/panomity.de/vr.panomity.com/plugins/depthmap_navigation.xml
<krpano>
	
	<!--
		depthmap_navigation.xml
		krpano 1.21
		
		https://krpano.com/plugins/xmlextensions/#depthmap_navigation
	
		Depthmap Navigation Controls
		- Arrow-keys or WASD-keys or Middle/Right-Mousebutton Navigation on Desktop
		- On-Screen-Touchpad for Mobile Devices
		- VR-Controller Joystick/Touchpad support for WebVR
		- Optional Depthmap/3D-Model Hit/Collision-Detection
		
		Keyboard Keys:
		- Arrow/WASD for forward/backward/left/right moving
		- holding SHIFT for faster movement
		- Q for moving up
		- Y or Z for moving down
		- F for toggling between walking and flying
		- C for toggling collision / groundcollision on/off
		
		Mouse:
		- Left-Mousebutton: normal looking around / rotating
		- Left+SHIFT or Middle- and Right-Mousebutton: moving around
		- Holding the ALT, CTRL or SHIFT-key: moving up and down
		- In Dollhouse-mode the moving around/up-down controls are swapped
		
		Settings:
		- movemode = "walking" or "flying"
		- touchmode = "shift" or "move" - the onscreen-touchpad movement mode
		- speed = movement speed
		- friction = movement friction
		- collision = collision-detection / stop on walls
		- groundcollision = collision-detection with the ground, enables gravity
		- usevrfloorlevel = use the real physical height in VR
		- eyelevel - the distance in cm between the ground/floor and the eyes/camera
		- collisionlevel - the height in cm where the collision checking should be done
		- smoothlevelchanges - a factor for smoothing level/height changes
		- stopdistance = keep this distance in cm to walls/surfaces
		- moveback = when hitting a wall, move back x times
		- bounceback = when hitting a wall, add a bounce movement
	-->
	
	<depthmap_navigation
			movemode="walking"
			touchmode="shift"
			speed.number="0.5"
			friction.number="0.9"
			collision.bool="true"
			groundcollision.bool="false"
			usevrfloorlevel.bool="false"
			eyelevel.number="160.0"
			collisionlevel.number="100.0"
			smoothlevelchanges.number="0.15"
			stopdistance.number="30.0"
			moveback.number="1.2"
			bounceback.number="1.6"
			/>


	<!-- remove the default keyboard controls -->
	<control keycodesleft="" keycodesright="" keycodesup="" keycodesdown="" />

	<!-- keyboard keycodes -->
	<keyb up="38" down="40" left="37" right="39" w="87" a="65" s="83" d="68" shift="16" ctrl="17" space="32" pageup="33" pagedown="34" />
	
	<!-- state variables for walking/flying -->
	<walkaround forward.int="0" backward.int="0" left.int="0" right.int="0" up.int="0" down.int="0" faster.int="0" jump.int="0" relativespeed.bool="false" />
	
	<!-- keyboard event handling -->
	<events name="depthmap_navigation" keep="true"
		onkeydown="depthmap_handlekey(1);"
		onkeyup="depthmap_handlekey(0);"
		/>
	
	<action name="depthmap_handlekey" args="keypressed" scope="local">
		if( keycode == keyb.up    OR keycode == keyb.w, copy(walkaround.forward,  keypressed);
		  , keycode == keyb.down  OR keycode == keyb.s, copy(walkaround.backward, keypressed);
		  , keycode == keyb.left  OR keycode == keyb.a, copy(walkaround.left,     keypressed);
		  , keycode == keyb.right OR keycode == keyb.d, copy(walkaround.right,    keypressed);
		  , keycode == keyb.shift,                      copy(walkaround.faster,   keypressed);
		  , keycode == keyb.space,                      copy(walkaround.jump,     keypressed);
		  , keycode == charcode('F') AND keypressed == 0,         switch(depthmap_navigation.movemode, 'walking', 'flying'); depthmap_showinfo(('Mode: ' + capitalize(depthmap_navigation.movemode)));
		  , keycode == charcode('C') AND keypressed == 0,         switch(depthmap_navigation.collision); depthmap_showinfo(('Collision: ' + (depthmap_navigation.collision ? 'On' : 'Off')));
		  , keycode == charcode('Q'),                             copy(walkaround.up,       keypressed);
		  , keycode == charcode('Y') OR keycode == charcode('Z'), copy(walkaround.down,     keypressed);
		);
	</action>
	
	
	<!-- walking/flying controls -->
	<action name="depthmap_walkaroundmovement" autorun="onstart" type="Javascript"><![CDATA[
		
		function CLAMP(v,vmin,vmax){ return v < vmin ? vmin : v > vmax ? vmax : v; };

		var mouse = krpano.mouse;
		var view = krpano.view;
		var dir = view.dir;
		var settings = krpano.depthmap_navigation
		var walkaround = krpano.walkaround;
		
		var vx=0, vy=0, vz=0;
		var rx=0;
		var touchpad_last_axis = [[0,0],[0,0]];
		var touchpad_move_speed = 5.0;
		var touchpad_rotate_speed = 1.5;
		var joystick_move_speed = 1.0;
		var joystick_rotate_speed = 1.0;
		var jumping = false;
		var lasttick = krpano.timertick;
		
		
		krpano.actions.renderloop( function()
		{
			var tick = krpano.timertick;
			var dt = tick - lasttick;
			lasttick = tick;
			
			var webvr = krpano.webvr;
			var friction = settings.friction;
			var acceleration = 1.0;
			var inertia = 1.0;
			var smoothlevelchanges = settings.smoothlevelchanges;
			var ty_raycast_offset = 0.0;
			
			var do_ground_collision = (settings.collision && settings.groundcollision && settings.movemode == "walking" && view.oz < 200);
				
			if (do_ground_collision)
			{
				ty_raycast_offset = settings.eyelevel - settings.collisionlevel;
			}
			
			// adjust the friction and acceleration depending on the framerate (an experimental API)
			if (krpano.display.getAdaptiveFrictions)
			{
				var adjustedmovment = krpano.display.getAdaptiveFrictions(friction, acceleration/friction, inertia, "fast");
				friction = adjustedmovment.friction;
				acceleration = adjustedmovment.accel * friction;
				inertia = adjustedmovment.inertia;
			}
			
			vx *= friction;
			vy *= friction;
			vz *= friction;
			rx *= friction;
			
			if (vx*vx + vy*vy + vz*vz < 0.001)
				vx = vy = vz = 0;
				
			if (rx*rx < 0.01)
				rx = 0;
			
			var h = view.hlookat * Math.PI / 180.0;
			var v = view.vlookat * Math.PI / 180.0;
			
			// 2D direction vector (walking)
			var lx2 = Math.sin(h);
			var lz2 = Math.cos(h);
			
			// 3D direction vector (flying)
			var lx3 = dir.x;
			var ly3 = dir.y;
			var lz3 = dir.z;
			
			var wx = walkaround.right - walkaround.left;
			var wz = walkaround.forward - walkaround.backward;
			var wy = walkaround.up - walkaround.down;
			
			// handle the touchpad or joystick input from the vr-controllers
			var vrcontroller = (webvr && webvr.enabled) ? webvr.vrcontroller : null;
			if (vrcontroller)
			{
				var vrcontroller_count = vrcontroller.length;
				for (var i=0; i < vrcontroller_count; i++)
				{
					var controller = vrcontroller[i];
					var axes = controller.axes;
					
					if (axes)
					{
						// when having a depthmap: move around (1), otherwise only rotate the pano (0)
						var controlmode = (krpano.display.havedepthmap || krpano.display.depthbuffer) ? 1 : 0;
					
						// when having two controllers use the touchpad/joystick from the right one only for rotating
						if (vrcontroller_count == 2 && controller.hand == "right")
							controlmode = 0;
						
						// joystick or touchpad?
						var y_axis_scale = +1.3;
						var is_touchpad = false;
						
						if (controller.id == "Daydream Controller" || controller.id == "Oculus Go Controller")
						{
							is_touchpad = true;
						}
						else if(controller.id == "OpenVR Gamepad")	// HTC Vive Controller
						{
							is_touchpad = true;
							y_axis_scale *= -1.0;
						}
						
						if (webvr.iswebxr)
						{
							// WebXR: axes[0,1] = touchpad, axes[2,3] = thumbstick
							if ( axes[0] != 0 || axes[1] != 0 )
							{
								is_touchpad = true;
							}
							else
							{
								// thumbstick - map axes for further processing
								axes = [axes[2],axes[3]];
							}
						}
						
						if (do_ground_collision)
						{
							var buttons = controller.buttons;
							
							// use buttons on the VR controllers for running and jumping
							if (controller.hand == "left")
							{
								walkaround.faster = buttons[0] && buttons[0].pressed ? +1 : 0;
							}
							else if (controller.hand == "right")
							{
								walkaround.jump = buttons[4] && buttons[4].pressed ? +1 : 0;
							}
						}
						 
						if (is_touchpad)
						{
							//  special touchpad control (swiping like)
							
							if (axes[0] != 0 && axes[1] != 0)
							{
								var dx = +(axes[0] - touchpad_last_axis[i][0]);
								var dz = -(axes[1] - touchpad_last_axis[i][1]) * y_axis_scale;
								touchpad_last_axis[i][0] = axes[0];
								touchpad_last_axis[i][1] = axes[1];
								
								if (Math.abs(dx) > 0.3) dx = 0;		// too fast changes are probably no swipes
								if (Math.abs(dz) > 0.3) dz = 0;
								
								if (controlmode == 0)	// rotate
								{
									rx += touchpad_rotate_speed * dx * acceleration;
								}
								else	// move
								{
									vx += touchpad_move_speed * ( dx*lz2 + dz*lx2) * acceleration;
									vz += touchpad_move_speed * (-dx*lx2 + dz*lz2) * acceleration;
								}
							}
						}
						else
						{
							// joystick - direct control

							if (controlmode == 0)	// rotate
							{
								if (Math.abs(axes[0]) > 0.2)
								{
									rx = joystick_rotate_speed * axes[0] * acceleration;
								}
							}
							else	// move
							{
							 	// ignore too small values, some vr-controllers, e.g. Windows MR ones, are constantly reporting small wrong values
								if ( Math.abs(axes[0]) > 0.2 ) wx += joystick_move_speed * axes[0] * acceleration;
								if ( Math.abs(axes[1]) > 0.2 ) wz -= joystick_move_speed * axes[1] * acceleration;
							}
						}
					}
				}
			}
			
			var wl = Math.sqrt(wx*wx + wz*wz);
			if (wl > 0)
			{
				if (walkaround.relativespeed)
				{
					wl *= acceleration * settings.speed;
				}
				else
				{
					// normalize the moving speed
					wl = acceleration * settings.speed / wl;
				}
				
				if (walkaround.faster > 0)
					wl *= 3.0;
					
				wx *= wl;
				wz *= wl;
				if (wx)
				{
					vx += wx*lz2;
					vz -= wx*lx2;
				}
				if (wz)
				{ 
					if (settings.movemode == "flying")
					{
						vx += wz*lx3;
						vz += wz*lz3; 
						vy += wz*ly3;
					}
					else
					{
						vx += wz*lx2;  
						vz += wz*lz2; 
					}
				}
			}
			
			if (do_ground_collision == false)
			{
				// move up or down
				vy -= 0.5 * acceleration * settings.speed * wy;
			}
			
			if ((mouse.leftbutton && mouse.shiftkey) || mouse.middlebutton || mouse.rightbutton)
			{
				var is_dollhouse_view = (view.oz > 100);
				var extrakey = mouse.ctrlkey | mouse.altkey;
				
				var dragspeed = (is_dollhouse_view ? 0.1 : 0.05) * acceleration;
				var dx = -dragspeed * mouse.dx;
				var dy = (extrakey ^ is_dollhouse_view) ? +dragspeed * mouse.dy : 0;
				var dz = (extrakey ^ is_dollhouse_view) ? 0 : +dragspeed * mouse.dy;
				
				vx += dx*dir.rx + dy*dir.ux + dz*dir.x;
				vy += dx*dir.ry + dy*dir.uy + dz*dir.y * (settings.movemode == "flying");
				vz += dx*dir.rz + dy*dir.uz + dz*dir.z;
			}
			
			var vspeed = Math.sqrt(vx*vx + vy*vy + vz*vz);
			
			if (vspeed > 0)
			{
				// simple collision testing
				if (settings.collision && view.oz < 200)		// do collision testing only in non-dollhouse-view
				{
					var hit = krpano.actions.raycastdepth(view.tx, view.ty + ty_raycast_offset, view.tz, vx, vy, vz);
					if (hit)
					{
						if (hit.d > 0 && hit.d < settings.stopdistance)
						{
							// slide along walls
							var vlen = Math.sqrt(vx*vx + vy*vy + vz*vz);
							if (vlen > 0)
							{
								var pushback = -(settings.stopdistance - hit.d) / vlen * settings.moveback;
								
								view.tx += pushback * vx;
								view.ty += pushback * vy;
								view.tz += pushback * vz;
								
								var hitscale = (vx*hit.nx + vy*hit.ny + vz*hit.nz) * settings.bounceback;
								
								vx -= hit.nx * hitscale;
								vy -= hit.ny * hitscale;
								vz -= hit.nz * hitscale;
							}
						}
					}
					
					
				}
				
				view.tx += vx;
				view.ty += vy;
				view.tz += vz;
			}
			
			var groundlevel = 0;
			
			if (do_ground_collision)
			{
				var floorlevel = settings.eyelevel;
				var jump_pressed = walkaround.jump || (wy > 0);
				var crouch_pressed = (wy < 0);
				
				if (crouch_pressed)
				{
					floorlevel *= 0.6;
				}
				
				if (webvr && webvr.enabled && settings.usevrfloorlevel && webvr.floorlevel > 0.0)
				{
					// take the real phyiscal floor level
					floorlevel = settings.eyelevel = webvr.floorlevel;
				}
			
				var floorhit = krpano.actions.raycastdepth(view.tx, view.ty, view.tz, 0, +1.0, 0);
				
				if (floorhit && floorhit.d > 0)
				{
					groundlevel = floorhit.y;
					
					
				
					var foot_floor_distance = floorhit.d - floorlevel;
					
					if (Math.abs(foot_floor_distance) < 1.0)
					{
						// on the floor, even out small differences
						view.ty += foot_floor_distance;
						jumping = false;
						vy = 0;
					}
					else if (foot_floor_distance <= 30.0)	// 30.0 = smooth also walking stairs down
					{
						if (jumping == false || vy > 0)
						{
							// below the floor => push up (but smoothed for nicer stairwalks)
							view.ty += foot_floor_distance * smoothlevelchanges;
						}
						
						if (foot_floor_distance <= 1.0)
						{
							jumping = false;
							vy = 0;
						}
					}
					else if (foot_floor_distance > 1.0)
					{
						var gravity = 4.0;
						 
						// in the air => apply gravity
						if (vy < 0.0 && jump_pressed)
						{
							gravity = 1.5;	// use a lower graviy as long as holding the jump key
							jumping = true;
						}
						
						vy += gravity * acceleration;
					}
					
					if (vy == 0 && jump_pressed)
					{
						var jump_inertia = 30.0;
						
						vy -= jump_inertia / inertia;
						
						jumping = true;
					}
				}
				else
				{
					// no floor? maybe below the floor?
					
					// trace a ray upward
					var backup_cull = krpano.image.depthmap.cull;
					krpano.image.depthmap.cull = "twosided";	// use the front- and back-face for hit-testing in this case
					floorhit = krpano.actions.raycastdepth(view.tx, view.ty, view.tz, 0, -1.0, 0);
					krpano.image.depthmap.cull = backup_cull;
					
					if (floorhit && floorhit.d > 0)
					{
						// shift up
						view.ty = floorhit.y - floorlevel;
					}
				}
			}
			
			if (rx != 0 && webvr)
			{
				webvr.hlookatoffset += rx;
			}
		});
	]]></action>
	
	
	
	<!-- some buttons -->
	
	<style name="depthmap_button" type="text" css="text-align:center;" padding="4 8" bgborder="0 0xFFFFFF 1" bgroundedge="1" bgshadow="0 1 4 0x000000 1.0" ondown="set(bgcolor, 0xDDDDDD);" onup="set(bgcolor, 0xFFFFFF);" />
	<style name="depthmap_info" type="text" css="color:#FFFFFF;text-align:center;" bgalpha="0.0" txtshadow="0 1 4 0x000000 1.0" enabled="false" />

	<layer name="moveup" keep="true" style="depthmap_button" html="▲" align="rightbottom" x="20" y="50" ondown="set(walkaround.up,1);"   onup="set(walkaround.up,0);" />
	<layer name="movedn" keep="true" style="depthmap_button" html="▼" align="rightbottom" x="20" y="20" ondown="set(walkaround.down,1);" onup="set(walkaround.down,0);" />

	

	<!-- info texts -->
	<layer name="depthmap_info" keep="true" style="depthmap_info" align="center" y="+25%" html="Walk around using the[br]Keyboard Arrow- or W,A,S,D-keys" 
		onloaded="delayedcall(depthmap_info, 3.0, tween(layer[depthmap_info].alpha,0.0,0.5); );"
		devices="desktop" 
		/>
	
	
	<action name="depthmap_showinfo" scope="local" args="info, time">
		tween(layer[depthmap_info].alpha,1.0,0.1);
		layer[depthmap_info].text = info;
		delayedcall(depthmap_info, 3.0, tween(layer[depthmap_info].alpha,0.0,0.5); );
	</action>
	

	<!-- drag area for touch devices -->
	<layer name="walkinfo_touch" keep="true" type="text" align="bottom"
		y="85"
		html="Hold down here[br]and drag around[br]for walking" bgalpha="0.3" devices="handheld"
		css="color:#FFFFFF;text-align:center;" txtshadow="0 1 4 0x000000 1.0"
		vcenter="true"
		width="140" height="140" bgroundedge="180" bgblur="2"
		ondown="dragcontrol();"
		/>
	
	<events name="walkinfo_touch" keep="true" devices="mobile"
		onresize="if(stagewidth GT stageheight,
					set(layer[walkinfo_touch], align=rightbottom, x=80, y=40);
				  ,
					set(layer[walkinfo_touch], align=bottom, x=0, y=85);
				);
				" 
		/>

	<action name="dragcontrol" scope="local" type="Javascript"><![CDATA[
		krpano.actions.tween(caller.path+".alpha",0.0);
		krpano.actions.asyncloop( function()
		{	
			if (caller.pressed)
			{
				if(krpano.depthmap_navigation.touchmode == 'move')
				{
					krpano.walkaround.relativespeed = true;
					var dx = (krpano.mouse.x - krpano.mouse.downx);
					var dy = (krpano.mouse.y - krpano.mouse.downy);
					var dl = Math.sqrt(dx*dx + dy*dy);
					if (dl > 0)
					{
						dx /= dl;
						dy /= dl;
						dl = Math.min(dl,120) / 70;
						dl = dl < 1.0 ? Math.pow(dl, 0.5) : Math.pow(dl, 1.1);
					}
					
					krpano.walkaround.forward = -dy * dl;
					krpano.walkaround.left    = -dx * dl;
				}
				else 
				{
					krpano.walkaround.relativespeed = false;
					krpano.walkaround.forward = krpano.mouse.dy * -0.25;
					krpano.walkaround.left    = krpano.mouse.dx * -0.25;
				}
				
				return true;	// keep looping
			}
			else
			{
				krpano.walkaround.left = 0;
				krpano.walkaround.forward = 0;
				krpano.actions.tween(caller.path+".alpha",1);
				
				return false;	// stop the loop
			}
		});
	]]></action>
	
</krpano>