Saturday, 3 December 2011

3D Foundations

To use 3D in WPF we need a minimum of an object, somewhere to draw it, a camera to see it and some light to illuminate the scene. Which in the following examples roughly correspond to GeometryModel3D, Viewport3D, PerspectiveCamera and AmbientLight respectively.
Starting with the Model and Viewport the bare minimum to describe a square is:
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>
                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
   </Viewport3D>
</Grid>
Each Mesh position is a triplet of X, Y and Z. Positive X is UP. Positive Y is RIGHT. Positive Z is OUT of the screen.
The Mesh triplets are numbered from 0 (zero) starting in BottomLeft and working anti-clockwise.

3 ------------ 2
|              |
|              |
|              |
0 ------------ 1
These form the indices used to cover the surface in triangles. Each triangle is drawn anti-clockwise to keep the "Normals" pointing in the same direction. I'm not going to mention Normals again.
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>

                     <MeshGeometry3D.TriangleIndices>0 1 2 2 3 0</MeshGeometry3D.TriangleIndices>

                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
   </Viewport3D>
</Grid>
The model has two surfaces and each can have its own material. The front surface, Material, has been coloured Maroon.
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>
                     <MeshGeometry3D.TriangleIndices>0 1 2 2 3 0</MeshGeometry3D.TriangleIndices>
                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
         
               <GeometryModel3D.Material>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Maroon</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.Material>

            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
   </Viewport3D>
</Grid>
At this point nothing can be seen on screen because there is no camera.
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>
                     <MeshGeometry3D.TriangleIndices>0 1 2 2 3 0</MeshGeometry3D.TriangleIndices>
                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
               <GeometryModel3D.Material>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Maroon</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.Material>
            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
         
      <Viewport3D.Camera>
         <PerspectiveCamera>
            <PerspectiveCamera.LookDirection>0,0,-1</PerspectiveCamera.LookDirection>
            <PerspectiveCamera.Position>0,0,2</PerspectiveCamera.Position>
            <PerspectiveCamera.FieldOfView>90</PerspectiveCamera.FieldOfView>
         </PerspectiveCamera>
      </Viewport3D.Camera>

   </Viewport3D>
</Grid>
At this point we should see a Black square which is the Maroon surface of the model in an unlit scene. Next we add some AmbientLight.
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>
                     <MeshGeometry3D.TriangleIndices>0 1 2 2 3 0</MeshGeometry3D.TriangleIndices>
                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
               <GeometryModel3D.Material>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Maroon</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.Material>
            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
      
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <AmbientLight Color="White" />
         </ModelVisual3D.Content>
      </ModelVisual3D>
      
      <Viewport3D.Camera>
         <PerspectiveCamera>
            <PerspectiveCamera.LookDirection>0,0,-1</PerspectiveCamera.LookDirection>
            <PerspectiveCamera.Position>0,0,2</PerspectiveCamera.Position>
            <PerspectiveCamera.FieldOfView>90</PerspectiveCamera.FieldOfView>
         </PerspectiveCamera>
      </Viewport3D.Camera>
   </Viewport3D>
</Grid>
We should now be able to see a Maroon surface. The Model's reverse surface, BackMaterial, will be coloured Blue.
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>
                     <MeshGeometry3D.TriangleIndices>0 1 2 2 3 0</MeshGeometry3D.TriangleIndices>
                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
               <GeometryModel3D.Material>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Maroon</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.Material>
      
               <GeometryModel3D.BackMaterial>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Blue</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.BackMaterial>

            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <AmbientLight Color="White" />
         </ModelVisual3D.Content>
      </ModelVisual3D>
      <Viewport3D.Camera>
         <PerspectiveCamera>
            <PerspectiveCamera.LookDirection>0,0,-1</PerspectiveCamera.LookDirection>
            <PerspectiveCamera.Position>0,0,2</PerspectiveCamera.Position>
            <PerspectiveCamera.FieldOfView>90</PerspectiveCamera.FieldOfView>
         </PerspectiveCamera>
      </Viewport3D.Camera>
   </Viewport3D>
</Grid>
Finally, reposition the camera and the direction it is looking in order to see the other side of the model. We should now see the blue surface.
<Grid Background="AliceBlue">
   <Viewport3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <GeometryModel3D>
               <GeometryModel3D.Geometry>
                  <MeshGeometry3D>
                     <MeshGeometry3D.Positions>-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5</MeshGeometry3D.Positions>
                     <MeshGeometry3D.TriangleIndices>0 1 2 2 3 0</MeshGeometry3D.TriangleIndices>
                  </MeshGeometry3D>
               </GeometryModel3D.Geometry>
               <GeometryModel3D.Material>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Maroon</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.Material>
               <GeometryModel3D.BackMaterial>
                  <DiffuseMaterial>
                     <DiffuseMaterial.Brush>Blue</DiffuseMaterial.Brush>
                  </DiffuseMaterial>
               </GeometryModel3D.BackMaterial>
            </GeometryModel3D>
         </ModelVisual3D.Content>
      </ModelVisual3D>
      <ModelVisual3D>
         <ModelVisual3D.Content>
            <AmbientLight Color="White" />
         </ModelVisual3D.Content>
      </ModelVisual3D>
      <Viewport3D.Camera>
         <PerspectiveCamera>
      
            <PerspectiveCamera.LookDirection>0,0,1</PerspectiveCamera.LookDirection>
            <PerspectiveCamera.Position>0,0,-2</PerspectiveCamera.Position>

            <PerspectiveCamera.FieldOfView>90</PerspectiveCamera.FieldOfView>
         </PerspectiveCamera>
      </Viewport3D.Camera>
   </Viewport3D>
</Grid>

No comments: