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); }
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); } } }
// 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); }
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; } } }
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; }
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; }
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); }