1
0
Fork 0
mirror of https://git.coom.tech/drummyfish/small3dlib.git synced 2024-11-21 20:39:57 +01:00
small3dlib/README.md

114 lines
8.5 KiB
Markdown
Raw Normal View History

2019-06-22 00:06:40 +02:00
# small3dlib
2019-07-01 18:41:15 +02:00
Public domain 3D software rasterizer for (not only) resource-limited computers.
2019-06-22 00:06:40 +02:00
2019-07-13 19:38:07 +02:00
If you like this, you may also like my similar project: [raycastlib](https://gitlab.com/drummyfish/raycastlib). These two libraries can very easily be combined together -- here is a proof-of-concept gif (environment rendered with raycastlib, cubes with small3dlib):
![](media/rcl_plus_s3l.gif)
2019-06-22 00:24:52 +02:00
## eye-candy previews
2019-07-02 00:22:30 +02:00
Pokitto (32bit embedded console, 48 MHz, 36 kB RAM):
![](media/pokitto_modelviewer.gif)
![](media/pokitto_level.gif)
![](media/pokitto_city.gif)
2019-07-02 14:28:57 +02:00
Gamebuino META (Arduino 32bit console, 48 MHz, 32 kB RAM):
![](media/gb_modelviewer.gif)
2019-07-01 18:38:54 +02:00
PC (SDL, offline rendering, terminal):
![](media/pc_modelviewer.gif)
![](media/pc_level.gif)
![](media/pc_city.gif)
![](media/pc_term.gif)
![](media/pc_island.png)
![](media/pc_alligator.png)
2019-06-22 00:24:52 +02:00
## features
2019-06-25 17:05:16 +02:00
- Very **fast, small and efficient**.
- Uses **only integer math** (32bit).
- **No dependencies** (uses only stdint standard library), extremely portable.
2019-08-26 13:55:18 +02:00
- **Single header**, KISS, suckless.
2019-06-25 17:05:16 +02:00
- **Pure C99**, tested to run as C++ as well.
- Still **flexible** -- pixels are left for you to draw in any way you want with a custom fragment-shader like function.
- **Perspective correction**, 3 modes: none (linear only), full (per-pixel), approximation (per-N-pixels).
- **Different drawing strategies** to choose from: none, z-buffer (none, full, reduced), triangle sorting (back-to-front, fron-to-back with stencil buffer).
- Triangles provide **barycentric coordinates**, thanks to which practically anything that can be achieved with OpenGL can be achieved (texturing, shading, normal-mapping, texture fitering, transparency, PBR, shadow mapping, MIP mapping, ...).
2019-08-20 02:40:10 +02:00
- **Top-left rasterization rule**, pixels of adjacent triangles don't overlap or have holes (just like in OpenGL).
2020-06-18 14:58:58 +02:00
- **Tested on multiple platforms** (little endian PC, Pokitto and Gamebuino META embedded consoles, big endian PowerPC emulator).
- **Extremely portable** due to no dependencies, no float, no build systems, low HW requirements, endian independence etc.
2019-06-25 17:05:16 +02:00
- **Many compile-time options** to tune the performance vs quality.
- **Similar to OpenGL** in principle, but simpler, easier to use, with higher-level features.
- **Tools** (Python scripts) for converting 3D models and textures to C array format used by the library.
2019-06-26 21:49:13 +02:00
- **Well commented** and formatted code. Automatic documentation (comments + provided Doxyfile).
2020-06-18 14:58:58 +02:00
- Completely **free of legal restrictions**, public domain, do literally anything you want.
2019-06-22 15:45:59 +02:00
**NOTE**: Backwards compatibility isn't a goal of this libraray. It is meant to
be an as-is set of tools that the users is welcome to adjust for their
specific project. So new features will be preferred to keeping the same
interface.
2019-06-22 00:24:52 +02:00
## limitations
2019-06-25 17:05:16 +02:00
- **No scenegraph** (object parenting), just a scene list. Parenting can still be achieved by using cutom transform matrices.
- Though performance is high, due to multiplatformness it **probably can't match platform-specific rasterizers written in assembly**.
- There is **no far plane**.
2020-06-18 15:05:03 +02:00
- There is **no subpixel accuracy** (PS1 style graphics).
- There is **no antialiasing**, but you can still achieve it by supersampling (render in higher resolution and downscale) or filters like FXAA.
- There is a near plane but a **proper culling by it (subdividing triangles) is missing**. You can either cull whole triangles completely or "push" them by the near plane. These options are okay when drawing a model not very close to the camera, but e.g. 3D environments may suffer from artifacts.
2019-06-25 17:05:16 +02:00
- Due to the limitations of 32bit integer arithmetics, some types of movement (particularly camera) **may look jerky, and artifact may appear** in specific situations.
2019-06-22 00:24:52 +02:00
## how to use
2019-06-25 17:21:58 +02:00
For start take a look at the [helloTerminal.c](https://gitlab.com/drummyfish/small3dlib/blob/master/programs/helloTerminal.c) program. It is only a little bit more complex than a simple hello world.
2019-06-26 21:10:37 +02:00
For more see the other examples and **the library code itself**, it is meant to be self-documenting -- you'll find the description of a lot of things at the start of the file.
2019-06-25 17:21:58 +02:00
The basic philosophy is:
2019-07-03 16:25:38 +02:00
- The library implements only a rendering back-end, it doesn't perform any drawing to the actual screen,
2019-06-25 17:21:58 +02:00
hence there is no dependency on any library such as OpenGL or SDL. It just calls your front-end function
and tells you which pixels you should write. How you do it is up to you.
- Before including the header, define `S3L_PIXEL_FUNCTION` to the name of a function you will use to
draw pixels. It is basically a fragment/pixel shader function that the library will call. You will
be passed info about the pixel and can decide what to do with it, so you can process it, discard it,
or simply write it to the screen.
2019-07-12 21:10:01 +02:00
- Also init screen resolution, either by defining `S3L_RESOLUTION_X` and `S3L_RESOLUTION_Y` (before including the library) or by setting `S3L_resolutionX` and `S3L_resolutionY` variables.
2019-06-25 17:21:58 +02:00
- Use the provided Python tools to convert your model and textures to C arrays, include them in your
program and set up the scene struct.
2019-07-03 16:25:38 +02:00
- Init the 3D models and the scene with provided init functions (`S3L_init*`), set the position of the camera.
2020-06-18 15:11:52 +02:00
- Call `S3L_newFrame` to prepare for rendering, then call `S3L_drawScene` on the scene to perform the frame rendering.
This will cause the library to start rendering and calling the `S3L_PIXEL_FUNCTION` in order to draw the frame. You can of course
2019-06-25 17:21:58 +02:00
modify the function or write a similar one of your own using the more low-level functions which are
also provided.
- Fixed point arithmetics is used as a principle, but there is no abstraction above it, everything is simply
an integer (`S3L_Unit` type). The space is considered to be a dense grid, and what would normally be
a 1.0 float value is an int value equal to `S3L_FRACTIONS_PER_UNIT` units. Numbers are normalized by this
2020-06-18 15:11:52 +02:00
constant, so e.g. the sin function returns a value from `-S3L_FRACTIONS_PER_UNIT` to `S3L_FRACTIONS_PER_UNIT`. You have to
pass numbers of this format to the library functions, but of course you may chooe to use floats in other places of your program.
2019-06-22 00:24:52 +02:00
2019-06-22 04:00:14 +02:00
## tips/troubleshooting
2019-06-22 00:24:52 +02:00
2019-06-25 17:05:16 +02:00
- Don't forget to **compile with -O3!** This drastically improves performance.
2019-07-01 20:02:49 +02:00
- Your pixel drawing function (`S3L_PIXEL_FUNC`) will mostly be the performance bottleneck, try to make it as fast as possible. The number of pixels is usually much higher than the number of triangles or vertices processed, so you should focus on pixels the most.
2019-06-25 17:21:58 +02:00
- In your `S3L_PIXEL_FUNC` **use a per-triangle cache!** This saves a lot of CPU time. Basically make sure you don't compute per-triangle values per-pixel, but only once, with the first pixel of the triangle. You can do this by remembering the last `triangleID` and only recompute the value when the ID changes. See the examples for how this is done.
2019-07-12 21:10:01 +02:00
- Some things, such as screen resolution, can be specified as static (compile time, can't change during run time) or dynamic. If you can, prefer setting them to static and a power of two (e.g. `#define S3L_RESOLUTION_X 512`) to increase performance!
2019-06-22 15:39:00 +02:00
- Seeing buggy triangles flashing in front of the camera? With the limited 32bit arithmetic far-away things may be overflowing. Try to scale down the scene. If you also don't mind it, set `S3L_STRICT_NEAR_CULLING` to `1` -- this should probably solve it.
2019-06-26 21:21:42 +02:00
- Seeing triangles weirdly deform in front of the camera? Due to the lack of proper near plane culling one of the options (`S3L_STRICT_NEAR_CULLING == 0`) deals with this by pushing the vertices in front of the near plane. To fix this either manually subdivide your model into more triangles or turn on `S3L_STRICT_NEAR_CULLING` (which will however make the close triangles disappear).
2019-06-22 15:48:22 +02:00
- Seeing triangles disappear randomly in sorted modes? This is because the size of the memory for triangle sorting is limited by default -- increase `S3L_MAX_TRIANGLES_DRAWN`.
2019-06-24 02:24:43 +02:00
- Sorted mode sorts triangles before drawing, but sometimes you need to control the drawing order more precisely. This can be done by reordering the objects in the scene list or rendering the scene multiple times without clearing the screen.
## license
2019-07-04 00:36:21 +02:00
Everything is CC0 1.0 (public domain, https://creativecommons.org/publicdomain/zero/1.0/) + a waiver of all other IP rights (including patents).
The art used in demos is either my own released under CC0 or someone else's released under CC0.
2019-06-25 16:53:10 +02:00
Please support free software and free culture by using free licenses and/or waivers.
2019-06-26 21:49:13 +02:00
If you'd like to support me or just read something about me and my projects, visit my site: [www.tastyfish.cz](http://www.tastyfish.cz/).