srp
software rendering pipeline
Loading...
Searching...
No Matches
Rasterization

Functions that perform primitive rasterization & data interpolation. More...

Collaboration diagram for Rasterization:
static double signedAreaParallelogram (const vec3d *restrict a, const vec3d *restrict b)
 
static void calculateBarycentricCoordinatesForPointAndBarycentricDeltas (const vec3d *restrict SSPositions, const vec3d *restrict edgeVectors, vec2d point, double *restrict barycentricCoordinates, double *restrict barycentricDeltaX, double *restrict barycentricDeltaY)
 
static bool triangleIsEdgeFlatTopOrLeft (const vec3d *restrict edgeVector)
 
static void triangleInterpolatePositionAndVertexVariables (const SRPvsOutput vertices[3], const double barycentricCoordinates[3], const SRPShaderProgram *restrict sp, SRPInterpolated *pInterpolatedBuffer, vec4d *interpolatedPosition)
 
void drawTriangle (const SRPFramebuffer *fb, const SRPvsOutput vertices[3], const SRPShaderProgram *restrict sp, size_t primitiveID)
 

Detailed Description

Functions that perform primitive rasterization & data interpolation.

Function Documentation

◆ calculateBarycentricCoordinatesForPointAndBarycentricDeltas()

static void calculateBarycentricCoordinatesForPointAndBarycentricDeltas ( const vec3d *restrict  SSPositions,
const vec3d *restrict  edgeVectors,
vec2d  point,
double *restrict  barycentricCoordinates,
double *restrict  barycentricDeltaX,
double *restrict  barycentricDeltaY 
)
static

Calculate barycentric coordinates for a point and barycentric coordinates' delta values.

Parameters
[in]SSPositionsVertices' positions in screen-space
[in]edgeVectorsTriangle's edge vectors, where 0th element is a vector pointing from vertex 0 to vertex 1, 1th - from vertex 1 to vertex 2 and so on.
[in]pointA point for which to calculate the barycentric coordinates
[out]barycentricCoordinatesA pointer to 3-element double array to where output barycentric coordinates to
[out]barycentricDeltaX,barycentricDeltaYA pointer to 3-element double array to where to output the X and Y barycentric delta values. These show how much does the barycentric coordinates change if we move one pixel to the +X or to the +Y direction. Used in incremental computation of barycentric coordinates when looping over triangle's bounding box

◆ drawTriangle()

void drawTriangle ( const SRPFramebuffer fb,
const SRPvsOutput  vertices[3],
const SRPShaderProgram *restrict  sp,
size_t  primitiveID 
)

Draw the triangle that is specified by three vertices to the framebuffer

Parameters
[in]`fb`The framebuffer to draw to
[in]`vertices`Pointer to an array of 3 SRPvsOutputs
[in]`sp`The shader program to use
[in]`primitiveID`Primitive ID of this triangle
Todo:
Why compute these two edge vectors twice?
Todo:
Are rasterization rules working? Rough equality here?
Todo:
Avoid VLA (custom allocator?)
Todo:
fix rasterizer to accept both cw and ccw vertices and add correct frontFacing here!
Todo:
fragCoord should be window-space: see https://www.khronos.org/opengl/wiki/Fragment_Shader#Inputs
Todo:
SRPfsOutput.fragDepth may be set to 0 manually by the user

◆ signedAreaParallelogram()

static double signedAreaParallelogram ( const vec3d *restrict  a,
const vec3d *restrict  b 
)
static

Get a parallelogram's signed area. The two vectors define a parallelogram. Used for barycentric coordinates' initialization in calculateBarycentricCoordinatesForPointAndBarycentricDeltas()

◆ triangleInterpolatePositionAndVertexVariables()

static void triangleInterpolatePositionAndVertexVariables ( const SRPvsOutput  vertices[3],
const double  barycentricCoordinates[3],
const SRPShaderProgram *restrict  sp,
SRPInterpolated pInterpolatedBuffer,
vec4d interpolatedPosition 
)
static

Interpolate the fragment position and vertex variables inside the triangle.

Parameters
[in]verticesA pointer to an array of 3 vertices
[in]barycentricCoordinatesBarycentric coordinates of the fragment
[in]spA pointer to shader program to use
[out]pInterpolatedBufferA pointer to the buffer where interpolated variables will appear. Must be big enough to hold all of them
[out]interpolatedPositionA pointer to vec4d where interpolated position will appear.

Let \( v_0, v_1, v_2 \) be points in space that form a triangle and \( a, b, c \) be barycentric coordinates for a point \( P \) according to \( v_0, v_1, v_2 \) respectively. Then, by the property of barycentric coordinates \( P = av_0 + bv_1 + cv_2 \). This can be extrapolated to arbitrary values assigned to vertices, so this property lies in the core of so-called "affine" attribute interpolation.

But this method does not take into account that we have performed the perspective divide, so the texture (or whatever) will appear "skewed" on the primitive.

It can be shown (see the "see also" section) that perspective-correct Z value can be obtained by linearly interpolating between the reciprocals of input Z values, and similarly for arbitrary parameters. This is called perspective-correct attribute interpolation.

See also
https://www.comp.nus.edu.sg/%7Elowkl/publications/lowk_persp_interp_techrep.pdf
https://www.youtube.com/watch?v=F5X6S35SW2s

◆ triangleIsEdgeFlatTopOrLeft()

static bool triangleIsEdgeFlatTopOrLeft ( const vec3d *restrict  edgeVector)
static

Check if a triangle's edge is flat top or left. Used in rasterization rules.

Parameters
[in]edgeVectorA pointer to an edge vector (pointing from one vertex to the other)
Returns
Whether or not this edge is flat top or left
Todo:
Does it matter if I pass edge 0->1 or 1->0 (numbers = vertex indices)? This should be documented.