示例#1
0
        protected override double GetAttenuatedContribution(Point3D modelPosition, double nonAttenuatedValue)
        {
            // distance+falloff Attenuated raw contribution
            double attenuatedContribution = base.GetAttenuatedContribution(modelPosition, nonAttenuatedValue);

            Vector3D surfaceDirection = MathEx.Normalize(modelPosition - this.position);
            double   cosSurfaceAngle  = MathEx.DotProduct(surfaceDirection, direction);
            double   surfaceAngle     = MathEx.ToDegrees(Math.Acos(cosSurfaceAngle));

            double angleFactor;

            if (surfaceAngle <= innerConeAngle)
            {
                angleFactor = 1.0;
            }
            // Make sure we render in the larger bound, since it will affect our final error
            else if (surfaceAngle > innerConeAngle &&
                     surfaceAngle < (outerConeAngle + RenderTolerance.SpotLightAngleTolerance))
            {
                // Do DX light equation fade
                angleFactor  = cosSurfaceAngle - cosInnerConeAngle;
                angleFactor /= cosOuterConeAngle - cosInnerConeAngle;
                angleFactor  = Math.Max(0, angleFactor);

                //
                angleFactor = 1.0 - angleFactor;
            }
            else // Greater than outer cone angle
            {
                angleFactor = 0.0;
            }

            double totalContribution = attenuatedContribution * angleFactor;

            // If we're within SpotLightAngleTolerance degrees of being unlit, then set
            // error based on how much light we expect
            if (Math.Abs(surfaceAngle - outerConeAngle) < RenderTolerance.SpotLightAngleTolerance)
            {
                // This is so close, we may or may not light this point
                // So we compute the maximum possible error by scaling (255,255,255) by the
                // light contribution we would have if we DID light it.
                Color expected   = ColorOperations.ScaleOpaque(lightColor, totalContribution);
                Color angleError = ColorOperations.Modulate(expected, lightToleranceColor);

                lastIlluminationError = ColorOperations.Add(lastIlluminationError, angleError);
            }
            return(totalContribution);
        }
示例#2
0
        protected virtual double GetAttenuatedContribution(Point3D modelPosition, double nonAttenuatedValue)
        {
            Vector3D lightDirection = this.position - modelPosition;
            double   distance       = MathEx.Length(lightDirection);

            double attenuation = constantAttenuation
                                 + linearAttenuation * distance
                                 + quadraticAttenuation * distance * distance;

            // We want to make sure the we have no augmenting or negative attenuation
            attenuation = Math.Max(1.0, attenuation);

            double finalContribution;

            if (distance > range) // We don't light things that are out of range
            {
                finalContribution = 0.0;
            }
            else
            {
                // We take specular and diffuse and divide to attenuate
                finalContribution = nonAttenuatedValue / attenuation;
            }

            // Prevent negative contributions
            finalContribution = Math.Max(finalContribution, 0);

            if (Math.Abs(distance - range) < RenderTolerance.LightingRangeTolerance)
            {
                // This is so close, we may or may not light this point
                // So we compute the maximum possible error by scaling (255,255,255) by the
                // light contribution we would have if we DID light it.
                Color expected   = ColorOperations.ScaleOpaque(lightColor, finalContribution);
                Color rangeError = ColorOperations.Modulate(expected, lightToleranceColor);

                // We then add this error to our accumulated error for this illumination call
                lastIlluminationError = ColorOperations.Add(lastIlluminationError, rangeError);
            }

            // We don't clamp to 1, since this would break attenuating the falloff
            //  of a spotlight.

            return(finalContribution);
        }
示例#3
0
        protected double GetSpecularContribution(Vector3D view, Vector3D normal, Vector3D light, double exponent)
        {
            System.Diagnostics.Debug.Assert(RenderTolerance.SpecularLightDotProductTolerance >= 0);

            // Make vectors unit length
            normal = MathEx.Normalize(normal);
            light  = MathEx.Normalize(light);
            view   = MathEx.Normalize(view);

            double spec  = 0.0;
            double nDotl = MathEx.DotProduct(light, normal);

            if (nDotl >= -RenderTolerance.SpecularLightDotProductTolerance)
            {
                Vector3D half = MathEx.Normalize(light + view);

                spec = Math.Max(MathEx.DotProduct(normal, half), 0);
                spec = Math.Pow(spec, exponent);

                // We want a +/- tolerance bound on the dot product computation
                if (Math.Abs(nDotl) <= RenderTolerance.SpecularLightDotProductTolerance)
                {
                    // This is so close, we may or may not light this point
                    // So we compute the maximum possible error by scaling (0,255,255,255) by the
                    // light contribution we would have if we DID light it.
                    Color expected  = ColorOperations.ScaleOpaque(lightColor, spec);
                    Color specError = ColorOperations.Modulate(expected, lightToleranceColor);

                    // We then add this error to our accumulated error for this illumination call
                    lastIlluminationError = ColorOperations.Add(lastIlluminationError, specError);

                    // ignore it for our rendering
                    spec = 0.0;
                }
            }
            return(spec);
        }
示例#4
0
        /// <summary>
        /// Gouraud shading computes lighting per-vertex, in this method.
        /// Final pixel values are gathered from interpolating between pixels.
        /// Lighting is precomputed in this step per material.
        /// </summary>
        /// <param name="v">Input/Output per-vertex data.</param>
        protected override void ComputeVertexProgram(Vertex v)
        {
            // No color here ...
            v.Color = emptyColor;
            // Tolerance
            v.ColorTolerance = emptyColor;

            v.PrecomputedLight          = new Color[textures.Length];
            v.PrecomputedLightTolerance = new Color[textures.Length];
            int      textureIndex = 0;
            Point3D  position     = v.PositionAsPoint3D;
            Vector3D normal       = v.Normal;

            // Precompute lighting for all textures
            foreach (TextureFilter texture in textures)
            {
                HdrColor color     = emptyColor;
                HdrColor tolerance = emptyColor;

                if (texture != null)
                {
                    // Lighting is done in Premultiplied color space.
                    //
                    //  - BIG NOTE! - We do not actually premultiply the light contribution
                    //    because lighting is always opaque and premultiplying opaque colors
                    //    is a no-op.
                    //
                    //  - Tolerance CANNOT be done in Premultiplied color space because
                    //    it needs to know the final pixel color in order to premultiply properly.
                    //    We won't know the final pixel color until ComputePixelProgram is called.

                    // We ignore Alpha values during the computation and set the final value to
                    //  materialColor.A at the end.  This is why you will not see any clamping of
                    //  light values, etc in the code below.

                    Color materialColor = ColorOperations.PreMultiplyColor(texture.MaterialColor);

                    switch (texture.MaterialType)
                    {
                    case MaterialType.Diffuse:
                        foreach (LightEquation light in lightEquations)
                        {
                            Color lightContribution = light.IluminateDiffuse(position, normal);

                            if (light is AmbientLightEquation)
                            {
                                // AmbientColor knobs are reminiscent of additive material passes
                                //  because the alpha value will not be considered in the final color value
                                //  (i.e. premultiply to scale RGB by alpha, then never use alpha again)
                                Color ambientColor = ColorOperations.PreMultiplyColor(texture.AmbientColor);
                                color += ColorOperations.Modulate(lightContribution, ambientColor);
                            }
                            else
                            {
                                color += ColorOperations.Modulate(lightContribution, materialColor);
                            }
                            tolerance += light.GetLastError();
                        }
                        break;

                    case MaterialType.Specular:
                        foreach (LightEquation light in lightEquations)
                        {
                            // Don't need to check light equation type, since Ambient will return black
                            Color lightContribution = light.IluminateSpecular(position, normal, texture.SpecularPower);
                            color += ColorOperations.Modulate(lightContribution, materialColor);

                            tolerance += light.GetLastError();
                        }
                        break;

                    case MaterialType.Emissive:
                        color = materialColor;
                        break;
                    }

                    // Alpha is only considered at the end.  Overwrite whatever happened during the precomputation.
                    //  - Note that the alpha of the AmbientColor knob is NOT considered in the final value.

                    color.A = ColorOperations.ByteToDouble(materialColor.A);
                }

                v.PrecomputedLight[textureIndex]          = color.ClampedValue;
                v.PrecomputedLightTolerance[textureIndex] = tolerance.ClampedValue;

                textureIndex++;
            }
        }
示例#5
0
        /// <summary>
        /// Lights this pixel using precomputed lighting information.
        /// </summary>
        /// <param name="v">Interpolated vertex for this pixel position.</param>
        protected override void ComputePixelProgram(Vertex v)
        {
            bool  rendered = false;
            Color totalTexturingTolerance = emptyColor;

            for (int pass = 0; pass < textures.Length; pass++)
            {
                // A Filter can be null if the Material or the Brush are null.
                // For those cases, we skip the material entirely.
                if (textures[pass] == null)
                {
                    continue;
                }
                TextureFilter currentTexture = textures[pass];
                rendered = true;

                // We need extra information for trilinear
                if (currentTexture is TrilinearTextureFilter)
                {
                    ((TrilinearTextureFilter)currentTexture).MipMapFactor = v.MipMapFactor;
                }

                // Textures are not stored in premultiplied color space.
                // This means that we have to wait until we find the lookup tolerance before we can premultiply
                //  (otherwise Alpha will be way off)

                Color texel          = currentTexture.FilteredTextureLookup(v.TextureCoordinates);
                Color texelTolerance = emptyColor;
                if (currentTexture.HasErrorEstimation)
                {
                    texelTolerance = currentTexture.FilteredErrorLookup(
                        v.UVToleranceMin,
                        v.UVToleranceMax,
                        texel);
                }

                // Now we can premultiply.
                Color premultTexel          = ColorOperations.PreMultiplyColor(texel);
                Color premultTexelTolerance = ColorOperations.PreMultiplyTolerance(texelTolerance, texel.A);

                // Modulate precomputed lighting (which is also premultiplied) by the Brush value
                Color premultColor     = ColorOperations.Modulate(v.PrecomputedLight[pass], premultTexel);
                Color premultTolerance = ColorOperations.Modulate(v.PrecomputedLight[pass], premultTexelTolerance);

                // PrecomputedLightTolerance is NOT premultipled yet (see ComputeVertexProgram above).
                //  This is because we needed to know the final alpha value of lighting * texture.
                //
                Color premultLightTolerance = ColorOperations.PreMultiplyTolerance(v.PrecomputedLightTolerance[pass], premultColor.A);
                premultTolerance = ColorOperations.Add(premultTolerance, premultLightTolerance);

                // For additive materials, we need to force the alpha channel to zero.
                // See notes on premultiplied blending in ColorOperations.cs
                if (currentTexture.MaterialType != MaterialType.Diffuse)
                {
                    premultColor.A = 0x00;
                    // Nothing needs to be done to tolerance's alpha
                    //  because the framebuffer's alpha value will be used in the blend
                }

                // we need to blend
                // Write to frame buffer according to alpha value of pixel
                v.Color = ColorOperations.PreMultipliedAlphaBlend(premultColor, v.Color);

                // Accumulate tolerance for each material pass
                totalTexturingTolerance = ColorOperations.PreMultipliedToleranceBlend(
                    premultTolerance,
                    totalTexturingTolerance,
                    premultColor.A);
            }

            // Only set a pixel if we actually rendered at least one material for it ...
            if (rendered)
            {
                // Add texturing tolerance to our existing lighting tolerance.
                v.ColorTolerance = ColorOperations.Add(v.ColorTolerance, totalTexturingTolerance);

                // Send the pixel to be rendered
                buffer.SetPixel(
                    (int)Math.Floor(v.ProjectedPosition.X),
                    (int)Math.Floor(v.ProjectedPosition.Y),
                    (float)v.ProjectedPosition.Z,
                    v.Color,
                    v.ColorTolerance
                    );
            }
        }