-- Navigation: a walkable mesh baked from Sponza's floor, a path traced along the nave round the -- columns (drawn as a chain of thin posts), and six Foxes wandering between random points on the -- mesh without walking through the columns or each other (onNavArrived sends each to a new spot). local font = fontLoad("Singe/FreeSansBold.ttf", 28) local frames = 0 fontSelect(font) sceneEnable(true) sceneSetBackground(120, 150, 200, 255) sceneSetAmbient(120, 126, 150) sceneSetShadowSize(2048) local model = modelLoad("testScripts/Models/Sponza.glb") local sponza = modelInstance(model) local sun = lightNew(LIGHT_DIRECTIONAL) nodeSetPosition(sun, 5, 22, 4) nodeLookAt(sun, -2, 0, -1.5) lightSetIntensity(sun, 4.5) lightSetColor(sun, 255, 236, 205) lightSetShadow(sun, true) -- The mesh: an agent 0.4 wide and 1.6 tall that climbs 0.3 and walks slopes to 45 degrees. local nav = navNew(0.4, 1.6, 45, 0.3) navAddNode(nav, sponza) navBuild(nav) -- The path from one end of the nave to the other, as posts at its corners and along its legs. local marker = materialNew() materialSetColor(marker, 255, 60, 40) materialSetEmissive(marker, 120, 20, 10) local path = navPath(nav, 11, 0.2, 0, -11, 0.2, 0) local pathPosts = 0 if path then for i = 1, #path do local post = nodeNew() nodeSetMesh(post, meshCylinder(0.08, 0.6, 8), marker) nodeSetPosition(post, path[i][1], path[i][2] + 0.3, path[i][3]) pathPosts = pathPosts + 1 if i < #path then local dx, dy, dz = path[i + 1][1] - path[i][1], path[i + 1][2] - path[i][2], path[i + 1][3] - path[i][3] local length = math.sqrt(dx * dx + dy * dy + dz * dz) for s = 1, math.floor(length / 0.8) do local t = s * 0.8 / length local p = nodeNew() nodeSetMesh(p, meshSphere(0.06, 8), marker) nodeSetPosition(p, path[i][1] + dx * t, path[i][2] + dy * t + 0.1, path[i][3] + dz * t) end end end end -- The Foxes, each an agent sent to a random point and, when it arrives, to another. local foxModel = modelLoad("testScripts/Models/Fox.glb") local agents = {} local foxes = {} for i = 1, 6 do local fox = modelInstance(foxModel) nodeSetScale(fox, 0.01) local x, y, z = navRandomPoint(nav) nodeSetPosition(fox, x, y, z) animationPlay(fox, "Walk", true) local agent = navAgentNew(nav, fox, 0.35, 1.0, 1.4) local tx, ty, tz = navRandomPoint(nav) navAgentMoveTo(agent, tx, ty, tz) agents[agent] = fox foxes[i] = fox end function onNavArrived(agent) local x, y, z = navRandomPoint(nav) navAgentMoveTo(agent, x, y, z) end local camera = nodeNew() cameraSet(camera) cameraSetPerspective(60, 0.05, 100) local stops = { { 10, 3, 0, -10, 0.5, 0 }, -- Down the nave along the path { 0, 5.5, 1, 0, 0.3, -6 }, -- From the gallery height over the atrium, the Foxes about { 4, 1.2, 0.5, -6, 0.6, 0.5 }, -- Low along the nave among them { -9, 1.6, 0.3, 8, 0.4, 0 }, -- From the far end back along the path } function onOverlayUpdate() local stop = stops[math.min(#stops, math.floor(frames / 45) + 1)] frames = frames + 1 nodeSetPosition(camera, stop[1], stop[2], stop[3]) nodeLookAt(camera, stop[4], stop[5], stop[6]) overlayClear() fontPrint(20, 20, string.format("Navigation, frame %d path corners %d", frames, pathPosts)) if frames == 40 or frames == 85 or frames == 130 or frames == 175 then singeScreenshot() for agent, fox in pairs(agents) do local x, y, z = nodeGetWorldPosition(fox) local vx, vy, vz = navAgentGetVelocity(agent) debugPrint(string.format("frame %d agent %d at %.1f %.1f %.1f moving %.2f %.2f", frames, agent, x, y, z, vx, vz)) end end if frames == 180 then singeQuit() end end