예제 #1
0
        private int RayIntersectionDistanceInternal(Vector3 start, Vector3 end,
                                                    out Vector3 [] afT)
        {
            int riQuantity;
            // convert ray to box coordinates
            Vector3 direction  = end - start;
            Vector3 kDiff      = start - center;
            Vector3 kOrigin    = new Vector3(kDiff.Dot(axes[0]), kDiff.Dot(axes[1]), kDiff.Dot(axes[2]));
            Vector3 kDirection = new Vector3(direction.Dot(axes[0]), direction.Dot(axes[1]), direction.Dot(axes[2]));
            float   fT0        = 0.0f;
            float   fT1        = float.MaxValue;

            afT = new Vector3[] { Vector3.Zero, Vector3.Zero };
            bool bIntersects = FindIntersection(kOrigin, kDirection, ref fT0, ref fT1);

            if (bIntersects)
            {
                if (fT0 > 0.0f)
                {
                    if (fT1 <= 1.0f)
                    {
                        riQuantity = 2;
                        afT[0]     = start + fT0 * direction;
                        afT[1]     = start + fT1 * direction;
                    }
                    else
                    {
                        riQuantity = 1;
                        afT[0]     = start + fT0 * direction;
                    }
                }
                else                    // fT0 == 0.0
                {
                    if (fT1 <= 1.0f)
                    {
                        riQuantity = 1;
                        afT[0]     = start + fT1 * direction;
                    }
                    else                       // fT1 == INFINITY
                                               // assert:  should not get here
                    {
                        riQuantity = 0;
                    }
                }
            }
            else
            {
                riQuantity = 0;
            }

            return(riQuantity);
        }
예제 #2
0
        public override float RayIntersectionDistance(Vector3 start, Vector3 end)
        {
            // set up quadratic Q(t) = a*t^2 + 2*b*t + c
            Vector3 kDiff     = start - center;
            Vector3 direction = end - start;
            float   fA        = direction.LengthSquared;
            float   fB        = kDiff.Dot(direction);
            float   fC        = kDiff.LengthSquared - radius * radius;

            float afT0, afT1;
            float fDiscr = fB * fB - fA * fC;

            if (fDiscr < 0.0)
            {
                return(float.MaxValue);
            }
            else if (fDiscr > 0.0)
            {
                float fRoot = (float)Math.Sqrt(fDiscr);
                float fInvA = 1.0f / fA;
                afT0 = (-fB - fRoot) * fInvA;
                afT1 = (-fB + fRoot) * fInvA;
                if (afT1 >= 0.0)
                {
                    return(Math.Min((afT0 * direction).Length, (afT1 * direction).Length));
                }
                else if (afT1 >= 0.0)
                {
                    return(((start + afT1 * direction) - start).Length);
                }
                else
                {
                    return(float.MaxValue);
                }
            }
            else
            {
                afT0 = -fB / fA;
                if (afT0 >= 0.0)
                {
                    return(afT0 * direction.Length);
                }
                else
                {
                    return(float.MaxValue);
                }
            }
        }
예제 #3
0
        // Returns a (not-necessaryly unit) normal vector
        public Vector3 NormalVector(Vector3 p, Vector3 displacement)
        {
            const float cornerEpsilon = 0.001f;

            // First find out if we're at a corner
            for (int i = 0; i < 8; i++)
            {
                Vector3 corner = Corner(i);
                Vector3 d      = (p - corner);
                if (d.LengthSquared < cornerEpsilon)
                {
                    // This is the corner, so figure out which face to
                    // return.  Robin says that the best face is the one
                    // most in line with the displacement vector, which is
                    // the face that has the smallest cross product with
                    // the displacement vector
                    float   minCross = float.MaxValue;
                    Vector3 norm     = Vector3.Zero;
                    for (int j = 0; j < 3; j++)
                    {
                        Vector3 tc1 = Corner(cornerFaces[i, j, 0]) - corner;
                        Vector3 tc2 = Corner(cornerFaces[i, j, 1]) - corner;
                        // I wish we didn't have to normalize the bastard;
                        // sqrt is expensive!
                        Vector3 cross = tc1.Cross(tc2).ToNormalized();
                        float   cd    = cross.Dot(displacement);
                        if (cd < minCross)
                        {
                            minCross = cd;
                            norm     = cross;
                        }
                    }
                    return(norm);
                }
            }
            // It's not at a corner, so return the norm of the face
            // containing point p

            // ??? Need to finish
            return(Vector3.Zero);
        }
예제 #4
0
        private void AdjustCenterAndRadius(SphereTreeNode s)
        {
            // Don't adjust the root node
            if (parent == null)
            {
                return;
            }
            if (radius == 0)
            {
                center = s.center;
                radius = s.radius;
                return;
            }
            // Adjust the center and radius of this sphere do it
            // encompasses s
            Vector3 diff   = (s.center - center);
            float   sqDist = diff.Dot(diff);
            float   rDiff  = s.radius - radius;

            if (rDiff * rDiff >= sqDist)
            {
                // One is contained in the other
                if (s.radius >= radius)
                {
                    center = s.center;
                    radius = s.radius;
                }
            }
            else
            {
                float dist      = (float)Math.Sqrt(sqDist);
                float oldRadius = radius;
                radius = (dist + radius + s.radius) * 0.5f;
                if (dist > Primitives.epsilon)
                {
                    center += ((radius - oldRadius) / dist) * diff;
                }
            }
        }
예제 #5
0
        private void generateButton_Click(object sender, EventArgs e)
        {
            Cursor previousCursor = Cursor.Current;
            Cursor.Current = Cursors.WaitCursor;
            doneLabel.Visible = false;
            //outputPictureBox.Visible = false;

            if (generateLogFile.Checked) {
                string p = "NormalBump.log";
                FileStream f = new FileStream(p, FileMode.Create, FileAccess.Write);
                logStream = new StreamWriter(f);
                logStream.Write(string.Format("{0} Started writing to {1}\n",
                                              DateTime.Now.ToString("hh:mm:ss"), p));
            }

            // run the algorithm
            Bitmap normalMap = new Bitmap(normalMapTextBox.Text);
            Bitmap bumpMap = new Bitmap(bumpMapTextBox.Text);

            if (normalMap.Width != bumpMap.Width) {
                ShowError("Normal Map width {0} is not the same as Bump Map width {1}",
                          normalMap.Width, bumpMap.Width);
                return;
            }

            if (normalMap.Height != bumpMap.Height) {
                ShowError("Normal Map height {0} is not the same as Bump Map height {1}",
                          normalMap.Height, bumpMap.Height);
                return;
            }

            Bitmap outputMap = (Bitmap)normalMap.Clone();

            PixelFormat normalFormat = normalMap.PixelFormat;
            PixelFormat bumpFormat = bumpMap.PixelFormat;

            // This will be set by the slider
            float scaleFactor = (float)trackBar.Value / 100f;

            if (reverseBumpDirection.Checked)
                scaleFactor = - scaleFactor;

            Vector3 unitZ = new Vector3(0f, 0f, 1f);
            float epsilon = 0.0000001f;

            // Loop through the bump map pixels, computing the normals
            // into the output map
            int w = normalMap.Width;
            int h = normalMap.Height;
            for(int x=0; x < w; x++) {
                for(int y=0; y < h; y++) {
                    // Fetch the normal map normal vector
                    Color c = normalMap.GetPixel(x, y);
                    Vector3 normal = new Vector3(colorToFloat(c.R),
                                                 colorToFloat(c.G),
                                                 colorToFloat(c.B)).ToNormalized();
                    Vector3 result = normal;

                    // If we're at the edge, use the normal vector
                    if (x < w - 1 && y < h - 1) {
                        // Compute the bump normal vector
                        int xyLevel = bumpLevel(bumpMap, x, y);
                        float dx = scaleFactor * (bumpLevel(bumpMap, x+1, y) - xyLevel);
                        float dy = scaleFactor * (bumpLevel(bumpMap, x, y+1) - xyLevel);
                        float dz = 255f;
                        Vector3 bumpNormal = new Vector3(dx, dy, dz).ToNormalized();
                        if (generateLogFile.Checked)
                            Log("X {0}, Y {1}, normal {2}, bumpNormal {3}\n",
                                x, y, normal, bumpNormal);
                        Vector3 axis = unitZ.Cross(normal);
                        if (axis.Length > epsilon) {
                            float cosAngle = unitZ.Dot(normal);
                            float angle = (float)Math.Acos(cosAngle);
                            Quaternion q = Quaternion.FromAngleAxis(angle, axis);
                            Matrix3 rot = q.ToRotationMatrix();
                            result = rot * bumpNormal;
                            if (generateLogFile.Checked)
                                Log("   Angle {0}, Quaternion {1}, Result {2}\n", angle, q, result);
                        }
                    }
                    Color resultColor = Color.FromArgb(floatToColor(result.x),
                                                       floatToColor(result.y),
                                                       floatToColor(result.z));
                    outputMap.SetPixel(x, y, resultColor);
                }
            }

            if (generateLogFile.Checked)
                logStream.Close();

            outputMap.Save(outputMapTextBox.Text);

            outputPictureBox.Image = outputMap;
            outputPictureBox.Visible = true;

            Cursor.Current = previousCursor;
            doneLabel.Visible = true;
        }
예제 #6
0
        private void generateButton_Click(object sender, EventArgs e)
        {
            Cursor previousCursor = Cursor.Current;

            Cursor.Current    = Cursors.WaitCursor;
            doneLabel.Visible = false;
            //outputPictureBox.Visible = false;

            if (generateLogFile.Checked)
            {
                string     p = "NormalBump.log";
                FileStream f = new FileStream(p, FileMode.Create, FileAccess.Write);
                logStream = new StreamWriter(f);
                logStream.Write(string.Format("{0} Started writing to {1}\n",
                                              DateTime.Now.ToString("hh:mm:ss"), p));
            }

            // run the algorithm
            Bitmap normalMap = new Bitmap(normalMapTextBox.Text);
            Bitmap bumpMap   = new Bitmap(bumpMapTextBox.Text);

            if (normalMap.Width != bumpMap.Width)
            {
                ShowError("Normal Map width {0} is not the same as Bump Map width {1}",
                          normalMap.Width, bumpMap.Width);
                return;
            }

            if (normalMap.Height != bumpMap.Height)
            {
                ShowError("Normal Map height {0} is not the same as Bump Map height {1}",
                          normalMap.Height, bumpMap.Height);
                return;
            }

            Bitmap outputMap = (Bitmap)normalMap.Clone();

            PixelFormat normalFormat = normalMap.PixelFormat;
            PixelFormat bumpFormat   = bumpMap.PixelFormat;

            // This will be set by the slider
            float scaleFactor = (float)trackBar.Value / 100f;

            if (reverseBumpDirection.Checked)
            {
                scaleFactor = -scaleFactor;
            }

            Vector3 unitZ   = new Vector3(0f, 0f, 1f);
            float   epsilon = 0.0000001f;

            // Loop through the bump map pixels, computing the normals
            // into the output map
            int w = normalMap.Width;
            int h = normalMap.Height;

            for (int x = 0; x < w; x++)
            {
                for (int y = 0; y < h; y++)
                {
                    // Fetch the normal map normal vector
                    Color   c      = normalMap.GetPixel(x, y);
                    Vector3 normal = new Vector3(colorToFloat(c.R),
                                                 colorToFloat(c.G),
                                                 colorToFloat(c.B)).ToNormalized();
                    Vector3 result = normal;

                    // If we're at the edge, use the normal vector
                    if (x < w - 1 && y < h - 1)
                    {
                        // Compute the bump normal vector
                        int     xyLevel    = bumpLevel(bumpMap, x, y);
                        float   dx         = scaleFactor * (bumpLevel(bumpMap, x + 1, y) - xyLevel);
                        float   dy         = scaleFactor * (bumpLevel(bumpMap, x, y + 1) - xyLevel);
                        float   dz         = 255f;
                        Vector3 bumpNormal = new Vector3(dx, dy, dz).ToNormalized();
                        if (generateLogFile.Checked)
                        {
                            Log("X {0}, Y {1}, normal {2}, bumpNormal {3}\n",
                                x, y, normal, bumpNormal);
                        }
                        Vector3 axis = unitZ.Cross(normal);
                        if (axis.Length > epsilon)
                        {
                            float      cosAngle = unitZ.Dot(normal);
                            float      angle    = (float)Math.Acos(cosAngle);
                            Quaternion q        = Quaternion.FromAngleAxis(angle, axis);
                            Matrix3    rot      = q.ToRotationMatrix();
                            result = rot * bumpNormal;
                            if (generateLogFile.Checked)
                            {
                                Log("   Angle {0}, Quaternion {1}, Result {2}\n", angle, q, result);
                            }
                        }
                    }
                    Color resultColor = Color.FromArgb(floatToColor(result.x),
                                                       floatToColor(result.y),
                                                       floatToColor(result.z));
                    outputMap.SetPixel(x, y, resultColor);
                }
            }

            if (generateLogFile.Checked)
            {
                logStream.Close();
            }

            outputMap.Save(outputMapTextBox.Text);

            outputPictureBox.Image   = outputMap;
            outputPictureBox.Visible = true;

            Cursor.Current    = previousCursor;
            doneLabel.Visible = true;
        }
예제 #7
0
        private int RayIntersectionDistanceInternal(Vector3 start, Vector3 end,
                                                    out float [] afT)
        {
            Vector3 direction    = end - start;
            Vector3 capDirection = topcenter - bottomcenter;
            // set up quadratic Q(t) = a*t^2 + 2*b*t + c
            Vector3 kU;
            Vector3 kV;
            Vector3 kW          = capDirection;
            float   fWLength    = kW.Normalize();
            float   fInvWLength = 1.0f / fWLength;

            GenerateOrthonormalBasis(out kU, out kV, ref kW);
            Vector3 kD          = new Vector3(kU.Dot(direction), kV.Dot(direction), kW.Dot(direction));
            float   fDLength    = kD.Normalize();
            float   fInvDLength = 1.0f / fDLength;
            Vector3 kDiff       = start - bottomcenter;
            Vector3 kP          = new Vector3(kU.Dot(kDiff), kV.Dot(kDiff), kW.Dot(kDiff));
            float   fRadiusSqr  = capRadius * capRadius;

            afT = new float[] { 0f, 0f };
            float fInv, fA, fB, fC, fDiscr, fRoot, fT, fTmp;

            if (Math.Abs(kD.z) >= 1.0 - ScaleEpsilon)
            {
                // line is parallel to capsule axis
                fDiscr = fRadiusSqr - kP.x * kP.x - kP.y * kP.y;
                if (fDiscr >= 0.0)
                {
                    fRoot  = (float)Math.Sqrt(fDiscr);
                    afT[0] = -(kP.z + fRoot) * fInvDLength;
                    afT[1] = (fWLength - kP.z + fRoot) * fInvDLength;
                    return(2);
                }
                else
                {
                    return(0);
                }
            }

            // test intersection with infinite cylinder
            fA     = kD.x * kD.x + kD.y * kD.y;
            fB     = kP.x * kD.x + kP.y * kD.y;
            fC     = kP.x * kP.x + kP.y * kP.y - fRadiusSqr;
            fDiscr = fB * fB - fA * fC;
            if (fDiscr < 0.0)
            {
                return(0);
            }

            int iQuantity = 0;

            if (fDiscr > 0.0)
            {
                // line intersects infinite cylinder in two places
                fRoot = (float)Math.Sqrt(fDiscr);
                fInv  = 1.0f / fA;
                fT    = (-fB - fRoot) * fInv;
                fTmp  = kP.z + fT * kD.z;
                if (0.0f <= fTmp && fTmp <= fWLength)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                }

                fT   = (-fB + fRoot) * fInv;
                fTmp = kP.z + fT * kD.z;
                if (0.0f <= fTmp && fTmp <= fWLength)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                }

                if (iQuantity == 2)
                {
                    return(2);
                }
            }
            else
            {
                // line is tangent to infinite cylinder
                fT   = -fB / fA;
                fTmp = kP.z + fT * kD.z;
                if (0.0 <= fTmp && fTmp <= fWLength)
                {
                    afT[0] = fT * fInvDLength;
                    return(1);
                }
            }

            // test intersection with bottom hemisphere
            // fA = 1
            fB    += kP.z * kD.z;
            fC    += kP.z * kP.z;
            fDiscr = fB * fB - fC;
            if (fDiscr > 0.0)
            {
                fRoot = (float)Math.Sqrt(fDiscr);
                fT    = -fB - fRoot;
                fTmp  = kP.z + fT * kD.z;
                if (fTmp <= 0.0f)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                    if (iQuantity == 2)
                    {
                        return(2);
                    }
                }

                fT   = -fB + fRoot;
                fTmp = kP.z + fT * kD.z;
                if (fTmp <= 0.0)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                    if (iQuantity == 2)
                    {
                        return(2);
                    }
                }
            }
            else if (fDiscr == 0.0)
            {
                fT   = -fB;
                fTmp = kP.z + fT * kD.z;
                if (fTmp <= 0.0)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                    if (iQuantity == 2)
                    {
                        return(2);
                    }
                }
            }

            // test intersection with top hemisphere
            // fA = 1
            fB -= kD.z * fWLength;
            fC += fWLength * (fWLength - 2.0f * kP.z);

            fDiscr = fB * fB - fC;
            if (fDiscr > 0.0f)
            {
                fRoot = (float)Math.Sqrt(fDiscr);
                fT    = -fB - fRoot;
                fTmp  = kP.z + fT * kD.z;
                if (fTmp >= fWLength)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                    if (iQuantity == 2)
                    {
                        return(2);
                    }
                }

                fT   = -fB + fRoot;
                fTmp = kP.z + fT * kD.z;
                if (fTmp >= fWLength)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                    if (iQuantity == 2)
                    {
                        return(2);
                    }
                }
            }
            else if (fDiscr == 0.0)
            {
                fT   = -fB;
                fTmp = kP.z + fT * kD.z;
                if (fTmp >= fWLength)
                {
                    afT[iQuantity++] = fT * fInvDLength;
                    if (iQuantity == 2)
                    {
                        return(2);
                    }
                }
            }
            return(iQuantity);
        }