-- Terrain: rolling hills from a heightmap image (testScripts/hills.png from util/makeHills.py) -- with a tiled ground texture, under the sky with fog; the dragon stands on a slope placed by -- terrainGetHeight, and crates dropped on the hills tumble down them on the height field body. local font = fontLoad("Singe/FreeSansBold.ttf", 28) local frames = 0 fontSelect(font) sceneEnable(true) sceneSetSky("testScripts/sky.png") sceneSetFog(190, 200, 215, 40, 160) sceneSetShadowSize(2048) sceneSetShadowDistance(80) local ground = materialNew() materialSetTexture(ground, "testScripts/brick.ktx2") materialSetTiling(ground, 24, 24) materialSetRoughness(ground, 0.95) local hills = nodeNew() nodeSetMesh(hills, meshHeightmap("testScripts/hills.png", 120, 14, 120), ground) bodyNew(hills, BODY_STATIC, SHAPE_MESH) -- The dragon, its feet on the slope wherever the terrain is there. local dragon = modelInstance(modelLoad("testScripts/Models/DragonModel.glb")) nodeSetScale(dragon, 0.4) nodeSetPosition(dragon, -8, terrainGetHeight(hills, -8, 3) or 0, 3) nodeSetRotation(dragon, 0, 40, 0) -- Crates dropped along a ridge. local wood = materialNew() materialSetColor(wood, 150, 100, 55) local crates = {} for i = 1, 10 do local crate = nodeNew() nodeSetMesh(crate, meshBox(1, 1, 1), wood) local x, z = -20 + i * 4, -12 nodeSetPosition(crate, x, (terrainGetHeight(hills, x, z) or 0) + 6, z) nodeSetRotation(crate, i * 17, i * 31, 0) bodyNew(crate, BODY_DYNAMIC, SHAPE_BOX, 1, 1, 1) crates[i] = crate end local sun = lightNew(LIGHT_DIRECTIONAL) nodeSetPosition(sun, 30, 40, 20) nodeLookAt(sun, 0, 0, 0) lightSetIntensity(sun, 2.5) lightSetShadow(sun, true) local camera = nodeNew() cameraSet(camera) cameraSetPerspective(55, 0.1, 300) local stops = { { 0, 12, 40, 0, 4, 0 }, -- The hills from the valley's edge { -18, 8, 12, -8, 4, 3 }, -- The dragon on its slope { 4, 10, -2, 0, 3, -14 }, -- The crates on the ridge { 30, 25, 30, 0, 2, 0 }, -- High corner view, fog in the distance } 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]) local x, y, z = nodeGetWorldPosition(crates[5]) local ground = terrainGetHeight(hills, x, z) or 0 overlayClear() fontPrint(20, 20, string.format("Terrain, frame %d crate 5 at %.1f %.1f %.1f, ground %.1f", frames, x, y, z, ground)) if frames == 40 or frames == 85 or frames == 130 or frames == 175 then singeScreenshot() debugPrint(string.format("frame %d crate 5 at %.2f %.2f %.2f ground %.2f", frames, x, y, z, ground)) end if frames == 180 then singeQuit() end end