void GenerateOrthonormalBasis(out Vector3 rkU, out Vector3 rkV, ref Vector3 rkW) { rkU = Vector3.Zero; if (Math.Abs(rkW.x) >= Math.Abs(rkW.y) && Math.Abs(rkW.x) >= Math.Abs(rkW.z)) { rkU.x = -rkW.y; rkU.y = +rkW.x; rkU.z = 0.0f; } else { rkU.x = 0.0f; rkU.y = +rkW.z; rkU.z = -rkW.y; } rkU.ToNormalized(); rkV = rkW.Cross(rkU); }
// 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 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; }
void GenerateOrthonormalBasis(out Vector3 rkU, out Vector3 rkV, ref Vector3 rkW) { rkU = Vector3.Zero; if ( Math.Abs(rkW.x) >= Math.Abs(rkW.y) && Math.Abs(rkW.x) >= Math.Abs(rkW.z) ) { rkU.x = -rkW.y; rkU.y = +rkW.x; rkU.z = 0.0f; } else { rkU.x = 0.0f; rkU.y = +rkW.z; rkU.z = -rkW.y; } rkU.ToNormalized(); rkV = rkW.Cross(rkU); }
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; }