mirror of
https://git.coom.tech/drummyfish/small3dlib.git
synced 2025-01-05 03:36:19 +01:00
Add new near cross strategy
This commit is contained in:
parent
ad34790ec3
commit
7670658db6
4 changed files with 125 additions and 24 deletions
|
@ -83,8 +83,7 @@ And advantages at the same time :)
|
|||
- There is **no far plane**.
|
||||
- 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.
|
||||
- Due to the limitations of 32bit integer arithmetics, some types of movement (particularly camera) **may look jerky, and artifact may appear** in specific situations.
|
||||
- Due to the limitations of 32bit integer arithmetics some types of movement (particularly camera) **may look jerky, and artifact may appear** in specific situations.
|
||||
|
||||
## how to use
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#define S3L_FLAT 0
|
||||
#define S3L_NEAR_CROSS_STRATEGY 1
|
||||
#define S3L_NEAR_CROSS_STRATEGY 3
|
||||
#define S3L_PERSPECTIVE_CORRECTION 2
|
||||
#define S3L_SORT 0
|
||||
#define S3L_STENCIL_BUFFER 0
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define S3L_NEAR_CROSS_STRATEGY 2
|
||||
#define S3L_NEAR_CROSS_STRATEGY 3
|
||||
|
||||
#if TEXTURES
|
||||
#define S3L_PERSPECTIVE_CORRECTION 2
|
||||
|
|
142
small3dlib.h
142
small3dlib.h
|
@ -10,7 +10,7 @@
|
|||
license: CC0 1.0 (public domain)
|
||||
found at https://creativecommons.org/publicdomain/zero/1.0/
|
||||
+ additional waiver of all IP
|
||||
version: 0.860d
|
||||
version: 0.900d
|
||||
|
||||
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
|
||||
|
@ -203,8 +203,7 @@ typedef uint16_t S3L_Index;
|
|||
expensive, but the results will be geometrically correct, even though
|
||||
barycentric correction is not performed so texturing artifacts will
|
||||
appear. Can be ideal with S3L_FLAT.
|
||||
3: NOT IMPLEMENTED YET
|
||||
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
|
||||
correct rendering. */
|
||||
|
||||
|
@ -249,7 +248,7 @@ typedef uint16_t S3L_Index;
|
|||
#endif
|
||||
|
||||
#if S3L_PERSPECTIVE_CORRECTION
|
||||
#define S3L_COMPUTE_DEPTH 1 // PC inevitably computes depth, so enable it
|
||||
#define S3L_COMPUTE_DEPTH 1 // PC inevitably computes depth, so enable it
|
||||
#endif
|
||||
|
||||
#ifndef S3L_COMPUTE_DEPTH
|
||||
|
@ -556,7 +555,7 @@ typedef struct
|
|||
|
||||
S3L_Unit barycentric[3]; /**< Barycentric coords correspond to the three
|
||||
vertices. These serve to locate the pixel on a
|
||||
triangle and interpolate values between it's
|
||||
triangle and interpolate values between its
|
||||
three points. Each one goes from 0 to
|
||||
S3L_FRACTIONS_PER_UNIT (including), but due to
|
||||
rounding error may fall outside this range (you
|
||||
|
@ -1853,6 +1852,16 @@ void S3L_newFrame(void)
|
|||
S3L_stencilBufferClear();
|
||||
}
|
||||
|
||||
/*
|
||||
the following serves to communicate info about if the triangle has been split
|
||||
and how the barycentrics should be remapped.
|
||||
*/
|
||||
uint8_t _S3L_projectedTriangleState = 0; // 0 = normal, 1 = cut, 2 = split
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
S3L_Vec4 _S3L_triangleRemapBarycentrics[6];
|
||||
#endif
|
||||
|
||||
void S3L_drawTriangle(
|
||||
S3L_Vec4 point0,
|
||||
S3L_Vec4 point1,
|
||||
|
@ -2337,6 +2346,37 @@ void S3L_drawTriangle(
|
|||
*barycentric2 =
|
||||
S3L_FRACTIONS_PER_UNIT - *barycentric0 - *barycentric1;
|
||||
#endif
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
|
||||
if (_S3L_projectedTriangleState != 0)
|
||||
{
|
||||
S3L_Unit newBarycentric[3];
|
||||
|
||||
newBarycentric[0] = S3L_interpolateBarycentric(
|
||||
_S3L_triangleRemapBarycentrics[0].x,
|
||||
_S3L_triangleRemapBarycentrics[1].x,
|
||||
_S3L_triangleRemapBarycentrics[2].x,
|
||||
p.barycentric);
|
||||
|
||||
newBarycentric[1] = S3L_interpolateBarycentric(
|
||||
_S3L_triangleRemapBarycentrics[0].y,
|
||||
_S3L_triangleRemapBarycentrics[1].y,
|
||||
_S3L_triangleRemapBarycentrics[2].y,
|
||||
p.barycentric);
|
||||
|
||||
newBarycentric[2] = S3L_interpolateBarycentric(
|
||||
_S3L_triangleRemapBarycentrics[0].z,
|
||||
_S3L_triangleRemapBarycentrics[1].z,
|
||||
_S3L_triangleRemapBarycentrics[2].z,
|
||||
p.barycentric);
|
||||
|
||||
p.barycentric[0] = newBarycentric[0];
|
||||
p.barycentric[1] = newBarycentric[1];
|
||||
p.barycentric[2] = newBarycentric[2];
|
||||
}
|
||||
#endif
|
||||
|
||||
S3L_PIXEL_FUNCTION(&p);
|
||||
} // tests passed
|
||||
|
||||
|
@ -2569,9 +2609,10 @@ void _S3L_mapProjectedVertexToScreen(S3L_Vec4 *vertex, S3L_Unit focalLength)
|
|||
/**
|
||||
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
|
||||
triangles are returned (return value will be 1).
|
||||
triangles are returned (the info about splitting or cutting the triangle is
|
||||
passed in global variables, see above).
|
||||
*/
|
||||
uint8_t _S3L_projectTriangle(
|
||||
void _S3L_projectTriangle(
|
||||
const S3L_Model3D *model,
|
||||
S3L_Index triangleIndex,
|
||||
S3L_Mat4 matrix,
|
||||
|
@ -2582,9 +2623,9 @@ uint8_t _S3L_projectTriangle(
|
|||
_S3L_projectVertex(model,triangleIndex,1,matrix,&(transformed[1]));
|
||||
_S3L_projectVertex(model,triangleIndex,2,matrix,&(transformed[2]));
|
||||
|
||||
uint8_t result = 0;
|
||||
_S3L_projectedTriangleState = 0;
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 2
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3
|
||||
uint8_t infront = 0;
|
||||
uint8_t behind = 0;
|
||||
uint8_t infrontI[3];
|
||||
|
@ -2602,6 +2643,15 @@ uint8_t _S3L_projectTriangle(
|
|||
behind++;
|
||||
}
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
for (int i = 0; i < 3; ++i)
|
||||
S3L_vec4Init(&(_S3L_triangleRemapBarycentrics[i]));
|
||||
|
||||
_S3L_triangleRemapBarycentrics[0].x = S3L_FRACTIONS_PER_UNIT;
|
||||
_S3L_triangleRemapBarycentrics[1].y = S3L_FRACTIONS_PER_UNIT;
|
||||
_S3L_triangleRemapBarycentrics[2].z = S3L_FRACTIONS_PER_UNIT;
|
||||
#endif
|
||||
|
||||
#define interpolateVertex \
|
||||
S3L_Unit ratio =\
|
||||
((transformed[be].z - S3L_NEAR) * S3L_FRACTIONS_PER_UNIT) /\
|
||||
|
@ -2612,7 +2662,15 @@ uint8_t _S3L_projectTriangle(
|
|||
transformed[in].y = transformed[be].y -\
|
||||
((transformed[be].y - transformed[in].y) * ratio) /\
|
||||
S3L_FRACTIONS_PER_UNIT;\
|
||||
transformed[in].z = S3L_NEAR;
|
||||
transformed[in].z = S3L_NEAR;\
|
||||
if (beI != 0) {\
|
||||
beI->x = (beI->x * ratio) / S3L_FRACTIONS_PER_UNIT;\
|
||||
beI->y = (beI->y * ratio) / S3L_FRACTIONS_PER_UNIT;\
|
||||
beI->z = (beI->z * ratio) / S3L_FRACTIONS_PER_UNIT;\
|
||||
ratio = S3L_FRACTIONS_PER_UNIT - ratio;\
|
||||
beI->x += (beB->x * ratio) / S3L_FRACTIONS_PER_UNIT;\
|
||||
beI->y += (beB->y * ratio) / S3L_FRACTIONS_PER_UNIT;\
|
||||
beI->z += (beB->z * ratio) / S3L_FRACTIONS_PER_UNIT; }
|
||||
|
||||
if (infront == 2)
|
||||
{
|
||||
|
@ -2620,8 +2678,17 @@ uint8_t _S3L_projectTriangle(
|
|||
for (uint8_t i = 0; i < 2; ++i)
|
||||
{
|
||||
uint8_t be = behindI[0], in = infrontI[i];
|
||||
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
S3L_Vec4 *beI = &(_S3L_triangleRemapBarycentrics[in]),
|
||||
*beB = &(_S3L_triangleRemapBarycentrics[be]);
|
||||
#else
|
||||
S3L_Vec4 *beI = 0, *beB = 0;
|
||||
#endif
|
||||
|
||||
interpolateVertex
|
||||
|
||||
_S3L_projectedTriangleState = 1;
|
||||
}
|
||||
}
|
||||
else if (infront == 1)
|
||||
|
@ -2631,20 +2698,41 @@ uint8_t _S3L_projectTriangle(
|
|||
transformed[4] = transformed[infrontI[0]];
|
||||
transformed[5] = transformed[infrontI[0]];
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
_S3L_triangleRemapBarycentrics[3] =
|
||||
_S3L_triangleRemapBarycentrics[behindI[1]];
|
||||
_S3L_triangleRemapBarycentrics[4] =
|
||||
_S3L_triangleRemapBarycentrics[infrontI[0]];
|
||||
_S3L_triangleRemapBarycentrics[5] =
|
||||
_S3L_triangleRemapBarycentrics[infrontI[0]];
|
||||
#endif
|
||||
|
||||
for (uint8_t i = 0; i < 2; ++i)
|
||||
{
|
||||
uint8_t be = behindI[i], in = i + 4;
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
S3L_Vec4 *beI = &(_S3L_triangleRemapBarycentrics[in]),
|
||||
*beB = &(_S3L_triangleRemapBarycentrics[be]);
|
||||
#else
|
||||
S3L_Vec4 *beI = 0, *beB = 0;
|
||||
#endif
|
||||
|
||||
interpolateVertex
|
||||
}
|
||||
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
_S3L_triangleRemapBarycentrics[infrontI[0]] =
|
||||
_S3L_triangleRemapBarycentrics[4];
|
||||
#endif
|
||||
|
||||
transformed[infrontI[0]] = transformed[4];
|
||||
|
||||
_S3L_mapProjectedVertexToScreen(&transformed[3],focalLength);
|
||||
_S3L_mapProjectedVertexToScreen(&transformed[4],focalLength);
|
||||
_S3L_mapProjectedVertexToScreen(&transformed[5],focalLength);
|
||||
|
||||
result = 1;
|
||||
_S3L_projectedTriangleState = 2;
|
||||
}
|
||||
|
||||
#undef interpolateVertex
|
||||
|
@ -2653,8 +2741,6 @@ uint8_t _S3L_projectTriangle(
|
|||
_S3L_mapProjectedVertexToScreen(&transformed[0],focalLength);
|
||||
_S3L_mapProjectedVertexToScreen(&transformed[1],focalLength);
|
||||
_S3L_mapProjectedVertexToScreen(&transformed[2],focalLength);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void S3L_drawScene(S3L_Scene scene)
|
||||
|
@ -2709,7 +2795,7 @@ void S3L_drawScene(S3L_Scene scene)
|
|||
already projected vertices, but after some testing this was abandoned,
|
||||
no gain was seen. */
|
||||
|
||||
uint8_t split = _S3L_projectTriangle(model,triangleIndex,matFinal,
|
||||
_S3L_projectTriangle(model,triangleIndex,matFinal,
|
||||
scene.camera.focalLength,transformed);
|
||||
|
||||
if (S3L_triangleIsVisible(transformed[0],transformed[1],transformed[2],
|
||||
|
@ -2720,11 +2806,18 @@ void S3L_drawScene(S3L_Scene scene)
|
|||
S3L_drawTriangle(transformed[0],transformed[1],transformed[2],modelIndex,
|
||||
triangleIndex);
|
||||
|
||||
if (split) // draw potential subtriangle
|
||||
if (_S3L_projectedTriangleState == 2) // draw potential subtriangle
|
||||
{
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
_S3L_triangleRemapBarycentrics[0] = _S3L_triangleRemapBarycentrics[3];
|
||||
_S3L_triangleRemapBarycentrics[1] = _S3L_triangleRemapBarycentrics[4];
|
||||
_S3L_triangleRemapBarycentrics[2] = _S3L_triangleRemapBarycentrics[5];
|
||||
#endif
|
||||
|
||||
S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
|
||||
modelIndex, triangleIndex);
|
||||
}
|
||||
#else
|
||||
S3L_UNUSED(split);
|
||||
|
||||
if (S3L_sortArrayLength >= S3L_MAX_TRIANGES_DRAWN)
|
||||
break;
|
||||
|
@ -2799,15 +2892,24 @@ void S3L_drawScene(S3L_Scene scene)
|
|||
require a lot of memory, which for small resolutions could be even
|
||||
worse than z-bufer. So this seems to be the best way memory-wise. */
|
||||
|
||||
uint8_t split = _S3L_projectTriangle(model,triangleIndex,matFinal,
|
||||
scene.camera.focalLength,transformed);
|
||||
_S3L_projectTriangle(model,triangleIndex,matFinal,scene.camera.focalLength,
|
||||
transformed);
|
||||
|
||||
S3L_drawTriangle(transformed[0],transformed[1],transformed[2],modelIndex,
|
||||
triangleIndex);
|
||||
|
||||
if (split)
|
||||
if (_S3L_projectedTriangleState == 2)
|
||||
{
|
||||
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||
_S3L_triangleRemapBarycentrics[0] = _S3L_triangleRemapBarycentrics[3];
|
||||
_S3L_triangleRemapBarycentrics[1] = _S3L_triangleRemapBarycentrics[4];
|
||||
_S3L_triangleRemapBarycentrics[2] = _S3L_triangleRemapBarycentrics[5];
|
||||
#endif
|
||||
|
||||
S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
|
||||
modelIndex, triangleIndex);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue