3D scenes
Build a 3D scene: place meshes, light them, aim the camera, and finish the picture with bloom and fog.
Make a scene and show it
scene.new creates a scene, a 3D world with its own camera, and
Scene:mount shows it in your UI, as a canvas is shown. Y points up,
and a unit is whatever you decide: a meter, a tile, a block.
This program stands three shapes on a floor, lights them from one side, and circles the camera around them:
local color = datumhue.color
local vec3 = datumhue.math.vec3
local quat = datumhue.math.quat
local scene = datumhue.scene.new({
width = 640,
height = 400,
hdr = true,
})
scene:mount({ width = 640, height = 400 })
scene.background = color("#1e2326")
-- A floor and three shapes standing on it.
scene:plane({ scale = vec3(20, 1, 20), color = color("#4f585e") })
scene:cube({ pos = vec3(-1.6, 0.5, 0), color = color("#7fbbb3") })
scene:sphere({ pos = vec3(0, 0.5, 0), color = color("#e67e80") })
scene:torus({
pos = vec3(1.6, 0.6, 0),
rotation = quat.from_euler(math.pi / 2, 0, 0),
material = datumhue.material.standard({
color = color("#dbbc7f"),
roughness = 0.2,
clearcoat = 1,
}),
})
-- Sunlight from above and to one side, casting shadows.
scene:directional_light({
direction = vec3(-0.4, -1, -0.3),
intensity = 8000,
shadows = true,
})
scene.ambient = { color = color("#ffffff"), brightness = 200 }
-- Bright areas glow, and the far floor fades into the dark.
scene.bloom = { intensity = 0.2 }
scene.fog = { color = color("#1e2326"), near = 5, far = 14 }
-- The camera circles the middle of the scene.
local camera = scene.camera
datumhue.on_update(function()
local t = datumhue.time.now() * 0.4
camera.pos = vec3(math.sin(t) * 6, 3, math.cos(t) * 6)
camera:look_at(vec3(0, 0.5, 0))
end)
In this example: datumhue.color datumhue.math.vec3 datumhue.math.quat datumhue.scene.new Scene:mount Scene.background Scene:plane Scene:cube Scene:sphere Scene:torus datumhue.math.quat.from_euler datumhue.material.standard Scene:directional_light Scene.ambient Scene.bloom Scene.fog Scene.camera datumhue.on_update datumhue.time.now SceneCamera.pos SceneCamera:look_at
Place meshes
Scene:cube, Scene:sphere, Scene:plane, Scene:torus and the other
mesh constructors each return a SceneNode, placed by its pos,
rotation and scale. A rotation is a Quat; build one from angles in
radians with math.quat.from_euler. A node stays where you put it until
you change it: assign SceneNode.pos or SceneNode.rotation, or tween
it with SceneNode:animate.
Scene:group gathers nodes under one frame that moves them together.
Scene:model adds a glTF model, and Scene:sprite a flat picture that
turns to face the camera.
Choose a material
A mesh's color gives it a plain surface of that color. For more,
pass a material: material.standard sets how metallic and rough the
surface is, adds a glow of its own with emissive, and wraps it in
textures. material.unlit ignores the lights and shows its color at
full strength. A shader works as a material too, and
like material.unlit it ignores the lights. A shader you write can
instead be the shader of material.standard: the base color of the
material, which the lights shade.
Light it
Scene.ambient lights every surface evenly from all sides, so nothing
is pitch black. Add lights for direction and shadow:
Scene:directional_light shines one way across the whole scene, like
the sun; Scene:point_light shines out from a point, like a bulb; and
Scene:spot_light shines a cone. A light with shadows = true casts
shadows.
Aim the camera
Scene.camera is the scene's one camera. Set SceneCamera.pos, then
call SceneCamera:look_at with the point to aim at. To move the camera
smoothly, set it every frame, as the program does, or tween it with
SceneCamera:animate. SceneCamera:set_orthographic switches to a flat
projection with no perspective, for strategy maps and isometric views.
Finish the picture
Assign a table to Scene.bloom to make bright areas glow, and to
Scene.fog to fade distant things into a color. Assign nil to either
to turn it off again. Scene.background is the color behind
everything, and Scene.vignette, Scene.tonemapping and
Scene.exposure adjust the final image further.
Find what is under the pointer
Scene:screen_to_ray turns a point of the scene's image into a ray from
the camera, and Scene:raycast returns the nearest node that ray hits.
To find the node under the pointer, read the pointer over the mounted
scene with UiElement:mouse_position, and scale it to the image with
UiElement:to_texture_coords first.
See also
- Bodies, joints and collisions, for nodes that fall and collide
- Shaders
- Draw shapes and text
- Coordinates and units
Reference used on this page: datumhue.color datumhue.math.vec3 datumhue.math.quat datumhue.scene.new Scene:mount Scene.background Scene:plane Scene:cube Scene:sphere Scene:torus datumhue.math.quat.from_euler datumhue.material.standard Scene:directional_light Scene.ambient Scene.bloom Scene.fog Scene.camera datumhue.on_update datumhue.time.now SceneCamera.pos SceneCamera:look_at SceneNode.pos SceneNode.rotation SceneNode:animate Scene:group Scene:model Scene:sprite datumhue.material.unlit Scene:point_light Scene:spot_light SceneCamera:animate SceneCamera:set_orthographic Scene.vignette Scene.tonemapping Scene.exposure Scene:screen_to_ray Scene:raycast UiElement:mouse_position UiElement:to_texture_coords