I have a request about surface normals. At the following code snippet is from the URL :
http://www.kindohm.com/technical/wpf3dtutorial.htm
private Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D p2)
{
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions.Add(p0);
mesh.Positions.Add(p1);
mesh.Positions.Add(p2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
Vector3D normal = CalculateNormal(p0, p1, p2);
//
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
//
Material material = new DiffuseMaterial(
new SolidColorBrush(Colors.DarkKhaki));
GeometryModel3D model = new GeometryModel3D(
mesh, material);
Model3DGroup group = new Model3DGroup();
group.Children.Add(model);
return group;
}
private Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
{
Vector3D v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
Vector3D v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
return Vector3D.CrossProduct(v0, v1);
}
I can't understand why the code line "mesh.Normals.Add(normal);" is repeated three times.
Could you say me the reason.
Regards
J.Frank
It looks like you're creating a triangle out of three points. The normals are normals for each point in that triangle. It just so happens that in this case all the normals point in the same direction. That is, they are the same as the surface normal.
There are times when you'd want your point normals to be different from the surface normal. Like, when the triangle is a part of an object like a sphere. Then you'd want the point normals to be an average of the surface normals around it. That would allow you to do smooth shading and highlighting instead of just flat shading.
Related
I am currently working on a game in Godot which involves rendering countries on a globe. I have very little prior experience with Godot, but have experimented with it in the past.
I am using this data from Natural Earth for country borders, and have successfully gotten it to display on the globe using a line mesh. The data was originally in shapefile format, but I converted it to GeoJSON using mapshaper.org.
Picture
The data basically boils down to a list of points given in latitude and longitude, which I then converted into 3d points and created a mesh using SurfaceTool.
I am having trouble generating an actual surface for the mesh, however. Firstly, I am unable to find a built-in function to generate a triangle mesh from this data. I have looked into numerous solutions, including using the built-in Mesh.PRIMITIVE_TRIANGLE_FAN format, which doesn't work on concave shapes.
I have looked into triangulation algorithms such as delaunay triangulation, but have had little success implementing them.
My current plan is to generate a triangle mesh using the 2d data (x,y = longitude,latitude), and project it onto the surface of the sphere. In order to produce a curved surface, I will include the vertices of the sphere itself in the mesh (example).
I would like to know how to go about constructing a triangle mesh from this data. In essence, I need an algorithm that can do the following things:
Create a triangle mesh from a concave polygon (country border)
Connect the mesh to a series of points within this polygon
Allow for holes within the polygon (for lakes, etc.)
Here is an example of the result I am looking for.
Again, I am quite new to Godot and I am probably over-complicating things. If there is an easier way to go about rendering countries on a globe, please let me know.
This is my current code:
extends Node
export var radius = 1
export var path = "res://data/countries.json"
func coords(uv):
return (uv - Vector2(0.5, 0.5)) * 360
func uv(coords):
return (coords / 360) + Vector2(0.5, 0.5)
func sphere(coords, r):
var angles = coords / 180 * 3.14159
return Vector3(
r * cos(angles.y) * sin(angles.x),
r * sin(angles.y),
r * cos(angles.y) * cos(angles.x)
)
func generate_mesh(c):
var mesh = MeshInstance.new()
var material = SpatialMaterial.new()
material.albedo_color = Color(randf(), randf(), randf(), 1.0)
var st = SurfaceTool.new()
st.begin(Mesh.PRIMITIVE_LINE_STRIP)
for h in c:
var k = sphere(h, radius)
st.add_normal(k / radius)
st.add_uv(uv(h))
st.add_vertex(k)
st.index()
mesh.mesh = st.commit()
mesh.set_material_override(material)
return mesh
func load_data():
var file = File.new()
file.open(path, file.READ)
var data = JSON.parse(file.get_as_text()).result
file.close()
for feature in data.features:
var geometry = feature.geometry
var properties = feature.properties
if geometry.type == "Polygon":
for body in geometry.coordinates:
var coordinates = []
for coordinate in body:
coordinates.append(Vector2(coordinate[0], coordinate[1]))
add_child(generate_mesh(coordinates))
if geometry.type == "MultiPolygon":
for polygon in geometry.coordinates:
for body in polygon:
var coordinates = []
for coordinate in body:
coordinates.append(Vector2(coordinate[0], coordinate[1]))
add_child(generate_mesh(coordinates))
func _ready():
load_data()
What about using Geometry.triangulate_polygon() method to triangulate a polygon:
I want to calculate predicted Time of closest approach between an aircraft and Sunrise or Sunset keeping in mind:
Airplane Flying South-westbound as sunrise approaches
Red line is the GreatCircle Track on airplane.
Blue circle is the Airplane.
moment of intersection with sunrise and the Airplane
1- sun Declination (latitude) and crossing Longitude is known , plus the radius of sunrise which is approx 5450 Nautical miles, so sunrise can be shown as a circle with known centre and radius.
2- I used 2D Vector code which did not work since Great circle Path can not be applies to XY plane.
2- The Airplane is flying on Great circle Track which is curved and Latitude change is not Linear, how can I use Airplane Speed as Velocity Vector if latitude change is not constant ?
/// Va - Velocity of circle A.
Va = new Vector2(450, 0);
I used c# code
/// Calculate the time of closest approach of two moving circles. Also determine if the circles collide.
///
/// Input:
/// Pa - Position of circle A.
/// Pb - Position of circle B.
/// Va - Velocity of circle A.
/// Vb - Velocity of circle B.
/// Ra - Radius of circle A.
/// Rb - Radius of circle B.
// Set up the initial position, velocity, and size of the circles.
Pa = new Vector2(150, 250);
Pb = new Vector2(600, 400);
Va = new Vector2(450, 0);
Vb = new Vector2(-100, -250);
Ra = 60;
Rb = 30;
/// Returns:
/// collision - Returns True if a collision occured, else False.
/// The method returns the time to impact if collision=true, else it returns the time of closest approach.
public float TimeOfClosestApproach(Vector2 Pa, Vector2 Pb, Vector2 Va, Vector2 Vb, float Ra, float Rb, out bool collision)
{
Vector2 Pab = Pa - Pb;
Vector2 Vab = Va - Vb;
float a = Vector2.Dot(Vab, Vab);
float b = 2 * Vector2.Dot(Pab, Vab);
float c = Vector2.Dot(Pab, Pab) - (Ra + Rb) * (Ra + Rb);
// The quadratic discriminant.
float discriminant = b * b - 4 * a * c;
// Case 1:
// If the discriminant is negative, then there are no real roots, so there is no collision. The time of
// closest approach is then given by the average of the imaginary roots, which is: t = -b / 2a
float t;
if (discriminant < 0)
{
t = -b / (2 * a);
collision = false;
}
else
{
// Case 2 and 3:
// If the discriminant is zero, then there is exactly one real root, meaning that the circles just grazed each other. If the
// discriminant is positive, then there are two real roots, meaning that the circles penetrate each other. In that case, the
// smallest of the two roots is the initial time of impact. We handle these two cases identically.
float t0 = (-b + (float)Math.Sqrt(discriminant)) / (2 * a);
float t1 = (-b - (float)Math.Sqrt(discriminant)) / (2 * a);
t = Math.Min(t0, t1);
// We also have to check if the time to impact is negative. If it is negative, then that means that the collision
// occured in the past. Since we're only concerned about future events, we say that no collision occurs if t < 0.
if (t < 0)
collision = false;
else
collision = true;
}
// Finally, if the time is negative, then set it to zero, because, again, we want this function to respond only to future events.
if (t < 0)
t = 0;
return t;
}
I accept any answer in any language:
JAVA , JS, Objective-C , Swift , C#.
All I am looking for is the Algorithm. and how to Represent the Airplane Speed as Velocity Vector2D or Vector3D.
I'm having a bit of trouble with the Wavefront exporter of Blender.
Actually I'm developing a parser for .obj mesh. I created a mesh in Blender, set up its UVs, normals and so on... When I'm loading this mesh with my loader, UVs get placed correctly but not normals, in fact they are all flipped!
If I flip all normals in Blender, the mesh is correctly displayed in my app. The strange thing is that if a create a simple cube, export it, load it, display it in my app, it'll be correctly displayed without having to "badly" flip in Blender.
I tried a lot with the parameters of exporter, I set my mesh smooth so that I'm sure I get per vertex normals...
I tried by setting backface culling ON/OFF, in fact I tried a lot of thing I found on teh Internet without result.
Here is a bit of my code :
//I add information about vertices / uv / normals in 3 collections
//vertex
case "v":
l_vertex = new VPrimVertex(new VPrimVector3(Double.Parse(l_words[1]), Double.Parse(l_words[2]), Double.Parse(l_words[3])));
ListeVertices.Add(l_vertex);
break;
//vertex normal
case "vn":
ListeNormales.Add(new VPrimVector3(Double.Parse(l_words[1]), Double.Parse(l_words[2]), Double.Parse(l_words[3])));
break;
//vertex UV
case "vt":
//pas la même orientation UV entre Wavefront et WPF d'où le 1-V
ListeUVs.Add(new VPrimPointUV(Double.Parse(l_words[1]), 1.0-Double.Parse(l_words[2])));
break;
//face
case "f":
//pas un triangle
if (l_words.Length > 4)
{
Triangule(l_words);
}
//triangle
else
{
ComputeFace(l_words);
}
break;
.
.
.
Computeface(){
...
//for each face :
//for each vertex of a face :
//p_face[i] contains strings like v1/vt1/vn1
l_stringVertex = p_face[i].Split('/');
l_vertex = ListeVertices.ElementAt(int.Parse(l_stringVertex[0]) - 1);
l_vertex.AddAdjacent(l_face);
l_vertex.Normale = ListeNormales.ElementAt(int.Parse(l_stringVertex[2]) - 1);
l_face.AddVertex(l_vertex);
l_face.UVList.Add(m_listeUVs.ElementAt(int.Parse(l_stringVertex[1]) - 1));
...
}
And then I fill WPF MeshGeometry3D with all thoses datas.
private void Finalise()
{
Point3D l_point3D;
Vector3D l_vector;
Point l_point;
VPrimPointUV l_pointUV;
int i;
foreach (VPrimFace l_face in Racine.SubdivideList)
{
i = 0;
foreach (VPrimVertex l_vertex in l_face.VertexList)
{
l_point3D = new Point3D(l_vertex.Position.X, l_vertex.Position.Y, l_vertex.Position.Z);
CurrentMesh.MeshGeometry3D.Positions.Add(l_point3D);
l_vertex.moyenneNormaleFacesAdjacentes();
l_vector = new Vector3D(l_vertex.Normale.X, l_vertex.Normale.Y, l_vertex.Normale.Z);
CurrentMesh.MeshGeometry3D.Normals.Add(l_vector);
if (Texture)
{
l_pointUV = l_face.UVList.ElementAt(i);
l_point = new Point(l_pointUV.U, l_pointUV.V);
CurrentMesh.MeshGeometry3D.TextureCoordinates.Add(l_point);
}
CurrentMesh.MeshGeometry3D.TriangleIndices.Add(CurrentMesh.MeshGeometry3D.Positions.Count-1);
i += 1;
}
}
}
If you have any idea...Thank you
On Blender 2.66
I'm trying to fill a round circle (transparent other than the outline of the circle) in an ImageView.
I have the code working:
public void setPercentage(int p) {
if (this.percentage != p ) {
this.percentage = p;
this.invalidate();
}
}
#Override public void onDraw(Canvas canvas) {
Canvas tempCanvas;
Paint paint;
Bitmap bmCircle = null;
if (this.getWidth() == 0 || this.getHeight() == 0 )
return ; // nothing to do
mergedLayersBitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888);
tempCanvas = new Canvas(mergedLayersBitmap);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setFilterBitmap(false);
bmCircle = drawCircle(this.getWidth(), this.getHeight());
tempCanvas.drawBitmap(bmCircle, 0, 0, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
tempCanvas.clipRect(0,0, this.getWidth(), (int) FloatMath.floor(this.getHeight() - this.getHeight() * ( percentage/100)));
tempCanvas.drawColor(0xFF660000, PorterDuff.Mode.CLEAR);
canvas.drawBitmap(mergedLayersBitmap, null, new RectF(0,0, this.getWidth(), this.getHeight()), new Paint());
canvas.drawBitmap(mergedLayersBitmap, 0, 0, new Paint());
}
static Bitmap drawCircle(int w, int h) {
Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
p.setColor(drawColor);
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
It kind of works. However, I have two issues: I run out of memory quickly and the GC goes crazy. How can I utilize the least amount of memory for this operation?
I know I Shouldn't be instantiating objects in onDraw, however I'm not sure where to draw then. Thank you.
pseudo would look something like this.
for each pixel inside CircleBitmap {
if (pixel.y is < Yboundary && pixelIsInCircle(pixel.x, pixel.y)) {
CircleBitmap .setPixel(x, y, Color.rgb(45, 127, 0));
}
}
that may be slow, but it would work, and the smaller the circle the faster it would go.
just know the basics, bitmap width and height, for example 256x256, the circles radius, and to make things easy make the circle centered at 128,128. then as you go pixel by pixel, check the pixels X and Y to see if it falls inside the circle, and below the Y limit line.
then just use:
CircleBitmap .setPixel(x, y, Color.rgb(45, 127, 0));
edit: to speed things up, don't even bother looking at the pixels above the Y limit.
in case if you want to see another solution (perhaps cleaner), look at this link, filling a circle gradually from bottom to top android
I have a collection of latitudes and longitudes and I'll be grabbing sets of these and want to draw a polygon based on them.
The datasets won't be the outline so will need an algorithm to establish which ones make up the outline of a polygon containing all the latitudes and longitudes supplied. This polygon needs to be flexible so the polygon can be concave if the points dictate that.
Any help would be appreciated.
** UPDATE **
Sorry, should have put more detail.
My code below produces a horrible looking polygon. As explain in my first post I want to create a nice concave or convex polygon based on the latlng's provided.
Just need a way of plotting the outer latlngs.
Apologies if this is still asking too much but thought it was worth one last try.
function initialize() {
var myLatLng = new google.maps.LatLng(51.407431, -0.727142);
var myOptions = {
zoom: 12,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var bermudaTriangle;
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var triangleCoords = [
new google.maps.LatLng(51.392692, -0.740358),
new google.maps.LatLng(51.400618, -0.742469),
new google.maps.LatLng(51.40072, -0.72418),
new google.maps.LatLng(51.400732, -0.743817),
new google.maps.LatLng(51.401258, -0.743386),
new google.maps.LatLng(51.401264, -0.741445),
new google.maps.LatLng(51.401443, -0.725555),
new google.maps.LatLng(51.401463, -0.744042),
new google.maps.LatLng(51.402281, -0.739059)
];
var minX = triangleCoords[0].lat();
var maxX = triangleCoords[0].lat();
var minY = triangleCoords[0].lng();
var maxY = triangleCoords[0].lng();
for (var i = 1; i < triangleCoords.length; i++) {
if (triangleCoords[i].lat() < minX) minX = triangleCoords[i].lat();
if (triangleCoords[i].lat() > maxX) maxX = triangleCoords[i].lat();
if (triangleCoords[i].lng() < minY) minY = triangleCoords[i].lng();
if (triangleCoords[i].lng() > maxY) maxY = triangleCoords[i].lng();
}
// Construct the polygon
bermudaTriangle = new google.maps.Polygon({
paths: triangleCoords,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#FF0000",
fillOpacity: 0.35
});
bermudaTriangle.setMap(map);
}
Your problem is not enough defined : with a given set of points, you may end up with many different polygons if you do not add a constraint other than 'create a nice concave or convex polygon'.
And even a simple example shows that :
imagine a triangle ABC, and let D be the center of this triangle, what output will you expect for {A,B,C,D} set of points ?
ABC, since D is inside ?
or ADBCA polygon ?
or ABDCA polygon ?
or ABCDA polygon ?
now if you say 'well D is in the center, it's obvious we should discard D', let D be closer and closer from, say, the AB segment. When do you decide the best output is ABC or ADBCA ?
So you have to add constraints to be able to build an algorithm, since if you cannot not decide by yourself for the above {A,B,C,D} example, how could a computer do ? :-) For example if you call AvgD the average distance beetween points, you could add the constraint that no segment of your outer polygon should be longer than 1.2*AvgD (or, better, Alpha*AvgD, and you try your algorithm with different alpha).
To solve your issue, i would use first a classical hull algorithm to get the outer convex polygon (which is deterministic), then break down the segments that are 'too' long (with the constraint(s) you want) putting more and more inner points into the outlining until all constraints are ok. Something like 'digging holes' into the convex polygon.
'Breaking down' a too long segment is also a thing you can do in quite different maners. One may be to search for the nearest not-in-the-outline point from the middle point of the segment. Another would be to choose the point having lowest radius with current segment... Now that you have your new point, break the segment in two, update your list of too-loong segment, and do it again until you're done (or until you reach a 'satisfactory' average length for too long segments, or ...)
Good luck !