I'm new to using the vertex buffer in XNA. In my project I construct one using a very large amount of vertices. I have been drawing the primitives heretofore with DrawUserIndexedPrimitives(), but I have grown out of that and need more efficiency, so I am trying to figure out the basics of buffers.
I think I've successfully implemented a buffer (and have been very satisfied with the performance improvements), except that all the faces look wrong. Here's how the primitives looked without the buffer: http://i.imgur.com/ygsnB.jpg (the intended look), and here's how they look without: http://i.imgur.com/rQN1p.jpg
Here's my code for loading a vertex buffer and index buffer:
private void RefreshVertexBuffer()
{
List<VertexPositionNormalTexture> vertices = new List<VertexPositionNormalTexture>();
List<int> indices = new List<int>();
//rebuild the vertex list and index list
foreach(var entry in blocks)
{
Block block = entry.Value;
for (int q = 0; q < block.Quads.Count; q++)
{
vertices.AddRange(block.Quads[q].Corners);
int offset = vertices.Count;
foreach (Triangle tri in block.Quads[q].Triangles)
{
indices.Add(tri.Indices[0] + offset);
indices.Add(tri.Indices[1] + offset);
indices.Add(tri.Indices[2] + offset);
}
}
}
vertexBuffer = new DynamicVertexBuffer(graphics, typeof(VertexPositionNormalTexture), vertices.Count, BufferUsage.None);
indexBuffer = new DynamicIndexBuffer(graphics, IndexElementSize.ThirtyTwoBits, indices.Count, BufferUsage.None);
vertexBuffer.SetData<VertexPositionNormalTexture>(vertices.ToArray(), 0, vertices.Count);
indexBuffer.SetData<int>(indices.ToArray(), 0, indices.Count);
}
and here is the draw call for plain rendering:
public void Render(Planet planet, Camera camera)
{
effect.View = camera.View;
effect.Projection = camera.Projection;
effect.World = planet.World;
foreach (KeyValuePair<Vector3, Block> entry in planet.Geometry.Blocks)
{
int blockID = planet.BlockMap.Blocks[entry.Value.U][entry.Value.V][entry.Value.W];
if (blockID == 1)
effect.Texture = dirt;
else if (blockID == 2)
effect.Texture = rock;
effect.CurrentTechnique.Passes[0].Apply();
foreach (Quad quad in entry.Value.Quads)
{
foreach (Triangle tri in quad.Triangles)
{
graphics.DrawUserIndexedPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
quad.Corners, 0, quad.Corners.Length, tri.Indices, 0, 1);
}
}
}
}
...and for the vertex buffer rendering:
public void RenderFromBuffer(Planet planet, Camera camera)
{
effect.View = camera.View;
effect.Projection = camera.Projection;
effect.World = planet.World;
graphics.SetVertexBuffer(planet.Geometry.VertexBuffer);
graphics.Indices = planet.Geometry.IndexBuffer;
effect.CurrentTechnique.Passes[0].Apply();
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, planet.Geometry.VertexBuffer.VertexCount, 0, planet.Geometry.IndexBuffer.IndexCount / 6);
}
My indices may be off? Or is this due to some quirks with how the graphics device acts with a buffer vs. user indexed?
Edit: It may also have something to do with the way I stitch triangle indices. When I built this project with DrawUserIndexedPrimitives, I ran into some issues similar to this where triangles facing a certain direction would draw on the wrong 'side' (or, the wrong face would be culled). So I came up with this solution:
Triangle[] tris;
if (faceDirection == ADJACENT_FACE_NAMES.BOTTOM | faceDirection == ADJACENT_FACE_NAMES.OUTER | faceDirection == ADJACENT_FACE_NAMES.LEFT)
{
//create the triangles for the quad
tris = new Triangle[2]{
new Triangle( //the bottom triangle
new int[3] {
0, //the bottom left corner
1, //the bottom right corner
2 //the top left corner
}),
new Triangle( //the top triangle
new int[3] {
1, //the bottom right corner
3, //the top right corner
2 //the top left corner
})};
}
else
{
tris = new Triangle[2]{
new Triangle(
new int[3] {
2, //the top left corner
1,
0
}),
new Triangle(
new int[3] {
2,
3,
1
})
};
}
The problem is that the triangles are being culled. So you have two options to fix this:
You can change the order of the triangle indices.
foreach (Triangle tri in block.Quads[q].Triangles)
{
indices.Add(tri.Indices[1] + offset);
indices.Add(tri.Indices[0] + offset);
indices.Add(tri.Indices[2] + offset);
}
You can change your RasterizerState...
Default rasterizer state is RasterizerState.CullClockwise...
You can change it to RasterizerState.CullCounterClockwise
EDIT:
this line has a bug:
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, planet.Geometry.VertexBuffer.VertexCount, 0, planet.Geometry.IndexBuffer.IndexCount / 6)
should be:
graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, planet.Geometry.VertexBuffer.VertexCount, 0, planet.Geometry.IndexBuffer.IndexCount / 3)
Related
Most important code just for example. Func UPDATE is called in every draw frame.
I want implement jumping virtualJumpActive == true logic.
I invert procedure for virtualJumpActive == true to make scene object and camera position set by cannonjs position but just in some short time.
My camera.posY follow fixed values for now.
I wanna only Y (for cannonjs Z / jumping ) to be navigated by physics and other XY
to be navigated by camera (WASD user control)...
It is little intricate situation, i have 3 factors
position of camera
position of player (hands)
position of player collision object
In normal regime player collision object follow camera and player.
In jump moment i wanna apply by vertical force and make camera follow collision object. Also i wanna that always Y component depens on physics data. In that way i will have jumping on top of other objects.
var playerUpdater = {
UPDATE: () => {
App.scene[objName].rotation.rotateY(
matrixEngine.Events.camera.yaw + 180)
var detPitch;
var limit = 2;
if(matrixEngine.Events.camera.pitch < limit &&
matrixEngine.Events.camera.pitch > -limit) {
detPitch = matrixEngine.Events.camera.pitch * 2;
} else if(matrixEngine.Events.camera.pitch > limit) {
detPitch = limit * 2;
} else if(matrixEngine.Events.camera.pitch < -(limit + 2)) {
detPitch = -(limit + 2) * 2;
}
if(matrixEngine.Events.camera.virtualJumpActive == true) {
// invert logic
// Scene object set
App.scene[objName].rotation.rotateX(-detPitch);
var detPitchPos = matrixEngine.Events.camera.pitch;
if(detPitchPos > 4) detPitchPos = 4;
App.scene[objName].position.setPosition(
App.scene.playerCollisonBox.physics.currentBody.position.x,
App.scene.playerCollisonBox.physics.currentBody.position.z,
App.scene.playerCollisonBox.physics.currentBody.position.y
)
// Cannonjs object set
// Switched Z - Y
matrixEngine.Events.camera.xPos = App.scene.playerCollisonBox.physics.currentBody.position.x;
matrixEngine.Events.camera.zPos = App.scene.playerCollisonBox.physics.currentBody.position.y;
matrixEngine.Events.camera.yPos = App.scene.playerCollisonBox.physics.currentBody.position.z;
// App.scene.playerCollisonBox.
// physics.currentBody.velocity.set(0, 0, 0);
App.scene.playerCollisonBox.
physics.currentBody.angularVelocity.set(0, 0, 0);
setTimeout(() => {
matrixEngine.Events.camera.virtualJumpActive = false;
matrixEngine.Events.camera.virtualJumpY = 2;
}, 350);
} else {
// Scene object set
App.scene[objName].rotation.rotateX(-detPitch);
var detPitchPos = matrixEngine.Events.camera.pitch;
if(detPitchPos > 4) detPitchPos = 4;
App.scene[objName].position.setPosition(
matrixEngine.Events.camera.xPos,
matrixEngine.Events.camera.yPos - 0.3 + detPitchPos / 50,
matrixEngine.Events.camera.zPos,
)
// Cannonjs object set
// Switched Z - Y
App.scene.playerCollisonBox.
physics.currentBody.position.set(
matrixEngine.Events.camera.xPos,
matrixEngine.Events.camera.zPos,
matrixEngine.Events.camera.yPos);
App.scene.playerCollisonBox.
physics.currentBody.velocity.set(0, 0, 0);
App.scene.playerCollisonBox.
physics.currentBody.angularVelocity.set(0, 0, 0);
}
}
};
.full {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
<object class="full" data="https://fps-matrix-engine.vercel.app"/>
Any suggestion ?
More data:
Stackoverflow Question ref code =>
https://codepen.io/zlatnaspirala/pen/eYKrmdM?editors=0010
Source code github
Last update
https://fps-matrix-engine.vercel.app
I'm using plotbands in a gauge chart to represent angle ranges. But I'm facing a problem with the plotband angles when the "from" value is higher than the "to" value.
JSFiddle
As you can see, the plotband is set as from: 270, to: 45 but it really is rendered as if it was set as from: 45, to: 270. That renders exactly the oposite angle range that I need.
The only way that I can find to do that is setting two plotbands, one from 270 to 360 and another one from 0 to 45, but that seems very unconvenient.
Is there any easy way to achieve what I'm trying to do?
As I have mentioned in my comment, I think that you should be able to override getPlotBand method in your code for enabling plotBands with bigger from value than to value:
(function(H) {
H.wrap(H.Axis.prototype, 'init', function(proceed, chart, userOptions) {
this.getPlotBandPath = function(from, to, options) {
var center = this.center,
startAngleRad = this.startAngleRad,
pick = H.pick,
map = H.map,
pInt = H.pInt,
fullRadius = center[2] / 2,
radii = [
pick(options.outerRadius, '100%'),
options.innerRadius,
pick(options.thickness, 10)
],
offset = Math.min(this.offset, 0),
percentRegex = /%$/,
start,
end,
open,
isCircular = this.isCircular, // X axis in a polar chart
ret;
// Polygonal plot bands
if (this.options.gridLineInterpolation === 'polygon') {
ret = this.getPlotLinePath(from).concat(this.getPlotLinePath(to, true));
// Circular grid bands
} else {
// Keep within bounds
from = Math.max(from, this.min);
to = Math.min(to, this.max);
// Plot bands on Y axis (radial axis) - inner and outer radius depend on to and from
if (!isCircular) {
radii[0] = this.translate(from);
radii[1] = this.translate(to);
}
// Convert percentages to pixel values
radii = map(radii, function(radius) {
if (percentRegex.test(radius)) {
radius = (pInt(radius, 10) * fullRadius) / 100;
}
return radius;
});
// Handle full circle
if (options.shape === 'circle' || !isCircular) {
start = -Math.PI / 2;
end = Math.PI * 1.5;
open = true;
} else {
start = startAngleRad + this.translate(from);
end = startAngleRad + this.translate(to);
}
radii[0] -= offset; // #5283
radii[2] -= offset; // #5283
ret = this.chart.renderer.symbols.arc(
this.left + center[0],
this.top + center[1],
radii[0],
radii[0], {
start: start, // Math is for reversed yAxis (#3606)
end: end,
innerR: pick(radii[1], radii[0] - radii[2]),
open: open
}
);
}
return ret;
}
proceed.call(this, chart, userOptions);
});
}(Highcharts))
Live example:
http://jsfiddle.net/2Ljk7usL/9/
I have a binary image and a color image of the same size. I need to iterate each blob (white pixel blocks) of the binary image and use it as a mask and find the mean color of this blob region from the color image.
I have tried:
HierarchyIndex[] hierarchy;
Point[][] contours;
binaryImage.FindContours(out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone);
using (Mat mask = Mat.Zeros(matColor.Size(), MatType.CV_8UC1))
foreach (var bl in contours)
if (Cv2.ContourArea(bl) > 5)
{
mask.DrawContour(bl, Scalar.White, -1);
Rect rect = Cv2.BoundingRect(bl);
Scalar mean = Cv2.Mean(colorImage[rect], mask[rect]);
mask.DrawContour(bl, Scalar.Black, -1);
}
which works for the blobs not having holes. However in my case I have many blob regions having huge holes that affects the mean calculation.
I couldn't figure it out how to solve it using the hierarchy info; or with another approach.
(My code is for OpenCVSharp but answer in any other wrapper or language is wellcome.)
Edit: I've added an example image. The traffic signs part is the problem.
Actually I think I have solved this problem with this method:
using PLine = List<Point>;
using Shape = List<List<Point>>;
internal static IEnumerable<Tuple<PLine, Shape>> FindContoursWithHoles(this Mat mat)
{
Point[][] contours;
HierarchyIndex[] hierarchy;
mat.FindContours(out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);
Dictionary<int, bool> dic = new Dictionary<int, bool>();
for (int i = 0; i < contours.Length; i++)
if (hierarchy[i].Parent < 0)
dic[i] = true;
bool ok = false;
while (!ok)
{
ok = true;
for (int i = 0; i < contours.Length; i++)
if (dic.ContainsKey(i))
{
bool isParent = dic[i];
var hi = hierarchy[i];
if (hi.Parent >= 0) dic[hi.Parent] = (!isParent);
if (hi.Child >= 0) dic[hi.Child] = (!isParent);
while (hi.Next >= 0)
{
dic[hi.Next] = isParent;
hi = hierarchy[hi.Next];
if (hi.Parent >= 0) dic[hi.Parent] = (!isParent);
if (hi.Child >= 0) dic[hi.Child] = (!isParent);
}
hi = hierarchy[i];
while (hi.Previous >= 0)
{
dic[hi.Previous] = isParent;
hi = hierarchy[hi.Previous];
if (hi.Parent >= 0) dic[hi.Parent] = (!isParent);
if (hi.Child >= 0) dic[hi.Child] = (!isParent);
}
}
else
ok = false;
}
foreach (int i in dic.Keys.Where(a => dic[a]))
{
PLine pl = contours[i].ToList();
Shape childs = new Shape();
var hiParent = hierarchy[i];
if (hiParent.Child >= 0)
{
childs.Add(contours[hiParent.Child].ToList());
var hi = hierarchy[hiParent.Child];
while (hi.Next >= 0)
{
childs.Add(contours[hi.Next].ToList());
hi = hierarchy[hi.Next];
}
hi = hierarchy[hiParent.Child];
while (hi.Previous >= 0)
{
childs.Add(contours[hi.Previous].ToList());
hi = hierarchy[hi.Previous];
}
}
yield return Tuple.Create(pl, childs);
}
}
By drawing the holes as black, we can use each blob as a single mask:
var blobContours = blobs.FindContoursWithHoles().ToList();
using (Mat mask = Mat.Zeros(mat0.Size(), MatType.CV_8UC1))
for (int i = 0; i < blobContours.Count; i++)
{
var tu = blobContours[i];
var bl = tu.Item1;
if (Cv2.ContourArea(bl) > 100)
{
mask.DrawContour(bl, Scalar.White, -1);
foreach (var child in tu.Item2)
mask.DrawContour(child, Scalar.Black, -1);
Rect rect = Cv2.BoundingRect(bl);
Scalar mean = Cv2.Mean(mat0[rect], mask[rect]);
}
}
I think there should be an easier way.
And yet there is another problem. In some cases, an individual red part of the sign (which is a seperate white blob) does not found as a parent outside circle and a child inside circle, but a large parent contour outside with two circles as children (ie. hole inside another hole, makes a seperate blob which is not found as a parent). Yes it is hierarchically correct but does not help me. I hope I could make my self clear, sorry for my English.
#Miki thank you very much. I was able to achieve what I want using ConnectedComponents. Its simple and fast:
var cc = Cv2.ConnectedComponentsEx(binaryImage, PixelConnectivity.Connectivity8);
foreach (var bl in cc.Blobs)
using (Mat mask = new Mat())
{
cc.FilterByBlob(binaryImage, mask, bl);
Rect rect = bl.Rect;
Scalar mean = Cv2.Mean(colorImage[rect], mask[rect]);
}
I'm able to find the rectangles if the image is created in paint..
I'm not able to find the rectangles in Sanp shot or Screen Shot taken
It's not recognizing Rectangle in Snapshot imagees...
Pls help me
string path = "D:\\testc.png";
Bitmap image = (Bitmap)Bitmap.FromFile(path);
BlobCounter blobCounter = new BlobCounter();
blobCounter.FilterBlobs = true;
blobCounter.MinHeight = 1;
blobCounter.MinWidth = 1;
blobCounter.ProcessImage(image);
Blob[] blobs = blobCounter.GetObjectsInformation();
var retcs = blobCounter.GetObjects(image,true);
SimpleShapeChecker shapeChecker = new SimpleShapeChecker();
foreach (var blob in blobs)
{
List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blob);
List<IntPoint> cornerPoints;
// use the shape checker to extract the corner points
if (shapeChecker.IsQuadrilateral(edgePoints, out cornerPoints))
{
// only do things if the corners form a rectangle
if (shapeChecker.CheckPolygonSubType(cornerPoints) == PolygonSubType.Rectangle)
{
// here i use the graphics class to draw an overlay, but you
// could also just use the cornerPoints list to calculate your
// x, y, width, height values.
List<Point> Points = new List<Point>();
foreach (var point in cornerPoints)
{
Points.Add(new Point(point.X, point.Y));
}
Graphics g = Graphics.FromImage(image);
g.DrawPolygon(new Pen(Color.Red, 5.0f), Points.ToArray());
image.Save("D:\\result.png");
}
}
}
I noticed that the Xlabels of my Timechart are out of sync with the X-
values. The points should be right above the labels. On the left side
it OK, but it shifts towards the right. I don't know how to solve this
What i get:
http://tinypic.com/r/2uqj905/7
How it should be like:
http://www.achartengine.org/dimages/average_temperature.png
I tried a line chart or converted the date to a double but that had no
effect.
Any help would be be nice.
regards, Christian
This is some of my code:
XYMultipleSeriesRenderer renderer = buildRenderer(colors, styles);
renderer.setPointSize(5.5f);
renderer.setZoomEnabled(false, false);
renderer.setMarginsColor(Color.parseColor("#00FF0000"));
renderer.setAxisTitleTextSize(16);
renderer.setYLabelsAlign(Align.RIGHT);
renderer.setLabelsTextSize(15);
renderer.setLegendTextSize(15);
renderer.setMargins(new int[] { 10, 65, 18, 10 });
int length = renderer.getSeriesRendererCount();
for (int i = 0; i < length; i++) {
XYSeriesRenderer seriesRenderer = (XYSeriesRenderer) renderer
.getSeriesRendererAt(i);
seriesRenderer.setFillPoints(true);
seriesRenderer.setLineWidth(4.0f); // dikte van lijn
}
MinMax minMax = determineMinMax(targetSteps, samples);
setChartSettings(renderer, context.getString(R.string.graph_title),
dateLabelOnScreenType(type),
context.getString(R.string.graph_y_axis), minMax.minX,
minMax.maxX, minY, maxY, Color.WHITE,
Color.BLACK);
renderer.setXLabels(7);
renderer.setYLabels(0);
renderer.setDisplayChartValues(false);
renderer.setShowGrid(true);
renderer.setPanEnabled(false, false);
// set the data
String[] titles = new String[] {
context.getString(R.string.graph_legend_target),
context.getString(R.string.graph_legend_actual) };
XYMultipleSeriesDataset dataSet = buildDateDataset(titles,
xSeriesList,
ySeriesList);
TimeChart chart = new TimeChart(dataSet, renderer);
chart.setDateFormat(dateFormatOnSampleType(type));
GraphicalView gview = new GraphicalView(context, chart);
renderer.setYLabelsAlign(Align.RIGHT);
Change to:
renderer.setYLabelsAlign(Align.CENTER);
The solution to this was added recently. Just call:
renderer.setXRoundedLabels(false)