Thank you ThomH for reading and your comment.ThomH wrote: ↑Mon Sep 21, 2020 10:21 pm the classic serial implementation for affine texturing a polygon is just two adds per pixel. In pseudo-C:
... with appropriate modifications to fixed point. You can set up offset_x/y at the start of each scan line either by tracking them along each edge and doing a divide, or by plane or barycentric calculations.Code: Select all
for(x = start ... end) { pixel[x][y] = pixel[texture_x][texture_y]; texture_x += offset_x; texture_y += offset_y; }
For now I've managed to put the calculation under the following form:
Code: Select all
for(x = start ... end) {
pixel[x][y] = pixel[texture_x][texture_y];
texture_x = K * (y-y0) - R * (x-x0);
texture_y = S * (x-x0) - T * (y-y0);
}
with (x0, y0) screen coordinates of reference point of texture
and K, R, S and T being values computed with trigonometry
Which is similar to what you describe because:
- Along a given scanline, terms (y-y0) don't vary so they can be considered as constant and then it can be written like that:
Code: Select all
texture_x = C_1 - R * (x-x0); texture_y = S * (x-x0) - C_2;
- As for terms (x-x0), they only increment by one from one pixel to the following one.
So, considering the nth pixel in the scanline, its texture coordinates are:and considering its immediate neighbour on its rightCode: Select all
texture_x[n] = C_1 - R * (x-x0); texture_y[n] = S * (x-x0) - C_2;
Code: Select all
texture_x[n+1] = C_1 - R * ((x+1)-x0) = C_1 - R*(x-x0) -R = texture_x[n] - R texture_y[n+1] = S * ((x+1)-x0) - C_2 = S*(x-x0) - C_2 + S = texture_y[n] + S
Code: Select all
texture_x[n+1] = texture_x[n] -R
texture_y[n+1] = texture_y[n] + S
I have R and S under the shape Ra/Rb and Sa/Sb with Rb<Ra and Sb<Sa.
Either I do the division and work with Q8.8 fixed point values to keep precision and accuracy.
Code: Select all
R = Ra / Rb
S = Sa / Sb
for(x = start ... end) {
pixel[x][y] = pixel[texture_x][texture_y];
texture_x -= R;
texture_y += S;
}
Code: Select all
for(x = start ... end) {
pixel[x][y] = pixel[texture_x][texture_y];
texture_x += -Rb;
ErrorX = Ra - texture_x;
If (|ErrorX*2| > Rb) Then
texture_x -= Ra
texture_y += Sb;
ErrorY = Sa - texture_y;
If (|ErrorY*2| > Sb) Then
texture_y -= Sa
}
In second case, I have no division and then 3 or 4 8-bits additions for each pixel.
So it's hard to figure out what's more efficient.
For now I only protyped in python the formulae given at the beginning of this post (i.e I haven't integrated the iterative formulation of the texture_x/y calculation)
I use this simple texture file:
When I do a projection on a plane 3D surface (it's not real perspective fill .. it's just image stretching ) by using floating point arithmetic it gives the following result: (I draw triangles to see the shape onto which I map the image)
And when i use 8 bits integer calculation (with lookup tables for euclidian norm, arctan, sin and cosine), it gives:
It doesn't look too dirty but last steps of calculation (the ones that compute R=Ra/Rb and S=Sa/Sb) are still done on floating point values and they are not incremental. So it might get a bit dirtier when I will deal with that.
What are plane or barycentric calculations ?