private Number4[] CreatePixelShaderInput(ref BarycentricCoordinates coordinates) { float w = InterpolationUtility.PrecalculateW( coordinates.Alpha, coordinates.Beta, coordinates.Gamma, _p0.W, _p1.W, _p2.W); var v0Data = _primitive.Vertices[0].OutputData; var v1Data = _primitive.Vertices[1].OutputData; var v2Data = _primitive.Vertices[2].OutputData; // Calculate interpolated attribute values for this fragment. // TODO: Optimize this. var result = new Number4[_primitive.Vertices[0].OutputData.Length]; foreach (var outputInputBinding in OutputInputBindings.Bindings) { var v0Value = v0Data[outputInputBinding.Register]; var v1Value = v1Data[outputInputBinding.Register]; var v2Value = v2Data[outputInputBinding.Register]; if (outputInputBinding.SystemValueType != Name.Undefined) { throw new NotImplementedException(); } // Create input values. Normally, this will require interpolation // of the vertex attributes. Number4 inputValue; switch (outputInputBinding.InterpolationMode) { case InterpolationMode.Constant: inputValue = v0Value; break; case InterpolationMode.Linear: inputValue = InterpolationUtility.Perspective( coordinates.Alpha, coordinates.Beta, coordinates.Gamma, ref v0Value, ref v1Value, ref v2Value, _p0.W, _p1.W, _p2.W, w); break; case InterpolationMode.LinearNoPerspective: inputValue = InterpolationUtility.Linear( coordinates.Alpha, coordinates.Beta, coordinates.Gamma, ref v0Value, ref v1Value, ref v2Value); break; default: throw new InvalidOperationException("Unrecognised interpolation mode: " + outputInputBinding.InterpolationMode); } // Apply component mask so that we don't overwrite other values in this register. result[outputInputBinding.Register].WriteMaskedValue( inputValue, outputInputBinding.ComponentMask); } return(result); }
private bool IsSampleInsideTriangle(ref BarycentricCoordinates coordinates, out float depth) { // TODO: Use fill convention. // If any of these tests fails, the current pixel is not inside the triangle. if (coordinates.IsOutsideTriangle) { depth = 0; return(false); } // Calculate depth. depth = InterpolationUtility.Linear(coordinates.Alpha, coordinates.Beta, coordinates.Gamma, _p0.Z, _p1.Z, _p2.Z); //// Clip to near and far planes. //if (depth < 0 || depth > 1) // return false; //// Clip to 0 < w. //// TODO: Is this right? //// TODO: We do the same thing later on for attribute interpolations, can it be optimised? //var w = InterpolationUtility.Linear(coordinates.Alpha, coordinates.Beta, coordinates.Gamma, _p0.W, _p1.W, _p2.W); //if (w <= 0) // return false; // The exact value to compare against depends on fill mode - if we're rendering wireframe, // then check whether sample position is within the "wireframe threshold" (i.e. 1 pixel) of an edge. switch (RasterizerState.FillMode) { case FillMode.Solid: return(true); case FillMode.Wireframe: // TODO: This threshold thing is not correct. const float wireframeThreshold = 0.1f; return(coordinates.Alpha < wireframeThreshold || coordinates.Beta < wireframeThreshold || coordinates.Gamma < wireframeThreshold); default: throw new NotSupportedException(); } }