-- The Khronos Sponza atrium, packed with util/packGlb.py from the glTF-Sample-Models 2.0 Sponza. -- A warm sun falls through the roof opening onto the atrium floor with hard shadows, braziers along the nave -- add pools of firelight with particle flames and smoke, each crackling from where it stands (the -- listener is the camera), and dust drifts in the sunbeams; the camera walks the ground floor, -- crosses the atrium, climbs to the gallery, then passes the columns. 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) sceneSetBloom(1.2, 0.25) local model = modelLoad("testScripts/Models/Sponza.glb") local sponza = modelInstance(model) -- The sun: high and warm so it falls through the roof opening onto the atrium floor. 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) -- Braziers: warm point lights along the nave, the two nearest the camera path casting shadows, -- each with a flame and a thread of smoke. local fire = materialNew() materialSetColor(fire, 60, 40, 30) local crackle = soundLoad("testScripts/crackle.wav") local braziers = {} for i, p in ipairs({ { 6.5, 1.1, -2.2 }, { 6.5, 1.1, 2.2 }, { -6.5, 1.1, -2.2 }, { -6.5, 1.1, 2.2 }, { 0, 1.1, -2.4 }, { 0, 1.1, 2.4 } }) do local bowl = nodeNew() nodeSetMesh(bowl, meshCylinder(0.35, 0.25, 12), fire) nodeSetPosition(bowl, p[1], p[2] - 0.15, p[3]) local glowNode = nodeNew() nodeSetPosition(glowNode, p[1], p[2] + 0.35, p[3]) local lamp = lightNew(LIGHT_POINT) nodeSetParent(lamp, glowNode) lightSetColor(lamp, 255, 170, 80) lightSetIntensity(lamp, 6) lightSetRange(lamp, 12) lightSetShadow(lamp, i <= 2) local flame = emitterNew(glowNode) emitterSetBlend(flame, PARTICLE_ADD) emitterSetRate(flame, 60) emitterSetLife(flame, 0.4, 0.8) emitterSetSpeed(flame, 0.5, 1.1) emitterSetDirection(flame, 0, 1, 0) emitterSetSpread(flame, 18) emitterSetSize(flame, 0.22, 0.04, 0.15) emitterSetColor(flame, 255, 190, 90, 255, 255, 60, 0, 0) emitterSetRadius(flame, 0.1) emitterStart(flame) local smoke = emitterNew(glowNode) emitterSetRate(smoke, 12) emitterSetLife(smoke, 2.5, 4) emitterSetSpeed(smoke, 0.4, 0.7) emitterSetDirection(smoke, 0, 1, 0) emitterSetSpread(smoke, 12) emitterSetSize(smoke, 0.15, 0.8, 0.15) emitterSetColor(smoke, 90, 80, 75, 90, 50, 45, 45, 0) emitterSetSpin(smoke, -25, 25) emitterSetLit(smoke, true) emitterSetSoftness(smoke, 0.4) emitterStart(smoke) local channel = soundPlay(crackle, -1) if channel >= 0 then soundSetNode(channel, glowNode) soundSetRange(channel, 1.5, 14) end braziers[i] = glowNode end -- Dust in the sunbeams over the atrium floor. local air = nodeNew() nodeSetPosition(air, 0, 3, 0) local dust = emitterNew(air) emitterSetRate(dust, 40) emitterSetLife(dust, 5, 8) emitterSetSpeed(dust, 0.05, 0.25) emitterSetSpread(dust, 180) emitterSetSize(dust, 0.05, 0.05) emitterSetColor(dust, 255, 240, 210, 0, 255, 240, 210, 190) emitterSetRadius(dust, 5) emitterSetMax(dust, 400) emitterStart(dust) emitterBurst(dust, 300) local camera = nodeNew() cameraSet(camera) cameraSetPerspective(65, 0.05, 100) local stops = { { 10, 1.6, 0, -10, 2.5, 0 }, -- Ground floor, along the nave past the braziers { 1.2, 1.6, 5.2, -1, 3.5, -5 }, -- Across the atrium toward the far arcade { -9, 5.5, -1, 6, 3, 1 }, -- From the upper gallery { 5, 1.2, -1.5, -8, 2, 1.5 }, -- Low, past the columns and a brazier } 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, "Sponza, frame " .. frames) if frames == 40 or frames == 85 or frames == 130 or frames == 175 then singeScreenshot() local total, drawn, calls, textureKB = sceneGetStats() debugPrint(string.format("frame %d draws %d in view %d calls %d texture %d KB", frames, total, drawn, calls, textureKB)) for channel = 0, 5 do local x, y, z, gain = soundGetPosition(channel) debugPrint(string.format("frame %d brazier channel %d at %.1f %.1f %.1f gain %.2f", frames, channel, x, y, z, gain)) end end if frames == 180 then singeQuit() end end