HaScene is a simple ASCII 3D scene editor written in Haskell, using Functional Programming. It is a final project for CSE 230 Programming Languages at UCSD, inspired by this famous piece of C code. The editor is capable of reading 3D .obj models from files, rendering a simple 3D scene with shading using ASCII characters through soft rasterization, and manipulating the position and rotation of different 3D objects, and manipulate the position and rotation of different 3D object. The UI is implemented using the brick library
-
Prepare a Haskell environment on Linux (We haven't tested the application on other platforms). You could refer to this article: Getting start with Haskell.
-
Clone this responsory:
git clone https://github.com/TaKeTube/HaScene.git
- Run stack build:
stack build
- Execute HaScene:
stack exec HaScene
You can move the camera in this mode.
w / a / s / d: forward / backward / down / right
⇧ Shift + w: up
⇧ Shift + s: down
Press i to enter / exit this mode. You can manipulate 3D objects in this mode.
j / k: select 3D object from the object list
Translation
w / a / s / d: forward / backward / down / right
⇧ Shift + w: up
⇧ Shift + s: down
Rotation
Assume z-up, right-handed.
↑ ↓ / ← →: rotate along y / z axis
⇧ Shift + ← →: rotate along x axis
Though the default scene is hard-coded into the file, the 3D model files (.obj files) are not.
You can edit the hard coded scene in HaScene.hs
, defaultScene
function. Here is the default example:
defaultScene :: String -> IO [Mesh]
defaultScene filename = do
temp <- buildMesh "src/models/hat.obj" "hat"
let obj1 = translateMesh Move (translate 1 Right (V3 0 0 (-1)) (V3 0 0 0)) $
translateMesh Scale (V3 1.5 0 0) temp
temp <- buildMesh "src/models/cube.obj" "cube"
let obj2 = translateMesh Move (translate 2 Left (V3 0 0 (-1)) (V3 0 0 0)) $
translateMesh Scale (V3 0.8 0 0) temp
temp <- buildMesh "src/models/bunny.obj" "bunny"
let obj3 = translateMesh Move (translate 8 Left (V3 0 0 (-1)) (V3 0 0 0)) $
translateMesh Move (translate 1 Down (V3 0 0 (-1)) (V3 0 0 0)) $
translateMesh Scale (V3 30.0 0 0) temp
temp <- buildMesh "src/models/pirate-ship.obj" "ship"
let obj4 = translateMesh Move (translate 5 Right (V3 0 0 (-1)) (V3 0 0 0)) temp
temp <- buildMesh "src/models/dragon.obj" "dragon"
let obj5 = translateMesh Move (translate 10 Forward (V3 0 0 (-1)) (V3 0 0 0)) $
translateMesh Scale (V3 1.2 0 0) temp
return [obj1, obj2, obj3, obj4, obj5]
HaScene consists of 3 parts: UI, rendering, and main control.
The main control part consists of the core logic, including keyboard input, object manipulation, and reading 3D model files, among others.
The UI part is implemented using the brick library.
The rendering part is a soft rasterizer.
As you can see from the diagram, we have features like MVP transformation, z-culling, blackface culling, simple Lambert shading, perspective-correct interpolation, scan line algorithm, z-buffering, etc.