I am drawing a traingleStrip using VertexPositionTexture and BasicEffect that extends from the first person perspective of the screen out a certain distance on the Z axis.
In a loop I pass start and end vectors to this code to create my vertices.
public VertexPositionTexture[] vertices = new VertexPositionTexture[4];
private int xPos = 4;
public waypointLineSegment(Vector3 startPoint, Vector3 endPoint)
{
this.texture = texture1;
vertices[0].Position = new Vector3(endPoint.X - xPos, endPoint.Y, endPoint.Z); //Upper Left Point
vertices[0].TextureCoordinate = new Vector2(0, 1);
vertices[1].Position = new Vector3(startPoint.X - xPos, endPoint.Y, startPoint.Z); //Lower Left point
vertices[1].TextureCoordinate = new Vector2(0, 0);
vertices[2].Position = new Vector3(endPoint.X + xPos, endPoint.Y, endPoint.Z); //Upper Right Point
vertices[2].TextureCoordinate = new Vector2(1, 1);
vertices[3].Position = new Vector3(startPoint.X + xPos, endPoint.Y, startPoint.Z); //Lower Right Point
vertices[3].TextureCoordinate = new Vector2(1, 0);
}
I initialize like this:
protected override void Initialize()
{
graphics.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
basicEffect = new BasicEffect(graphics.GraphicsDevice);
base.Initialize();
}
I render the plane in this way:
Vector3 transformedReference = Vector3.Transform(new Vector3(0, 0, 10), aRotationInt);
Vector3 cameraLookat = firstPersonVector + transformedReference;
view = Matrix.CreateLookAt(firstPersonVector, cameraLookat, Vector3.Up);
basicEffect.View = view;
foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
{
pass.Apply();
graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, allVertices, 0, 2);
}
This works great. But, when I apply a rotation to the view, the strip will disappear every once in a while. Then it will reappear with a single degree of more or less rotation applied.
I cannot find a pattern. It might happen at 37 degrees or 315 etc. I have set the GraphicsDevice RasterizerState to CullMode.None. Can anyone help?:
Related
I generate the scene above using the OnDraw method below:
protected override void OnDraw(SKCanvas canvas, int width, int height)
{
int i = 0;
int step = 0;
List<SKRect> rects = new List<SKRect>();
// get the 2D equivalent of the 3D matrix
var rotationMatrix = rotationView.Matrix;
// get the properties of the rectangle
var length = Math.Min(width / 6, height / 6);
canvas.Clear(EffectMedia.Colors.XamarinLightBlue);
foreach (var n in numbers)
{
var rect = new SKRect(0 + step, 0, 100 + step, 100);
rects.Add(rect);
step += 120;
}
//var sideHoriz = rotationMatrix.MapPoint(new SKPoint(0, 1)).Y > 0;
var sideVert = rotationMatrix.MapPoint(new SKPoint(1, 0)).X > 0;
var paint = new SKPaint
{
Color = sideVert ? EffectMedia.Colors.XamarinPurple : EffectMedia.Colors.XamarinGreen,
Style = SKPaintStyle.Fill,
IsAntialias = true
};
// first do 2D translation to the center of the screen
canvas.Translate((width - (120 * numbers.Count)) / 2, height / 2);
// The following line is disabled because it makes the whole canvas rotate!
// canvas.Concat(ref rotationMatrix);
foreach (var n in numbers)
{
canvas.RotateDegrees((float)-3);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
var shadow = SKShader.CreateLinearGradient(
new SKPoint(0, 0), new SKPoint(0, length * 2),
new[] { paint.Color.WithAlpha(127), paint.Color.WithAlpha(0) },
null,
SKShaderTileMode.Clamp);
var paintShadow = new SKPaint
{
Shader = shadow,
Style = SKPaintStyle.Fill,
IsAntialias = true,
BlendMode = SKBlendMode.SoftLight
};
foreach (var r in rects)
{
r.Offset(0, 105);
canvas.DrawRoundRect(r, 30, 30, paintShadow);
}
i++;
}
}
The idea is to make all those rounded boxes rotate (vertically) around their own axis.
I tried using SKPath + Transform, saving&restoring the rotationMatrix and/or the canvas but I can't find a way to have 6 rotating boxes ( canvas.Concat(ref rotationMatrix); makes the whole canvas rotate [*]).
Do you have any hint on how that can be achieved?
Note [*]: there's a call to rotationView.RotateYDegrees(5) every X milliseconds to update the rotationMatrix used by OnDraw.
This is what I'd like to achieve, any hints / directions would be really appreciated... :-)
The following piece of code rotates those shapes around their Z-axis:
canvas.Save();
canvas.RotateDegrees(degrees, rects[i].MidX, rects[i].MidY);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
canvas.Restore();
Thanks
I have a rectangle bounds (10, 20, 100, 200) and the CGPoints are StartPoint (0.5, 0.5) and EndPoints as (1, 1). From these points how needs to calculate the segments bounds ? I need to apply this bounds for CGGradient for start point and end points.
Eg Code :
GradientColor gradientColor1 = new GradientColor(){StartPoint = new CGPoint(0.5, 0), EndPoint= new CGPoint(0.5, 1)};
GradientStop stop1 = new GradientStop() { Color = UIColor.Red, Offset = 0.1f };
GradientStop stop2 = new GradientStop() { Color = UIColor.Blue, Offset = 0.9f };
can you please help me out of this?
Here an an example that will create a left to right linear gradient within the current CGContext.
using (var context = UIGraphics.GetCurrentContext ()) {
context.SaveState();
var startPoint = new CGPoint(rect.Left, 0);
var endPoint = new CGPoint(rect.Right, 0);
var components = new CGColor[] { UIColor.Red.CGColor, UIColor.Blue.CGColor };
using (var rgb = CGColorSpace.CreateDeviceRGB()) {
var gradient = new CGGradient(rgb, components);
context.DrawLinearGradient(gradient, startPoint, endPoint, CGGradientDrawingOptions.DrawsBeforeStartLocation);
};
context.RestoreState();
}
Changing the start and end points you can have the gradient paint right to left, up/down, diagonal, etc..
I had a working shape but when I try to change the coordinates it disappears.
Here is what I did.
This is class level variables:
private BasicEffect _effect;
private VertexPositionColor[] _vertices = new VertexPositionColor[5];
Then in Initialization method I put these:
float aspectRatio = (float)GraphicsDevice.Viewport.Bounds.Width / GraphicsDevice.Viewport.Bounds.Height;
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), aspectRatio, 0.1f, 1000.0f);
Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 10), Vector3.Zero, Vector3.Up);
_effect = new BasicEffect(GraphicsDevice);
_effect.LightingEnabled = false;
_effect.TextureEnabled = false;
_effect.VertexColorEnabled = true;
_effect.Projection = projection;
_effect.View = view;
_effect.World = Matrix.Identity;
Color color = Color.Black;
_vertices[0] = new VertexPositionColor(new Vector3(-1, -1, 0), color);
_vertices[2] = new VertexPositionColor(new Vector3(-1, 1, 0), color);
_vertices[2] = new VertexPositionColor(new Vector3(1, -1, 0), color);
_vertices[3] = new VertexPositionColor(new Vector3(1, 1, 0), color);
And in draw method I put:
foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
{
// Apply the pass
pass.Apply();
// Draw the square
GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, _vertices, 0, 2);
}
This is working fine. but when I change it to this one it doesn't work anymore.
_vertices[1].Position = new Vector3(-0.10f, 1.37f, -3.0f);
_vertices[0].Position = new Vector3(-0.15f, 1.40f, -3.0f);
_vertices[2].Position = new Vector3(-0.00f, 1.40f, -3.0f);
_vertices[4].Position = new Vector3(0.15f, 1.40f, -3.0f);
_vertices[3].Position = new Vector3(0.10f, 1.37f, -3.0f);
another change that i made:
GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, _vertices, 0, 3);
any idea?
Thanks in advance
It may be that you are drawing your polygons backwards. Meaning you are declaring your vertices in the wrong direction and you may need to change the order. I am not sure which is the correct direction to declare vertices.
Alternatively you can turn off back face culling which will draw
both sides of polygons. This will have a performance hit 2 draws for each polygon. You could try turning this off first and if it fixes it then you know that my first point is the cause.
I made my borders with this:
class Maze
{
private Body _agentBody;
private Sprite _box;
private GameplayScreen _screen;
private float _offset;
public Maze(World world, GameplayScreen screen, Vector2 position)
{
_agentBody = BodyFactory.CreateBody(world, position);
_agentBody.BodyType = BodyType.Dynamic;
_agentBody.IsStatic = true;
_agentBody.Restitution = 0.2f;
_agentBody.Friction = 0.2f;
_offset = ConvertUnits.ToDisplayUnits(1f);
// spodek
_agentBody.CreateFixture(new PolygonShape(PolygonTools.CreateRectangle(1f, 0.05f, new Vector2(0f, 1f), 0), 1f));
// spodek
_agentBody.CreateFixture(new PolygonShape(PolygonTools.CreateRectangle(1f, 0.05f, new Vector2(0f, -1f), 0), 1f));
// pravy bok
_agentBody.CreateFixture(new PolygonShape(PolygonTools.CreateRectangle(0.05f, 1f, new Vector2(1f, 0f), 0), 1f));
// levy bok
_agentBody.CreateFixture(new PolygonShape(PolygonTools.CreateRectangle(0.05f, 1f, new Vector2(-1f, 0f), 0), 1f));
_screen = screen;
//GFX
AssetCreator creator = _screen.ScreenManager.Assets;
_box = new Sprite(creator.TextureFromVertices(PolygonTools.CreateRectangle(1f, 0.05f),
MaterialType.Blank, Color.White, 1f));
}
public Body Body
{
get { return _agentBody; }
}
public void Draw()
{
SpriteBatch batch = _screen.ScreenManager.SpriteBatch;
batch.Draw(_box.Texture, ConvertUnits.ToDisplayUnits(_agentBody.Position), null,
Color.White, _agentBody.Rotation, _box.Origin + new Vector2(0f, _offset), 1f, SpriteEffects.None, 0f);
batch.Draw(_box.Texture, ConvertUnits.ToDisplayUnits(_agentBody.Position), null,
Color.White, _agentBody.Rotation, _box.Origin + new Vector2(0f, -_offset), 1f, SpriteEffects.None, 0f);
batch.Draw(_box.Texture, ConvertUnits.ToDisplayUnits(_agentBody.Position), null,
Color.White, _agentBody.Rotation + MathHelper.Pi / 2f, _box.Origin + new Vector2(0f, _offset), 1f, SpriteEffects.None, 0f);
batch.Draw(_box.Texture, ConvertUnits.ToDisplayUnits(_agentBody.Position), null,
Color.White, _agentBody.Rotation + MathHelper.Pi / 2f, _box.Origin + new Vector2(0f, -_offset), 1f, SpriteEffects.None, 0f);
}
}
And these are my little particles:
for (int i = 0; i < 8; i++)
{
_sands[i] = BodyFactory.CreateRectangle(_world, 0.05f, 0.05f, 1f);
_sands[i].IsStatic = false;
_sands[i].Restitution = 0.1f;
_sands[i].Friction = 0.1f;
_sands[i].Position = new Vector2(1.8f + i * 0.2f, 2.2f);
}
_sand = new Sprite(ScreenManager.Assets.TextureFromShape(_sands[0].FixtureList[0].Shape,
MaterialType.Dots,
Color.SandyBrown, 0.8f));
I draw it this way:
foreach (Body sand in _sands)
{
spriteBatch.Draw(_sand.Texture, ConvertUnits.ToDisplayUnits(sand.Position), null, Color.SandyBrown, sand.Rotation, _sand.Origin, 1f, SpriteEffects.None, 0f);
}
_maze.Draw();
But I can't figure out why if I rotate with borders then why partlicles are still in place. I tried change restitution of particles and when there is 1f they are restitute (bouncing) allright and I can rotate with borders and they restitute from new position of borders but when I have settings like above particles fall down, the ones which are inside of borders they stopped at bottom border and others fall down entirely. So after start I have first image and after I rotate with borders I get seccond image. What I am doing wrong? Why when I change restitution they are bouncing a with 0.2 they are not?
Edit:
New lines in maze constructor:
agentBody = BodyFactory.CreateBody(world, position);
_agentBody.BodyType = BodyType.Dynamic;
_agentBody.IgnoreGravity = true;
_agentBody.Restitution = 0.1f;
_agentBody.Friction = 1f;
_offset = ConvertUnits.ToDisplayUnits(1.5f);
FixtureFactory.AttachRectangle(3f, 0.1f, 1f, new Vector2(0, 1.55f), _agentBody);
FixtureFactory.AttachRectangle(3f, 0.1f, 1f, new Vector2(0f, -1.55f), _agentBody);
FixtureFactory.AttachRectangle(width, 3f, 1f, new Vector2(-1.55f, 0f), _agentBody);
FixtureFactory.AttachRectangle(width, 3f, 1f, new Vector2(1.55f, 0f), _agentBody);
This is how it looks with debug view:
Rotating with body:
public override void HandleInput(GameTime gameTime, InputState input)
{
if (input == null)
throw new ArgumentNullException("input");
// Read in our gestures
foreach (GestureSample gesture in input.Gestures)
{
if (gesture.GestureType == GestureType.HorizontalDrag)
{
if (gesture.Delta.X < 0)
{
_maze.Body.Rotation += 0.02f;
}
else if (gesture.Delta.X > 0)
{
_maze.Body.Rotation -= 0.02f;
}
}
}
The little particle bodies are probably sleeping once they stop moving. The frame around them is a static body so the engine does not expect it to ever move, but you are moving it. In this situation the little particle bodies will not wake up.
You will need to set the little particle bodies so that they cannot sleep, or make the frame around them a dynamic or kinematic body. As a general rule, if a body is gonna move, don't make it a static body.
I have come to inquire about instancing in XNA
I am a beginning XNA developer, only recently stepping up from 2D to 3D games.
I'm trying to draw a large number of cubes made solely out of vertices in code. As one might suspect, drawing a large number of these cubes causes quite a bit of stress on my computer.
As I was looking for a way to increase performance I came across the term "instancing".
Not knowing how instancing works in XNA 4.0, I've looked around for a tutorial suitable for someone of my level.
However, the only tutorial I've come across (http://blogs.msdn.com/b/shawnhar/archive/2010/06/17/drawinstancedprimitives-in-xna-game-studio-4-0.aspx) is a bit too advanced for me. I think he's using models, meshes and whatnot instead of vertices, so I can't figure out which piece of code is actually relevant to what I'm after.
Which is why I come to you. If someone could give me a simple (if possible) tutorial or code snippets explaining how to use instancing with cubes (or any figures) drawn with vertices in XNA 4.0, I'd be much obliged.
This is the simplest code snippet i could come up with. Its an adaptation of a code I made a couple of months ago to display some cubes, just like what you need, no models nor nothing fancy.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
namespace HardwareInstancing
{
public class Instancing
{
Texture2D texture;
Effect effect;
VertexDeclaration instanceVertexDeclaration;
VertexBuffer instanceBuffer;
VertexBuffer geometryBuffer;
IndexBuffer indexBuffer;
VertexBufferBinding[] bindings;
InstanceInfo[] instances;
struct InstanceInfo
{
public Vector4 World;
public Vector2 AtlasCoordinate;
};
Int32 instanceCount = 10000;
public void Initialize(GraphicsDevice device)
{
GenerateInstanceVertexDeclaration();
GenerateGeometry(device);
GenerateInstanceInformation(device, instanceCount);
bindings = new VertexBufferBinding[2];
bindings[0] = new VertexBufferBinding(geometryBuffer);
bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1);
}
public void Load(ContentManager Content)
{
effect = Content.Load<Effect>("InstancingShader");
texture = Content.Load<Texture2D>("default_256");
}
private void GenerateInstanceVertexDeclaration()
{
VertexElement[] instanceStreamElements = new VertexElement[2];
instanceStreamElements[0] =
new VertexElement(0, VertexElementFormat.Vector4,
VertexElementUsage.Position, 1);
instanceStreamElements[1] =
new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector2,
VertexElementUsage.TextureCoordinate, 1);
instanceVertexDeclaration = new VertexDeclaration(instanceStreamElements);
}
//This creates a cube!
public void GenerateGeometry(GraphicsDevice device)
{
VertexPositionTexture[] vertices = new VertexPositionTexture[24];
#region filling vertices
vertices[0].Position = new Vector3(-1, 1, -1);
vertices[0].TextureCoordinate = new Vector2(0, 0);
vertices[1].Position = new Vector3(1, 1, -1);
vertices[1].TextureCoordinate = new Vector2(1, 0);
vertices[2].Position = new Vector3(-1, 1, 1);
vertices[2].TextureCoordinate = new Vector2(0, 1);
vertices[3].Position = new Vector3(1, 1, 1);
vertices[3].TextureCoordinate = new Vector2(1, 1);
vertices[4].Position = new Vector3(-1, -1, 1);
vertices[4].TextureCoordinate = new Vector2(0, 0);
vertices[5].Position = new Vector3(1, -1, 1);
vertices[5].TextureCoordinate = new Vector2(1, 0);
vertices[6].Position = new Vector3(-1, -1, -1);
vertices[6].TextureCoordinate = new Vector2(0, 1);
vertices[7].Position = new Vector3(1, -1, -1);
vertices[7].TextureCoordinate = new Vector2(1, 1);
vertices[8].Position = new Vector3(-1, 1, -1);
vertices[8].TextureCoordinate = new Vector2(0, 0);
vertices[9].Position = new Vector3(-1, 1, 1);
vertices[9].TextureCoordinate = new Vector2(1, 0);
vertices[10].Position = new Vector3(-1, -1, -1);
vertices[10].TextureCoordinate = new Vector2(0, 1);
vertices[11].Position = new Vector3(-1, -1, 1);
vertices[11].TextureCoordinate = new Vector2(1, 1);
vertices[12].Position = new Vector3(-1, 1, 1);
vertices[12].TextureCoordinate = new Vector2(0, 0);
vertices[13].Position = new Vector3(1, 1, 1);
vertices[13].TextureCoordinate = new Vector2(1, 0);
vertices[14].Position = new Vector3(-1, -1, 1);
vertices[14].TextureCoordinate = new Vector2(0, 1);
vertices[15].Position = new Vector3(1, -1, 1);
vertices[15].TextureCoordinate = new Vector2(1, 1);
vertices[16].Position = new Vector3(1, 1, 1);
vertices[16].TextureCoordinate = new Vector2(0, 0);
vertices[17].Position = new Vector3(1, 1, -1);
vertices[17].TextureCoordinate = new Vector2(1, 0);
vertices[18].Position = new Vector3(1, -1, 1);
vertices[18].TextureCoordinate = new Vector2(0, 1);
vertices[19].Position = new Vector3(1, -1, -1);
vertices[19].TextureCoordinate = new Vector2(1, 1);
vertices[20].Position = new Vector3(1, 1, -1);
vertices[20].TextureCoordinate = new Vector2(0, 0);
vertices[21].Position = new Vector3(-1, 1, -1);
vertices[21].TextureCoordinate = new Vector2(1, 0);
vertices[22].Position = new Vector3(1, -1, -1);
vertices[22].TextureCoordinate = new Vector2(0, 1);
vertices[23].Position = new Vector3(-1, -1, -1);
vertices[23].TextureCoordinate = new Vector2(1, 1);
#endregion
geometryBuffer = new VertexBuffer(device, VertexPositionTexture.VertexDeclaration,
24, BufferUsage.WriteOnly);
geometryBuffer.SetData(vertices);
#region filling indices
int[] indices = new int [36];
indices[0] = 0; indices[1] = 1; indices[2] = 2;
indices[3] = 1; indices[4] = 3; indices[5] = 2;
indices[6] = 4; indices[7] = 5; indices[8] = 6;
indices[9] = 5; indices[10] = 7; indices[11] = 6;
indices[12] = 8; indices[13] = 9; indices[14] = 10;
indices[15] = 9; indices[16] = 11; indices[17] = 10;
indices[18] = 12; indices[19] = 13; indices[20] = 14;
indices[21] = 13; indices[22] = 15; indices[23] = 14;
indices[24] = 16; indices[25] = 17; indices[26] = 18;
indices[27] = 17; indices[28] = 19; indices[29] = 18;
indices[30] = 20; indices[31] = 21; indices[32] = 22;
indices[33] = 21; indices[34] = 23; indices[35] = 22;
#endregion
indexBuffer = new IndexBuffer(device, typeof(int), 36, BufferUsage.WriteOnly);
indexBuffer.SetData(indices);
}
private void GenerateInstanceInformation(GraphicsDevice device, Int32 count)
{
instances = new InstanceInfo[count];
Random rnd = new Random();
for (int i = 0; i < count; i++)
{
//random position example
instances[i].World = new Vector4(-rnd.Next(400),
-rnd.Next(400),
-rnd.Next(400), 1);
instances[i].AtlasCoordinate = new Vector2(rnd.Next(0, 2), rnd.Next(0, 2));
}
instanceBuffer = new VertexBuffer(device, instanceVertexDeclaration,
count, BufferUsage.WriteOnly);
instanceBuffer.SetData(instances);
}
//view and projection should come from your camera
public void Draw(ref Matrix view, ref Matrix projection, GraphicsDevice device)
{
device.Clear(Color.CornflowerBlue);
effect.CurrentTechnique = effect.Techniques["Instancing"];
effect.Parameters["WVP"].SetValue(view * projection);
effect.Parameters["cubeTexture"].SetValue(texture);
device.Indices = indexBuffer;
effect.CurrentTechnique.Passes[0].Apply();
device.SetVertexBuffers(bindings);
device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 24, 0, 12, instanceCount);
}
}
}
I've used THIS texture alongside with this shader:
float4x4 WVP;
texture cubeTexture;
sampler TextureSampler = sampler_state
{
texture = <cubeTexture>;
mipfilter = LINEAR;
minfilter = LINEAR;
magfilter = LINEAR;
};
struct InstancingVSinput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSoutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
InstancingVSoutput InstancingVS(InstancingVSinput input, float4 instanceTransform : POSITION1,
float2 atlasCoord : TEXCOORD1)
{
InstancingVSoutput output;
float4 pos = input.Position + instanceTransform;
pos = mul(pos, WVP);
output.Position = pos;
output.TexCoord = float2((input.TexCoord.x / 2.0f) + (1.0f / 2.0f * atlasCoord.x),
(input.TexCoord.y / 2.0f) + (1.0f / 2.0f * atlasCoord.y));
return output;
}
float4 InstancingPS(InstancingVSoutput input) : COLOR0
{
return tex2D(TextureSampler, input.TexCoord);
}
technique Instancing
{
pass Pass0
{
VertexShader = compile vs_3_0 InstancingVS();
PixelShader = compile ps_3_0 InstancingPS();
}
}
which should be named InstancingShader.fx and placed in your Content folder.
Using it from your Game1 is as simple as calling:
instancing = new Instancing();
instancing.Initialize(this.GraphicsDevice);
instancing.Load(Content);
and in your Draw method:
instancing.Draw(ref camera.View, ref camera.Projection, GraphicsDevice);