Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Audio;
- using Microsoft.Xna.Framework.Content;
- using Microsoft.Xna.Framework.GamerServices;
- using Microsoft.Xna.Framework.Graphics;
- using Microsoft.Xna.Framework.Input;
- using Microsoft.Xna.Framework.Media;
- namespace DrawingTriangles
- {
- /// <summary>
- /// This is the main type for your game
- /// </summary>
- public class Game1 : Microsoft.Xna.Framework.Game
- {
- GraphicsDeviceManager graphics;
- VertexBuffer vertexBuffer;
- VertexBuffer vertexBuffer2;
- int modelindexes = 0;
- short[] indexElements;
- IEnumerable<TriangleVertices> triverts = new List<TriangleVertices> { };
- TriangleVertices[] trisvertss;
- TriangleVertices[] tristext;
- VertexPositionColor[] vertices;
- VertexPositionColor[] vertices2;
- VertexPositionColor[] vertices3;
- VertexPositionColor[] vertices4;
- VertexPositionColor[] vertices5;
- int finder;
- Vector3 lightDir = new Vector3(-0.3333333f, 0.6666667f, -0.6666667f); //directional light parameter. its a vector 3 that you draw a line from 0,0,0 to - and get an arrow.
- BasicEffect basicEffect;
- Matrix world = Matrix.CreateTranslation(0, 0, -625) * Matrix.CreateScale(new Vector3(0.005f, 0.005f, 0.004f)) * Matrix.CreateRotationX(MathHelper.ToRadians(-90));
- Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 3), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
- Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(60), 800f / 480f, 0.01f, 100f);
- Model testModel;
- List<TriangleVertices> triverts2;
- Vector3[] allVertex;
- TriangleVertices[] number1;
- List<Edge> edgelist;
- List<Edge> edgelist2;
- double angle = 0;
- public Game1()
- {
- graphics = new GraphicsDeviceManager(this);
- graphics.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;
- Content.RootDirectory = "Content";
- }
- /// <summary>
- /// Allows the game to perform any initialization it needs to before starting to run.
- /// This is where it can query for any required services and load any non-graphic
- /// related content. Calling base.Initialize will enumerate through any components
- /// and initialize them as well.
- /// </summary>
- protected override void Initialize()
- {
- base.Initialize();
- }
- public struct TriangleVertices
- {
- /// <summary>Initializes a new triangle vertices instance</summary>
- /// <param name="a">First vertex of the triangle</param>
- /// <param name="b">Second vertex of the triangle</param>
- /// <param name="c">Third vertex of the triangle</param>
- public TriangleVertices(Vector3 a, Vector3 b, Vector3 c)
- {
- this.A = a;
- this.B = b;
- this.C = c;
- }
- /// <summary>The triangle's first vertex</summary>
- public Vector3 A;
- /// <summary>The triangle's second vertex</summary>
- public Vector3 B;
- /// <summary>The triangle's third vertex</summary>
- public Vector3 C;
- }
- public class Face
- {
- /// <summary>Initializes a new face</summary>
- /// <param name="normal"></param>
- public Face(Vector3 normal)
- {
- this.Normal = normal;
- }
- /// <summary>Normal vector of the face</summary>
- public Vector3 Normal;
- }
- public class Edge
- {
- /// <summary>Initializes a new edge</summary>
- /// <param name="leftVertex">Vertex on the left side of the edge</param>
- /// <param name="rightVertex">Vertex on the right side of the edge</param>
- public Edge(Vector3 leftVertex, Vector3 rightVertex)
- {
- this.LeftVertex = leftVertex;
- this.RightVertex = rightVertex;
- }
- /// <summary>The vertex on the left side of the edge</summary>
- public Vector3 LeftVertex;
- /// <summary>The vertex on the right side of the edge</summary>
- public Vector3 RightVertex;
- /// <summary>The face to the top of the edge</summary>
- public Face UpperFace;
- /// <summary>The face to the bottom of the edge</summary>
- public Face LowerFace;
- }
- /// <summary>
- /// LoadContent will be called once per game and is the place to load
- /// all of your content.
- /// </summary>
- protected override void LoadContent()
- {
- testModel = Content.Load<Model>("teststage2");
- basicEffect = new BasicEffect(GraphicsDevice);
- foreach (ModelMesh mesh in testModel.Meshes)
- {
- foreach (ModelMeshPart part in mesh.MeshParts)
- {
- modelindexes += part.IndexBuffer.IndexCount;
- }
- }
- vertices = new VertexPositionColor[modelindexes];
- triverts = new TriangleVertices[0];
- int offset = 0;
- foreach (ModelMesh mesh in testModel.Meshes)
- {
- foreach (ModelMeshPart part in mesh.MeshParts)
- {
- VertexDeclaration declaration = part.VertexBuffer.VertexDeclaration;
- VertexElement vertexPosition = new VertexElement();
- // This where we store the vertices until transformed
- allVertex = new Vector3[part.NumVertices];
- // Read the vertices from the buffer in to the array
- part.VertexBuffer.GetData<Vector3>(
- part.VertexOffset * declaration.VertexStride + vertexPosition.Offset,
- allVertex,
- 0,
- part.NumVertices,
- declaration.VertexStride);
- // Each primitive is a triangle
- indexElements = new short[part.PrimitiveCount * 3];
- part.IndexBuffer.GetData<short>(
- part.StartIndex * 2,
- indexElements,
- 0,
- part.PrimitiveCount * 3);
- VertexPositionColor[] borrowVerts = new VertexPositionColor[indexElements.Length];
- for (int i = 0; i < indexElements.Length; i++)
- {
- borrowVerts[i].Position.X = allVertex[indexElements[i]].X;
- borrowVerts[i].Position.Y = allVertex[indexElements[i]].Y;
- borrowVerts[i].Position.Z = allVertex[indexElements[i]].Z;
- vertices[offset + i].Position = borrowVerts[i].Position;
- }
- offset += indexElements.Length;
- }
- }
- Vector3 vert = new Vector3();
- Vector3 vert2 = new Vector3();
- Vector3 vert3 = new Vector3();
- trisvertss = new TriangleVertices[vertices.Length / 3];
- TriangleVertices number0;
- number0.A = vertices[0].Position;
- number0.B = vertices[1].Position;
- number0.C = vertices[2].Position;
- number1 = new TriangleVertices[vertices.Length / 3];
- for (int i = 0; i < vertices.Length / 3; i += 3)
- {
- number1[i].A = vertices[i].Position;
- number1[i].B = vertices[i + 1].Position;
- number1[i].C = vertices[i + 2].Position;
- }
- triverts2 = new List<TriangleVertices> { number0 };
- int j = vertices.Length / 3; //number of triangles
- int k = 0; //counter
- //method to make 3 vertices triangle format for each triangle and add them to a list.
- for (int i = 0; i < j; i++)
- {
- vert = vertices[(i * 3)].Position;
- vert2 = vertices[(i * 3) + 1].Position;
- vert3 = vertices[(i * 3) + 2].Position;
- if (k < j)
- {
- trisvertss[k].A = vert;
- trisvertss[k].B = vert2;
- trisvertss[k].C = vert3;
- TriangleVertices tristorage = new TriangleVertices(vert, vert2, vert3);
- if (k > 0)
- {
- triverts2.Add(tristorage);
- }
- Enumerable.Concat<TriangleVertices>(triverts, triverts2);
- k++;
- }
- }
- triverts = triverts.Concat(triverts2);
- edgelist = new List<Edge>(trisvertss.Length * 3);
- //method for breaking up the triangles into edges.
- foreach (TriangleVertices triangle in trisvertss)
- {
- Face face = new Face(Vector3.Cross(triangle.B - triangle.A, triangle.C - triangle.A));
- Edge edge;
- edge = new Edge(triangle.A, triangle.B);
- edge.UpperFace = face;
- edgelist.Add(edge);
- edge = new Edge(triangle.B, triangle.C);
- edge.UpperFace = face;
- edgelist.Add(edge);
- edge = new Edge(triangle.C, triangle.A);
- edge.UpperFace = face;
- edgelist.Add(edge);
- }
- vertices4 = new VertexPositionColor[vertices.Length];
- vertices5 = new VertexPositionColor[vertices.Length];
- for(int i = 0; i < trisvertss.Length; i++)
- {
- Face face = new Face(Vector3.Cross(trisvertss[i].B - trisvertss[i].A, trisvertss[i].C - trisvertss[i].A));
- float upperFaceDot = Vector3.Dot(face.Normal, lightDir);
- //these are cap triangles.
- if (upperFaceDot > 0)
- {
- vertices4[i * 3] = new VertexPositionColor(trisvertss[i].A, new Color(0, 0, 0, 0));
- vertices4[i * 3 + 1] = new VertexPositionColor(trisvertss[i].B, new Color(0, 0, 0, 0));
- vertices4[i * 3 + 2] = new VertexPositionColor(trisvertss[i].C, new Color(0, 0, 0, 0));
- }
- }
- //whatever is left is the other cap! since we're splitting the model in 2 and adding quads to extend the shape out.
- for (int i = 0; i < trisvertss.Length; i++)
- {
- vertices5[i * 3] = new VertexPositionColor(trisvertss[i].A, Color.Gray);
- vertices5[i * 3 + 1] = new VertexPositionColor(trisvertss[i].B, Color.Gray);
- vertices5[i * 3 + 2] = new VertexPositionColor(trisvertss[i].C, Color.Gray);
- }
- edgelist2 = new List<Edge>(edgelist.Count / 2);
- //method for adding only non-repeating edges to a new edgelist. using the variable finder to find duplicates to discard.
- for (int i = 0; i < edgelist.Count; i++)
- {
- finder = edgelist.FindIndex(item => item.RightVertex == edgelist[i].LeftVertex && item.LeftVertex == edgelist[i].RightVertex);
- edgelist[i].LowerFace = edgelist[finder].UpperFace;
- if (i < finder)
- {
- edgelist2.Add(edgelist[i]);
- }
- }
- edgelist.Clear(); //no longer need this.
- foreach (Edge edge in edgelist2)
- {
- float upperFaceDot = Vector3.Dot(edge.UpperFace.Normal, lightDir);
- float lowerFaceDot = Vector3.Dot(edge.LowerFace.Normal, lightDir);
- bool upperFaceVisible = (upperFaceDot > 0);
- bool lowerFacevisible = (lowerFaceDot > 0);
- Edge nuEdge;
- if (lowerFacevisible)
- {
- if (!upperFaceVisible)
- {
- nuEdge = new Edge(edge.RightVertex, edge.LeftVertex);
- edgelist.Add(nuEdge);
- }
- }
- else
- {
- if (upperFaceVisible)
- {
- nuEdge = new Edge(edge.LeftVertex, edge.RightVertex);
- edgelist.Add(nuEdge);
- }
- }
- }
- vertices2 = new VertexPositionColor[edgelist.Count * 3 * 2];
- Vector3 extrusion = lightDir * 4000;
- for (int i = 0; i < edgelist.Count ; i++)
- {
- Plane planar = new Plane(edgelist[i].LeftVertex, edgelist[i].LeftVertex + extrusion, edgelist[i].RightVertex);
- //BUILD QUADS
- vertices2[(i * 6) + 5] = new VertexPositionColor(edgelist[i].LeftVertex, new Color(0, 0, 0, 0));
- vertices2[(i * 6) + 4] = new VertexPositionColor(edgelist[i].LeftVertex + extrusion, new Color(0, 0, 0, 0));
- vertices2[(i * 6) + 3] = new VertexPositionColor(edgelist[i].RightVertex + extrusion, new Color(0, 0, 0, 0));
- vertices2[(i * 6) + 2] = new VertexPositionColor(edgelist[i].LeftVertex, new Color(0, 0, 0, 0));
- vertices2[(i * 6) + 1] = new VertexPositionColor(edgelist[i].RightVertex + extrusion, new Color(0, 0, 0, 0));
- vertices2[(i * 6)] = new VertexPositionColor(edgelist[i].RightVertex, new Color(0, 0, 0, 0));
- }
- vertices3 = new VertexPositionColor[(vertices4.Length * 2) + vertices2.Length];
- int backfaces = vertices4.Length;
- //add triangles flipped.
- for (int i = 0; i < vertices4.Length; i++)
- {
- vertices3[i] = new VertexPositionColor(vertices4[backfaces - 1].Position + extrusion, new Color(0, 0, 0, 0));
- backfaces--;
- }
- //add more triangles from the shadow volume
- for (int i = vertices4.Length; i < vertices4.Length + vertices2.Length; i++)
- {
- vertices3[i] = vertices2[i - vertices4.Length];
- }
- //finish adding the other cap here.
- for (int i = vertices2.Length + vertices4.Length; i < (vertices4.Length * 2) + vertices2.Length; i++)
- {
- vertices3[i] = new VertexPositionColor(vertices4[i - (vertices2.Length + vertices4.Length)].Position, new Color(0, 0, 0, 0));
- }
- tristext = new TriangleVertices[trisvertss.Count()];
- vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), vertices3.Length, BufferUsage.WriteOnly);
- vertexBuffer.SetData<VertexPositionColor>(vertices3);
- vertexBuffer2 = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), vertices5.Length, BufferUsage.WriteOnly);
- vertexBuffer2.SetData<VertexPositionColor>(vertices5);
- }
- protected override void UnloadContent()
- {
- }
- protected override void Update(GameTime gameTime)
- {
- if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
- this.Exit();
- angle += 0.01f;
- view = Matrix.CreateLookAt(
- new Vector3(5 * (float)Math.Sin(angle), -2, 5 * (float)Math.Cos(angle)),
- new Vector3(0, 0, 0),
- Vector3.UnitY);
- base.Update(gameTime);
- }
- DepthStencilState addIfMirror = new DepthStencilState()
- {
- DepthBufferEnable = true,
- DepthBufferWriteEnable = false,
- StencilEnable = true,
- //TwoSidedStencilMode = true,
- StencilFunction = CompareFunction.Always,
- StencilPass = StencilOperation.Increment,
- //CounterClockwiseStencilPass = StencilOperation.Decrement
- };
- DepthStencilState addIfMirror2 = new DepthStencilState()
- {
- DepthBufferEnable = true,
- DepthBufferWriteEnable = false,
- StencilEnable = true,
- StencilFunction = CompareFunction.Always,
- StencilPass = StencilOperation.Decrement,
- };
- DepthStencilState checkMirror = new DepthStencilState()
- {
- StencilEnable = true,
- StencilFunction = CompareFunction.Equal,
- ReferenceStencil = 1,
- StencilPass = StencilOperation.Keep
- };
- /// <summary>
- /// This is called when the game should draw itself.
- /// </summary>
- /// <param name="gameTime">Provides a snapshot of timing values.</param>
- protected override void Draw(GameTime gameTime)
- {
- GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer | ClearOptions.Stencil, Color.CornflowerBlue, 1, 0);
- DepthStencilState depthStencil = new DepthStencilState();
- depthStencil.DepthBufferEnable = true;
- depthStencil.DepthBufferWriteEnable = true;
- //depthStencil.
- depthStencil.StencilEnable = true;
- GraphicsDevice.DepthStencilState = depthStencil;
- GraphicsDevice.Clear(Color.CornflowerBlue);
- basicEffect.World = world;
- basicEffect.View = view;
- basicEffect.Projection = projection;
- basicEffect.VertexColorEnabled = true;
- //RENDER LEVEL IN GRAY COLOR.
- GraphicsDevice.SetVertexBuffer(vertexBuffer2);
- GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
- basicEffect.CurrentTechnique.Passes[0].Apply();
- GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffer2.VertexCount / 3);
- //DO STENCIL OPERATIONS RENDERING FRONT AND BACK FACES OF SHADOW VOLUME!
- GraphicsDevice.BlendState = BlendState.AlphaBlend;
- GraphicsDevice.DepthStencilState = addIfMirror; //increment stencil
- GraphicsDevice.SetVertexBuffer(vertexBuffer);
- basicEffect.CurrentTechnique.Passes[0].Apply();
- GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
- GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffer.VertexCount / 3);
- GraphicsDevice.DepthStencilState = addIfMirror2; //decrement stencil
- GraphicsDevice.RasterizerState = RasterizerState.CullClockwise;
- GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffer.VertexCount / 3);
- //RENDER THE SHADOW ITSELF
- GraphicsDevice.BlendState = BlendState.Opaque;
- GraphicsDevice.DepthStencilState = checkMirror;
- GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0); //need to clear the depth buffer. not sure why that is but it's the way it's done.
- GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
- GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, vertexBuffer.VertexCount / 3);
- base.Draw(gameTime);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement