Rasterizer: Pre-divide vertex attributes by W
Execute the division-by-W for perspective-correct interpolation of values in the clipper, moving them out of the rasterization inner loop.
This commit is contained in:
		@@ -91,10 +91,17 @@ static void InitScreenCoordinates(OutputVertex& vtx)
 | 
			
		||||
    viewport.zscale     = float24::FromRawFloat24(registers.viewport_depth_range);
 | 
			
		||||
    viewport.offset_z   = float24::FromRawFloat24(registers.viewport_depth_far_plane);
 | 
			
		||||
 | 
			
		||||
    float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
 | 
			
		||||
    vtx.color *= inv_w;
 | 
			
		||||
    vtx.tc0 *= inv_w;
 | 
			
		||||
    vtx.tc1 *= inv_w;
 | 
			
		||||
    vtx.tc2 *= inv_w;
 | 
			
		||||
    vtx.pos.w = inv_w;
 | 
			
		||||
 | 
			
		||||
    // TODO: Not sure why the viewport width needs to be divided by 2 but the viewport height does not
 | 
			
		||||
    vtx.screenpos[0] = (vtx.pos.x / vtx.pos.w + float24::FromFloat32(1.0)) * viewport.halfsize_x + viewport.offset_x;
 | 
			
		||||
    vtx.screenpos[1] = (vtx.pos.y / vtx.pos.w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y;
 | 
			
		||||
    vtx.screenpos[2] = viewport.offset_z - vtx.pos.z / vtx.pos.w * viewport.zscale;
 | 
			
		||||
    vtx.screenpos[0] = (vtx.pos.x * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_x + viewport.offset_x;
 | 
			
		||||
    vtx.screenpos[1] = (vtx.pos.y * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y;
 | 
			
		||||
    vtx.screenpos[2] = viewport.offset_z - vtx.pos.z * inv_w * viewport.zscale;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
 | 
			
		||||
 
 | 
			
		||||
@@ -757,6 +757,26 @@ struct float24 {
 | 
			
		||||
        return float24::FromFloat32(ToFloat32() - flt.ToFloat32());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float24& operator *= (const float24& flt) {
 | 
			
		||||
        value *= flt.ToFloat32();
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float24& operator /= (const float24& flt) {
 | 
			
		||||
        value /= flt.ToFloat32();
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float24& operator += (const float24& flt) {
 | 
			
		||||
        value += flt.ToFloat32();
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float24& operator -= (const float24& flt) {
 | 
			
		||||
        value -= flt.ToFloat32();
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float24 operator - () const {
 | 
			
		||||
        return float24::FromFloat32(-ToFloat32());
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -106,10 +106,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
 | 
			
		||||
    int bias1 = IsRightSideOrFlatBottomEdge(vtxpos[1].xy(), vtxpos[2].xy(), vtxpos[0].xy()) ? -1 : 0;
 | 
			
		||||
    int bias2 = IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
 | 
			
		||||
 | 
			
		||||
    const Math::Vec3<float24> w_inverse = Math::MakeVec(
 | 
			
		||||
            float24::FromFloat32(1.0f) / v0.pos.w,
 | 
			
		||||
            float24::FromFloat32(1.0f) / v1.pos.w,
 | 
			
		||||
            float24::FromFloat32(1.0f) / v2.pos.w);
 | 
			
		||||
    auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
 | 
			
		||||
 | 
			
		||||
    auto textures = registers.GetTextures();
 | 
			
		||||
    auto tev_stages = registers.GetTevStages();
 | 
			
		||||
@@ -158,7 +155,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
 | 
			
		||||
            //
 | 
			
		||||
            // The generalization to three vertices is straightforward in baricentric coordinates.
 | 
			
		||||
            auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) {
 | 
			
		||||
                auto attr_over_w = Math::MakeVec(attr0, attr1, attr2) * w_inverse;
 | 
			
		||||
                auto attr_over_w = Math::MakeVec(attr0, attr1, attr2);
 | 
			
		||||
                float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
 | 
			
		||||
                return interpolated_attr_over_w * interpolated_w_inverse;
 | 
			
		||||
            };
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user