A simple mesh viewer for MacOS based on Swift and Metal and using Assimp for loading meshes

Overview

Metal Mesh Viewer

A simple triangle mesh viewer for MacOS

This application is a simple (triangle) mesh viewer that should be capable of rendering even large meshes interactively on a Mac. It was made by creating a project with the game template using Swift and Metal. Models are loaded using the Assimp library via a C/C++ bridge. Using Assimp for model loading ensures that a fairly wide range of file formats are supported.

From a graphics point of view, the project is kept as simple as possible. The shading is based on matcaps. Smooth shading, flat shading and wireframe rendering modes are supported. While assets may contain textures, these are not used by the viewer since the focus is on the geometry.

Why is this useful?

This project could be of interest to different people for different reasons. Of course, if you want a simple mesh viewer that happens to work on MacOS, this application might be of interest. For others, this could simply be a relatively compact example of how a Swift/Metal computer graphics program can be put together. After all this is a relatively simple app made from the Swift/Metal game-app default project in Xcode, and I myself learned several things from the development. Specifically, I learned

  • how to make a simple app without a xib file or a story board (I threw out the xib file). This turned out to be much less confusing than trying to connect the visual representation of the interface with the code.
  • how to implement a recently opened files menu using the NSDocumentController (in a not otherwise document based application). Not as easy as I had hoped, but actually not as hard as I feared either.
  • how to connect a C/C++ library to Swift code by creating a framework that bridges the two. This is actually why the project contains two targets. It turned out to be much easier to have C++ code in the project if I made a separate framework that is then included.
  • how to manually set up the vertex, normal, and index buffers used to convey the mesh to the GPU. The example project creates an MDLMesh which is then turned into an MTKMesh. This is all good and well, but if the MDL asset loader is not used then it is actually nicer to roll your own simple mesh class.
  • a bit about how Metal works and also Swift.

Moreover, the shaders also demonstrate some computer graphics techniques which might be of interest.

  • The rendering is based on matcaps. Matcaps let you render fairly plausible surfaces and simply require an image of a sphere. The shading is then done by mapping the normal of the mesh to the pixel in the image of the sphere where the sphere would have the same normal. This is done, essentially, by dropping the z coordinate of the normal.
  • The wireframe rendering is based on computing the distance to the edges of the triangle using the barycentric coordinates of the triangle. When we are close to the edge, the color is changed to edge color. To go from barycentrics to edge distance, we need to divide each barycentric coordinate with the length of its screen space gradient. This method turned out to be easy to implement in Metal, and it does not require any attributes to be added to the vertices because Metal exposes the barycentrics as potential inputs to the fragment shader.
  • For flat shading, we again use derivatives. The normal is computed per pixel as the cross product of the x and y derivatives of the eye space coordinates. Correct flat shading would otherwise require you to send the mesh to the GPU with every vertex repeated for each triangle since the vertices would need to have different normals for each triangle. Thus, computing the normal per pixel adds a bit of GPU work, but it can be done with the exact same input to the shaders as smooth shading.
  • A benefit of the way flat shading and wireframe rendering has been implemented is that we can send exactly the same geometry with the same attributes for smooth shading, flat shading, and wireframe. Thus, we only need to change shaders and not modify the assets when rendering in a different mode. That makes the switch very fast - actually instant as far as I can tell.

User Interaction

  1. Keys:

    • 'f' toggles between flat and smooth shading.
    • 'w' turns wireframe on and off.
    • 'r' resets the virtual trackball.
    • 'x' makes X the up axis.
    • 'y' makes Y the up axis (this is the default).
    • 'z' makes Z the up axis.
    • '1'-'4' switches between matcaps.
  2. Mouse/trackpad:

    • dragging with the left mouse button rotates whereas
    • the right button pans.
    • Scroll wheel - scroll gesture on a trackpad - zooms in and out.

Prerequisites

Compiling this project requires that Xcode is installed. Also, assimp needs to be installed. This is as simple as > sudo port install assimp if you are using MacPorts. The Xcode project presupposes that assimp is installed in /opt/local. If you have installed it elsewhere, you may need to change locations for header files and library.

Design Decisions

The decision to use Metal was based on the fact that on Apple platforms it is likely to be the fastest option, and I wanted an application that would provide interactive frame rates for large meshes. Using Metal without Swift would be tricky, so that led to the choice of programming language.

Matcaps are used for shading in order to keep things simple while trying to make the shading as flexible and visually pleasing as possible. Matcaps provide a lot of options and visual "oomph" for almost no coding. I have embedded several matcap images in the project, and these are, of course, easy to change or add to.

You might also like...
Agrume - 🍋 An iOS image viewer written in Swift with support for multiple images.
Agrume - 🍋 An iOS image viewer written in Swift with support for multiple images.

Agrume An iOS image viewer written in Swift with support for multiple images. Requirements Swift 5.0 iOS 9.0+ Xcode 10.2+ Installation Use Swift Packa

Swift/iOS viewer for photography galleries or portfolios
Swift/iOS viewer for photography galleries or portfolios

Swift/iOS viewer for photography galleries or portfolios. The app is intended for photographers who participate in classical photo clubs: a portfolio covers (curated) images that were presented and critiqued within a photo club.

Image viewer (or Lightbox) with support for local and remote videos and images
Image viewer (or Lightbox) with support for local and remote videos and images

Table of Contents Features Focus Browse Rotation Zoom tvOS Setup Installation License Author Features Focus Select an image to enter into lightbox mod

Photo Browser / Viewer inspired by Facebook's and Tweetbot's with ARC support, swipe-to-dismiss, image progress and more
Photo Browser / Viewer inspired by Facebook's and Tweetbot's with ARC support, swipe-to-dismiss, image progress and more

IDMPhotoBrowser IDMPhotoBrowser is a new implementation based on MWPhotoBrowser. We've added both user experience and technical features inspired by F

APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS.
APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS.

APNGKit is a high performance framework for loading and displaying APNG images in iOS and macOS. It's built on top of a modified version of libpng wit

Lightbox is a convenient and easy to use image viewer for your iOS app
Lightbox is a convenient and easy to use image viewer for your iOS app

Lightbox is a convenient and easy to use image viewer for your iOS app, packed with all the features you expect: Paginated image slideshow. V

A snappy image viewer with zoom and interactive dismissal transition.

A snappy image viewer with zoom and interactive dismissal transition. Features Double tap to zoom in/out Interactive dismissal transition Animate in f

Slide image viewer library similar to Twitter and LINE.
Slide image viewer library similar to Twitter and LINE.

Overview You can use it simply by passing the necessary information! Serrata is a UI library that allows you to intuitively view images. Features King

A snappy image viewer with zoom and interactive dismissal transition.

A snappy image viewer with zoom and interactive dismissal transition. Features Double tap to zoom in/out Interactive dismissal transition Animate in f

Owner
J. Andreas Bærentzen
J. Andreas Bærentzen
Swift Package Manager plug-in to compile Metal files that can be debugged in Xcode Metal Debugger.

MetalCompilerPlugin Swift Package Manager plug-in to compile Metal files that can be debugged in Xcode Metal Debugger. Description Swift Package Manag

Jonathan Wight 10 Oct 30, 2022
GPU-based media processing library using Metal written in Swift

GPU-based media processing library using Metal written in Swift. Overview MetalAcc is a GPU-Based media processing library that lets you apply GPU-acc

Jiawei Wang 259 Dec 17, 2022
A python library to run metal compute kernels on MacOS 12

metalcompute for Python A python library to run metal compute kernels on MacOS Usage Example execution from M1-based Mac running MacOS 12.0: > ./build

Andrew Baldwin 21 Nov 7, 2022
Simple PhotoBrowser/Viewer inspired by facebook, twitter photo browsers written by swift

SKPhotoBrowser [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) Simple PhotoBrowser

keishi suzuki 2.4k Jan 6, 2023
GPUImage 3 is a BSD-licensed Swift framework for GPU-accelerated video and image processing using Metal.

GPUImage 3 Janie Clayton http://redqueengraphics.com @RedQueenCoder Brad Larson http://www.sunsetlakesoftware.com @bradlarson contact@sunsetlakesoftwa

Brad Larson 2.4k Jan 3, 2023
📷 A composable image editor using Core Image and Metal.

Brightroom - Composable image editor - building your own UI Classic Image Editor PhotosCrop Face detection Masking component ?? v2.0.0-alpha now open!

Muukii 2.8k Jan 3, 2023
📷 A composable image editor using Core Image and Metal.

Brightroom - Composable image editor - building your own UI Classic Image Editor PhotosCrop Face detection Masking component ?? v2.0.0-alpha now open!

Muukii 2.8k Jan 2, 2023
EbImagesSwiftUI - SDWebImageSwiftUI - a SwiftUI image loading framework, which based on SDWebImage

SDWebImageSwiftUI What's for SDWebImageSwiftUI is a SwiftUI image loading framew

An Tran 1 Jan 6, 2022
LCWebImage - An asynchronous image loading framework based on AFNetworking.

LCWebImage is an asynchronous image loading framework based on AFNetworking, which supports memory and disk caching, and provides functions such as custom caching, custom image decoding, and custom network configuration.

LiuChang 27 Jul 23, 2022
Swift image slideshow with circular scrolling, timer and full screen viewer

?? ImageSlideshow Customizable Swift image slideshow with circular scrolling, timer and full screen viewer ?? Example To run the example project, clon

Petr Zvoníček 1.7k Dec 21, 2022