1
0
Fork 0
mirror of https://git.coom.tech/drummyfish/small3dlib.git synced 2025-04-07 02:06:20 +02:00

Add ortho projection

This commit is contained in:
Miloslav Ciz 2022-10-01 17:21:12 +02:00
parent 63a241a0a5
commit 6a2cfb5ce6
3 changed files with 28 additions and 38 deletions

View file

@ -55,6 +55,7 @@ PC (SDL, offline rendering, terminal):
- **Extremely portable** due to no dependencies, no float, no build systems, low HW requirements, endian independence etc. - **Extremely portable** due to no dependencies, no float, no build systems, low HW requirements, endian independence etc.
- **Many compile-time options** to tune the performance vs quality. - **Many compile-time options** to tune the performance vs quality.
- **Similar to OpenGL** in principle, but simpler, easier to use, with higher-level features. - **Similar to OpenGL** in principle, but simpler, easier to use, with higher-level features.
- **Perspective and orthographic** projections.
- **Tools** (Python scripts) for converting 3D models and textures to C array format used by the library. - **Tools** (Python scripts) for converting 3D models and textures to C array format used by the library.
- **Well commented** and formatted code. Automatic documentation (comments + provided Doxyfile). - **Well commented** and formatted code. Automatic documentation (comments + provided Doxyfile).
- Completely **free of legal restrictions**, public domain, do literally anything you want. - Completely **free of legal restrictions**, public domain, do literally anything you want.

View file

@ -1,4 +1,3 @@
- orthographics projection - did I forget this lol?
- Add option to compute sin with Bhaskaras approx instead of using a LUT. - Add option to compute sin with Bhaskaras approx instead of using a LUT.
- camera's focallength attribute could really rather be stored in - camera's focallength attribute could really rather be stored in
transformation.scale.z, while scale.x and scale.y could be used for transformation.scale.z, while scale.x and scale.y could be used for

View file

@ -10,7 +10,7 @@
license: CC0 1.0 (public domain) license: CC0 1.0 (public domain)
found at https://creativecommons.org/publicdomain/zero/1.0/ found at https://creativecommons.org/publicdomain/zero/1.0/
+ additional waiver of all IP + additional waiver of all IP
version: 0.904d version: 0.905d
Before including the library, define S3L_PIXEL_FUNCTION to the name of the Before including the library, define S3L_PIXEL_FUNCTION to the name of the
function you'll be using to draw single pixels (this function will be called function you'll be using to draw single pixels (this function will be called
@ -166,7 +166,6 @@
many rendering bugs and imprecisions happening due to overflows, but this will many rendering bugs and imprecisions happening due to overflows, but this will
also consumer more RAM and may potentially be slower on computers with smaller also consumer more RAM and may potentially be slower on computers with smaller
native integer. */ native integer. */
#define S3L_USE_WIDER_TYPES 0 #define S3L_USE_WIDER_TYPES 0
#endif #endif
@ -233,7 +232,6 @@ typedef
3: Perform both geometrical and barycentric correction of triangle crossing 3: Perform both geometrical and barycentric correction of triangle crossing
the near plane. This is significantly more expensive but results in the near plane. This is significantly more expensive but results in
correct rendering. */ correct rendering. */
#define S3L_NEAR_CROSS_STRATEGY 0 #define S3L_NEAR_CROSS_STRATEGY 0
#endif #endif
@ -243,8 +241,7 @@ typedef
for the whole triangle. This can be used to create flat-shaded renders and for the whole triangle. This can be used to create flat-shaded renders and
will be a lot faster. With this option on you will probably want to use will be a lot faster. With this option on you will probably want to use
sorting instead of z-buffer. */ sorting instead of z-buffer. */
#define S3L_FLAT 0
#define S3L_FLAT 0
#endif #endif
#if S3L_FLAT #if S3L_FLAT
@ -262,7 +259,6 @@ typedef
2: Approximation (computing only at every S3L_PC_APPROX_LENGTHth pixel). 2: Approximation (computing only at every S3L_PC_APPROX_LENGTHth pixel).
Quake-style approximation is used, which only computes the PC after Quake-style approximation is used, which only computes the PC after
S3L_PC_APPROX_LENGTH pixels. This is reasonably accurate and fast. */ S3L_PC_APPROX_LENGTH pixels. This is reasonably accurate and fast. */
#define S3L_PERSPECTIVE_CORRECTION 0 #define S3L_PERSPECTIVE_CORRECTION 0
#endif #endif
@ -270,7 +266,6 @@ typedef
/** For S3L_PERSPECTIVE_CORRECTION == 2, this specifies after how many pixels /** For S3L_PERSPECTIVE_CORRECTION == 2, this specifies after how many pixels
PC is recomputed. Should be a power of two to keep up the performance. PC is recomputed. Should be a power of two to keep up the performance.
Smaller is nicer but slower. */ Smaller is nicer but slower. */
#define S3L_PC_APPROX_LENGTH 32 #define S3L_PC_APPROX_LENGTH 32
#endif #endif
@ -300,13 +295,11 @@ typedef
2: Use reduced-size z-buffer (of bytes). This is fast and somewhat accurate, 2: Use reduced-size z-buffer (of bytes). This is fast and somewhat accurate,
but inaccuracies can occur and a considerable amount of memory is but inaccuracies can occur and a considerable amount of memory is
needed. */ needed. */
#define S3L_Z_BUFFER 0 #define S3L_Z_BUFFER 0
#endif #endif
#ifndef S3L_REDUCED_Z_BUFFER_GRANULARITY #ifndef S3L_REDUCED_Z_BUFFER_GRANULARITY
/** For S3L_Z_BUFFER == 2 this sets the reduced z-buffer granularity. */ /** For S3L_Z_BUFFER == 2 this sets the reduced z-buffer granularity. */
#define S3L_REDUCED_Z_BUFFER_GRANULARITY 5 #define S3L_REDUCED_Z_BUFFER_GRANULARITY 5
#endif #endif
@ -314,7 +307,6 @@ typedef
/** Whether to use stencil buffer for drawing -- with this a pixel that would /** Whether to use stencil buffer for drawing -- with this a pixel that would
be resterized over an already rasterized pixel (within a frame) will be be resterized over an already rasterized pixel (within a frame) will be
discarded. This is mostly for front-to-back sorted drawing. */ discarded. This is mostly for front-to-back sorted drawing. */
#define S3L_STENCIL_BUFFER 0 #define S3L_STENCIL_BUFFER 0
#endif #endif
@ -336,21 +328,18 @@ typedef
because we prevent computing pixels that will be overwritten by nearer because we prevent computing pixels that will be overwritten by nearer
ones, but we need a 1b stencil buffer for this (enable S3L_STENCIL_BUFFER), ones, but we need a 1b stencil buffer for this (enable S3L_STENCIL_BUFFER),
so a bit more memory is needed. */ so a bit more memory is needed. */
#define S3L_SORT 0 #define S3L_SORT 0
#endif #endif
#ifndef S3L_MAX_TRIANGES_DRAWN #ifndef S3L_MAX_TRIANGES_DRAWN
/** Maximum number of triangles that can be drawn in sorted modes. This /** Maximum number of triangles that can be drawn in sorted modes. This
affects the size of the cache used for triangle sorting. */ affects the size of the cache used for triangle sorting. */
#define S3L_MAX_TRIANGES_DRAWN 128 #define S3L_MAX_TRIANGES_DRAWN 128
#endif #endif
#ifndef S3L_NEAR #ifndef S3L_NEAR
/** Distance of the near clipping plane. Points in front or EXATLY ON this /** Distance of the near clipping plane. Points in front or EXATLY ON this
plane are considered outside the frustum. This must be >= 0. */ plane are considered outside the frustum. This must be >= 0. */
#define S3L_NEAR (S3L_F / 4) #define S3L_NEAR (S3L_F / 4)
#endif #endif
@ -361,7 +350,6 @@ typedef
#ifndef S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE #ifndef S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE
/** Affects the S3L_computeModelNormals function. See its description for /** Affects the S3L_computeModelNormals function. See its description for
details. */ details. */
#define S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE 6 #define S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE 6
#endif #endif
@ -371,7 +359,6 @@ typedef
higher values can fix this -- in theory all higher values will have the same higher values can fix this -- in theory all higher values will have the same
speed (it is a shift value), but it mustn't be too high to prevent speed (it is a shift value), but it mustn't be too high to prevent
overflow. */ overflow. */
#define S3L_FAST_LERP_QUALITY 11 #define S3L_FAST_LERP_QUALITY 11
#endif #endif
@ -524,7 +511,9 @@ void S3L_mat4Xmat4(S3L_Mat4 m1, S3L_Mat4 m2);
typedef struct typedef struct
{ {
S3L_Unit focalLength; ///< Defines the field of view (FOV). S3L_Unit focalLength; /**< Defines the field of view (FOV). 0 sets an
orthographics projection (scale is controlled
with camera's scale in its transform). */
S3L_Transform3D transform; S3L_Transform3D transform;
} S3L_Camera; } S3L_Camera;
@ -1669,6 +1658,9 @@ void S3L_transform3DInit(S3L_Transform3D *t)
static inline void S3L_perspectiveDivide(S3L_Vec4 *vector, static inline void S3L_perspectiveDivide(S3L_Vec4 *vector,
S3L_Unit focalLength) S3L_Unit focalLength)
{ {
if (focalLength == 0)
return;
vector->x = (vector->x * focalLength) / vector->z; vector->x = (vector->x * focalLength) / vector->z;
vector->y = (vector->y * focalLength) / vector->z; vector->y = (vector->y * focalLength) / vector->z;
} }
@ -1719,8 +1711,10 @@ void S3L_project3DPointToScreen(
result->w = result->w =
(point.z <= 0) ? 0 : (point.z <= 0) ? 0 :
( (
camera.focalLength > 0 ?(
(s * camera.focalLength * S3L_RESOLUTION_X) / (s * camera.focalLength * S3L_RESOLUTION_X) /
(point.z * S3L_F) (point.z * S3L_F)) :
((camera.transform.scale.x * S3L_RESOLUTION_X) / S3L_F)
); );
} }
@ -1945,10 +1939,8 @@ void S3L_newFrame(void)
S3L_stencilBufferClear(); S3L_stencilBufferClear();
} }
/* /* the following serves to communicate info about if the triangle has been split
the following serves to communicate info about if the triangle has been split and how the barycentrics should be remapped. */
and how the barycentrics should be remapped.
*/
uint8_t _S3L_projectedTriangleState = 0; // 0 = normal, 1 = cut, 2 = split uint8_t _S3L_projectedTriangleState = 0; // 0 = normal, 1 = cut, 2 = split
#if S3L_NEAR_CROSS_STRATEGY == 3 #if S3L_NEAR_CROSS_STRATEGY == 3
@ -2585,7 +2577,15 @@ void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 m)
S3L_mat4Transpose(r); // transposing creates an inverse transform S3L_mat4Transpose(r); // transposing creates an inverse transform
S3L_Mat4 s;
S3L_makeScaleMatrix(
cameraTransform.scale.x,
cameraTransform.scale.y,
cameraTransform.scale.z,s);
S3L_mat4Xmat4(m,r); S3L_mat4Xmat4(m,r);
S3L_mat4Xmat4(m,s);
} }
int8_t S3L_triangleWinding( int8_t S3L_triangleWinding(
@ -2603,11 +2603,9 @@ int8_t S3L_triangleWinding(
return winding > 0 ? 1 : (winding < 0 ? -1 : 0); return winding > 0 ? 1 : (winding < 0 ? -1 : 0);
} }
/** /** Checks if given triangle (in Screen Space) is at least partially visible,
Checks if given triangle (in Screen Space) is at least partially visible,
i.e. returns false if the triangle is either completely outside the frustum i.e. returns false if the triangle is either completely outside the frustum
(left, right, top, bottom, near) or is invisible due to backface culling. (left, right, top, bottom, near) or is invisible due to backface culling. */
*/
static inline int8_t S3L_triangleIsVisible( static inline int8_t S3L_triangleIsVisible(
S3L_Vec4 p0, S3L_Vec4 p0,
S3L_Vec4 p1, S3L_Vec4 p1,
@ -2658,12 +2656,8 @@ _S3L_TriangleToSort S3L_sortArray[S3L_MAX_TRIANGES_DRAWN];
uint16_t S3L_sortArrayLength; uint16_t S3L_sortArrayLength;
#endif #endif
void _S3L_projectVertex( void _S3L_projectVertex(const S3L_Model3D *model, S3L_Index triangleIndex,
const S3L_Model3D *model, uint8_t vertex, S3L_Mat4 projectionMatrix, S3L_Vec4 *result)
S3L_Index triangleIndex,
uint8_t vertex,
S3L_Mat4 projectionMatrix,
S3L_Vec4 *result)
{ {
uint32_t vertexIndex = model->triangles[triangleIndex * 3 + vertex] * 3; uint32_t vertexIndex = model->triangles[triangleIndex * 3 + vertex] * 3;
@ -2696,12 +2690,10 @@ void _S3L_mapProjectedVertexToScreen(S3L_Vec4 *vertex, S3L_Unit focalLength)
vertex->y = sY; vertex->y = sY;
} }
/** /** Projects a triangle to the screen. If enabled, a triangle can be potentially
Projects a triangle to the screen. If enabled, a triangle can be potentially
subdivided into two if it crosses the near plane, in which case two projected subdivided into two if it crosses the near plane, in which case two projected
triangles are returned (the info about splitting or cutting the triangle is triangles are returned (the info about splitting or cutting the triangle is
passed in global variables, see above). passed in global variables, see above). */
*/
void _S3L_projectTriangle( void _S3L_projectTriangle(
const S3L_Model3D *model, const S3L_Model3D *model,
S3L_Index triangleIndex, S3L_Index triangleIndex,
@ -2712,7 +2704,6 @@ void _S3L_projectTriangle(
_S3L_projectVertex(model,triangleIndex,0,matrix,&(transformed[0])); _S3L_projectVertex(model,triangleIndex,0,matrix,&(transformed[0]));
_S3L_projectVertex(model,triangleIndex,1,matrix,&(transformed[1])); _S3L_projectVertex(model,triangleIndex,1,matrix,&(transformed[1]));
_S3L_projectVertex(model,triangleIndex,2,matrix,&(transformed[2])); _S3L_projectVertex(model,triangleIndex,2,matrix,&(transformed[2]));
_S3L_projectedTriangleState = 0; _S3L_projectedTriangleState = 0;
#if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3 #if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3
@ -2999,7 +2990,6 @@ void S3L_drawScene(S3L_Scene scene)
S3L_drawTriangle(transformed[3],transformed[4],transformed[5], S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
modelIndex, triangleIndex); modelIndex, triangleIndex);
} }
} }
#endif #endif
} }