Reputation: 41
I'm working on a simple 3D model viewer, I need to be able to support very large models (100,000 + triangles) and have smooth movement while rotating the camera.
To optimize the drawing instead of creating a GeometryModel3D of each segment in a polymesh I want to use the full list of vertices and triangle indexes. The speed up was amazing but now the lighting is messed up. Each triangle now has its own shade.
I think the issue is related to normals, if I manually set all normals to Vector3(0,0,1) then I get even lighting. But when I try to see the side of the model or the reverse side it is dark. I also attempted to use a formulae to calculate the normals of each triangle but the result was the same: One large model would be messed up, separate models would look good. So maybe it isn't a normal issue?
I'm curious as to why when the models are separate everything works correctly and by combining the models causes issues.
The polyMesh object contains a bunch of faces which contain which vertex indices it uses. Either a triangle or a quad. The polyMesh has all vertex information.
var models = new Model3DCollection();
var brush = new SolidColorBrush(GetColorFromEntity(polyMesh));
var material = new DiffuseMaterial(brush);
foreach (var face in polyMesh.FaceRecord)
{
var indexes = new Int32Collection();
if (face.VertexIndexes.Count == 4)
{
indexes.Add(face.VertexIndexes[0]);
indexes.Add(face.VertexIndexes[1]);
indexes.Add(face.VertexIndexes[2]);
indexes.Add(face.VertexIndexes[2]);
indexes.Add(face.VertexIndexes[3]);
indexes.Add(face.VertexIndexes[0]);
}
else
{
indexes.Add(face.VertexIndexes[0]);
indexes.Add(face.VertexIndexes[1]);
indexes.Add(face.VertexIndexes[2]);
}
MeshGeometry3D mesh = new MeshGeometry3D()
{
Positions = GetPoints(polyMesh.Vertices),
TriangleIndices = indexes,
};
GeometryModel3D model = new GeometryModel3D()
{
Geometry = mesh,
Material = material,
};
models.Add(model);
}
return models;
If I take the Mesh and the Geometry out of the loop and create one large mesh things go wrong.
var models = new Model3DCollection();
var brush = new SolidColorBrush(GetColorFromEntity(polyMesh));
var material = new DiffuseMaterial(brush);
var indexes = new Int32Collection();
foreach (var face in polyMesh.FaceRecord)
{
//Add indices as above (code trimmed to save space.)
indexes.Add(face.VertexIndexes[0]);
}
MeshGeometry3D mesh = new MeshGeometry3D()
{
Positions = GetPoints(polyMesh.Vertices),
TriangleIndices = indexes,
};
GeometryModel3D model = new GeometryModel3D()
{
Geometry = mesh,
Material = material,
};
models.Add(model);
return models;
Other important details: The model isn't just a flat surface it is a complex model of a road way. I can't show the whole model nor provide code for how it was imported. I am using HelixToolKit for camera controls and diagnostics.
Viewport code:
<h:HelixViewport3D ZoomExtentsWhenLoaded="True" IsPanEnabled="True" x:Name="ViewPort" IsHeadLightEnabled="True">
<h:HelixViewport3D.DefaultCamera>
<!--フリッカー回避方法 This code fixes a flicker bug! Found at http://stackoverflow.com/a/38243386 -->
<PerspectiveCamera NearPlaneDistance="25"/>
</h:HelixViewport3D.DefaultCamera>
<h:DefaultLights/>
</h:HelixViewport3D>
Setting a back material doesn't change anything. I'm hoping I'm just being a moron and missing something obvious as I am new to 3D.
Upvotes: 2
Views: 1338
Reputation: 41
Finally fixed this myself.
Came down to not enough knowledge about Wpf3D (or 3D in general?).
If a vertex is reused as in the combination model about then smoth shading is applied. The reason smooth shading looks so terrible on the flat side is that it is applying shading to the full 3D model. Each polyface I had was a 3D shape. Each segment on the wall was a different polymesh with ~6 faces. (front, up, down, left, right, back).
When each vertex position was unique the problem went away even when combining the models. When separate since each model had a copy of the positions they were unique. Found the answer from:
http://xoax.net/blog/automatic-3d-normal-vector-calculation-in-c-wpf-applications/
Upvotes: 2