Mipmapping for a SW renderer

Started by
5 comments, last by Hodgman 7 years, 4 months ago

I am writing a sofware renderer. I have no SIMD or multithreading functionality yet. When rasterizing a triangle I loop over all of the pixels in its bounding box (in screen coordinates) and interpolate and color the pixels that pass the edge function. I tried implementing mipmapping but found that to compute the texture coordinate differentials I needed the interpolated values for the right and bottom neighboring pixels (whose attributes are not interpolated at this point).

I thought of couple solutions:

1) Do another loop before the main one which would just calculate all of the interpolated texture coordinates so they are available in the main loop. (This is obviously slow)

2) Choose the right mip level of the texture by calculating the maximum differential from the 3 vertices of the rasterized triangle. Would this work?

Intuitively it seems to me that yes: consider two vertices, u1 = 0, u2 = 1 and in screen coordinates x1 = 100, x2 = 600. Then it makes sense to pick a larger texture. On the other hand if u1 = 0 and u2 = 0 and x1= 100, x2 = 101, then picking the

smallest texture sounds reasonable.

Would these solutions work and/or is there a better one?

Advertisement

AFAIK, GPU's rasterize using one or more coarse grids before they start shading individual pixels.

So, for example, your loop would iterate over 2x2 pixel blocks instead of iterating over individual pixels. For each 2x2 pixel block that passes the edge test, then process those 4 pixels (either in another internal loop, an unrolled loop, or in one go via SSE/SIMD instructions), discarding results for any pixels in the block that fail the edge test.

So the mipmap index calculation would look like this:

1) Calculate the interpolated texture coordinates for the 4 pixels.

2) Calculate the the largest du, dv for the top left pixel:


// (x,y) are current pixel coords
float duDx = pixel(x+1, y).u - pixel(x,y).u;
float dvDx = pixel(x+1, y).v - pixel(x,y).v;
float duDy = pixel(x, y+1).u - pixel(x,y).u;
float dvDy = pixel(x, y+1).v - pixel(x,y).v;

// choose max from these to calculate mipmap index

3) Now do I also use the index calculated for the topleft pixel as the index for the other 3 pixels?

been forever since i wrote a software renderer, but as i recall, you'd lerp across one edge of the texture, then the other edge, then lerp between the results to get the texel. or something like that. to add mip levels, you'd determine which texture mip level to use before you started ratserizing i would think. i don't recall offhand how triangle pixels were selected for mapping to the texture via lerps. i used a combo of "principles of interactive computer graphics" by neumann & sproulll, and "Zen of graphics programming" by abrash. the "bible" AKA foley van damm, et al should have the algos too. i think the rasterization algo came from abrash, or maybe neumann and sproull. newman and sproull had all the stuff like the sutherland-hodegmann clipping algo.

https://www.amazon.com/Principles-Interactive-Computer-Graphics-William/dp/0070664552

https://www.amazon.com/Zen-Graphics-Programming-Ultimate-Writing/dp/188357708X/ref=sr_1_fkmr0_3?s=books&ie=UTF8&qid=1481122808&sr=1-3-fkmr0&keywords=3d+graphics+abrash

https://www.amazon.com/Computer-Graphics-Principles-Practice-3rd/dp/0321399528

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

Also, some more information regarding mipmapping (regarding miplevel selection) - I'd suggest looking also at: https://www.opengl.org/registry/doc/glspec45.core.pdf, Chapter 8.14 - Texture minification.

The actual implementation is mostly done the exact way Hodgman described. You calculated your partial derivatives correctly - next, based on your derivatives you first need to decide whether you are going to need magnification or minification filter (based on the length of derivation vectors). In case of minification filter you need to select a mipmap - the equations are in the chapter in OpenGL specs (I just briefly looked at them though - there should be 2 for calculating derivatives length - one is approximation and it is used, another one is more accurate but due to using square root it is not used).

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

Thanks everyone for the suggestions.

Now do I also use the index calculated for the topleft pixel as the index for the other 3 pixels?
On GPU's, they call these two options coarse derivatives (use the top-left pixel's value for the whole 2x2 block) and fine derivatives (recalculate derivatives for each pixel in the block).

For most situations, it's hard to tell the quality difference between them.

This topic is closed to new replies.

Advertisement