I am experiencing an issue with wireframe within my 3D scene. For some strange reason, the wireframe is showing as incomplete in certain places. Moving the camera around makes some of the lines appear, and others disappear, instead of just being one complete wireframe. Here are a few pictures and some code. I am using SharpDX. Does anyone know what's going on?
(The following code has been trimmed down signifincantly to show only what I believe to be the relevant bits to this question)
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DirectInput;
using SharpDX.DXGI;
using SharpDX.Windows;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Windows.Forms;
using VoidwalkerEngine.Framework.DirectX;
using VoidwalkerEngine.Framework.DirectX.Rendering;
using VoidwalkerEngine.Framework.DirectX.Shaders;
using VoidwalkerEngine.Framework.Logic;
using VoidwalkerEngine.Framework.Maths;
namespace GrimoireTacticsGame.Client
{
public class GameWindow : RenderForm
{
/**
* Client Variables
*/
public Camera Camera { get; set; }
public Keyboard Keyboard { get; set; }
public Mouse Mouse { get; set; }
public bool IsMouseLookEnabled { get; private set; }
public Point CurrentMouseLocation { get; set; }
public Stopwatch ClientTimer { get; set; }
public int RenderFrequency { get; private set; }
public VsyncLevel Vsync { get; set; }
private bool _isResizeNeeded { get; set; } = true;
private Point _mouseLockLocation { get; set; }
private float _previousFrameDeltaTime { get; set; }
private int _frameCounter;
private System.DateTime _previousDateTime;
/**
* DirectX Variables
*/
private Texture2D _depthBuffer;
private SwapChain _swapChain;
private SwapChainDescription _swapChainDescription;
private Texture2D _backBuffer = null;
private RenderTargetView _renderView = null;
private DepthStencilView _depthView = null;
private SharpDX.Direct3D11.Device _device;
private DeviceContext _graphicsCardContext;
private Factory _factory;
public PointLightShaderArgs _pointLightArgs;
private BlendState BlendState { get; set; }
private RasterizerStateDescription RasterizerState { get; set; }
public List<StaticGeometry> StaticGeometry { get; set; }
/**
* Shaders
*/
public WorldShader WorldShader;
public GameWindow()
: base("Grimoire Tactics")
{
Initialize();
}
public void InitializeDirectX()
{
// SwapChain description
_swapChainDescription = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription = new ModeDescription(
this.ClientSize.Width,
this.ClientSize.Height,
new Rational(60, 1),
Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = this.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
SharpDX.Direct3D11.Device.CreateWithSwapChain(
DriverType.Hardware,
DeviceCreationFlags.None,
_swapChainDescription,
out _device,
out _swapChain);
_graphicsCardContext = _device.ImmediateContext;
_factory = _swapChain.GetParent<Factory>();
_factory.MakeWindowAssociation(this.Handle, WindowAssociationFlags.IgnoreAll);
/**
* Create RasterizerState
*/
RasterizerState = new RasterizerStateDescription
{
CullMode = CullMode.None,
DepthBias = 0,
DepthBiasClamp = 0,
FillMode = FillMode.Solid,
IsAntialiasedLineEnabled = false,
IsDepthClipEnabled = false,
IsFrontCounterClockwise = false,
IsMultisampleEnabled = false,
IsScissorEnabled = false,
SlopeScaledDepthBias = 0
};
_graphicsCardContext.Rasterizer.State = new RasterizerState(_device, RasterizerState);
/**
* Create BlendState
*/
BlendStateDescription blendStateDescription = new BlendStateDescription
{
AlphaToCoverageEnable = false,
};
blendStateDescription.RenderTarget[0].IsBlendEnabled = true;
blendStateDescription.RenderTarget[0].SourceBlend = BlendOption.SourceAlpha;
blendStateDescription.RenderTarget[0].DestinationBlend = BlendOption.InverseSourceAlpha;
blendStateDescription.RenderTarget[0].BlendOperation = BlendOperation.Add;
blendStateDescription.RenderTarget[0].SourceAlphaBlend = BlendOption.Zero;
blendStateDescription.RenderTarget[0].DestinationAlphaBlend = BlendOption.Zero;
blendStateDescription.RenderTarget[0].AlphaBlendOperation = BlendOperation.Add;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = ColorWriteMaskFlags.All;
this.BlendState = new BlendState(_device, blendStateDescription);
this._graphicsCardContext.OutputMerger.BlendState = this.BlendState;
}
private void InitializeShaders()
{
WorldShader = new WorldShader(_device);
}
private void Initialize()
{
this.StaticGeometry = new List<StaticGeometry>();
this.StartPosition = FormStartPosition.CenterScreen;
this.Camera = new Camera
{
MoveSpeed = 128f,
LookSpeed = 0.50f, // 0 ~ 1 (0.50 = 50%)
Location = new Vector3(0, 0, 0),
FieldOfView = 1.0f, // 0.7 ~ 1.20
NearZ = 1f,
FarZ = 8000f,
AccelerationMultiplier = 2.5f
};
InitializeDirectX();
InitializeShaders();
InitializeGeometry();
/**
* Initialize Clock
* Probably use a DateTime instead.
*/
ClientTimer = new Stopwatch();
/**
* Setup Handlers
*/
this.KeyDown += OnKeyDown;
this.KeyUp += OnKeyUp;
this.UserResized += OnResize;
this.MouseUp += OnMouseUp;
this.MouseMove += OnMouseMove;
this.MouseDown += OnMouseDown;
this.FormClosing += OnFormClosing;
/**
* Setup User Input
*/
DirectInput input = new DirectInput();
this.Keyboard = new Keyboard(input);
this.Keyboard.Properties.BufferSize = 128;
this.Keyboard.Acquire();
this.Mouse = new Mouse(input);
this.Mouse.Properties.BufferSize = 8;
this.Mouse.Acquire();
}
private void DrawScene(float deltaTime)
{
this.Text = this.Camera.Location.ToString();
float elapsedClientTime = ClientTimer.ElapsedMilliseconds / 1000.0f;
Matrix modelViewMatrix = Camera.ModelViewMatrix;
Matrix projectionMatrix = Camera.ProjectionMatrix;
Matrix modelViewProjectionMatrix = Camera.ModelViewProjectionMatrix;
if (!WorldShader.IsBound)
{
WorldShader.Bind(_graphicsCardContext);
}
this._pointLightArgs = new PointLightShaderArgs(
new Vector3(16, 32, 16),
1024,
new Vector3(0, 0.06f, 0),
new Vector4(0.5f, 0.5f, 0.5f, 1.0f),
new Vector4(1, 1, 1, 1));
_graphicsCardContext.UpdateSubresource(ref _pointLightArgs, WorldShader.PointLightShaderArgsBuffer);
foreach (StaticGeometry geometry in this.StaticGeometry)
{
if (geometry.IsVisible)
{
Matrix worldPositionMatrix = VoidwalkerMath.CreateRotationMatrix(geometry.Rotation) * Matrix.Translation(geometry.Location);
Matrix localMatrix = worldPositionMatrix * modelViewProjectionMatrix;
worldPositionMatrix.Transpose();
localMatrix.Transpose();
_graphicsCardContext.UpdateSubresource(ref localMatrix, WorldShader.LocalMatrixBuffer);
_graphicsCardContext.UpdateSubresource(ref worldPositionMatrix, WorldShader.WorldPositionBuffer);
Vector2 textureResolution = geometry.Mesh.DiffuseMaterial.Resolution;
_graphicsCardContext.UpdateSubresource(ref textureResolution, WorldShader.TextureResolutionBuffer);
geometry.Draw(_graphicsCardContext);
}
}
}
private void OnRenderFrame()
{
if (_isResizeNeeded)
{
ResizeFrameBuffers();
}
float elapsedClientTime = ClientTimer.ElapsedMilliseconds / 1000.0f;
float currentFrameDeltaTime = elapsedClientTime - _previousFrameDeltaTime;
_previousFrameDeltaTime = elapsedClientTime;
System.DateTime dateTimeNow = System.DateTime.Now;
System.TimeSpan subtractedTime = dateTimeNow.Subtract(_previousDateTime);
if (subtractedTime.TotalSeconds >= 1)
{
this.RenderFrequency = _frameCounter;
_frameCounter = 0;
this._previousDateTime = dateTimeNow;
}
_graphicsCardContext.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
_graphicsCardContext.ClearRenderTargetView(_renderView, Color.CornflowerBlue);
CheckKeyboardInput(currentFrameDeltaTime);
DrawScene(elapsedClientTime);
_swapChain.Present((int)this.Vsync, PresentFlags.None);
_frameCounter++;
}
private void OnKeyUp(object sender, KeyEventArgs args)
{
switch (args.KeyCode)
{
case Keys.F2:
RasterizerStateDescription previousDescription = _graphicsCardContext.Rasterizer.State.Description;
FillMode mode;
mode = previousDescription.FillMode == FillMode.Solid
? FillMode.Wireframe
: FillMode.Solid;
_graphicsCardContext.Rasterizer.State = new RasterizerState(_device, new RasterizerStateDescription
{
CullMode = previousDescription.CullMode,
DepthBias = previousDescription.DepthBias,
DepthBiasClamp = previousDescription.DepthBiasClamp,
FillMode = mode,
IsAntialiasedLineEnabled = previousDescription.IsAntialiasedLineEnabled,
IsDepthClipEnabled = previousDescription.IsDepthClipEnabled,
IsFrontCounterClockwise = previousDescription.IsFrontCounterClockwise,
IsMultisampleEnabled = previousDescription.IsMultisampleEnabled,
IsScissorEnabled = previousDescription.IsScissorEnabled,
SlopeScaledDepthBias = previousDescription.SlopeScaledDepthBias
});
break;
}
}
private void ResizeFrameBuffers()
{
Utilities.Dispose(ref _backBuffer);
Utilities.Dispose(ref _renderView);
Utilities.Dispose(ref _depthBuffer);
Utilities.Dispose(ref _depthView);
_swapChain.ResizeBuffers(_swapChainDescription.BufferCount, this.ClientSize.Width, this.ClientSize.Height, Format.Unknown, SwapChainFlags.None);
_backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
_renderView = new RenderTargetView(_device, _backBuffer);
_depthBuffer = new Texture2D(_device, new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = this.ClientSize.Width,
Height = this.ClientSize.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
_depthView = new DepthStencilView(_device, _depthBuffer);
_graphicsCardContext.Rasterizer.SetViewport(new Viewport(0, 0, this.ClientSize.Width, this.ClientSize.Height, 0.0f, 1.0f));
_graphicsCardContext.OutputMerger.SetTargets(_depthView, _renderView);
Camera.AspectRatio = this.ClientSize.Width / (float)this.ClientSize.Height;
_isResizeNeeded = false;
}
}
}
Nevermind, I figured it out. I have to disable alpha blending. Should have guessed that.
blendStateDescription.RenderTarget[0].IsBlendEnabled = false;
Related
How I can add transparency to simple vertex objects in Direct3D?
I used information from here with no result:
https://learn.microsoft.com/ru-ru/windows/win32/direct3d9/vertex-alpha
I initialize device like this:
PresentParameters presentParams = new PresentParameters();
presentParams.SwapEffect = SwapEffect.Discard;
presentParams.DeviceWindowHandle = this.Handle;
presentParams.BackBufferFormat = Format.A8R8G8B8;
presentParams.PresentFlags = PresentFlags.LockableBackBuffer;
presentParams.BackBufferWidth = this.ClientSize.Width;
presentParams.BackBufferHeight = this.ClientSize.Height;
presentParams.Windowed = true;
var device = new Device(_direct3d, 0, DeviceType.Hardware, this.Handle, _createFlags, presentParams);device.SetRenderState(RenderState.Lighting, false);
// ..tried different variations of flags here with no result..
device.SetRenderState(RenderState.DiffuseMaterialSource, ColorSource.Color1);
var surface = device.GetBackBuffer(0, 0);
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
Vertex class declaration:
[StructLayout(LayoutKind.Sequential)]
public struct ColoredVertex : IEquatable<ColoredVertex>
{
public Vector3 Position { get; set; }
public int Color { get; set; }
public static VertexElement[] Format
{
get
{
return new VertexElement[] {
new VertexElement(0,0,DeclarationType.Float3,DeclarationMethod.Default,DeclarationUsage.PositionTransformed,0),
new VertexElement(0,12,DeclarationType.Color,DeclarationMethod.Default,DeclarationUsage.Color,0),
VertexElement.VertexDeclarationEnd
};
}
}
public ColoredVertex(Vector3 position, int color)
: this()
{
Position = position;
Color = color;
}
Then I draw primitives.
Color contains alpha which is 50 for a second triangle so I hope the triangle will be transparent.. but no
_device.BeginScene();
var colorN1 = Color.FromArgb(255, 100, 100, 100);
var triangleN1 = new ColoredVertex[] {
new ColoredVertex(new Vector3(10f, 10f, 0.0f), colorN1.ToArgb()),
new ColoredVertex(new Vector3(1000.0f, 10.0f, 0.0f), colorN1.ToArgb()),
new ColoredVertex(new Vector3(1000f, 800f, 0.0f), colorN1.ToArgb()),
};
using (var decl = new VertexDeclaration(_device, ColoredVertex.Format))
{
_device.VertexFormat = VertexFormat.Diffuse;
_device.VertexDeclaration = decl;
_device.DrawUserPrimitives<ColoredVertex>(PrimitiveType.TriangleList, 1, triangleN1);
}
var colorN2 = Color.FromArgb(50, 100, 0, 0);
var triangleN2 = new ColoredVertex[] {
new ColoredVertex(new Vector3(100f, 100f, 1.0f), colorN2.ToArgb()),
new ColoredVertex(new Vector3(800.0f, 100.0f, 1.0f), colorN2.ToArgb()),
new ColoredVertex(new Vector3(700f, 900f, 1.0f), colorN2.ToArgb()),
};
using (var decl = new VertexDeclaration(_device, ColoredVertex.Format))
{
_device.VertexFormat = VertexFormat.Diffuse;
_device.VertexDeclaration = decl;
_device.DrawUserPrimitives<ColoredVertex>(PrimitiveType.TriangleList, 1, triangleN2);
}
_device.EndScene();
_device.Present();
These RenderState flags did the magic:
_device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
_device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha);
_device.SetRenderState(RenderState.AlphaBlendEnable, true);
I'm trying to write simple DirectX 11 app using C# and SharpDX. I wanted to test basic drawing but when i run the program, i will get entire form filled with red color. When i change the vertices its drawing unwanted shapes. Clear color works.
I tried changing some properties but nothing helps.
Here is the code:
private Vector3[] Vertices = new Vector3[]
{
new Vector3(-0.5f, 0.5f, 0), new Vector3(0.5f, 0.5f, 0), new Vector3(0, -0.5f, 0)
};
private D3D11.Buffer VertexBuffer;
public Game()
{
RenderForm = new RenderForm("Test Form");
RenderForm.ClientSize = new Size(Width, Height);
RenderForm.AllowUserResizing = false;
InitDeviceResources();
InitShaders();
InitVertexBuffer();
}
public void Run()
{
RenderLoop.Run(RenderForm, RenderCallback);
}
private void InitVertexBuffer()
{
VertexBuffer = D3D11.Buffer.Create<Vector3>(Device, BindFlags.VertexBuffer, Vertices);
}
private void InitShaders()
{
using (ShaderBytecode vertexShaderBytecode = ShaderBytecode.CompileFromFile("vertexShader.hlsl", "main", "vs_4_0", ShaderFlags.Debug))
{
InputSignature = ShaderSignature.GetInputSignature(vertexShaderBytecode);
VertexShader = new VertexShader(Device, vertexShaderBytecode);
}
using (ShaderBytecode pixelShaderBytecode = ShaderBytecode.CompileFromFile("pixelShader.hlsl", "main", "ps_4_0", ShaderFlags.Debug))
{
PixelShader = new PixelShader(Device, pixelShaderBytecode);
}
Context.VertexShader.Set(VertexShader);
Context.PixelShader.Set(PixelShader);
Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
InputLayout = new InputLayout(Device, InputSignature, InputElements);
Context.InputAssembler.InputLayout = InputLayout;
}
private void InitDeviceResources()
{
ModeDescription backBufferDesc = new ModeDescription(Width, Height, new Rational(60, 1), Format.B8G8R8A8_UNorm);
SwapChainDescription swapChainDesc = new SwapChainDescription()
{
BufferCount = 1,
IsWindowed = true,
OutputHandle = RenderForm.Handle,
ModeDescription = backBufferDesc,
SampleDescription = new SampleDescription(1, 0),
Usage = Usage.RenderTargetOutput
};
D3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.None, swapChainDesc, out Device, out SwapChain);
Context = Device.ImmediateContext;
Viewport = new Viewport(0, 0, Width, Height);
Context.Rasterizer.SetViewport(Viewport);
using (Texture2D backBuffer = SwapChain.GetBackBuffer<Texture2D>(0))
{
RenderTarget = new RenderTargetView(Device, backBuffer);
}
}
private void RenderCallback()
{
Draw();
}
private void Draw()
{
Context.OutputMerger.SetRenderTargets(RenderTarget);
Context.ClearRenderTargetView(RenderTarget, new Color4(0, 0, 1, 1));
Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(VertexBuffer, Utilities.SizeOf<Vector3>(), 0));
Context.Draw(Vertices.Count(), 0);
SwapChain.Present(1, PresentFlags.None);
}
I finally solved this. There must be Format.R32G32B32_Float instead of Format.R32G32B32A32_Float
So here's the problem I've been trying to solve. Given:
a) A product image. Expected to be full color
b) A mask of that image: RGBA(0,0,0,0) means ignore, RGBA(255,255,255,255) means replace
c) A composite image: This is composited with the mask
The idea is to composite the mask with the composite image, which will result in all white pixels becoming the composite pixels, but the transparent pixels remain transparent. This finally gets overlayed on top of the product image, effectively transforming only the pixels in the mask region.
I have this working perfectly, except for one small problem. Every pass through my Composite function seems to shrink the output by a scale of 0.5.
There's a bit of code in my solution, so I'll post what I think is necessary but feel free to ask for more.
Here's my Composite methods:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
using GL = OpenTK.Graphics.OpenGL.GL;
using HintMode = OpenTK.Graphics.OpenGL.HintMode;
using HintTarget = OpenTK.Graphics.OpenGL.HintTarget;
using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using PixelType = OpenTK.Graphics.OpenGL.PixelType;
using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
using Utilities = OpenTK.Platform.Utilities;
namespace SpriteSheetMaker
{
public static class ImageBlender
{
static DebugLogger logger = DebugLogger.GetInstance(#"debug.txt");
//Mask should be white where replacing, and transparent elsewhere
public static TexturedPolygon Composite(TexturedPolygon __baseImage, TextureBlendItem item, int level = 1)
{
var oldScale = OpenGLHelpers.Scale.Clone();
var oldSize = OpenGLHelpers.Canvas.Size;
var newSize = __baseImage.Texture2D.Texture2D.Size;
logger.WriteLine("Composite Requested. Mask Details: " + __baseImage.Rotation + " --- " + __baseImage.Scale + " --- " + __baseImage.Translation);
OpenGLHelpers.ClearScreen();
var _baseImage = __baseImage.Clone();
_baseImage.Texture2D.Texture2D.Save("composite_test_base" + level + ".png");
var _mask = item.Mask.Clone();
var _composite = item.Composite.Clone();
logger.WriteLine("Composite Requested. Mask Details: " + __baseImage.Rotation + " --- " + __baseImage.Scale + " --- " + __baseImage.Translation);
_mask.ResetTransform();
_composite.ResetTransform();
_baseImage.ResetTransform();
GL.Enable(EnableCap.Blend);
// render the mask
_mask.Draw();
//Blend the composite
GL.Disable(EnableCap.Blend);
GL.Enable(EnableCap.Blend);
GL.BlendEquation(BlendEquationMode.Min);
_composite.Draw();
GL.Disable(EnableCap.Blend); ;
//Not sure exactly what this does
GL.Enable(EnableCap.Blend);
GL.BlendEquation(BlendEquationMode.FuncAdd);
//Grab the composite and save it into a variable, because we are clearing the screen now
var bmp = OpenGLHelpers.GrabScreenshot(oldSize);
var _composite_2 = new BaseTextureImage(bmp).GetDrawable();
_composite_2.ResetTransform();
//Now we have the composited mask, we can simply draw it over the original image
OpenGLHelpers.ClearScreen();
_baseImage.Draw();
_composite_2.Draw();
bmp = OpenGLHelpers.GrabScreenshot(oldSize);
// OpenGLHelpers.Canvas.Resize(oldSize);
return new BaseTextureImage(bmp).GetDrawable();
}
public static TexturedPolygon Composite(TexturedPolygon _baseImage, List<TextureBlendItem> blends)
{
TexturedPolygon rtn = _baseImage.Clone();
bool doScaleFix = true;
int idx = 0;
foreach(var blend in blends)
{
var c = Composite(rtn, blend, (idx+1));
c.Texture2D.Texture2D.Save("composite_test_" + idx + ".png");
c.Scale = _baseImage.Scale;
c.Rotation = _baseImage.Rotation;
c.Translation = _baseImage.Translation;
rtn = c;
doScaleFix = false;
idx++;
}
return rtn;
}
}
}
Here is the TexturedPolygon class
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
using GL = OpenTK.Graphics.OpenGL.GL;
using HintMode = OpenTK.Graphics.OpenGL.HintMode;
using HintTarget = OpenTK.Graphics.OpenGL.HintTarget;
using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using PixelType = OpenTK.Graphics.OpenGL.PixelType;
using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
using Utilities = OpenTK.Platform.Utilities;
using System.Drawing.Imaging;
using System.Reflection;
namespace SpriteSheetMaker
{
public class TexturedPolygon : BasePolygon
{
public BaseTextureImage Texture2D { get; set; }
public TexturedPolygon(BaseTextureImage texture, List<Vector3> pts) : base(pts)
{
Texture2D = texture;
}
public new TexturedPolygon Clone()
{
TexturedPolygon polygon = new TexturedPolygon(Texture2D, Vertices);
polygon.FillColor = this.FillColor.Clone();
polygon.EdgeColor = this.EdgeColor.Clone();
polygon.EdgeWidth = this.EdgeWidth;
polygon.Translation = this.Translation.Clone();
polygon.Rotation = this.Rotation.Clone();
polygon.Scale = this.Scale.Clone();
return polygon;
}
public TexturedPolygon(List<Vector3> pts) : base(pts)
{
}
public override void _draw()
{
if (Texture2D == null)
{
GL.ClearColor(Color.Transparent);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
this._basePolygonDraw();
return;
}
var bb = NoTransformBoundingBox();
GL.ClearColor(Color.Transparent);
GL.BindTexture(TextureTarget.Texture2D, Texture2D.TextureID);
GL.Enable(EnableCap.Texture2D);
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
GL.Begin(PrimitiveType.Polygon);
for(int i = 0; i < Vertices.Count; i++)
{
var pt = Vertices[i];
var fillColor = GetVertexFillColor(i);
var alpha = fillColor.Alpha;
GL.Color4(1.0, 1.0, 1.0, alpha);
var texX = (pt.X - (float)bb.Left) / (bb.Right - (float)bb.Left);
var texY = (pt.Y - (float)bb.Top) / (bb.Bottom - (float)bb.Top);
GL.TexCoord2(texX, texY);
GL.Vertex2(pt.X, pt.Y);
}
GL.End();
// GL.Disable(EnableCap.Texture2D);
}
}
}
Here is the BasePolygon class:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
using GL = OpenTK.Graphics.OpenGL.GL;
using HintMode = OpenTK.Graphics.OpenGL.HintMode;
using HintTarget = OpenTK.Graphics.OpenGL.HintTarget;
using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using PixelType = OpenTK.Graphics.OpenGL.PixelType;
using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
using Utilities = OpenTK.Platform.Utilities;
namespace SpriteSheetMaker
{
public class BasePolygon : BaseTexture
{
protected List<Vector3> Vertices = new List<Vector3>();
public GeometryColor FillColor = new GeometryColor();
public GeometryColor EdgeColor = new GeometryColor();
public float EdgeWidth = 1.0f;
public List<Vector3> CurrentVertices
{
get
{
return Vertices.ToList();
}
}
Point[] _points
{
get
{
return Vertices.Select(x => x.ToPoint()).ToArray();
}
}
protected override List<Vector3> GetPolygonPoints()
{
List<Vector3> rtn = new List<Vector3>();
foreach(var pt in Vertices)
{
rtn.Add(pt.Clone());
}
return rtn;
}
protected void AlignToOrigin()
{
var ctr = NoTransformCenter();
for(int i = 0; i < Vertices.Count; i++)
{
var pt = Vertices[i];
pt = pt.Subtract(ctr);
Vertices[i] = pt;
}
Translation = ctr.Clone();
}
protected void AlignToCenter()
{
var ctr = NoTransformCenter();
for (int i = 0; i < Vertices.Count; i++)
{
var pt = Vertices[i];
pt = pt.Add(Translation);
Vertices[i] = pt;
}
Translation = Vector3.ZERO;
}
public static BasePolygon ClonePolygon(BasePolygon poly)
{
return poly.Clone();
}
public BasePolygon Clone()
{
BasePolygon polygon = new BasePolygon();
polygon.Vertices = this.CurrentVertices;
polygon.FillColor = this.FillColor.Clone();
polygon.EdgeColor = this.EdgeColor.Clone();
polygon.EdgeWidth = this.EdgeWidth;
polygon.Translation = this.Translation.Clone();
polygon.Rotation = this.Rotation.Clone();
polygon.Scale = this.Scale.Clone();
return polygon;
}
public BasePolygon(List<Vector3> pts)
{
AddVertexes(pts);
AlignToOrigin();
}
public BasePolygon(params Vector3[] pts)
{
AddVertexes(pts.ToList());
AlignToOrigin();
}
protected void AddVertex(Vector3 pt)
{
Vertices.Add(pt.Clone());
}
protected void AddVertexes(IEnumerable<Vector3> pts)
{
pts.ToList().ForEach(x =>
{
AddVertex(x);
});
}
protected void RemoveVertex(Vector3 pt)
{
Vertices.Remove(pt);
}
protected void RemoveVertexes(IEnumerable<Vector3> pts)
{
pts.ToList().ForEach(x =>
{
RemoveVertex(x);
});
}
public override void _draw()
{
this._basePolygonDraw();
}
public ColorLibrary.sRGB GetVertexFillColor(int index)
{
var pct = ((float)index + 1.0f) / (float)Vertices.Count;
var colorIdx = (int)((FillColor.Colors.Count - 1.0f) * pct);
return FillColor.Colors[colorIdx];
}
public ColorLibrary.sRGB GetVertexEdgeColor(int index)
{
var pct = ((float)index + 1.0f) / (float)Vertices.Count;
var colorIdx = (int)Math.Round((float)(EdgeColor.Colors.Count - 1.0f) * pct);
return EdgeColor.Colors[colorIdx];
}
protected void _basePolygonDraw()
{
this.wireframe();
this.fill();
}
private void wireframe()
{
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Nicest);
var pts = Vertices;
ColorLibrary.sRGB color1;
ColorLibrary.sRGB color2;
GL.Begin(PrimitiveType.Lines);
for (var i = 0; i < pts.Count; i++)
{
var idx2 = (i + 1) % pts.Count;
color1 = GetVertexEdgeColor(i);
color2 = GetVertexEdgeColor(idx2);
var a = pts[i];
var b = pts[idx2];
GL.Color4(color1.R, color1.G, color1.B, color1.Alpha);
GL.Vertex3(a.OpenTKVector);
GL.Color4(color2.R, color2.G, color2.B, color2.Alpha);
GL.Vertex3(b.OpenTKVector);
}
GL.End();
}
private void fill()
{
GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest);
GL.Hint(HintTarget.PolygonSmoothHint, HintMode.Nicest);
GL.BindTexture(TextureTarget.Texture2D, 0);
var pts = Vertices;
ColorLibrary.sRGB color;
GL.Begin(PrimitiveType.Polygon);
for(int i = 0; i < pts.Count; i++)
{
color = GetVertexFillColor(i);
var pt = pts[i];
GL.Color4(color.R, color.G, color.B, color.Alpha);
GL.Vertex3(pt.OpenTKVector);
}
GL.End();
}
}
}
and here is the BaseTexture class
using ....
namespace SpriteSheetMaker
{
public abstract class BaseTexture
{
protected static Random rnd = new Random();
public Vector3 Translation = new Vector3(0, 0, 0);
public Vector3 Scale = new Vector3(1, 1, 1);
public Vector3 Rotation = new Vector3(0, 0, 0);
public Vector3 Velocity = new Vector3(0, 0, 0);
public void ResetTransform()
{
Translation = Vector3.ZERO;
Scale = Vector3.ONE;
Rotation = Vector3.ZERO;
}
private Guid _guid = Guid.NewGuid();
public Guid Guid
{
get
{
return _guid;
}
private set
{
_guid = value;
}
}
public bool DrawBounds = false;
public enum CollisionDirection
{
None = 0,
Up = 1,
Right = 2,
Down = 3,
Left = 4
}
public RectangleF NoTransformBoundingBox()
{
var poly = GetPolygonPoints();
var rect = Utility.PointsToRectangle(poly);
return rect;
}
protected abstract List<Vector3> GetPolygonPoints();
public Vector3 NoTransformCenter()
{
var poly = GetPolygonPoints();
var ctr = Vector3.Average(poly);
return ctr;
}
protected virtual RectangleF NonRotatedBoundingBox()
{
var polyPts = GetPolygonPoints();
foreach (var p in polyPts)
{
p.X = (Translation.X + Scale.X * p.X);
p.Y = (Translation.Y + Scale.Y * p.Y);
}
var rect = Utility.PointsToRectangle(polyPts);
return rect;
}
public RectangleF BoundingBox()
{
if(this.Rotation.Z == 0)
{
return NonRotatedBoundingBox();
}
return RotatedBoundingBox();
}
private RectangleF RotatedBoundingBox()
{
var polyPts = GetPolygonPoints();
foreach(var p in polyPts)
{
p.X = Translation.X + Scale.X*p.X;
p.Y = Translation.Y + Scale.Y*p.Y;
}
var ctr = this.Center();
var theta = this.Rotation.Z;
var ptsRotated = Utility.RotatePoints(polyPts, ctr, theta);
var bb = Utility.GetBoundsFromPoints(ptsRotated);
var rotated = new RectangleF(bb.Left, bb.Top, bb.Width, bb.Height);
return rotated;
}
public bool IsColliding(BaseTexture tex)
{
var bb = this.BoundingBox();
var bb2 = tex.BoundingBox();
return RectangleF.Intersect(bb, bb2) != RectangleF.Empty;
}
public CollisionDirection CollisionSide(BaseTexture tex)
{
var isColliding = IsColliding(tex);
if (!isColliding)
{
return CollisionDirection.None;
}
var ctrThis = this.Center();
var ctrThat = tex.Center();
var angleTo = ctrThis.AngleTo(ctrThat);
var pi = Math.PI;
var two_pi = 2*pi;
var pi_over_2 = pi/2.0;
var pi_over_4 = pi/4.0;
//0 to 45
if (angleTo >= 0 && angleTo <= pi_over_4)
{
return CollisionDirection.Right;
}
//45 to 135
else if (angleTo >= pi_over_4 && angleTo <= (pi_over_4) + (pi_over_2))
{
return CollisionDirection.Down;
}
//135 to 225
else if (angleTo >= (pi_over_4) + (pi_over_2) && angleTo <= (pi) + (pi_over_4))
{
return CollisionDirection.Left;
}
//225 to 315
else if (angleTo >= (pi) + (pi_over_4) && angleTo <= two_pi - pi_over_4)
{
return CollisionDirection.Up;
}
//315 to 360
else if (angleTo >= two_pi - pi_over_4 && angleTo <= two_pi)
{
return CollisionDirection.Right;
}
else
{
return CollisionDirection.None;
}
}
public Vector3 Center()
{
return NoTransformCenter().Add(this.Translation);
}
public float NoTransformRadius
{
get
{
var bb = NoTransformBoundingBox();
return (float)(Math.Max(bb.Width, bb.Height));
}
}
public float Radius
{
get
{
var bb = BoundingBox();
return (float)(Math.Max(bb.Width, bb.Height));
}
}
public abstract void _draw();
protected void _draw_bounds()
{
var bb = BoundingBox();
var ctr = Utility.RectangleCenter(bb);
var ctr2 = this.Center();
RectanglePolygon rec = RectanglePolygon.Create(ctr, bb.Width, bb.Height);
var fillColor = new ColorLibrary.sRGB(1,1,1);
fillColor.Alpha = 0.0;
rec.FillColor.SetSolid(fillColor);
rec.EdgeColor.SetSolid(new ColorLibrary.sRGB(1,0,0));
rec.Draw();
}
public virtual void Draw()
{
GL.ClearColor(Color.Transparent);
if (this.DrawBounds)
{
this._draw_bounds();
}
var ctr = NoTransformCenter();
OpenGLHelpers.RotationPivot = ctr;
OpenGLHelpers.AddTransform(Rotation,Scale,Translation);
OpenGLHelpers.ApplyTransforms();
_draw();
OpenGLHelpers.SubtractTransform(Rotation,Scale,Translation);
GL.PopMatrix();
// GL.Flush();
}
public override bool Equals(object obj)
{
var o = obj as BaseTexture;
return o.Guid == Guid;
}
}
}
If you need any more code, like the methods inside of OpenGLHelpers, I can provide that. Just keep in mind that generally my drawing code works. I didn't set any projection here, so that's why I reset the transforms. The translation and rotation are zero for now anyway, so it's really just to reset the scale. My base drawing method is normalized from [0,1], and the scale is what stretches the image to whatever dimensions desired.
Also, here is what I mean by the scale gets messed up. That red flask looking shape is supposed to complete cover the inside of the flask, and also, the flask itself got shrunk down! So it double shrunk...
That shows the iterations through 4 pass throughs. The smiley faces were another mask/composite combo added on
Base Image:
Mask 1:
Composite 1:
Thank you to whoever helps
I got it working!
So there were 2 problems.
I was using -0.5 to 0.5 as my domain range, when -1 to 1 was more appropriate
I also had miscellaneous issues, such as needing to make sure all of my textures were actually in the viewport, and to resize the glControl to fit the product texture
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I'm currently working on an exercise for my c# class. I am having some trouble with one particular part and would really appreciate some help.
I am working on an exercise in which we are given an incomplete project file.
The project has multiple classes, this class is for controlling squares that are placed on the board.
namespace HareAndTortoise {
public partial class SquareControl : PictureBox {
public const int SQUARE_SIZE = 100;
private Square square; // A reference to the corresponding square object
private BindingList<Player> players; // References the players in the overall game.
private bool[] containsPlayers = new bool[6];//HareAndTortoiseGame.MAX_PLAYERS];
public bool[] ContainsPlayers {
get {
return containsPlayers;
}
set {
containsPlayers = value;
}
}
// Font and brush for displaying text inside the square.
private Font textFont = new Font("Microsoft Sans Serif", 8);
private Brush textBrush = Brushes.White;
public SquareControl(Square square, BindingList<Player> players) {
this.square = square;
this.players = players;
// Set GUI properties of the whole square.
Size = new Size(SQUARE_SIZE, SQUARE_SIZE);
Margin = new Padding(0); // No spacing around the cell. (Default is 3 pixels.)
Dock = DockStyle.Fill;
BorderStyle = BorderStyle.FixedSingle;
BackColor = Color.CornflowerBlue;
SetImageWhenNeeded();
}
private void SetImageWhenNeeded()
{
if (square is Square.Win_Square)
{
LoadImageFromFile("Win.png");
textBrush = Brushes.Black;
}
else if (square is Square.Lose_Square)
{
LoadImageFromFile("Lose.png");
textBrush = Brushes.Red;
}
else if (square is Square.Chance_Square)
{
LoadImageFromFile("monster-green.png");
}
else if (square.Name == "Finish")
{
LoadImageFromFile("checkered-flag.png");
}
else
{
// No image needed.
}
}
private void LoadImageFromFile(string fileName) {
Image image = Image.FromFile(#"Images\" + fileName);
Image = image;
SizeMode = PictureBoxSizeMode.StretchImage; // Zoom is also ok.
}
protected override void OnPaint(PaintEventArgs e) {
// Due to a limitation in WinForms, don't use base.OnPaint(e) here.
if (Image != null)
e.Graphics.DrawImage(Image, e.ClipRectangle);
string name = square.Name;
// Create rectangle for drawing.
float textWidth = textFont.Size * name.Length;
float textHeight = textFont.Height;
float textX = e.ClipRectangle.Right - textWidth;
float textY = e.ClipRectangle.Bottom - textHeight;
RectangleF drawRect = new RectangleF(textX, textY, textWidth, textHeight);
// When debugging this method, show the drawing-rectangle on the screen.
//Pen blackPen = new Pen(Color.Black);
//e.Graphics.DrawRectangle(blackPen, textX, textY, textWidth, textHeight);
// Set format of string.
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Far; // Right-aligned.
// Draw string to screen.
e.Graphics.DrawString(name, textFont, textBrush, drawRect, drawFormat);
// Draw player tokens (when any players are on this square).
const int PLAYER_TOKENS_PER_ROW = 3;
const int PLAYER_TOKEN_SIZE = 30; // pixels.
const int PLAYER_TOKEN_SPACING = (SQUARE_SIZE - (PLAYER_TOKEN_SIZE * PLAYER_TOKENS_PER_ROW)) / (PLAYER_TOKENS_PER_ROW - 1);
for (int i = 0; i < containsPlayers.Length; i++) {
if (containsPlayers[i]) {
int xPosition = i % PLAYER_TOKENS_PER_ROW;
int yPosition = i / PLAYER_TOKENS_PER_ROW;
int xPixels = xPosition * (PLAYER_TOKEN_SIZE + PLAYER_TOKEN_SPACING);
int yPixels = yPosition * (PLAYER_TOKEN_SIZE + PLAYER_TOKEN_SPACING);
Brush playerTokenColour = players[i].PlayerTokenColour;
e.Graphics.FillEllipse(playerTokenColour, xPixels, yPixels, PLAYER_TOKEN_SIZE, PLAYER_TOKEN_SIZE);
}
}//endfor
}
}
}
The program trips up at:
else if (square.Name == "Finish")
{
LoadImageFromFile("checkered-flag.png");
}
I know it is because of square.name but from going through the code, I cant see why square.Name is not recognizable.
Square is passed from another class using this method
private void SetUpGuiGameBoard()
{
for (int i = 0; i <= 55; i++)
{
Square q = Board.GetGameBoardSquare(i);
SquareControl sq = new SquareControl(q, null);
int coloumn;
int row;
if (i == 0)
{
BackColor = Color.BurlyWood;
}
if (i == 55)
{
BackColor = Color.BurlyWood;
}
MapSquareNumToTablePanel(i, out coloumn, out row);
tableLayoutPanel1.Controls.Add(sq, coloumn, row);
}
and Squares are created in this class
private static Square[] gameBoard = new Square[56];
static public void SetUpBoard()
{
for (int i = 1; i == 55; i++)
{
gameBoard[i] = new Square("Ordinary Square", i);
}
gameBoard[0] = new Square("Start", 0);
gameBoard[4] = new Square.Lose_Square("Lose Square", 4);
gameBoard[5] = new Square.Chance_Square("Chance Square", 5);
gameBoard[9] = new Square.Win_Square("Win Square", 9);
gameBoard[11] = new Square.Chance_Square("Chance Square", 11);
gameBoard[14] = new Square.Lose_Square("Lose Square", 14);
gameBoard[17] = new Square.Chance_Square("Chance Square", 17);
gameBoard[19] = new Square.Win_Square("Win Square", 19);
gameBoard[24] = new Square.Lose_Square("Lose Square", 24);
gameBoard[29] = new Square.Win_Square("Win Square", 29);
gameBoard[34] = new Square.Lose_Square("Lose Square", 34);
gameBoard[35] = new Square.Chance_Square("Chance Square", 35);
gameBoard[39] = new Square.Win_Square("Win Square", 39);
gameBoard[44] = new Square.Lose_Square("Lose Square", 44);
gameBoard[47] = new Square.Chance_Square("Chance Square", 47);
gameBoard[49] = new Square.Win_Square("Win Square", 49);
gameBoard[53] = new Square.Chance_Square("Chance Square", 53);
gameBoard[55] = new Square("Finish", 56);
}
public static Square GetGameBoardSquare(int n)
{
return gameBoard[n];
}
public static Square StartSquare()
{
return gameBoard[0];
}
public static Square NextSquare(int n)
{
return gameBoard[(n+1)];
}
}
The answer already provided is the best way for prevention of any null reference exception. For more clarification I can suggest you to check the call stack at the point the debugger reaches the SquareControl constructor. At this point you should check why the Square object being passed in is a 'NULL'. That will lead you to the root cause of the problem. Hope this helps.
So I've been playing around with SlimDX for quite a while now,
and experienced some issues with big STL files.
While on OpenGL they load without flinching I get down to 1-2 FPS an soon as I load files of about 100mb (same issues with multiple files) in SharpGL. Did I miss anything, or is there anything I am simply doing not right at all ?
Edit: Just to specify my question: is performance with SlimDX on 1.000.000+ vertices always that poor ?
Edit: I know, that using an index buffer would be more efficient, as well as I know that CullingMode.None isn't really a FPS-Saver, but in the OpenGL test I've even used two sided lighting and a bit of smoothing, which should be as hard as creating (in the worst case) 3 times as many points as necessary.
Edit: Out of curiosity I modified the code to include an indexBuffer, and it really did have some impact on the FPS, I am validating this right now
BasicFramework.cs
#region Using Statements
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using SlimDX;
using SlimDX.Direct3D11;
using SlimDX.DXGI;
using SlimDX.Windows;
using Device = SlimDX.Direct3D11.Device;
using Texture2D = SlimDX.Direct3D11.Texture2D;
#endregion
namespace SlimDX_Evaluation
{
public abstract class BasicFramework : IDisposable
{
#region Membervariables
//Objects
private RenderForm renderForm;
private SwapChain swapChain;
private Factory factory;
private Device device;
private DeviceContext deviceContext;
private Texture2D backBufffer;
private Texture2D depthBuffer;
private RenderTargetView renderTargetView;
private DepthStencilView depthStencilView;
private TimeSpan lastFrameTime;
private Stopwatch clock;
//Variables
private bool userResized;
private bool isResizing;
#endregion
#region Constructors
/**
* The Constructor initializes the default behavior of the Framework.
* It is not supposed to be replaced, the customization should be done in the Constructor
*/
public BasicFramework() : this("My Title") { }
public BasicFramework(string title)
{
//Create the winForm
renderForm = new RenderForm(title);
renderForm.ClientSize = new System.Drawing.Size(800, 480);
renderForm.MaximizeBox = true;
renderForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
//Hook into Windows.Forms Event
renderForm.ClientSizeChanged += HandleClientSizeChanged;
//Generate SwapChain
var desc = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription = new ModeDescription(renderForm.ClientSize.Width,
renderForm.ClientSize.Height,
new Rational(60, 1),
Format.B8G8R8A8_UNorm),
IsWindowed = true,
OutputHandle = renderForm.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput,
};
Device.CreateWithSwapChain(
DriverType.Hardware,
DeviceCreationFlags.None,
desc,
out device,
out swapChain
);
//Set DeviceContext
deviceContext = device.ImmediateContext;
// prevent DXGI handling of alt+enter,prt scrn, etc which doesn't work properly with Winforms
using (var factory = swapChain.GetParent<Factory>())
factory.SetWindowAssociation(renderForm.Handle, WindowAssociationFlags.IgnoreAll);
//Generate Backbuffer
backBufffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
renderTargetView = new RenderTargetView(device, backBufffer);
//Generate Depthbuffer and DepthBufferView
depthBuffer = new Texture2D(device, new Texture2DDescription()
{
Format = Format.D16_UNorm,
ArraySize = 1,
MipLevels = 1,
Width = renderForm.ClientSize.Width,
Height = renderForm.ClientSize.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None,
});
depthStencilView = new DepthStencilView(device, depthBuffer);
//Define Rasterizer
RasterizerStateDescription rasterizerDescription = new RasterizerStateDescription()
{
CullMode = CullMode.None,
FillMode = FillMode.Solid,
IsAntialiasedLineEnabled = true,
IsFrontCounterclockwise = true,
IsMultisampleEnabled = true,
IsDepthClipEnabled = true,
IsScissorEnabled = false
};
deviceContext.Rasterizer.State = RasterizerState.FromDescription(device, rasterizerDescription);
//Set ViewPort
deviceContext.Rasterizer.SetViewports(new Viewport(
0,
0,
renderForm.Width,
renderForm.Height));
deviceContext.OutputMerger.SetTargets(depthStencilView, renderTargetView);
//Force recalibration on first load
userResized = true;
}
#endregion
#region Run
public void Run()
{
clock = new Stopwatch();
clock.Start();
this.lastFrameTime = clock.Elapsed;
Initialize();
LoadContent();
MessagePump.Run(renderForm, () =>
{
if (userResized)
{
backBufffer.Dispose();
RenderTargetView.Dispose();
depthBuffer.Dispose();
depthStencilView.Dispose();
//Resize the buffers
swapChain.ResizeBuffers(
0,
renderForm.ClientSize.Width,
renderForm.ClientSize.Height,
Format.Unknown,
SwapChainFlags.None
);
//Get the new Backbuffer
backBufffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
//Renew RenderTargetView
renderTargetView = new RenderTargetView(device, backBufffer);
//Create the new DepthBuffer
depthBuffer = new Texture2D(device, new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = renderForm.ClientSize.Width,
Height = renderForm.ClientSize.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
//Create DepthBufferView
depthStencilView = new DepthStencilView(device, depthBuffer);
//SetUp Targets and Viewports for Rendering
deviceContext.Rasterizer.SetViewports(new Viewport(0, 0, renderForm.Width, renderForm.Height));
deviceContext.OutputMerger.SetTargets(depthStencilView, renderTargetView);
//finished resizing
isResizing = userResized = false;
}
TimeSpan timeSinceLastFrame = clock.Elapsed - this.lastFrameTime;
this.lastFrameTime = clock.Elapsed;
Update(clock.Elapsed, timeSinceLastFrame);
BeginFrame();
Draw(clock.Elapsed, timeSinceLastFrame);
EndFrame();
});
UnloadContent();
}
#endregion
#region MethodsToOverride
public virtual void Update(TimeSpan totalRunTime, TimeSpan timeSinceLastFrame)
{
}
public virtual void Draw(TimeSpan totalRunTime, TimeSpan timeSinceLastFrame)
{
}
public virtual void BeginFrame()
{
}
public void EndFrame()
{
swapChain.Present(0, PresentFlags.None); //Presents the image to the user
}
public virtual void Initialize()
{
}
public virtual void LoadContent()
{
}
public virtual void UnloadContent()
{
}
public virtual void Dispose()
{
renderForm.Dispose();
backBufffer.Dispose();
deviceContext.ClearState();
deviceContext.Flush();
device.Dispose();
deviceContext.Dispose();
depthBuffer.Dispose();
depthStencilView.Dispose();
swapChain.Dispose();
}
#endregion
#region Handlers
private void HandleResize(object sender, EventArgs e)
{
backBufffer.Dispose();
RenderTargetView.Dispose();
depthBuffer.Dispose();
depthStencilView.Dispose();
//Resize the buffers
swapChain.ResizeBuffers(
0,
renderForm.ClientSize.Width,
renderForm.ClientSize.Height,
Format.Unknown,
SwapChainFlags.None
);
//Get the new Backbuffer
backBufffer = Texture2D.FromSwapChain<Texture2D>(swapChain, 0);
//Renew RenderTargetView
renderTargetView = new RenderTargetView(device, backBufffer);
//Create the new DepthBuffer
depthBuffer = new Texture2D(device, new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = renderForm.ClientSize.Width,
Height = renderForm.ClientSize.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
//Create DepthBufferView
depthStencilView = new DepthStencilView(device, depthBuffer);
//SetUp Targets and Viewports for Rendering
deviceContext.Rasterizer.SetViewports(new Viewport(0, 0, renderForm.Width, renderForm.Height));
deviceContext.OutputMerger.SetTargets(depthStencilView, renderTargetView);
//finished resizing
isResizing = userResized = false;
TimeSpan timeSinceLastFrame = clock.Elapsed - this.lastFrameTime;
this.lastFrameTime = clock.Elapsed;
Update(clock.Elapsed, timeSinceLastFrame);
BeginFrame();
Draw(clock.Elapsed, timeSinceLastFrame);
EndFrame();
}
private void HandleClientSizeChanged(object sender, EventArgs e)
{
userResized = true;
}
#endregion
#region GetAndSet
public Device Device
{
get
{
return this.device;
}
}
public DeviceContext DeviceContext
{
get
{
return this.deviceContext;
}
}
public RenderTargetView RenderTargetView
{
get
{
return this.renderTargetView;
}
}
public RenderForm RenderForm
{
get
{
return this.renderForm;
}
}
public DepthStencilView DepthStencilView
{
get
{
return this.depthStencilView;
}
}
#endregion
}
}
SimpleIntegration.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using SlimDX;
using SlimDX.D3DCompiler;
using SlimDX.Direct3D11;
using Buffer = SlimDX.Direct3D11.Buffer;
using System.Diagnostics;
namespace SlimDX_Evaluation
{
class SampleIntegration : BasicFramework
{
#region Members
private VertexShader vertexShader;
private PixelShader pixelShader;
private Buffer constantBuffer;
private VertexBufferBinding vertexBufferBinding_model;
private int vertCount;
private Stopwatch timer;
private long lastFrame;
private int frameCount;
private Matrix view;
private Matrix proj;
private Matrix viewProj;
Matrix worldViewProj;
#endregion
public override void Draw(TimeSpan totalRunTime, TimeSpan timeSinceLastFrame)
{
//Output FPS
frameCount++;
if (timer.ElapsedMilliseconds - lastFrame >= 1000)
{
Console.WriteLine("FPS: " + frameCount);
lastFrame = timer.ElapsedMilliseconds;
frameCount = 0;
}
worldViewProj = Matrix.Multiply(Matrix.RotationAxis(Vector3.UnitY, timer.ElapsedMilliseconds / 1000.0f), viewProj);
//Update ConstantBuffer
var buffer = new MyConstantBuffer();
buffer.worldViewProj = worldViewProj;
var data = new DataStream(System.Runtime.InteropServices.Marshal.SizeOf(new MyConstantBuffer()), true, true);
data.Write(buffer);
data.Position = 0;
DeviceContext.UpdateSubresource(new DataBox(0, 0, data),constantBuffer,0);
//Clear
Device.ImmediateContext.ClearRenderTargetView(RenderTargetView, Color.WhiteSmoke);
Device.ImmediateContext.ClearDepthStencilView(DepthStencilView, DepthStencilClearFlags.Depth, 1.0f, 0);
//Draw
DeviceContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
DeviceContext.InputAssembler.SetVertexBuffers(0, vertexBufferBinding_model);
Device.ImmediateContext.Draw(vertCount, 0);
base.Draw(totalRunTime, timeSinceLastFrame);
}
public override void LoadContent()
{
//Initialize the timer
timer = new Stopwatch();
timer.Start();
//Initialize Matrices
view = Matrix.LookAtLH(new Vector3(0, 100, -500), new Vector3(0, 0, 0), Vector3.UnitY);
proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, RenderForm.ClientSize.Width / RenderForm.ClientSize.Height, 0.1f, 10000.0f);
viewProj = Matrix.Multiply(view, proj);
//Load Shaders
ShaderBytecode vertexShaderByteCode;
ShaderBytecode pixelShaderByteCode;
try
{
vertexShaderByteCode = ShaderBytecode.CompileFromFile("Shaders/shader.hlsl", "VShader", "vs_4_0",ShaderFlags.None,EffectFlags.None);
pixelShaderByteCode = ShaderBytecode.CompileFromFile("Shaders/shader.hlsl", "PShader", "ps_4_0",ShaderFlags.None,EffectFlags.None);
}
catch (System.Exception ex)
{
throw ex;
}
vertexShader = new VertexShader(Device, vertexShaderByteCode);
pixelShader = new PixelShader(Device, pixelShaderByteCode);
DeviceContext.VertexShader.Set(vertexShader);
DeviceContext.PixelShader.Set(pixelShader);
var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
//Define first 16 floats as Position, next 16 as Color, next 12 normal (4 cords, 4 Color, 3 normal parts)
InputElement[] elements = new InputElement[]
{
new InputElement("POSITION", 0, SlimDX.DXGI.Format.R32G32B32A32_Float, 0, 0),
new InputElement("COLOR" , 0, SlimDX.DXGI.Format.R32G32B32A32_Float, 16, 0),
new InputElement("NORMAL" , 0, SlimDX.DXGI.Format.R32G32B32_Float, 32, 0),
};
//Define Layout for the InputAssembler
DeviceContext.InputAssembler.InputLayout = new InputLayout(Device, signature, elements);
//Generate and link constant buffers
constantBuffer = new Buffer(Device, System.Runtime.InteropServices.Marshal.SizeOf(new Matrix()), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
DeviceContext.VertexShader.SetConstantBuffer(constantBuffer,0);
//load STL and generate Vertices from it
ModuleWorks.Meshf meshf = ModuleWorks.MeshHelper.ReadSTLf(#"C:\ModuleWorks\STL\Homer.stl", ModuleWorks.Unit.Metric);
try
{
vertCount = meshf.TriangleCount * 3;
var vertices_model = new DataStream(vertCount * System.Runtime.InteropServices.Marshal.SizeOf(typeof(Vertex)), true, true);
var stopWatch = new Stopwatch();
stopWatch.Start();
for (int x = 0; x < meshf.TriangleCount; x++)
{
var triangle = meshf.GetTriangle(x);
var normal = triangle.Normal;
vertices_model.Write(new Vertex(meshf.GetPoint(triangle.Idx1).X, meshf.GetPoint(triangle.Idx1).Y, meshf.GetPoint(triangle.Idx1).Z, 1.0f, 0.0f, 0.0f, 1.0f, normal.X, normal.Y, normal.Z));
vertices_model.Write(new Vertex(meshf.GetPoint(triangle.Idx2).X, meshf.GetPoint(triangle.Idx2).Y, meshf.GetPoint(triangle.Idx2).Z, 1.0f, 0.0f, 0.0f, 1.0f, normal.X, normal.Y, normal.Z));
vertices_model.Write(new Vertex(meshf.GetPoint(triangle.Idx3).X, meshf.GetPoint(triangle.Idx3).Y, meshf.GetPoint(triangle.Idx3).Z, 1.0f, 0.0f, 0.0f, 1.0f, normal.X, normal.Y, normal.Z));
}
vertices_model.Position = 0;
//Generate VertexBufferBinding
var sizeInBytes = vertCount * System.Runtime.InteropServices.Marshal.SizeOf(typeof(Vertex));
var stride = System.Runtime.InteropServices.Marshal.SizeOf(typeof(Vector4)) * 2 + System.Runtime.InteropServices.Marshal.SizeOf(typeof(Vector3));
var vertexBuffer_model = new Buffer(Device, vertices_model, sizeInBytes, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
vertexBufferBinding_model = new VertexBufferBinding(vertexBuffer_model, stride, 0);
vertices_model.Close();
}
catch (System.Exception ex)
{
Console.WriteLine(ex);
return;
}
}
public override void Dispose()
{
vertexShader.Dispose();
pixelShader.Dispose();
constantBuffer.Dispose();
base.Dispose();
}
}
}
shader.hlsl
cbuffer matrixBuffer : register(b0)
{
float4x4 worldViewProj;
};
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
float3 normal : NORMAL;
};
VOut VShader(float4 position : POSITION, float4 color : COLOR, float3 normal : NORMAL)
{
VOut output = (VOut)0;
output.position = mul(worldViewProj, position);
output.normal = normalize(mul((float3x3)worldViewProj,normal));
output.color = color;
return output;
}
float4 PShader(VOut vout) : SV_TARGET
{
return vout.color;
}
Thanks in advance
I solved it.
The issue was based on an inperformant approach to adding the vertices.
For further information, checkout this nice paper I've found