I am using C# and the SharpDX library to do some rendering on a project that I am working on. However, I am only able to get the object to fully draw on the first pass, each subsequent pass it will only draw points. It doesn't matter if I use FillMode.Solid, or FillMode.Wireframe. I've also disabled culling. If I rotate the camera around the object, I still only see points. I have images displaying the issue and key points in my files. Having looked at this code for the past few days, I am completely out of ideas, and perhaps some fresh eyes will be able to figure it out.
Additionally, it only appears to draw the first triangle, not the second one.
Here are the pictures:
Here is my code:
Mesh init
rCom.mesh = new Components.Mesh3D(this.render.Device,
new Components.VertexStructures.Color[] {
new Components.VertexStructures.Color(
new SharpDX.Vector3(-1.0f, -1.0f, 0.0f), new SharpDX.Vector4(1.0f, 0.0f, 0.0f, 1.0f)),
new Components.VertexStructures.Color(
new SharpDX.Vector3(-1.0f, 1.0f, 0.0f), new SharpDX.Vector4(0.0f, 1.0f, 0.0f, 1.0f)),
new Components.VertexStructures.Color(
new SharpDX.Vector3(1.0f, 1.0f, 0.0f), new SharpDX.Vector4(0.0f, 0.0f, 1.0f, 1.0f)),
new Components.VertexStructures.Color(
new SharpDX.Vector3(1.0f, -1.0f, 0.0f), new SharpDX.Vector4(1.0f, 1.0f, 1.0f, 1.0f))
},
new[] {
0, 1, 2, 0, 2, 3
}
);
Vertex structure - color
public static class VertexStructures
{
...
public struct Color
{
public SharpDX.Vector3 pos;
public SharpDX.Vector4 col;
public static int sizeInBytes
{ get { return Vector3.SizeInBytes + Vector4.SizeInBytes; } }
public Color(SharpDX.Vector3 pos, SharpDX.Vector4 col)
{ this.pos = pos; this.col = col; }
}
...
}
Mesh Class
public class Mesh3D
{
private D3D10.Device device;
public D3D10.VertexBufferBinding vertexBuffer;
public D3D10.Buffer indexBuffer;
public int numberOfVertices;
public int numberOfIndices;
public static D3D10.Buffer CreateBuffer<T>(D3D10.Device device, BindFlags bindFlags, params T[] items)
where T : struct
{
var len = Utilities.SizeOf(items);
var stream = new DataStream(len, true, true);
foreach (var item in items)
stream.Write(item);
stream.Position = 0;
var buffer = new D3D10.Buffer(device, stream, len, ResourceUsage.Default,
bindFlags, CpuAccessFlags.None, ResourceOptionFlags.None);
return buffer;
}
...
public Mesh3D(D3D10.Device device, VertexStructures.Color[] vertices, int[] indices = null)
{
this.numberOfVertices = vertices.Length;
this.numberOfIndices = indices.Length;
this.vertexBuffer = new VertexBufferBinding(
CreateBuffer<VertexStructures.Color>(device, BindFlags.VertexBuffer, vertices),
VertexStructures.Color.sizeInBytes, 0);
if (indices != null)
this.indexBuffer = CreateBuffer<int>(device, BindFlags.IndexBuffer, indices);
}
...
}
Render Update Code
public override void Update(double timeDelta = 0.0f)
{
// Clear our backbuffer with the rainbow color
d3d10Device.ClearRenderTargetView(this.renderTargetView, (Color4)SharpDX.Color.CornflowerBlue);
float time = (float)(timeDelta / 1000.0f); // time in milliseconds?
// Do actual drawing here
foreach (RenderComponent com in this._components)
{
// Get any required components
PositionComponent pos = com.entity.GetComponent<PositionComponent>();
// Set up required buffers
var inputAssembler = this.d3d10Device.InputAssembler;
inputAssembler.SetVertexBuffers(0, com.mesh.vertexBuffer);
if (com.mesh.indexBuffer != null)
inputAssembler.SetIndexBuffer(com.mesh.indexBuffer, Format.R32_UInt, 0);
// Set up effect variables
// These matrices should always be defined in the shader, even if they're not used
com.shader.shader.GetVariableByIndex(0).AsMatrix().SetMatrix(this.camera.viewMatrix);
com.shader.shader.GetVariableByIndex(1).AsMatrix().SetMatrix(this.camera.projectionMatrix);
com.shader.shader.GetVariableByIndex(2).AsMatrix().SetMatrix(pos.rotationXMatrix);
com.shader.shader.GetVariableByIndex(3).AsMatrix().SetMatrix(pos.rotationYMatrix);
com.shader.shader.GetVariableByIndex(4).AsMatrix().SetMatrix(pos.rotationZMatrix);
com.shader.shader.GetVariableByIndex(5).AsMatrix().SetMatrix(pos.scalingMatrix);
com.shader.shader.GetVariableByIndex(6).AsMatrix().SetMatrix(pos.translationLocalMatrix);
com.shader.shader.GetVariableByIndex(7).AsMatrix().SetMatrix(pos.translationWorldMatrix);
foreach (var shaderVars in com.shader.vars)
{
// Eventually, we'll use this to set all the required variables needed
}
// Run through each technique, pass, draw
int i = 0, j = 0;
foreach (var techniqueContainer in com.shader.inputLayouts)
{
var technique = com.shader.shader.GetTechniqueByIndex(i);
foreach (var passContainer in techniqueContainer)
{
var pass = technique.GetPassByIndex(j);
inputAssembler.InputLayout = passContainer;
pass.Apply();
this.d3d10Device.Draw(com.mesh.numberOfVertices, 0);
j += 1;
}
i += 1;
}
}
// Present our drawn scene waiting for one vertical sync
this.swapChain.Present(1, PresentFlags.None);
}
lastly, my shader file
matrix View;
matrix Projection;
matrix rotationXMatrix;
matrix rotationYMatrix;
matrix rotationZMatrix;
matrix scalingMatrix;
matrix translationLocalMatrix;
matrix translationWorldMatrix;
struct VS_IN
{
float4 pos : POSITION;
float4 col : COLOR;
};
struct PS_IN
{
float4 pos : SV_POSITION;
float4 col : COLOR;
};
PS_IN VS( VS_IN input )
{
PS_IN output = (PS_IN)0;
input.pos = mul(input.pos, rotationXMatrix);
input.pos = mul(input.pos, rotationYMatrix);
input.pos = mul(input.pos, rotationZMatrix);
input.pos = mul(input.pos, scalingMatrix);
input.pos = mul(input.pos, translationLocalMatrix);
input.pos = mul(input.pos, translationWorldMatrix);
input.pos = mul(input.pos, View);
input.pos = mul(input.pos, Projection);
output.pos = input.pos;
output.col = float4(1.0f, 1.0f, 1.0f, 1.0f);//input.col;
return output;
}
float4 PS( PS_IN input ) : SV_Target
{
return input.col;
}
technique10 Render
{
pass P0
{
SetGeometryShader( 0 );
SetVertexShader( CompileShader( vs_4_0, VS() ) );
SetPixelShader( CompileShader( ps_4_0, PS() ) );
}
}
Please let me know if any further information or code is needed. I really hope someone can help me with this, I can't figure it out.
In the code above you don't appear to be setting the topology (triangles vs lines vs points). See for instance MSDN documentation on Primitive Toplogies, as well as the SharpDX documentation on InputAssemblyStage.PrimitiveToplogy and the SharpDX documentation on the PrimitiveTopology enum.
In your Update() method you probably want to add
inputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
You should probably put this before your foreach for performance reasons since it doesn't change.
You didn't organize your points in a triangle block on update() stage.
Related
Need help because I'm new to OpenGL.
So, my task is to create a control that will draw in real time the process of cutting a workpiece on a CNC machine.
I tried to do it classically through glBegin, glEnd and everything works fine, but due to the large number of vertices, it starts to work slowly at the end. Therefore, I decided to try using VertexBufferArray () and VertexBuffer () - this also works, but in this situation I do not understand how to change the line width and its type (specifically, I have two types - a regular line and a dash-dotted line).
Here is my method where i use array
private void CreateBufferAndDraw(OpenGL GL)
{
try
{
if (shaderProgram == null && vertexBufferArray == null)
{
var vertexShaderSource = ManifestResourceLoader.LoadTextFile("vertex_shader.glsl");
var fragmentShaderSource = ManifestResourceLoader.LoadTextFile("fragment_shader.glsl");
shaderProgram = new ShaderProgram();
shaderProgram.Create(gL, vertexShaderSource, fragmentShaderSource, null);
attribute_vpos = (uint)gL.GetAttribLocation(shaderProgram.ShaderProgramObject, "vPosition");
attribute_vcol = (uint)gL.GetAttribLocation(shaderProgram.ShaderProgramObject, "vColor");
shaderProgram.AssertValid(gL);
}
if (_data == null)
{
_data = new vec3[_Points.Count];
}
else
{
if (_data.Length != _Points.Count)
{
_data = (vec3[])ResizeArray(_data, _Points.Count);
}
}
if (_dataColor == null)
{
_dataColor = new vec3[_Points.Count];
}
else
{
if (_dataColor.Length != _Points.Count)
{
_dataColor = (vec3[])ResizeArray(_dataColor, _Points.Count);
}
}
for (int i = _dataTail; i < _Points.Count; i++)
{
_data[i].y = _Points[i].Y;
_data[i].x = _Points[i].X;
_data[i].z = _Points[i].Z;
_dataColor[i] = new vec3(_Points[i].ToolColor.R / 255.0f, _Points[i].ToolColor.G / 255.0f, _Points[i].ToolColor.B / 255.0f);
}
_dataTail = _Points.Count;
// Create the vertex array object.
vertexBufferArray = new VertexBufferArray();
vertexBufferArray.Create(GL);
vertexBufferArray.Bind(GL);
// Create a vertex buffer for the vertex data.
var vertexDataBuffer = new VertexBuffer();
vertexDataBuffer.Create(GL);
vertexDataBuffer.Bind(GL);
vertexDataBuffer.SetData(GL, attribute_vpos, _data, false, 3);
// Now do the same for the colour data.
var colourDataBuffer = new VertexBuffer();
colourDataBuffer.Create(GL);
colourDataBuffer.Bind(GL);
colourDataBuffer.SetData(GL, attribute_vcol, _dataColor, false, 3);
// Unbind the vertex array, we've finished specifying data for it.
vertexBufferArray.Unbind(GL);
// Bind the shader, set the matrices.
shaderProgram.Bind(GL);
// Set matrixs for shader program
float rads = (90.0f / 360.0f) * (float)Math.PI * 2.0f;
mat4 _mviewdata = glm.translate(new mat4(1f), new vec3(_track_X, _track_Y, _track_Z));
mat4 _projectionMatrix = glm.perspective(rads, (float)this.trackgl_control.Height / (float)this.trackgl_control.Width, 0.001f, 1000f);
mat4 _modelMatrix = glm.lookAt(new vec3(0, 0, -1), new vec3(0, 0, 0), new vec3(0, -1, -1));
shaderProgram.SetUniformMatrix4(GL, "projectionMatrix", _projectionMatrix.to_array());
shaderProgram.SetUniformMatrix4(GL, "viewMatrix", _modelMatrix.to_array());
shaderProgram.SetUniformMatrix4(GL, "modelMatrix", _mviewdata.to_array());
// Bind the out vertex array.
vertexBufferArray.Bind(GL);
GL.LineWidth(5.0f);
// Draw the square.
GL.DrawArrays(OpenGL.GL_LINE_STRIP, 0, _dataTail);
// Unbind our vertex array and shader.
vertexBufferArray.Unbind(GL);
shaderProgram.Unbind(GL);
}
catch (Exception ex) { MessageBox.Show("CreateAndPlotData" + "\n" + ex.ToString()); }
}
This is what i get
As you see, all lines have the same width. So, my question is: Does anyone know what i can do about this?
And another one: what if i need to show a point of the current location of the instrument? I should create another array with one Vertex ?
p.s. Sry for my english, and here here is picture of what i get with glBegin/glEnd
No tag spamming intended.
I'm doing this project partially guided by tutorials in C ++ and C #. Therefore, if someone knows how to do this in C ++, then in this case I will just try to implement the same in C#.
I' trying to implement a renderer which uses only one VBO and one EBO to store all object vertices and indices.
For that, I found some tutorials and finally came up with a rather good result.
The problem is that it only works properly with ONE single object. As soon as I want to add another one, the rendering shows weird behaviour.
Can you help me with this?
You can find the full code here: https://github.com/BanditBloodwyn/TerritorySimulator.
The important classes are:
Rendering.Core.Rendering.Renderer.cs
Rendering.Core.Classes.Shapes.GLShape.cs
Rendering.Core.RenderGUI.RenderGUI.cs
This is the initializing method in the Renderer:
public void Initialize(GLShape[] shapeArray)
{
Shapes = shapeArray;
GL.Enable(EnableCap.DepthTest);
GL.ClearColor(0.0f, 0.0f, 0.10f, 1.0f);
InitializeBuffers(Shapes);
InitializeVertexArrayObject(Shapes);
SetupShader();
BindBuffers();
}
The submethods look like this.
private void InitializeBuffers(GLShape[] shapeArray)
{
int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);
// Vertex buffer
vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
offset += shape.VertexBufferSize;
}
// Element buffer
elementBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, shape.Indices);
offset += shape.IndexBufferSize;
}
}
private void InitializeVertexArrayObject(GLShape[] shapeArray)
{
foreach (GLShape shape in shapeArray)
{
shape.VertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(shape.VertexArrayObject);
}
}
private void SetupShader()
{
// shader
string vertexPath = Path.Combine(Environment.CurrentDirectory, #"GLSL\", "Vertex.vert");
string fragmentPath = Path.Combine(Environment.CurrentDirectory, #"GLSL\", "Fragment.frag");
shader = new Shader(vertexPath, fragmentPath);
shader.Use();
int vertexLocation = shader.GetAttribLocation("aPosition");
GL.EnableVertexAttribArray(vertexLocation);
GL.VertexAttribPointer(
vertexLocation,
3,
VertexAttribPointerType.Float,
false,
5 * sizeof(float),
0);
int texCoordLocation = shader.GetAttribLocation("aTexCoord");
GL.EnableVertexAttribArray(texCoordLocation);
GL.VertexAttribPointer(
texCoordLocation,
2,
VertexAttribPointerType.Float,
false,
5 * sizeof(float),
3 * sizeof(float));
shader.SetInt("texture0", 0);
shader.SetInt("texture1", 1);
}
private void BindBuffers()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
}
The render function itself looks like this.
public void Render()
{
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
if (Shapes == null || Shapes.Length == 0)
return;
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in Shapes)
{
foreach (var texture in shape.Textures)
{
if (LayerConfiguration.ShowEarthTexture)
texture.Key.Use(texture.Value);
else
texture.Key.MakeTransparent(texture.Value);
}
ApplyModelTransforms(shape, out Matrix4 model);
shader.SetMatrix4("model", model);
shader.SetMatrix4("view", Camera.GetViewMatrix());
GL.DrawElements(PrimitiveType.Triangles, shape.Indices.Length, DrawElementsType.UnsignedInt, offset);
offset += shape.IndexBufferSize;
}
shader.SetMatrix4("projection", Camera.GetProjectionMatrix());
shader.Use();
}
As soon as I want to add another one, the rendering shows weird behavior
Of course, because the indices for the 2nd and following objects are wrong. You need to add the sum of the vertices of the previous meshes to the indexes. To the indices of the first mesh you have to add 0, to the indices of the 2nd mesh you have to add the number of vertices of the 1st mesh, to the indices of the 3rd mesh you have to add the sum of the vertices of the 1st and 2nd mesh, ...
offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
GL.BufferSubData(
BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
offset += shape.IndexBufferSize;
firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}
Complete method InitializeBuffers:
private void InitializeBuffers(GLShape[] shapeArray)
{
int vertexBufferSize = shapeArray.Sum(shape => shape.VertexBufferSize);
int indexBufferSize = shapeArray.Sum(shape => shape.IndexBufferSize);
// Vertex buffer
vertexBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ArrayBuffer, vertexBufferObject);
GL.BufferData(BufferTarget.ArrayBuffer, vertexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
IntPtr offset = (IntPtr)0;
foreach (GLShape shape in shapeArray)
{
GL.BufferSubData(BufferTarget.ArrayBuffer, offset, shape.VertexBufferSize, shape.Vertices);
offset += shape.VertexBufferSize;
}
// Element buffer
elementBufferObject = GL.GenBuffer();
GL.BindBuffer(BufferTarget.ElementArrayBuffer, elementBufferObject);
GL.BufferData(BufferTarget.ElementArrayBuffer, indexBufferSize, (IntPtr)0, BufferUsageHint.StaticDraw);
offset = (IntPtr)0;
uint firstVertexIndex = 0;
foreach (GLShape shape in shapeArray)
{
var indexArray = shape.Indices.Select(index => index + firstVertexIndex).ToArray();
GL.BufferSubData(BufferTarget.ElementArrayBuffer, offset, shape.IndexBufferSize, indexArray);
offset += shape.IndexBufferSize;
firstVertexIndex += (uint)(shape.VertexBufferSize / (5 * sizeof(float)));
}
}
In a graphic application i am rendering an image to a texture, then i use that texture on a 3d model.
My problem is the following:
When the application starts everything is fine, but if i resize the view where i do the rendering and i make it bigger, the texture on the 3d model disappear (it doesnt turn black, i think that all values become 1). Making the image smaller doesnt make the texture to disappear, but it is shown incorrectly (not resized).
Here are some explanatory images:
Resize smaller
Not resized
Resize bigger, 1 pixel bigger is enough to make image disappear.
The code that generate the renderview is this:
private void CreateRenderToTexture(Panel view)
{
Texture2DDescription t2d = new Texture2DDescription()
{
Height = view.Height,
Width = view.Width,
Format = Format.R32G32B32A32_Float,
BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget, //| BindFlags.UnorderedAccess,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None,
SampleDescription = new SampleDescription(_multisample, 0),
MipLevels = 1,
Usage = ResourceUsage.Default,
ArraySize = 1,
};
_svgTexture = new Texture2D(_device, t2d);
_svgRenderView = new RenderTargetView(_device, _svgTexture);
}
private void RenderSVGToTexture()
{
_camera.SetDefaultProjection();
UpdatePerFrameBuffers();
_dc.OutputMerger.SetTargets(_depthStencil, _svgRenderView);//depth stencil has same dimension as all other buffers
_dc.ClearRenderTargetView(_svgRenderView, new Color4(1.0f, 1.0f, 1.0f));
_dc.ClearDepthStencilView(_depthStencil, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);
Entity e;
if (RenderingManager.Scene.Entity2DExists("svgimage"))
{
RenderingManager.Scene.GetEntity2D("svgimage", out e);
e.Draw(_dc);
}
_swapChain.Present(0, PresentFlags.None);
}
When rendering the 3D scene i call this function before rendering the model:
private void SetTexture()
{
Entity e;
if (!RenderingManager.Scene.GetEntity3D("model3d", out e))
return;
e.ShaderType = ResourceManager.ShaderType.MAIN_MODEL;
if (ResourceManager.SVGTexture == null )
{
e.ShaderType = ResourceManager.ShaderType.PNUVNOTEX;
return;
}
SamplerDescription a = new SamplerDescription();
a.AddressU = TextureAddressMode.Wrap;
a.AddressV = TextureAddressMode.Wrap;
a.AddressW = TextureAddressMode.Wrap;
a.Filter = Filter.MinPointMagMipLinear;
SamplerState b = SamplerState.FromDescription(ResourceManager.Device, a);
ShaderResourceView svgTexResourceView = new ShaderResourceView(ResourceManager.Device, Texture2D.FromPointer(ResourceManager.SVGTexture.ComPointer));
ResourceManager.Device.ImmediateContext.PixelShader.SetShaderResource(svgTexResourceView, 0);
ResourceManager.Device.ImmediateContext.PixelShader.SetSampler(b, 0);
b.Dispose();
svgTexResourceView.Dispose();
}
Pixel shader:
Texture2D svg : register(t0);
Texture2D errorEstimate : register(t1);
SamplerState ss : register(s0);
float4 main(float4 position : SV_POSITION, float4 color : COLOR, float2 uv : UV) : SV_Target
{
return color * svg.Sample(ss, uv);// *errorEstimate.Sample(ss, uv);
}
I dont understand what i am doing wrong, i hope that you can make me see the mistake that i am doing. Thank you, and sorry for the bad english!
As it (almost) always turn out i was making a very stupid mistake.
I wasn't calling the correct resize function.
Basically in the Renderer2D class there is a DoResize function that does the resize of the 2d only buffers, while in the abstract Renderer class there is the rest of the buffers resizing. The mistake is that in the parent class i was calling the wrong base resize function!
Parent class:
protected override void DoResize(uint width, uint height)
{
if (width == 0 || height == 0)
return;
base.DoResize(width, height); //Here i was calling base.Resize (which was deprecated after a change in the application architecture)
_camera.Width = width;
_camera.Height = height;
_svgTexture.Dispose();
_svgRenderView.Dispose();
CreateRenderToTexture(_viewReference);
ResizePending = false;
}
Base class
protected virtual void DoResize(uint width, uint height)
{
Width = width;
Height = height;
_viewport = new Viewport(0, 0, Width, Height);
_renderTarget.Dispose();
if (_swapChain.ResizeBuffers(2, (int)width, (int)height, Format.Unknown, SwapChainFlags.AllowModeSwitch).IsFailure)
Console.WriteLine("An error occured while resizing buffers.");
using (var resource = Resource.FromSwapChain<Texture2D>(_swapChain, 0))
_renderTarget = new RenderTargetView(_device, resource);
_depthStencil.Dispose();
CreateDepthBuffer();
}
Maybe the code i posted can be of help for someone who is trying to do some render to texture stuff, since i see that there is always people that can't make it work :)
Getting started using SharpGL after using other frameworks for OpenGL in C# I decided to start with the most simplest of examples to make sure I understood any syntax changes/niceties of SharpGL.
So I'm attempting to render a single solid coloured triangle which shouldn't be too difficult.
I have two Vertex Buffers, one that stores the points of the Triangle and the other that stores the colours at each of the points. These are built up like so (The points one is the same except it uses the points array):
var colorsVboArray = new uint[1];
openGl.GenBuffers(1, colorsVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
this.colorsPtr = GCHandle.Alloc(this.colors, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.colors.Length * Marshal.SizeOf<float>(), this.colorsPtr,
OpenGL.GL_STATIC_DRAW);
These are then set with the correct attrib pointer and enabled:
openGl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.EnableVertexAttribArray(0);
But now when I draw using the call:
openGl.DrawArrays(OpenGL.GL_TRIANGLES, 0, 3);
I don't get anything on the screen. No exceptions, but the background is simply blank.
Naturally I presumed that there were compilation issues with my shaders, fortunately SharpGL gives me an easy way of checking and both the Vertex and Fragment shaders are showing as correctly compiled and linked.
Can anyone see why this code does not correctly display any objects, it's basically the same code that I've used before.
Full Source:
internal class Triangle
{
private readonly float[] colors = new float[9];
private readonly ShaderProgram program;
private readonly float[] trianglePoints =
{
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
private IntPtr colorsPtr;
private IntPtr trianglePointsPtr;
private readonly VertexBufferArray vertexBufferArray;
public Triangle(OpenGL openGl, SolidColorBrush solidColorBrush)
{
for (var i = 0; i < this.colors.Length; i+=3)
{
this.colors[i] = solidColorBrush.Color.R / 255.0f;
this.colors[i + 1] = solidColorBrush.Color.G / 255.0f;
this.colors[i + 2] = solidColorBrush.Color.B / 255.0f;
}
this.vertexBufferArray = new VertexBufferArray();
this.vertexBufferArray.Create(openGl);
this.vertexBufferArray.Bind(openGl);
var colorsVboArray = new uint[1];
openGl.GenBuffers(1, colorsVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
this.colorsPtr = GCHandle.Alloc(this.colors, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.colors.Length * Marshal.SizeOf<float>(), this.colorsPtr,
OpenGL.GL_STATIC_DRAW);
var triangleVboArray = new uint[1];
openGl.GenBuffers(1, triangleVboArray);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, triangleVboArray[0]);
this.trianglePointsPtr = GCHandle.Alloc(this.trianglePoints, GCHandleType.Pinned).AddrOfPinnedObject();
openGl.BufferData(OpenGL.GL_ARRAY_BUFFER, this.trianglePoints.Length * Marshal.SizeOf<float>(), this.trianglePointsPtr,
OpenGL.GL_STATIC_DRAW);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER,triangleVboArray[0]);
openGl.VertexAttribPointer(0, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.BindBuffer(OpenGL.GL_ARRAY_BUFFER, colorsVboArray[0]);
openGl.VertexAttribPointer(1, 3, OpenGL.GL_FLOAT, false, 0, IntPtr.Zero);
openGl.EnableVertexAttribArray(0);
openGl.EnableVertexAttribArray(1);
var vertexShader = new VertexShader();
vertexShader.CreateInContext(openGl);
vertexShader.SetSource(new StreamReader(
Assembly.GetExecutingAssembly()
.GetManifestResourceStream(#"OpenGLTest.Shaders.Background.SolidColor.SolidColorVertex.glsl"))
.ReadToEnd());
vertexShader.Compile();
var fragmentShader = new FragmentShader();
fragmentShader.CreateInContext(openGl);
fragmentShader.SetSource(new StreamReader(
Assembly.GetExecutingAssembly()
.GetManifestResourceStream(#"OpenGLTest.Shaders.Background.SolidColor.SolidColorFragment.glsl"))
.ReadToEnd());
fragmentShader.Compile();
this.program = new ShaderProgram();
this.program.CreateInContext(openGl);
this.program.AttachShader(vertexShader);
this.program.AttachShader(fragmentShader);
this.program.Link();
}
public void Draw(OpenGL openGl)
{
this.program.Push(openGl, null);
this.vertexBufferArray.Bind(openGl);
openGl.DrawArrays(OpenGL.GL_TRIANGLES, 0, 3);
this.program.Pop(openGl, null);
}
}
Vertex Shader:
#version 430 core
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec3 vertex_color;
out vec3 color;
void main()
{
color = vertex_color;
gl_Position = vec4(vertex_position, 1.0);
}
Fragment Shader:
#version 430 core
in vec3 colour;
out vec4 frag_colour;
void main ()
{
frag_colour = vec4 (colour, 1.0);
}
Fixed this in the end fairly simply.
I had previously reviewed the SharpGL code and had noted that GL_DEPTH_TEST had been enabled, so I had presumed that the GL_DEPTH_BUFFER_BIT had been correctly cleared and I didn't have to do this.
After reviewing the Render code in SharpGL it turns out that this is not cleared by default but instead the onus is passed to the user to correctly clear the depth buffer.
Therefore I needed a simple call to clear to fix this:
this.openGl.Clear(OpenGL.GL_DEPTH_BUFFER_BIT);
What's wrong with my instancing below? I'm trying to draw multiple instances of a single box with vertex colors. The examples I adapted this code from used textures and a shader rather than vertex colors. So I suspect that I'm going wrong with VertexPositionColor or my use of BasicEffect. I don't need a texture so I tried to remove the shader. I should also mention this is part of a winforms application.
What I get out of this code is a big red X indicating something went terribly wrong.
What am I missing here? Obviously there's something I'm not understanding.
namespace Die
{
class DieRender
{
VertexDeclaration instanceVertexDeclaration;
VertexBuffer dieGeometryBuffer;
IndexBuffer dieIndexBuffer;
VertexBuffer instanceBuffer;
VertexBufferBinding[] bindings;
InstanceInfo[] instances;
int instanceCount = 3;
struct InstanceInfo
{
public Vector4 World;
};
public void Initialize(GraphicsDevice device) {
GenerateInstanceVertexDeclaration();
GenerateDieGeometry(device, Color.Blue);
GenerateInstanceInformation(device, instanceCount);
bindings = new VertexBufferBinding[2];
bindings[0] = new VertexBufferBinding(dieGeometryBuffer);
bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1);
}
private void GenerateInstanceVertexDeclaration() {
VertexElement[] instanceStreamElements = new VertexElement[1];
instanceStreamElements[0] =
new VertexElement(0, VertexElementFormat.Vector4,
VertexElementUsage.Position, 1);
instanceVertexDeclaration = new VertexDeclaration(instanceStreamElements);
}
public void GenerateDieGeometry(GraphicsDevice device, Color color) {
VertexPositionColor[] vertices = new VertexPositionColor[4];
int[] indices = new int[6];
vertices[0].Position = new Vector3(-1, 1, 0);
vertices[1].Position = new Vector3(1, 1, 0);
vertices[2].Position = new Vector3(-1, -1, 0);
vertices[3].Position = new Vector3(1, -1, 0);
for (int i = 0; i < vertices.Count(); i++)
vertices[i].Color = color;
dieGeometryBuffer = new VertexBuffer(device,VertexPositionColor.VertexDeclaration,
4, BufferUsage.WriteOnly);
dieGeometryBuffer.SetData(vertices);
indices[0] = 0; indices[1] = 1; indices[2] = 2;
indices[3] = 1; indices[4] = 3; indices[5] = 2;
dieIndexBuffer = new IndexBuffer(device, typeof(int), 6, BufferUsage.WriteOnly);
dieIndexBuffer.SetData(indices);
}
private void GenerateInstanceInformation(GraphicsDevice device, Int32 count) {
instances = new InstanceInfo[count];
Random rnd = new Random();
for (int i = 0; i < count; i++) {
instances[i].World = new Vector4(-rnd.Next(20),
-rnd.Next(20),
-rnd.Next(20), 0);
}
instanceBuffer = new VertexBuffer(device, instanceVertexDeclaration,
count, BufferUsage.WriteOnly);
instanceBuffer.SetData(instances);
}
public void Draw(Matrix world, Matrix view, Matrix projection, GraphicsDevice device) {
device.Clear(Color.White);
BasicEffect effect = new BasicEffect(device);
effect.EnableDefaultLighting();
effect.TextureEnabled = false;
effect.World = world;
effect.View = view;
effect.Projection = projection;
effect.VertexColorEnabled = true;
device.Indices = dieIndexBuffer;
device.SetVertexBuffers(bindings);
foreach (EffectPass pass in effect.CurrentTechnique.Passes) {
pass.Apply();
device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 4, 0, 2, instanceCount);
}
}
}
}
Ah! I found it... struggled with this for days and found the problem just as soon as I posted the question.
After enabling the exceptions from the CLR I caught the exception and found this similar question: XNA: The current vertex declaration does not include all the elements required by the current vertex shader. Normal0 is missing
Sorry if I wasted anybody's time.
Now... on to the next bug.