Introduction
Continue with the affine transformation (i.e. after transformation, the midpoint of the line segment is no longer the midpoint), this will result in some distortion and this artifact is even more noticeable when the triangle is large:


Condition for linear interpolation
When interpolating the attributes in a linear way, we are saying that given a set of vertices, vi (where i is any integer>=0) with a set of attributes ai (such as texture coordinates), we have a function mapping a vertex to the corresponding attributes, i.e.
Say, to interpolate a vertex inside a triangle in a linear way, the function f need to have the following properties:
which means that we can calculate the interpolated attributes using the same weight taffine function with the following form:
Depth interpolation
When a vertex is projected from view space to normalized device coordinates(NDC), we will have the following relation (ratio of the triangles) between the view space and NDC space:
substitute equation 1 and 2 into the plane equation of the triangle lies on:
So, 1/zview is an affine function of xndc and yndc which can be interpolated linearly across the screen space (the transform from NDC space to screen space is a linear transform).
Attributes interpolation
In last section, we know how to interpolate the depth of a pixel linearly in screen space, the next problem is to interpolate the vertex attributes(e.g. texture coordinates). In view space, we know that those attributes can be interpolated linearly, so those attributes can be calculated by an affine function with the vertex position as parameters e.g.
Similar to interpolate depth, substitute equation 1 and 2 into the above equation:
Therefore, u/zview is an another affine function of xndc and yndc which can be interpolated linearly across the screen space. Hence we can interpolating u linearly by first interpolate 1/zview and u/zview across screen space, and then divide them per pixel.
The last problem…
Now, we know that we can interpolate the view space depth and vertex attributes linearly across screen space. But during the rasterization state, we only have vertices in homogenous coordinates (vertices are transformed by the projection matrix already), how can we get the zview to do the perspective correct interpolation?
Consider the projection matrix (I use D3D one, but the same for openGL):
After transforming the vertex position, the wcoordinate will be the view space depth!
And look at the matrix again and consider the transformed zcoordinates, it will in a form of:
After transforming to the NDC,
So the depth value can be directly interpolated using zNDC for depth test.
Demo
A javascript demo to rasterize the triangles can be viewed here.
Screen shot of the demo 
Conclusion
In this post, the steps to linear interpolate the vertex in screen space is described. And for rasterizing the depth buffer only (e.g. for occlusion), the depth value can be linearly interpolated directly with the z coordinate in NDC space which is even simpler.
References
[1]
[3]