Reputation: 679
I'm struggling with properly mapping textures in wpf. First of all 3d is not my strength, but I have some sample code and images of output below. I'm taking a polygon, performing the triangulation, then attempting to map a rectangular texture on the output. The problem I'm getting is that I cannot map the texture to smoothly follow curve. One texture map utilized the 3dtools.dll library and it works great but the resulting texture map produced the output on the left. It doesn't slope like I want it to. The resulting image on the right is my attempt at manually mapping the texture coordinates to the image. I understand why it looks like it does, but I'm not really sure how to correct it?
private void simpleButtonClick(object sender, RoutedEventArgs e)
{
ClearViewport();
SetCamera();
PathGeometry FlatPath;
Geometry Geo = Geometry.Parse("M 0,0 L 0,10 C 4,4 6,6 10,10 V 0 C 6,-4 4,-6 0,0");
var GeoText = FormattedText.BuildGeometry(new Point(0, 0));
FlatPath =
Geo.GetFlattenedPathGeometry(.01,
ToleranceType.
Absolute);
var vertices = new List<Vertex>();
foreach (PathFigure Figure in FlatPath.Figures)
{
List<Point> PointList = DumpFigureToList(Figure);
vertices.AddRange(PointList.Select(p=>new Vertex((float)p.X,(float)p.Y)));
}
// Write out the data set we're actually going to triangulate
var angulator = new Triangulator();
List<Triad> triangles = angulator.Triangulation(vertices, true);
var Bounds = FlatPath.Bounds;
var mesh = new MeshGeometry3D();
var cube = new Model3DGroup();
var Count = 0;
foreach (var Tri in triangles)
{
Tri.MakeCounterClockwise(vertices);
if (FlatPath.FillContains(new Point(Tri.circumcircleX, Tri.circumcircleY)))
{
var p0 = new Point3D(vertices[Tri.a].x, vertices[Tri.a].y, 0);
var p1 = new Point3D(vertices[Tri.b].x, vertices[Tri.b].y, 0);
var p2 = new Point3D(vertices[Tri.c].x, vertices[Tri.c].y, 0);
mesh.Positions.Add(p0);
mesh.Positions.Add(p1);
mesh.Positions.Add(p2);
mesh.TriangleIndices.Add(Count);
Count++;
mesh.TriangleIndices.Add(Count);
Count++;
mesh.TriangleIndices.Add(Count);
Count++;
Vector3D normal = CalculateNormal(p0, p1, p2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.TextureCoordinates.Add(new Point((Bounds.Left - vertices[Tri.a].x) / Bounds.Width, vertices[Tri.a].y > 0 ? 1 : 0));
mesh.TextureCoordinates.Add(new Point((Bounds.Left - vertices[Tri.b].x) / Bounds.Width, vertices[Tri.b].y > 0 ? 1 : 0));
mesh.TextureCoordinates.Add(new Point((Bounds.Left - vertices[Tri.c].x) / Bounds.Width, vertices[Tri.c].y > 0 ? 1 : 0));
if (wireframeCheckBox.IsChecked == true)
{
var wireframe = new ScreenSpaceLines3D();
wireframe.Points.Add(p0);
wireframe.Points.Add(p1);
wireframe.Points.Add(p2);
wireframe.Points.Add(p0);
wireframe.Color = Colors.LightBlue;
wireframe.Thickness = 2;
this.mainViewport.Children.Add(wireframe);
}
}
}
//mesh.TextureCoordinates = _3DTools.MeshUtils.GeneratePlanarTextureCoordinates(mesh, new Vector3D(0, 0, 1));
var myBrush = new ImageBrush();
myBrush.ImageSource =
new BitmapImage(new Uri(@"curvedown.png", UriKind.Absolute));
Material material = new DiffuseMaterial(myBrush);
var model = new GeometryModel3D(mesh, material);
var group = new Model3DGroup();
group.Children.Add(model);
PointLight light = new PointLight(Colors.White, new Point3D(10,10,10));
group.Children.Add(light);
var Model = new ModelVisual3D();
Model.Content = group;
this.mainViewport.Children.Add(Model);
}
Here is the output of above with the wireframe. I'm on uses the commented out texture coordinate code. On the right the manual code (uncommented).
Upvotes: 1
Views: 2204
Reputation: 56
With the triangulation you have, it will never properly curve as you expect. To achieve that sort of curving, you will have to manually generate thin stripes. Something like
++++++++ |||||||| |||||||| ++++++++
-- where each + is a vertex -- but instead of making it straight, map it along different lines coming from a common point (a virtual circle), at specific offsets along the radii.
In pseudocode:
for each i from 0 to nStripes let angle = start + (end-start) * i / nStripes let p1 = Point where X = innerRadius * cos(angle) Y = innerRadius * sin(angle) let p2 = Point where X = outerRadius * cos(angle) Y = outerRadius * sin(angle) add vertex at p1 add vertex at p2
then afterwards connect the previously generated edges pairwise, so (0,1)+(2,3) will make a quad, (2,3)+(4,5) another, and so on...
You will have to decide on which number of stripes are good enough. Always keep in mind that texture mapping within a triangle is always done by linear interpolation, never a curve, so you cannot expect things like curves or trapezoids to magically look right.
Upvotes: 4