/// <summary> /// Sets the attribute ready for use in the VAO /// </summary> internal void SetAttribute(VertexLayout VertexLayout) { int offset = 0; if (VertexLayout.Position >= 0) { GL.VertexAttribPointer(VertexLayout.Position, 3, VertexAttribPointerType.Float, false, vertexSize, offset); offset += Vector3.SizeInBytes; } if (VertexLayout.Normal >= 0) { GL.VertexAttribPointer(VertexLayout.Normal, 3, VertexAttribPointerType.Float, false, vertexSize, offset); offset += Vector3.SizeInBytes; } if (VertexLayout.UV >= 0) { GL.VertexAttribPointer(VertexLayout.UV, 2, VertexAttribPointerType.Float, false, vertexSize, offset); offset += Vector2.SizeInBytes; //equivialant to API Vector2 } if (VertexLayout.Color >= 0) { GL.VertexAttribPointer(VertexLayout.Color, 4, VertexAttribPointerType.Float, false, vertexSize, offset); } }
/// <summary> /// Binds the VAO ready for drawing /// </summary> public void BindForDrawing(VertexLayout VertexLayout) { GL.BindVertexArray(handle); vbo.Bind(); vbo.EnableAttribute(VertexLayout); vbo.SetAttribute(VertexLayout); }
/// <summary> /// Draw using VAO /// </summary> /// <param name="VertexLayout"></param> /// <param name="DrawMode">Specifies the primitive or primitives that will be created from vertices</param> public void Draw(VertexLayout VertexLayout, PrimitiveType DrawMode) { vbo.Bind(); vbo.EnableAttribute(VertexLayout); vbo.SetAttribute(VertexLayout); ibo.Draw(DrawMode); vbo.DisableAttribute(VertexLayout); }
/// <summary> /// Draw using VAO /// </summary> /// <param name="VertexLayout"></param> /// <param name="DrawMode">Specifies the primitive or primitives that will be created from vertices</param> /// <param name="Start">Start position of vertex index</param> /// <param name="Count">Number of vertex indices to use</param> public void Draw(VertexLayout VertexLayout, PrimitiveType DrawMode, int Start, int Count) { vbo.Bind(); vbo.EnableAttribute(VertexLayout); vbo.SetAttribute(VertexLayout); ibo.Draw(DrawMode, Start, Count); vbo.DisableAttribute(VertexLayout); }
/// <summary>Enables a specific vertex attribute array</summary> internal void EnableAttribute(VertexLayout VertexLayout) { if (VertexLayout.Position >= 0) { GL.EnableVertexAttribArray(VertexLayout.Position); } if (VertexLayout.Normal >= 0) { GL.EnableVertexAttribArray(VertexLayout.Normal); } if (VertexLayout.UV >= 0) { GL.EnableVertexAttribArray(VertexLayout.UV); } if (VertexLayout.Color >= 0) { GL.EnableVertexAttribArray(VertexLayout.Color); } }
/// <summary> /// Sets the VAO vertex layout attributes /// </summary> /// <remarks> /// These attributes remain valid unless a different shader is used to draw the object, and will be remembered by the VAO /// </remarks> public void SetAttributes(VertexLayout VertexLayout) { vbo.Bind(); vbo.EnableAttribute(VertexLayout); vbo.SetAttribute(VertexLayout); }
public static void CreateVAO(this StaticBackground background, VertexLayout vertexLayout) { float y0, y1; if (background.KeepAspectRatio) { int tw = background.Texture.Width; int th = background.Texture.Height; double hh = System.Math.PI * background.BackgroundImageDistance * th / (tw * background.Repetition); y0 = (float)(-0.5 * hh); y1 = (float)(1.5 * hh); } else { y0 = (float)(-0.125 * background.BackgroundImageDistance); y1 = (float)(0.375 * background.BackgroundImageDistance); } const int n = 32; Vector3f[] bottom = new Vector3f[n]; Vector3f[] top = new Vector3f[n]; double angleValue = 2.61799387799149 - 3.14159265358979 / n; const double angleIncrement = 6.28318530717958 / n; /* * To ensure that the whole background cylinder is rendered inside the viewing frustum, * the background is rendered before the scene with z-buffer writes disabled. Then, * the actual distance from the camera is irrelevant as long as it is inside the frustum. * */ for (int i = 0; i < n; i++) { float x = (float)(background.BackgroundImageDistance * System.Math.Cos(angleValue)); float z = (float)(background.BackgroundImageDistance * System.Math.Sin(angleValue)); bottom[i] = new Vector3f(x, y0, z); top[i] = new Vector3f(x, y1, z); angleValue += angleIncrement; } float textureStart = 0.5f * (float)background.Repetition / n; float textureIncrement = -(float)background.Repetition / n; float textureX = textureStart; List <LibRenderVertex> vertexData = new List <LibRenderVertex>(); List <ushort> indexData = new List <ushort>(); for (int i = 0; i < n; i++) { int j = (i + 1) % n; int indexOffset = vertexData.Count; // side wall vertexData.Add(new LibRenderVertex { Position = top[i], UV = new Vector2f(textureX, 0.005f), Color = Color128.White }); vertexData.Add(new LibRenderVertex { Position = bottom[i], UV = new Vector2f(textureX, 0.995f), Color = Color128.White }); vertexData.Add(new LibRenderVertex { Position = bottom[j], UV = new Vector2f(textureX + textureIncrement, 0.995f), Color = Color128.White }); vertexData.Add(new LibRenderVertex { Position = top[j], UV = new Vector2f(textureX + textureIncrement, 0.005f), Color = Color128.White }); indexData.AddRange(new[] { 0, 1, 2, 3 }.Select(x => x + indexOffset).Select(x => (ushort)x)); // top cap vertexData.Add(new LibRenderVertex { Position = new Vector3f(0.0f, top[i].Y, 0.0f), UV = new Vector2f(textureX + 0.5f * textureIncrement, 0.1f), Color = Color128.White }); indexData.AddRange(new[] { 0, 3, 4 }.Select(x => x + indexOffset).Select(x => (ushort)x)); // bottom cap vertexData.Add(new LibRenderVertex { Position = new Vector3f(0.0f, bottom[i].Y, 0.0f), UV = new Vector2f(textureX + 0.5f * textureIncrement, 0.9f), Color = Color128.White }); indexData.AddRange(new[] { 5, 2, 1 }.Select(x => x + indexOffset).Select(x => (ushort)x)); // finish textureX += textureIncrement; } VertexArrayObject VAO = (VertexArrayObject)background.VAO; VAO?.UnBind(); VAO?.Dispose(); VAO = new VertexArrayObject(); VAO.Bind(); VAO.SetVBO(new VertexBufferObject(vertexData.ToArray(), BufferUsageHint.StaticDraw)); VAO.SetIBO(new IndexBufferObjectU(indexData.ToArray(), BufferUsageHint.StaticDraw)); VAO.SetAttributes(vertexLayout); VAO.UnBind(); background.VAO = VAO; }
/// <summary>Create an OpenGL/OpenTK VAO for a mesh</summary> /// <param name="isDynamic"></param> public static void CreateVAO(ref Mesh mesh, bool isDynamic, VertexLayout vertexLayout) { var hint = isDynamic ? BufferUsageHint.DynamicDraw : BufferUsageHint.StaticDraw; var vertexData = new List <LibRenderVertex>(); var indexData = new List <uint>(); var normalsVertexData = new List <LibRenderVertex>(); var normalsIndexData = new List <uint>(); for (int i = 0; i < mesh.Faces.Length; i++) { mesh.Faces[i].IboStartIndex = indexData.Count; mesh.Faces[i].NormalsIboStartIndex = normalsIndexData.Count; foreach (var vertex in mesh.Faces[i].Vertices) { var data = new LibRenderVertex { Position = mesh.Vertices[vertex.Index].Coordinates, Normal = vertex.Normal, UV = new Vector2f(mesh.Vertices[vertex.Index].TextureCoordinates) }; var coloredVertex = mesh.Vertices[vertex.Index] as ColoredVertex; if (coloredVertex != null) { data.Color = coloredVertex.Color; } else { data.Color = Color128.Transparent; } vertexData.Add(data); var normalsData = new LibRenderVertex[2]; normalsData[0].Position = data.Position; normalsData[1].Position = data.Position + data.Normal; for (int j = 0; j < normalsData.Length; j++) { normalsData[j].Color = Color128.White; } normalsVertexData.AddRange(normalsData); } indexData.AddRange(Enumerable.Range(mesh.Faces[i].IboStartIndex, mesh.Faces[i].Vertices.Length).Select(x => (uint)x)); normalsIndexData.AddRange(Enumerable.Range(mesh.Faces[i].NormalsIboStartIndex, mesh.Faces[i].Vertices.Length * 2).Select(x => (uint)x)); } VertexArrayObject VAO = (VertexArrayObject)mesh.VAO; VAO?.UnBind(); VAO?.Dispose(); VAO = new VertexArrayObject(); VAO.Bind(); VAO.SetVBO(new VertexBufferObject(vertexData.ToArray(), hint)); if (indexData.Count > 65530) { //Marginal headroom, although it probably doesn't matter VAO.SetIBO(new IndexBufferObjectI(indexData.ToArray(), hint)); } else { VAO.SetIBO(new IndexBufferObjectU(indexData.Select(x => (ushort)x).ToArray(), hint)); } VAO.SetAttributes(vertexLayout); VAO.UnBind(); mesh.VAO = VAO; VertexArrayObject NormalsVAO = (VertexArrayObject)mesh.NormalsVAO; NormalsVAO?.UnBind(); NormalsVAO?.Dispose(); NormalsVAO = new VertexArrayObject(); NormalsVAO.Bind(); NormalsVAO.SetVBO(new VertexBufferObject(normalsVertexData.ToArray(), hint)); if (normalsIndexData.Count > 65530) { //Marginal headroom, although it probably doesn't matter NormalsVAO.SetIBO(new IndexBufferObjectI(normalsIndexData.ToArray(), hint)); } else { NormalsVAO.SetIBO(new IndexBufferObjectU(normalsIndexData.Select(x => (ushort)x).ToArray(), hint)); } NormalsVAO.SetAttributes(vertexLayout); NormalsVAO.UnBind(); mesh.NormalsVAO = NormalsVAO; }
/// <summary>Create an OpenGL/OpenTK VAO for a mesh</summary> /// <param name="mesh">The mesh</param> /// <param name="isDynamic">Whether the mesh is dynamic (e.g. part of an animated object / train)</param> /// <param name="vertexLayout">The vertex layout to use</param> /// <param name="renderer">A reference to the base renderer</param> public static void CreateVAO(ref Mesh mesh, bool isDynamic, VertexLayout vertexLayout, BaseRenderer renderer) { try { var hint = isDynamic ? BufferUsageHint.DynamicDraw : BufferUsageHint.StaticDraw; var vertexData = new List <LibRenderVertex>(); var indexData = new List <uint>(); var normalsVertexData = new List <LibRenderVertex>(); var normalsIndexData = new List <uint>(); for (int i = 0; i < mesh.Faces.Length; i++) { mesh.Faces[i].IboStartIndex = indexData.Count; mesh.Faces[i].NormalsIboStartIndex = normalsIndexData.Count; foreach (var vertex in mesh.Faces[i].Vertices) { var data = new LibRenderVertex { Position = mesh.Vertices[vertex.Index].Coordinates, Normal = vertex.Normal, UV = new Vector2f(mesh.Vertices[vertex.Index].TextureCoordinates), Color = (mesh.Vertices[vertex.Index] as ColoredVertex)?.Color ?? Color128.White }; vertexData.Add(data); var normalsData = new LibRenderVertex[2]; normalsData[0].Position = data.Position; normalsData[1].Position = data.Position + data.Normal; for (int j = 0; j < normalsData.Length; j++) { normalsData[j].Color = Color128.White; } normalsVertexData.AddRange(normalsData); } indexData.AddRange(Enumerable.Range(mesh.Faces[i].IboStartIndex, mesh.Faces[i].Vertices.Length).Select(x => (uint)x)); normalsIndexData.AddRange(Enumerable.Range(mesh.Faces[i].NormalsIboStartIndex, mesh.Faces[i].Vertices.Length * 2).Select(x => (uint)x)); } VertexArrayObject VAO = (VertexArrayObject)mesh.VAO; VAO?.UnBind(); VAO?.Dispose(); VAO = new VertexArrayObject(); VAO.Bind(); VAO.SetVBO(new VertexBufferObject(vertexData.ToArray(), hint)); if (indexData.Count > 65530) { //Marginal headroom, although it probably doesn't matter VAO.SetIBO(new IndexBufferObjectUI(indexData.ToArray(), hint)); } else { VAO.SetIBO(new IndexBufferObjectUS(indexData.Select(x => (ushort)x).ToArray(), hint)); } VAO.SetAttributes(vertexLayout); VAO.UnBind(); mesh.VAO = VAO; VertexArrayObject NormalsVAO = (VertexArrayObject)mesh.NormalsVAO; NormalsVAO?.UnBind(); NormalsVAO?.Dispose(); NormalsVAO = new VertexArrayObject(); NormalsVAO.Bind(); NormalsVAO.SetVBO(new VertexBufferObject(normalsVertexData.ToArray(), hint)); if (normalsIndexData.Count > 65530) { //Marginal headroom, although it probably doesn't matter NormalsVAO.SetIBO(new IndexBufferObjectUI(normalsIndexData.ToArray(), hint)); } else { NormalsVAO.SetIBO(new IndexBufferObjectUS(normalsIndexData.Select(x => (ushort)x).ToArray(), hint)); } NormalsVAO.SetAttributes(vertexLayout); NormalsVAO.UnBind(); mesh.NormalsVAO = NormalsVAO; } catch (Exception e) { renderer.ForceLegacyOpenGL = true; renderer.currentHost.AddMessage(MessageType.Error, false, $"Creating VAO failed with the following error: {e}"); } }