I'm having difficulty drawing a gradient colored arc with Microsoft Maui Graphics.
I'm using Windows Forms, Visual Studio Preview 5, and .NET Core 6.
Here is what I have tried:
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Skia;
using System;
using System.Windows.Forms;
namespace MauiWinForms {
public partial class Form1:Form {
public Form1() {
InitializeComponent();
}
private void skglControl1_PaintSurface(object sender, SkiaSharp.Views.Desktop.SKPaintGLSurfaceEventArgs e) {
ICanvas canvas = new SkiaCanvas() { Canvas = e.Surface.Canvas };
var canvasWidth = skglControl1.Width = 800;
var canvasHeight = skglControl1.Height = 800;
canvas.FillColor = Colors.LightGrey;
canvas.FillRectangle(0, 0, canvasWidth, canvasHeight);
canvas.StrokeColor = Colors.Red;
canvas.DrawRectangle(1, 1, 800-2, 800-2);
var centerX = canvasWidth / 2;
var centerY = canvasHeight / 2;
canvas.StrokeColor = Colors.Teal;
canvas.StrokeSize = 10;
var X = centerX - 200;
canvas.DrawArc(X, 0, 400, 400, 0, 90, false, false);
var linearGradientPaint = new LinearGradientPaint {
StartColor = Colors.White,
EndColor = Colors.Green,
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 0)
};
var myRectangle = new RectangleF(X, 0, 410, 410);
canvas.SetFillPaint(linearGradientPaint, myRectangle);
canvas.DrawArc(X, 0, 400, 400, 0, -90, false, false);
}
private void skglControl1_SizeChanged(object sender, EventArgs e) => skglControl1.Invalidate();
}
}
And this is what I get:
As you can see, the linear gradient is not applied.
Any help will be greatly appreciated.
Charles
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
How to calculate the actual speed of all moving objects on video using the Lucals-kanade algorithm to calculate the optical flow ?
I need to do this on this video. The camera is fixed in one place (Fig. 1)
I find the key points and track them using the Lucas-Kanade algorithm (Fig. 2)
How to use this algorithm to update the actual speed of each car?
Thank you for your answers!
My code:
public class OpticalFlowLK : BaseFilter
{
private Mat prevFrame;
private Mat nextFrame;
private bool prevFrameEmpty = true;
private GFTTDetector gFTTDetector;
private Stopwatch sWatch;
private double time = 0.04;
public OpticalFlowLK()
{
TAG = "[Optical Flow Lucas Kanade]";
gFTTDetector = new GFTTDetector(500);
sWatch = new Stopwatch();
}
protected override Mat ProcessFrame(ref Mat frame)
{
Mat rez = new Mat();
frame.CopyTo(rez);
nextFrame = new Mat();
Mat gray = new Mat();
var tmpImg = gray.ToImage<Gray, Byte>();
CvInvoke.CvtColor(frame, nextFrame, Emgu.CV.CvEnum.ColorConversion.Bgr2Gray);
if (!prevFrameEmpty)
{
VectorOfKeyPoint prevFeatures = new VectorOfKeyPoint(gFTTDetector.Detect(prevFrame));
//Features2DToolbox.DrawKeypoints(rez, prevFeatures, rez, new Bgr(0, 0, 255));
PointF[] prevPts = new PointF[prevFeatures.Size];
for (int i = 0; i < prevFeatures.Size; i++)
{
prevPts[i] = prevFeatures[i].Point;
}
PointF[] nextPts;
byte[] status;
float[] errors;
sWatch.Start();
CvInvoke.CalcOpticalFlowPyrLK(prevFrame, nextFrame, prevPts, new Size(20, 20), 1, new MCvTermCriteria(20, 0.03), out nextPts, out status, out errors);
sWatch.Stop();
sWatch.Reset();
prevFrame = nextFrame.Clone();
for (int i = 0; i < status.Length; i++)
{
Point prevPt = new Point((int)prevPts[i].X,(int)nextPts[i].Y);
Point nextPt = new Point((int)nextPts[i].X,(int)nextPts[i].Y);
double lenght = Math.Sqrt(Math.Pow(prevPt.X - nextPt.X, 2) + Math.Pow(prevPt.Y - nextPt.Y, 2));
if (lenght > 3)
{
CvInvoke.Circle(rez, nextPt, 1, new MCvScalar(0, 255, 0), 2);
}
}
sWatch.Stop();
prevFrameEmpty = false;
}
else if (prevFrameEmpty)
{
prevFrame = nextFrame.Clone();
prevFrameEmpty = false;
}
return rez;
}
protected override bool InitFilter(ref Mat frame)
{
throw new NotImplementedException();
}
}
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
I am developing a wpf user control in a wpf user control library it uses Viewport3D.
I see the image in viewport on running application and I can save it to file with RenderTargetBitmap if I call it in a WPF Application.
But if I instantiate user control in the console application and try to export the empty image was saved. The code is
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(DoIt);
t.SetApartmentState(ApartmentState.STA);
t.Start();
Console.WriteLine("press enter");
Console.ReadLine();
}
static void DoIt()
{
var x = new WpfControlLibrary1.Showcase();
x.GenerateViewPort();
x.TakeScreenshot(300, 300);
}
}
public partial class Showcase : UserControl
{
private PerspectiveCamera _PerspectiveCamera = null;
public Showcase()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler((sender, e) => this.GenerateViewPort());
}
public void GenerateViewPort()
{
this._PerspectiveCamera = new PerspectiveCamera(new Point3D(0, 0, 5), new Vector3D(0, 0, -5), new Vector3D(0, 1, 0), 45);
var viewport3D = new Viewport3D() { Camera = this._PerspectiveCamera };
viewport3D.Children.Add(new ModelVisual3D() { Content = GenerateModel() });
viewport3D.Loaded += new RoutedEventHandler(this.viewport3D_Loaded);
this.grdAniContainer.Children.Add(viewport3D);
}
private static Model3DGroup GenerateModel()
{
...
}
void viewport3D_Loaded(object sender, RoutedEventArgs e)
{
...
}
public void TakeScreenshot(int width, int height)
{
takeScreenshot(this.grdAniContainer.Children[0], width, height);
}
private static void takeScreenshot(Visual visual, int width, int height)
{
var v = visual as Viewport3D;
v.Width = width;
v.Height = height;
v.Measure(new Size(width, height));
v.Arrange(new Rect(0, 0, width, height));
var vRect = new Rectangle();
vRect.Width = width;
vRect.Height = height;
vRect.Fill = Brushes.White;
vRect.Arrange(new Rect(0, 0, vRect.Width, vRect.Height));
var bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(vRect);
bmp.Render(v);
var png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(bmp));
var dlg = new SaveFileDialog();
dlg.DefaultExt = ".png";
dlg.Filter = "PNG Images (.png)|*.png";
if (dlg.ShowDialog() ?? false == true)
{
string filepath = dlg.FileName;
using (var stm = File.Create(filepath))
png.Save(stm);
}
}
}
Load event is not fired and viewport3D_Loaded is not handle in console application, so I invoke manually.
Is there a way for loading visuals in memory and render to file programmatically?
I need add this delegate after instantiate "bmp" in "takeScreenshot" method
v.Dispatcher.Invoke(((Action)(() => bmp.Render(v))), DispatcherPriority.Render);