Drawing meshes

Thus far we’ve only been drawing full-screen fragment shaders. This is great for post-processing effects or sdf art, but what if we want to draw a mesh?

Drawing a cube

You should see the sillouette of a cube on a gray background. Let’s break it down:

  • draw(Mesh, shader, shader) is a function that takes a mesh, a vertex shader, and a fragment shader and draws it to the screen.
  • The first shader { ... } on line 8 is the vertex shader. It’s run once for each vertex in the mesh. It’s job is to transform the vertex’s position from model space to screen space. More on this later.
  • The second shader { ... } on line 14 is the fragment shader. You’ve seen this before, but in this case it’s run once for each pixel in the mesh. It’s job is to output a color for each pixel.
  • The getCombinedMatrix call will be explained below.

You can also move the camera around by click and dragging. The env.camera is controlled like so:

  • orbit mode (default):
    • Left click drag: Rotate the camera around the origin
    • Middle click drag: Pan the camera
    • Scroll: Zoom in and out
  • free mode (hold right click to unlock):
    • WASD: Move the camera
    • Right click drag: Rotate the camera
    • Right click hold + Scroll: Incrase/decrease movement speed
    • E/Q: Move up/down
    • C/Z: Adjust fov

Vertex shaders and matrices

The vertex shader’s main job is to turn a vertex’s position from model space to clip space (a 2d screen coordinate). Typically this is done by multiplying the vertex’s position by a 4d matrix that contains teh necessary transformations. I won’t go into detail about how this works here but I’d suggest reading this article if you’re interested.

For now I’ll just outline some of the built-in shadeup helpers for this:

  1. env.camera.getCombinedMatrix() -> float4x4

    Returns a 4d matrix that transforms a vertex’s position from world space to clip space. This is the matrix that you’ll want to multiply your vertex’s position by in your vertex shader.

  2. env.camera.getProjectionMatrix() -> float4x4

    Returns a 4d matrix that transforms a vertex’s position from camera space to clip space. This is one part of the combined matrix.

  3. env.camera.getViewMatrix() -> float4x4

    Returns a 4d matrix that transforms a vertex’s position from world space to camera space. This is the other part of the combined matrix.

  4. matrix::perspective(fov: float, aspect: float, near: float, far: float) -> float4x4

    Returns a 4d matrix that transforms a vertex’s position from camera space to clip space. This is called internally by the camera.

  5. env.camera.getOrthographicMatrix() -> float4x4

    Returns a 4d matrix that transforms a vertex’s position from camera space to clip space. This is an alternate projection that doesn’t apply perspective.

Diffuse lighting

You should see a cube with a light source coming from the top right.

Diffuse lighting takes into account the angle between the surface normal and the light direction. The angle is calculated using the dot product. The dot product is a mathematical operation that returns a value between -1 and 1. If the two vectors are pointing in the same direction the dot product will be 1. If they’re pointing in opposite directions the dot product will be -1. If they’re perpendicular the dot product will be 0.

Other meshes

For more information on the built-in mesh helpers see the mesh module.