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

Fix persp. corr (ugly)

This commit is contained in:
Miloslav Číž 2019-06-01 15:40:29 +02:00
parent a7237a2aee
commit 625d2436eb
2 changed files with 45 additions and 149 deletions

View file

@ -1077,106 +1077,6 @@ typedef struct
#define S3L_stepFastLerp(state)\ #define S3L_stepFastLerp(state)\
state.valueScaled += state.stepScaled state.valueScaled += state.stepScaled
typedef struct
{
S3L_ScreenCoord p0[2]; ///< 2D coordinates of the 1st point projection
S3L_ScreenCoord p1[2]; ///< 2D coordinates of the 2nd point projection
S3L_Unit a[3]; ///< 3D coordinates of the 1st projected point of the line
S3L_Unit b[3]; ///< 3D coordinates of the 2nd projected point of the line
S3L_Unit pointDifference[3]; ///< [bx - ax, by - ay, bz - cz]
S3L_ScreenCoord c[2]; /**< helper point to for a plane for the intersection
with line */
S3L_Unit fcx; ///< precomputed helper product
S3L_Unit fcy; ///< precomputed helper product
S3L_Unit focalLength;
} S3L_PerspectiveCorrectionState; ///< State for computing persp. correction.
/**
Initializes the state of perspective correction along a line. The correction
itself is then done using S3L_correctPerspective function, using the state.
*/
void S3L_initPerspectiveCorrectionState(
S3L_ScreenCoord x0,
S3L_ScreenCoord y0,
S3L_Unit depth0,
S3L_ScreenCoord x1,
S3L_ScreenCoord y1,
S3L_Unit depth1,
S3L_Unit focalLength,
S3L_PerspectiveCorrectionState *state)
{
state->focalLength = focalLength;
state->p0[0] = x0;
state->p0[1] = y0;
state->p1[0] = x1;
state->p1[1] = y1;
state->a[0] = (x0 * (depth0 + focalLength)) / focalLength;
state->a[1] = (y0 * (depth0 + focalLength)) / focalLength;
state->a[2] = depth0;
state->b[0] = (x1 * (depth1 + focalLength)) / focalLength;
state->b[1] = (y1 * (depth1 + focalLength)) / focalLength;
state->b[2] = depth1;
state->pointDifference[0] = state->b[0] - state->a[0];
state->pointDifference[1] = state->b[1] - state->a[1];
state->pointDifference[2] = state->b[2] - state->a[2];
state->c[0] = x1 + y1 - y0;
state->c[1] = y1 - x1 + x0;
state->fcx = focalLength * state->c[0];
state->fcy = focalLength * state->c[1];
}
S3L_Unit S3L_correctPerspective(
S3L_Unit interpolationParameter, S3L_PerspectiveCorrectionState *state)
{
S3L_Unit p[2]; // lin. interpolated position between the projections
// TODO: perhaps this could be interpolated faster by stepping?
p[0] =
S3L_interpolateByUnit(state->p0[0],state->p1[0],interpolationParameter);
p[1] =
S3L_interpolateByUnit(state->p0[1],state->p1[1],interpolationParameter);
S3L_Unit a, b, c, d; // plane coeficients
a = state->focalLength * p[1] - state->fcy;
b = state->fcx - state->focalLength * p[0];
c = p[0] * state->c[1] - p[1] * state->c[0];
d = state->focalLength * c;
a >>= 4; // TODO: this sometimes prevents overflow, but should be solved better!
b >>= 4;
c >>= 4;
d >>= 4;
S3L_Unit result =
(
- a * state->a[0] - b * state->a[1] - c * state->a[2] - d
)
/
S3L_nonZero(
(
a * state->pointDifference[0] +
b * state->pointDifference[1] +
c * state->pointDifference[2]
) / S3L_FRACTIONS_PER_UNIT
);
return result < 0 ? 0 :
(result > S3L_FRACTIONS_PER_UNIT ? S3L_FRACTIONS_PER_UNIT : result);
}
static inline S3L_Unit S3L_interpolateBarycentric( static inline S3L_Unit S3L_interpolateBarycentric(
S3L_Unit value0, S3L_Unit value0,
S3L_Unit value1, S3L_Unit value1,
@ -1475,22 +1375,23 @@ void S3L_drawTriangle(
initSide(r,t,r,1) initSide(r,t,r,1)
initSide(l,t,l,1) initSide(l,t,l,1)
#define initPC(f,t,pc)\
S3L_initPerspectiveCorrectionState(\
f##PointPP->x,\
f##PointPP->y,\
f##PointPP->z,\
t##PointPP->x,\
t##PointPP->y,\
t##PointPP->z,\
camera->focalLength,\
&pc##PC);
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL #if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL
S3L_PerspectiveCorrectionState lPC, rPC, rowPC; S3L_Unit tPointRecipZ, lPointRecipZ, rPointRecipZ,
lRecip0, lRecip1, rRecip0, rRecip1;
initPC(t,l,l) tPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
initPC(t,r,r) / S3L_nonZero(tPointPP->z);
lPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
/ S3L_nonZero(lPointPP->z);
rPointRecipZ = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
/ S3L_nonZero(rPointPP->z);
lRecip0 = tPointRecipZ;
lRecip1 = lPointRecipZ;
rRecip0 = tPointRecipZ;
rRecip1 = rPointRecipZ;
#endif #endif
// clip to the screen in y dimension: // clip to the screen in y dimension:
@ -1519,20 +1420,22 @@ void S3L_drawTriangle(
{ {
initSide(l,l,r,0); initSide(l,l,r,0);
manageSplit(0,2,r) manageSplit(0,2,r)
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL #if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL
initPC(r,l,l) lRecip0 = rPointRecipZ;
initPC(r,t,r) lRecip1 = lPointRecipZ;
rRecip0 = rPointRecipZ;
rRecip1 = tPointRecipZ ;
#endif #endif
} }
else else
{ {
initSide(r,r,l,0); initSide(r,r,l,0);
manageSplit(1,2,l) manageSplit(1,2,l)
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL #if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL
initPC(l,r,r) rRecip0 = lPointRecipZ;
initPC(l,t,l) rRecip1 = rPointRecipZ;
lRecip0 = lPointRecipZ;
lRecip1 = tPointRecipZ;
#endif #endif
} }
} }
@ -1552,26 +1455,16 @@ void S3L_drawTriangle(
S3L_Unit rowLength = S3L_nonZero(rX - lX - 1); // prevent zero div S3L_Unit rowLength = S3L_nonZero(rX - lX - 1); // prevent zero div
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL #if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL
S3L_Unit S3L_Unit lOverZ, lRecipZ, rOverZ, rRecipZ, lT, rT;
lDepth, rDepth,
lT, rT; // perspective-corrected position along either side
lT = S3L_correctPerspective(S3L_getFastLerpValue(lSideFLS),&lPC); lT = S3L_getFastLerpValue(lSideFLS);
rT = S3L_correctPerspective(S3L_getFastLerpValue(rSideFLS),&rPC); rT = S3L_getFastLerpValue(rSideFLS);
lDepth = S3L_interpolateByUnit(lPC.a[2],lPC.b[2],lT); lOverZ = S3L_interpolateByUnitFrom0(lRecip1,lT);
rDepth = S3L_interpolateByUnit(rPC.a[2],rPC.b[2],rT); lRecipZ = S3L_interpolateByUnit(lRecip0,lRecip1,lT);
S3L_initPerspectiveCorrectionState( rOverZ = S3L_interpolateByUnitFrom0(rRecip1,rT);
S3L_interpolateByUnit(lPC.a[0],lPC.b[0],lT), rRecipZ = S3L_interpolateByUnit(rRecip0,rRecip1,rT);
S3L_interpolateByUnit(lPC.a[1],lPC.b[1],lT),
lDepth,
S3L_interpolateByUnit(rPC.a[0],rPC.b[0],rT),
S3L_interpolateByUnit(rPC.a[1],rPC.b[1],rT),
rDepth,
camera->focalLength,
&rowPC
);
#else #else
S3L_FastLerpState b0FLS, b1FLS; S3L_FastLerpState b0FLS, b1FLS;
@ -1619,16 +1512,8 @@ void S3L_drawTriangle(
#endif #endif
p.x = x; p.x = x;
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL
S3L_Unit rowT =
S3L_correctPerspective(S3L_interpolateFrom0(S3L_FRACTIONS_PER_UNIT,
x - lX,rowLength),&rowPC);
#endif
#if S3L_COMPUTE_DEPTH #if S3L_COMPUTE_DEPTH
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL #if S3L_PERSPECTIVE_CORRECTION != S3L_PC_FULL
p.depth = S3L_interpolateByUnit(lDepth,rDepth,rowT);
#else
p.depth = S3L_getFastLerpValue(depthFLS); p.depth = S3L_getFastLerpValue(depthFLS);
S3L_stepFastLerp(depthFLS); S3L_stepFastLerp(depthFLS);
#endif #endif
@ -1645,11 +1530,20 @@ void S3L_drawTriangle(
#endif #endif
#if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL #if S3L_PERSPECTIVE_CORRECTION == S3L_PC_FULL
p.depth = (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT) /
S3L_nonZero(S3L_interpolate(lRecipZ,rRecipZ,x - lX,rX - lX));
*barycentric0 = *barycentric0 =
S3L_interpolateByUnitFrom0(rT,rowT); (
S3L_interpolate(0,rOverZ,x - lX,rX - lX)
* p.depth
) / S3L_FRACTIONS_PER_UNIT;
*barycentric1 = *barycentric1 =
S3L_interpolateByUnitFrom0(lT,S3L_FRACTIONS_PER_UNIT - rowT); (
S3L_interpolate(lOverZ,0,x - lX,rX - lX)
* p.depth
) / S3L_FRACTIONS_PER_UNIT;
#else #else
*barycentric0 = S3L_getFastLerpValue(b0FLS); *barycentric0 = S3L_getFastLerpValue(b0FLS);
*barycentric1 = S3L_getFastLerpValue(b1FLS); *barycentric1 = S3L_getFastLerpValue(b1FLS);

View file

@ -7,7 +7,9 @@
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#define S3L_PRESET_HIGHEST_QUALITY //#define S3L_PRESET_HIGHEST_QUALITY
#define S3L_PERSPECTIVE_CORRECTION 1
#define S3L_PIXEL_FUNCTION drawPixel #define S3L_PIXEL_FUNCTION drawPixel