I am trying the calculate normal per vertex.
But I do something wrong. When I run the code I see this:
Here Is my code, Note that vertex1 is vertex before the current vertex and vertex2 is vertex after the current vertex.
for (int j = 0; j < meshes[t].face[i].numOfPoints; j++)
{
if (normalSetChange)
{
vector3D vertex1, vertex2;
if ((j < meshes[t].face[i].numOfPoints - 1) && (j > 0))
{
vertex1 = vertexes[meshes[t].face[i].vertex[j + 1]] - vertexes[meshes[t].face[i].vertex[j]];
vertex2 = vertexes[meshes[t].face[i].vertex[j - 1]] - vertexes[meshes[t].face[i].vertex[j]];
}
else if (j < meshes[t].face[i].numOfPoints - 1)
{
vertex1 = vertexes[meshes[t].face[i].vertex[j + 1]] - vertexes[meshes[t].face[i].vertex[j]];
vertex2 = vertexes[meshes[t].face[i].vertex[meshes[t].face[i].numOfPoints - 1]] - vertexes[meshes[t].face[i].vertex[j]];
}
else if (j > 0)
{
vertex1 = vertexes[meshes[t].face[i].vertex[0]] - vertexes[meshes[t].face[i].vertex[j]];
vertex2 = vertexes[meshes[t].face[i].vertex[j - 1]] - vertexes[meshes[t].face[i].vertex[j]];
}
normalSet = vector3D(vertex1.y * vertex2.z - vertex1.z * vertex2.y,
vertex1.z * vertex2.x - vertex1.x * vertex2.z,
vertex1.x * vertex2.y - vertex1.y * vertex2.x);
normalLength = sqrt(normalSet.x * normalSet.x + normalSet.y * normalSet.y + normalSet.z * normalSet.z);
normalSet.x /= normalLength;
normalSet.y /= normalLength;
normalSet.z /= normalLength;
writePolygonLineVCN(PolygonLineVCN(vertexes[meshes[t].face[i].vertex[j]], vertexestexCoordinate[meshes[t].face[i].texCoordinate[j]], normalSet), newFile[workOnCPU]);
}
else
writePolygonLineVCN(PolygonLineVCN(vertexes[meshes[t].face[i].vertex[j]], vertexestexCoordinate[meshes[t].face[i].texCoordinate[j]], vertexesNormals[meshes[t].face[i].normal[j]]), newFile[workOnCPU]);
}
You are computing normals per triangle, not per vertex. In fact you can clearly see "solid" normals in the image you posted.
In order to compute "smooth" normals, you need to assign to each vertex a normal which is an average of the normals of the triangles adjacent to that vertex.
Here's some pseudocode, which computed the weighted average of the normals based on the angle between the two edges adjacent to the vertex. (Maybe someone uses the area of the triangle as weight, I don't know if there is an universally accepted way to do it).
vector3D triangleNormalFromVertex(int face_id, int vertex_id) {
//This assumes that A->B->C is a counter-clockwise ordering
vector3D A = mesh.face[face_id].vertex[vertex_id];
vector3D B = mesh.face[face_id].vertex[(vertex_id+1)%3];
vector3D C = mesh.face[face_id].vertex[(vertex_id+2)%3];
vector3D N = cross(B-A,C-A);
float sin_alpha = length(N) / (length(B-A) * length(C-A) );
return normalize(N) * asin(sin_alpha);
}
void computeNormals() {
for (vertex v in mesh) {
vector3D N (0,0,0);
for (int i = 0;i < NumOfTriangles;++i) {
if (mesh.face[i].contains(v) ) {
int VertexID = index_of_v_in_triangle(i,v); //Can be 0,1 or 2
N = N + triangleNormalFromVertex(i,VertexID);
}
}
N = normalize(N);
add_N_to_normals_for_vertex_v(N,v);
}
}
Related
I'm writing a program that can draw a line between two points with filled circles. The circles:
- shouldn't overlap each other
- be as close together as possible
- and the centre of each circle should be on the line.
I've written a function to produce the circles, however I'm having trouble calculating position of each circle so that they are correctly lined up
void addCircles(scrPt endPt1, scrPt endPt2)
{
float xLength, yLength, length, cSquare, slope;
int numberOfCircles;
// Get the x distance between the two points
xLength = abs(endPt1.x - endPt2.x);
// Get the y distance between the two points
yLength = abs(endPt1.y - endPt2.y);
// Get the length between the points
cSquare = pow(xLength, 2) + pow(yLength, 2);
length = sqrt(cSquare);
// calculate the slope
slope = (endPt2.y - endPt1.y) / (endPt2.x - endPt1.x);
// Find how many circles fit inside the length
numberOfCircles = round(length / (radius * 2) - 1);
// set the position of each circle
for (int i = 0; i < numberOfCircles; i++)
{
scrPt circPt;
circPt.x = endPt1.x + ((radius * 2) * i);
circPt.y = endPt1.y + (((radius * 2) * i) * slope);
changeColor();
drawCircle (circPt.x, circPt.y);
}
This is what the above code produces:
I'm quite certain that the issue lies with this line, which sets the y value of the circle:
circPt.y = endPt1.y + (((radius * 2) * i) * slope);
Any help would be greatly appreciated
I recommend to calculate the direction of the line as a unit vector:
float xDist = endPt2.x - endPt1.x;
float yDist = endPt2.y - endPt1.y;
float length = sqrt(xDist*xDist + yDist *yDist);
float xDir = xDist / length;
float yDir = yDist / length;
Calculate the distance from one center point to the next one, numberOfSegments is the number of sections and not the number of circles:
int numberOfSegments = (int)trunc( length / (radius * 2) );
float distCpt = numberOfSegments == 0 ? 0.0f : length / (float)numberOfSegments;
A center point of a circle is calculated by the adding a vector the the start point of the line. The vector pints in the direction of the line and its length is given, by the distance between 2 circles multiplied by the "index" of the circle:
for (int i = 0; i <= numberOfSegments; i++)
{
float cpt_x = endPt1.x + xDir * distCpt * (float)i;
float cpt_y = endPt1.y + yDir * distCpt * (float)i;
changeColor();
drawCircle(cpt_x , cpt_y);
}
Note, the last circle on a line may be redrawn, by the first circle of the next line. You can change this by changing the iteration expression of the for loop - change <= to <:
for (int i = 0; i < numberOfSegments; i++)
In this case at the end of the line won't be drawn any circle at all.
After advice from krlzlx I have posted it as a new question.
From here:
3D Line Segment and Plane Intersection
I have a problem with this algorithm, I have implemented it like so:
template <class T>
class AnyCollision {
public:
std::pair<bool, T> operator()(Point3d &ray, Point3d &rayOrigin, Point3d &normal, Point3d &coord) const {
// get d value
float d = (normal.x * coord.x) + (normal.y * coord.y) + (normal.z * coord.z);
if (((normal.x * ray.x) + (normal.y * ray.y) + (normal.z * ray.z)) == 0) {
return std::make_pair(false, T());
}
// Compute the X value for the directed line ray intersecting the plane
float a = (d - ((normal.x * rayOrigin.x) + (normal.y * rayOrigin.y) + (normal.z * rayOrigin.z)) / ((normal.x * ray.x) + (normal.y * ray.y) + (normal.z * ray.z)));
// output contact point
float rayMagnitude = (sqrt(pow(ray.x, 2) + pow(ray.y, 2) + pow(ray.z, 2)));
Point3d rayNormalised((ray.x / rayMagnitude), (ray.y / rayMagnitude), (ray.z / rayMagnitude));
Point3d contact((rayOrigin.x + (rayNormalised.x * a)), (rayOrigin.y + (rayNormalised.y * a)), (rayOrigin.z + (rayNormalised.z * a))); //Make sure the ray vector is normalized
return std::make_pair(true, contact);
};
Point3d is defined as:
class Point3d {
public:
double x;
double y;
double z;
/**
* constructor
*
* 0 all elements
*/
Point3d() {
x = 0.0;
y = 0.0;
z = 0.0;
}
I am forced to use this structure, because in the larger system my component runs in it is defined like this and it cannot be changed.
My code compiles fine, but testing I get incorrect values for the point. The ratio of x, y, z is correct but the magnitude is wrong.
For example if:
rayOrigin.x = 0;
rayOrigin.y = 0;
rayOrigin.z = 0;
ray.x = 3;
ray.y = -5;
ray.z = 12;
normal.x = -3;
normal.y = 12;
normal.z = 0;
coord.x = 7;
coord.y = -5;
coord.z = 10;
I expect the point to be:
(0.63, 1.26, 1.89)
However, it is:
(3.52, -5.87, 14.09)
A magnitude of 5.09 too big.
And I also tested:
rayOrigin.x = 0;
rayOrigin.y = 0;
rayOrigin.z = 0;
ray.x = 2;
ray.y = 3;
ray.z = 3;
normal.x = 4;
normal.y = 1;
normal.z = 0;
p0.x = 2;
p0.y = 1;
p0.z = 5;
I expect the point to be:
(1.64, 2.45, 2.45)
However, it is:
(3.83761, 5.75642, 5.75642)
A magnitude of 2.34 too big?
Pseudocode (does not require vector normalization):
Diff = PlaneBaseCoordinate - RayOrigin
d = Normal.dot.Diff
e = Normal.dot.RayVector
if (e)
IntersectionPoint = RayOrigin + RayVector * d / e
otherwise
ray belongs to the plane or is parallel
Quick check:
Ray (0,0,0) (2,2,2) //to catch possible scale issues
Plane (0,1,0) (0,3,0) //plane y=1
Diff = (0,1,0)
d = 3
e = 6
IntersectionPoint = (0,0,0) + (2,2,2) * 3 / 6 = (1, 1, 1)
I'm currently working on 2D transformations (translation, scaling, shearing and rotation) in Qt. I have a problem with bilinear interpolation, which I want to use to cover the 'black pixels' in output image. I'm using matrix calculations to get new coordinates of pixels of input image. Then I use reverse matrix calculation to check which pixel of input image responds to output pixel. Result of that is some float number which I use to interpolation. I check the four neighbour points and calculate the value (color) of output pixel. I have checked my calculations 'by hand' and they seem to be good.
Can anyone find any bug in that code? (I cut out the parts of code which are responsible for interface such as sliders).
Geometric::Geometric(QWidget* parent) : QWidget(parent) {
resize(1000, 800);
displayLogoDefault = true;
a = shx = shy = x0 = y0 = 0;
scx = scy = 1;
tx = ty = 0;
x = 200, y = 200;
paintT = paintSc = paintR = paintShx = paintShy = false;
img = new QImage(600,600,QImage::Format_RGB32);
img2 = new QImage("logo.jpeg");
}
Geometric::~Geometric() {
delete img;
delete img2;
img = NULL;
img2 = NULL;
}
void Geometric::makeChange() {
displayLogoDefault = false;
// iteration through whole input image
for(int i = 0; i < img2->width(); i++) {
for(int j = 0; j < img2->height(); j++) {
// calculate new coordinates basing on given 2D transformations values
//I calculated that formula eariler by multiplying/adding matrixes
x = cos(a)*scx*(i-x0) - sin(a)*scy*(j-y0) + shx*sin(a)*scx*(i-x0) + shx*cos(a)*scy*(j-y0);
y = shy*(x) + sin(a)*scx*(i-x0) + cos(a)*scy*(j-y0);
// tx and ty goes for translation. scx and scy for scaling
// shx and shy for shearing and a is angle for rotation
x += (x0 + tx);
y += (y0 + ty);
if(x >= 0 && y >= 0 && x < img->width() && y < img->height()) {
// reverse matrix calculation formula to find proper pixel from input image
float tmx = x - x0 - tx;
float tmy = y - y0 - ty;
float recX = 1/scx * ( cos(-a)*( (tmx + shx*shy*tmx - shx*tmx) ) + sin(-a)*( shy*tmx - tmy ) ) + x0 ;
float recY = 1/scy * ( sin(-a)*(tmx + shx*shy*tmx - shx*tmx) - cos(-a)*(shy*tmx-tmy) ) + y0;
// here the interpolation starts. I calculate the color basing on four points from input image
// that points are taken from the reverse matrix calculation
float a = recX - floorf(recX);
float b = recY - floorf (recY);
if(recX + 1 > img2->width()) recX -= 1;
if(recY + 1 > img2->height()) recY -= 1;
QColor c1 = QColor(img2->pixel(recX, recY));
QColor c2 = QColor(img2->pixel(recX + 1, recY));
QColor c3 = QColor(img2->pixel(recX , recY + 1));
QColor c4 = QColor(img2->pixel(recX + 1, recY + 1));
float colR = b * ((1.0 - a) * (float)c3.red() + a * (float)c4.red()) + (1.0 - b) * ((1.0 - a) * (float)c1.red() + a * (float)c2.red());
float colG = b * ((1.0 - a) * (float)c3.green() + a * (float)c4.green()) + (1.0 - b) * ((1.0 - a) * (float)c1.green() + a * (float)c2.green());
float colB = b * ((1.0 - a) * (float)c3.blue() + a * (float)c4.blue()) + (1.0 - b) * ((1.0 - a) * (float)c1.blue() + a * (float)c2.blue());
if(colR > 255) colR = 255; if(colG > 255) colG = 255; if(colB > 255) colB = 255;
if(colR < 0 ) colR = 0; if(colG < 0 ) colG = 0; if(colB < 0 ) colB = 0;
paintPixel(x, y, colR, colG, colB);
}
}
}
// x0 and y0 are the starting point of image
x0 = abs(x-tx);
y0 = abs(y-ty);
repaint();
}
// function painting a pixel. It works directly on memory
void Geometric::paintPixel(int i, int j, int r, int g, int b) {
unsigned char *ptr = img->bits();
ptr[4 * (img->width() * j + i)] = b;
ptr[4 * (img->width() * j + i) + 1] = g;
ptr[4 * (img->width() * j + i) + 2] = r;
}
void Geometric::paintEvent(QPaintEvent*) {
QPainter p(this);
p.drawImage(0, 0, *img);
if (displayLogoDefault == true) p.drawImage(0, 0, *img2);
}
I have a program that loads in a heightmap, I then sort the vertices out to an array using the triangle list method, my question is how would i go about changing it to triangle strip? I want it to be one strip so the first row would be left to right, second row right to left etc doing this using for loops.
My code for the trianlge list method so far (not showing heightmap loader or number of vertices definition, also showing the normals calculator but i dont need any help adapting that):
for( int l = 0; l < m_HeightMapLength; ++l )
{
for( int w = 0; w < m_HeightMapWidth; ++w )
{
if( w < m_HeightMapWidth-1 && l < m_HeightMapLength-1 )
{
/*v0 = m_pHeightMap[mapIndex];
v1 = m_pHeightMap[mapIndex+m_HeightMapWidth];
v2 = m_pHeightMap[mapIndex+1];
v3 = m_pHeightMap[mapIndex+m_HeightMapWidth+1];
D3DXVECTOR3 vA = v0 - v1;
D3DXVECTOR3 vB = v1 - v2;
D3DXVECTOR3 vC = v3 - v1;
D3DXVECTOR3 vN1;
D3DXVec3Cross(&vN1, &vA, &vB);
D3DXVECTOR3 vN2;
D3DXVec3Cross(&vN2, &vB, &vC);*/
//D3DXVec3Normalize( &vN1, &vN1);
//D3DXVec3Normalize( &vN2, &vN2);
//T Left, Bot Left, T Right, T Right, Bot Left, Bot Right
//m_pMapVtxs[i++] = Vertex_Pos3fColour4ubNormal3f(D3DXVECTOR3( m_pHeightMap[mapIndex].x, m_pHeightMap[mapIndex].y, m_pHeightMap[mapIndex].z), MAP_COLOUR, D3DXVECTOR3(vN1.x, vN1.y, vN1.z));
//m_pMapVtxs[i++] = Vertex_Pos3fColour4ubNormal3f(D3DXVECTOR3( m_pHeightMap[mapIndex + m_HeightMapWidth].x, m_pHeightMap[mapIndex + m_HeightMapWidth].y, m_pHeightMap[mapIndex + m_HeightMapWidth].z), MAP_COLOUR, D3DXVECTOR3(vN1.x, vN1.y, vN1.z));
//m_pMapVtxs[i++] = Vertex_Pos3fColour4ubNormal3f(D3DXVECTOR3( m_pHeightMap[mapIndex+1].x, m_pHeightMap[mapIndex+1].y, m_pHeightMap[mapIndex+1].z), MAP_COLOUR, D3DXVECTOR3(vN1.x, vN1.y, vN1.z));
//m_pMapVtxs[i++] = Vertex_Pos3fColour4ubNormal3f(D3DXVECTOR3( m_pHeightMap[mapIndex+1].x, m_pHeightMap[mapIndex+1].y, m_pHeightMap[mapIndex+1].z), MAP_COLOUR, D3DXVECTOR3(vN2.x, vN2.y, vN2.z));
//m_pMapVtxs[i++] = Vertex_Pos3fColour4ubNormal3f(D3DXVECTOR3( m_pHeightMap[mapIndex + m_HeightMapWidth].x, m_pHeightMap[mapIndex + m_HeightMapWidth].y, m_pHeightMap[mapIndex + m_HeightMapWidth].z), MAP_COLOUR, D3DXVECTOR3(vN2.x, vN2.y, vN2.z));
//m_pMapVtxs[i++] = Vertex_Pos3fColour4ubNormal3f(D3DXVECTOR3( m_pHeightMap[mapIndex + m_HeightMapWidth+1].x, m_pHeightMap[mapIndex + m_HeightMapWidth+1].y, m_pHeightMap[mapIndex + m_HeightMapWidth+1].z), MAP_COLOUR, D3DXVECTOR3(vN2.x, vN2.y, vN2.z));
mapIndex++;
The for loops is my main problem to change it to strip, i already have the vertices mapped out on paper so thats my main problem, any insight greatly appreciated.
I assume m_pHeightMap is a 3d vector.
The strip will look like this:
+--+--+--+--+
|/ |/ |/ |/ |
+--+--+--+--+
| \| \| \| \|
+--+--+--+--+
We'll start at the bottom left corner, continue to the right, then one row up and continue to the left. But let's have a look at how to define a strip for a single row first:
for(int x = 0; i < m_HeightMapWidth; ++x)
{
add m_pHeightMap[x + y * m_HeightMapWidth]; //bottom vertex
add m_pHeightMap[x + (y + 1) * m_HeightMapWidth]; //top vertex
}
This works for every second row. The last vertex will be the row's top right vertex. There, we have to add a degenerated triangle. This is a triangle with the area 0 and will cause the rows to be separated. So:
add m_pHeightMap[m_HeightMapWidth + m_HeightMapWidth - 1]; //once again the last vertex
And for the row above that we add the vertices from right to left:
for(int x = m_HeightMapWidth - 1; i >= 0; --x)
{
add m_pHeightMap[x + y * m_HeightMapWidth]; //bottom vertex
add m_pHeightMap[x + (y + 1 ) * m_HeightMapWidth]; //top vertex
}
Note that the first vertex is the one we already added twice. Adding it a third time will preserve the triangles' orientation.
And we do this for each row. So alltogether:
for(int y = 0; y < m_HeightMapHeight - 1; ++y)
{
if(y % 2 == 0)
{
for(int x = 0; i < m_HeightMapWidth; ++x)
{
add m_pHeightMap[x + y * m_HeightMapWidth]; //bottom vertex
add m_pHeightMap[x + (y + 1) * m_HeightMapWidth]; //top vertex
}
add m_pHeightMap[(y + 2) * m_HeightMapWidth - 1]; //once again the last vertex
}
else
{
for(int x = m_HeightMapWidth - 1; i >= 0; --x)
{
add m_pHeightMap[x + y * m_HeightMapWidth]; //bottom vertex
add m_pHeightMap[x + (y + 1 ) * m_HeightMapWidth]; //top vertex
}
add m_pHeightMap[(y + 1) * m_HeightMapWidth]; //once again the last vertex
}
}
* The code is untested
How do I draw a cylinder with OpenGL in OpenTK?
Sample code from an older project of mine. This creates an "uncapped" cylinder (top and bottom are empty).
int segments = 10; // Higher numbers improve quality
int radius = 3; // The radius (width) of the cylinder
int height = 10; // The height of the cylinder
var vertices = new List<Vector3>();
for (double y = 0; y < 2; y++)
{
for (double x = 0; x < segments; x++)
{
double theta = (x / (segments - 1)) * 2 * Math.PI;
vertices.Add(new Vector3()
{
X = (float)(radius * Math.Cos(theta)),
Y = (float)(height * y),
Z = (float)(radius * Math.Sin(theta)),
});
}
}
var indices = new List<int>();
for (int x = 0; x < segments - 1; x++)
{
indices.Add(x);
indices.Add(x + segments);
indices.Add(X + segments + 1);
indices.Add(x + segments + 1);
indices.Add(x + 1);
indices.Add(x);
}
You can now render the cylinder like this:
GL.Begin(BeginMode.Triangles);
foreach (int index in indices)
GL.Vertex3(vertices[index]);
GL.End();
You can also upload vertices and indices into a vertex buffer object to improve performance.
Generating the geometry for a cylinder is quite simple (let's consider a Z-aligned cylinder). Let me use pseudocode:
points = list of (x,y,z)
where x = sin(a)*RADIUS, y = cos(a)*RADIUS, z = b,
for each a in [0..2*PI) with step StepA,
for each b in [0..HEIGHT] with step StepB
About the indices: Let us assume N equal to the number of "levels" or "slices" of the cylinder (which depends on HEIGHT and StepB) and M equal to the number of points on every "slice" (which depends on StepA).
The cylinder contains some quads, each spanning 2 neighbouring slices, so the indices would look like:
indices = list of (a,b,c,d)
where a = M * slice + point,
b = M * slice + (point+1) % M,
c = (M+1) * slice + (point+1) % M,
d = (M+1) * slice + point
for each slice in [0..N-2]
for each point in [0..M-1]
If you need normals for the cylinder, they are simple to generate:
normals = (x/RADIUS,y/RADIUS,0)
for each (x,y,z) in points
That's it for the round part of the cylinder, you might also want the "caps" but I believe they are easy to do.
I'll leave the fun part of translating my pseudocode into your language of choice for you. :)
The rest is to create/bind the VBO, load up the geometry, set pointers, use your shader of choice and call glDrawArrays(...) - any OpenGL 3 tutorial should cover this; are you familiar with that part?