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

Add screen projection function

This commit is contained in:
Miloslav Číž 2019-06-22 14:41:30 +02:00
parent a89f3c192f
commit 4ed5e5fd84
3 changed files with 82 additions and 11 deletions

View file

@ -29,6 +29,8 @@
S3L_Model3D models[3];
S3L_Scene scene;
S3L_Vec4 teleportPoint;
uint32_t pixels[S3L_RESOLUTION_X * S3L_RESOLUTION_Y];
uint32_t frame = 0;
@ -80,6 +82,20 @@ void sampleTxture(S3L_Unit u, S3L_Unit v, uint8_t *r, uint8_t *g, uint8_t *b)
*b = texture[index];
}
void drawTeleport(int16_t x, int16_t y, S3L_ScreenCoord size)
{
int16_t halfSize = size / 2;
S3L_ScreenCoord x0 = S3L_max(0,x - halfSize);
S3L_ScreenCoord x1 = S3L_min(S3L_RESOLUTION_X - 1,x + halfSize);
S3L_ScreenCoord y0 = S3L_max(0,y - halfSize);
S3L_ScreenCoord y1 = S3L_min(S3L_RESOLUTION_Y - 1,y + halfSize);
for (S3L_ScreenCoord j = y0; j < y1; ++j)
for (S3L_ScreenCoord i = x0; i < x1; ++i)
setPixel(i,j,255,0,0);
}
void drawPixel(S3L_PixelInfo *p)
{
if (p->triangleID != previousTriangle)
@ -142,6 +158,13 @@ void draw()
S3L_drawScene(scene);
S3L_Vec4 screenPoint;
project3DPointToScreen(teleportPoint,scene.camera,&screenPoint);
if (screenPoint.z < S3L_zBufferRead(screenPoint.x,screenPoint.y))
drawTeleport(screenPoint.x,screenPoint.y,screenPoint.w);
clock_t nowT = clock();
double timeDiff = ((double) (nowT - nextT)) / CLOCKS_PER_SEC;
@ -167,6 +190,11 @@ int main()
SDL_Surface *screenSurface = SDL_GetWindowSurface(window);
SDL_Event event;
teleportPoint.x = 6 * S3L_FRACTIONS_PER_UNIT;
teleportPoint.y = -3 * S3L_FRACTIONS_PER_UNIT;
teleportPoint.z = 2 * S3L_FRACTIONS_PER_UNIT;
teleportPoint.w = S3L_FRACTIONS_PER_UNIT;
nextT = clock();
S3L_initCamera(&scene.camera);

View file

@ -512,6 +512,15 @@ static inline S3L_Unit S3L_cos(S3L_Unit x);
S3L_Unit S3L_vec3Length(S3L_Vec4 v);
S3L_Unit S3L_sqrt(S3L_Unit value);
/** Projects a single point from 3D space to the screen space (pixels), which
can be useful e.g. for drawing sprites. The w component of input and result
holds the point size. If this size is 0 in the result, the sprite is outside
the view. */
void project3DPointToScreen(
S3L_Vec4 point,
S3L_Camera camera,
S3L_Vec4 *result);
/** Computes a normalized normal of given triangle. */
void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2,
S3L_Vec4 *n);
@ -1419,6 +1428,50 @@ void S3L_initTransoform3D(S3L_Transform3D *t)
t->scale.w = 0;
}
/**
Performs perspecive division (z-divide). Does NOT check for division by zero.
*/
static inline void S3L_perspectiveDivide(S3L_Vec4 *vector,
S3L_Unit focalLength)
{
vector->x = (vector->x * focalLength) / vector->z;
vector->y = (vector->y * focalLength) / vector->z;
}
void project3DPointToScreen(
S3L_Vec4 point,
S3L_Camera camera,
S3L_Vec4 *result)
{
S3L_Mat4 m;
S3L_makeCameraMatrix(camera.transform,&m);
S3L_Unit s = point.w;
point.w = S3L_FRACTIONS_PER_UNIT;
S3L_vec3Xmat4(&point,&m);
point.z = S3L_nonZero(point.z);
S3L_perspectiveDivide(&point,camera.focalLength);
S3L_ScreenCoord x, y;
S3L_mapProjectionPlaneToScreen(point,&x,&y);
result->x = x;
result->y = y;
result->z = point.z;
result->w =
(point.z < 0) ? 0 :
(
(s * camera.focalLength * S3L_RESOLUTION_X) /
(point.z * S3L_FRACTIONS_PER_UNIT)
);
}
void S3L_lookAt(S3L_Vec4 pointTo, S3L_Transform3D *t)
{
S3L_Vec4 v;
@ -2296,16 +2349,6 @@ void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 *m)
S3L_mat4Xmat4(m,&r);
}
/**
Performs perspecive division (z-divide). Does NOT check for division by zero.
*/
static inline void S3L_perspectiveDivide(S3L_Vec4 *vector,
S3L_Unit focalLength)
{
vector->x = (vector->x * focalLength) / vector->z;
vector->y = (vector->y * focalLength) / vector->z;
}
int8_t S3L_triangleWinding(
S3L_ScreenCoord x0,
S3L_ScreenCoord y0,

View file

@ -16,7 +16,7 @@ features:
- function to set/clear stencil buffer -- can be useful
- function to map one point in 3D space to screen, along with size (for mapping
billboards/sprites etc.)
billboards/sprites etc.) DONE
- Optimize persp. correction!