I am subdividing the triangles of mesh, and as you can guess, I need weight values for these new vertices. Currently I am using linear interpolation (Vnew.weight[i] = (V1.weight[i] + V2.weight[i]) * 0.5) but, it seems like I cannot get correct values.
Do you know a better solution for using interpolating the weights?
Edit:
Right know, I am using LBS, and dividing one triangles into two triangles by taking halfway point. This division is done as soon as triangle information is read from the file (I am using SMD files).
I think the problem is weights because, in the rest pose (Without any skinning) everything is fine. But when the poses are started to apply, and skinning is done, some crazy triangles, and holes appear. And when I looked closely to these "crazy triangles", their vertices are moving with the mesh but, not fast enough with other vertices.
And here is the code of division process, and interpolating vertices, normals, UVs, and weights
int pi=0;
while (1)
{
// Some control, and decleration
for (int w = 0; w < 3; w++)
{
// Some declerations
Vert v;
// Values are read from file into Cert v
// Using boneIndex2[] and boneWeight2[] because GLSL 1.30 does
// not support shader storage buffer object, and I need just
// 8 indices most for now.
v.boneIndex2[0] = 0;
v.boneIndex2[1] = 0;
v.boneIndex2[2] = 0;
v.boneIndex2[3] = 0;
v.boneWeight2[0] = 0;
v.boneWeight2[1] = 0;
v.boneWeight2[2] = 0;
v.boneWeight2[3] = 0;
m.vert.push_back(v);
pi++;
}
// Dividing the triangle
Vert a = m.vert[pi - 2];
Vert b = m.vert[pi - 1];
Vert v;
// Interpolate position
v.pos[0] = (a.pos[0] + b.pos[0]) / 2;
v.pos[1] = (a.pos[1] + b.pos[1]) / 2;
v.pos[2] = (a.pos[2] + b.pos[2]) / 2;
// Interpolate normal
v.norm[0] = (a.norm[0] + b.norm[0]) / 2;
v.norm[1] = (a.norm[1] + b.norm[1]) / 2;
v.norm[2] = (a.norm[2] + b.norm[2]) / 2;
// Interpolate UV
v.uv[0] = (a.uv[0] + b.uv[0]) / 2;
v.uv[1] = (a.uv[1] + b.uv[1]) / 2;
// Assign bone indices
// The new vertex should be treated by each bone of Vert a, and b
v.boneIndex[0] = a.boneIndex[0];
v.boneIndex[1] = a.boneIndex[1];
v.boneIndex[2] = a.boneIndex[2];
v.boneIndex[3] = a.boneIndex[3];
v.boneIndex2[0] = b.boneIndex[0];
v.boneIndex2[1] = b.boneIndex[1];
v.boneIndex2[2] = b.boneIndex[2];
v.boneIndex2[3] = b.boneIndex[3];
// Interpolate weights
float we[4];
we[0] = (a.boneWeight[0] + b.boneWeight[0]) / 2;
we[1] = (a.boneWeight[1] + b.boneWeight[1]) / 2;
we[2] = (a.boneWeight[2] + b.boneWeight[2]) / 2;
we[3] = (a.boneWeight[3] + b.boneWeight[3]) / 2;
// Assign weights
v.boneWeight[0] = we[0];
v.boneWeight[1] = we[1];
v.boneWeight[2] = we[2];
v.boneWeight[3] = we[3];
v.boneWeight2[0] = we[0];
v.boneWeight2[1] = we[1];
v.boneWeight2[2] = we[2];
v.boneWeight2[3] = we[3];
// Push new vertex
m.vert.push_back(v);
pi++;
// Push new faces
m.face.push_back(Face(pi - 4, pi - 1, pi - 2));
m.face.push_back(Face(pi - 4, pi - 3, pi - 1));
} // End of while(1)
You are blending weights that just might belong to different bones (i.e. if the bone indices are not equal).
Instead, gather all influencing bone indices from the two vertices. If only one vertex refers to any bone, use half of this weight. If both vertices refer to the bone, use the interpolation as you already did. Then, pick the four bones with the highest weights and re-normalize to a sum of 1.
Here is an example. Consider you have two vertices with these bone indices and weights:
v1 v2
index | weight index | weight
------+-------- ------+--------
0 | 0.2 2 | 0.1
1 | 0.5 3 | 0.6
2 | 0.1 4 | 0.2
3 | 0.2 5 | 0.1
You would start by building the table of joint weights:
index | weight
------+--------
0 | 0.2 / 2 = 0.1
1 | 0.5 / 2 = 0.25
2 | (0.1 + 0.1) / 2 = 0.1
3 | (0.2 + 0.6) / 2 = 0.4
4 | 0.2 / 2 = 0.1
5 | 0.1 / 2 = 0.05
Sort wrt weight and pick the four greatest:
index | weight
------+--------
3 | 0.4 *
1 | 0.25 *
0 | 0.1 *
2 | 0.1 *
4 | 0.1
5 | 0.05
These weights sum to 0.85. So divide the weights by 0.85 to get the final weights and indices:
index | weight
------+--------
3 | 0.47
1 | 0.29
0 | 0.12
2 | 0.12
The other option would be to extend your structure to use more (either static eight or dynamically) bones. But it's probably not worth the effort.
Related
I am looking at some Fortran code from an old scanned paper. The scan quality is not great so I may have copied it wrong. I tried to run this using an online Fortran compiler but it bombs out. Not being familiar with Fortran, I was wondering if someone can point out where the syntax does not make sense? The code is from a paper on sediment dynamics:
Komar, P.D. and Miller, M.C., 1975. On the comparison between the threshold of sediment motion under waves and unidirectional currents with a discussion of the practical evaluation of the threshold: Reply. Journal of Sedimentary Research, 45(1).
PROGRAM TSHOLD
REAL LI, LO
G = 981.0
PIE = 3.1416
RHOW = 1.00
READ (6O,1) DIAM, RHOS
1 FORMAT (2X, F6.3,2X, F5.3)
IF(DIAM .LT. 0.05) GO TO 5
A = 0.463 * PIE
B = 0.25
GO TO 7
5 A = 0.21
B = 0.50
7 PWR = 1.0 / (2.0 - B)
FAC = (A * (RHOS - RHOW) * G/(RHOW * PIE**B))**PWR
FAC1 = FAC * DIAM**((1.0 - B) * PWR)
T = 1.0
15 J = 1.20
LD = 156.13 * (T**2)
UM = FAC1 * T**(B*PWR)
WRITE(61,9) DIAM, T, UM
9 FORMAT(1H0, 10X, 17HGRAIN DIAMETER = ,F6.3,1X,2HCM //
1 11X, 14HWAVE PERIOD = ,F5.2, 1X, 3HSEC //
2 11X, 22HORBITAL VELOCITY, UM = ,F6.2, 1X, 6HCM/SECl //
3 20X, 6HHEIGHT, 5X, 5HDEPTH, 8X, 3HH/L, 6X, 7HH/DEPTH //
4 22X, 2HCM, 8X, 2HCM /)
C INCREMENT WAVE HEIGHT, CALCULATE DEPTH
H = 10.0
DO 12 K = 1.60
SING = PIE * H / (UM * T)
X = SING
IF(X.LT.1.0) GO TO 30
30 ASINH = X - 0.16666*X**3.0 + 0.07500* X ** 5.0 - 0.04464 * X ** 7.0
1 + 0.03038 * X ** 9.0 - 0.02237 * X ** 11.0
32 LI = LD * (SINH(ASINH)/COSH(ASINH))
OPTH = ASINH * LI / 6.2832
C CHECK WAVE STABILITY
RATIO = H / DPTH
IF(RATIO.GE.0.78) GO TO 11
STEEP = H / LI
TEST = 0.142 * (SINH(ASINH)/COSH(ASINH))
IF(STEEP.GE.TEST) GO TO 11
WRITE(61,10) H, OPTH, STEEP, RATIO
I0 FORMAT(IH0, 20X, F5.1, 4X, E9.3, 4X, F5.3, 4X, F4.2)
11 H = H + 10.0
12 CONTINUE
T = T + 1.0
15 CONTINUE
END
The problem is more likely that old Fortran requires fixed form code formatting where the number of spaces before a statement is very important.
Here are some general rules
Normal statements start at column 7 and beyond
Lines cannot exceed 72 columns
Any character placed on column 6 indicates the line is a continuation from the line above. I see that on the code above in the lines following 9 FORMAT(..
A number placed between columns 1-5 indicates a label, which can be a target of a GO TO statement, a DO statement or a formatting specification.
The character C on the first column, and sometimes any character on the first column indicate the line is a comment line.
see https://people.cs.vt.edu/~asandu/Courses/MTU/CS2911/fortran_notes/node4.html for more info.
Based on the rules above, here is how to enter the code, with the correct spacing. I run the F77 code through a converter to make it compatible with F90 and F77 at the same time. The code below might compile with the online compiler now.
PROGRAM TSHOLD
REAL LI, LO
G = 981.0
PIE = 3.1416
RHOW = 1.00
READ (60,1) DIAM, RHOS
1 FORMAT (2X, F6.3,2X, F5.3)
IF(DIAM .LT. 0.05) GO TO 5
A = 0.463 * PIE
B = 0.25
GO TO 7
5 A = 0.21
B = 0.50
7 PWR = 1.0 / (2.0 - B)
FAC = (A * (RHOS - RHOW) * G/(RHOW * PIE**B))**PWR
FAC1 = FAC * DIAM**((1.0 - B) * PWR)
T = 1.0
DO 15 J=1,20
LD = 156.13 * (T**2)
UM = FAC1 * T**(B*PWR)
WRITE(61,9) DIAM, T, UM
9 FORMAT(1H0, 10X, 17HGRAIN DIAMETER = ,F6.3,1X,2HCM // &
& 11X, 14HWAVE PERIOD = ,F5.2, 1X, 3HSEC // &
& 11X, 22HORBITAL VELOCITY, UM = ,F6.2, 1X, 6HCM/SECl // &
& 20X, 6HHEIGHT, 5X, 5HDEPTH, 8X, 3HH/L, 6X, 7HH/DEPTH // &
& 22X, 2HCM, 8X, 2HCM /)
! INCREMENT WAVE HEIGHT, CALCULATE DEPTH
H = 10.0
DO 12 K = 1,60
SING = PIE * H / (UM * T)
X = SING
IF(X.LT.1.0) GO TO 30
30 ASINH = X - 0.16666*X**3.0 + 0.07500* X ** 5.0 - 0.04464 * X ** 7.&
& + 0.03038 * X ** 9.0 - 0.02237 * X ** 11.0
32 LI = LD * (SINH(ASINH)/COSH(ASINH))
OPTH = ASINH * LI / 6.2832
! CHECK WAVE STABILITY
RATIO = H / DPTH
IF(RATIO.GE.0.78) GO TO 11
STEEP = H / LI
TEST = 0.142 * (SINH(ASINH)/COSH(ASINH))
IF(STEEP.GE.TEST) GO TO 11
WRITE(61,10) H, OPTH, STEEP, RATIO
10 FORMAT(G14.4, 20X, F5.1, 4X, E9.3, 4X, F5.3, 4X, F4.2)
11 H = H + 10.0
12 CONTINUE
T = T + 1.0
15 CONTINUE
END
I found several transcription errors, replacing commas with dots, zeros with the letter O, and a missing DO statement.
I just finished coding a C++ program to manage a 3D matrix with dynamically allocated memory.
In order to use a contiguous chunk of memory, I decided to use a mapping function to physically store the elements of my matrix to 1D array.
For this purpose, I have a T *_3D_matrix pointer to the array, which is defined as
_3D_matrix = new T[height * width * depth];
where height, width and depth are input parameters for the constructor.
The program works just fine, I even tested it with Valgrind and no memory problems happen.
What I don't get is: my array has got height * width * depth = 12 elements, and the mapping function seems to map some elements out of the [0..11] range.
What am I missing here?
EDIT:
This is the output I get from recreating the same matrix and printing it in my program.
Lets say we have a "3D" array defined as
some_type m[1][3][2];
That would look something like this if we draw it:
+------------+-------------+------------+-------------+------------+------------+
| m[0] |
+------------+-------------+------------+-------------+------------+------------+
| m[0][0] | m[0][1] | m[0][2] |
+------------+-------------+------------+-------------+------------+------------+
| m[0][0][0] | m[0][0][1] | m[0][1][0] | m[0][1][1] | m[0][2][0] | m[0][2][1] |
+------------+-------------+------------+-------------+------------+------------+
If x represents the first "dimension", y the second, and z the third, then an expressions such as m[x][y][z] would with a flat array be like m[x * 3 * 2 + y * 3 + z]. The number 3 is the number of elements in the second dimension, and 2 is the number of elements in the third dimension.
Generalized, an array like
some_type m[X][Y][Z];
would as a flat array have the formula x * Y * Z + y * Z + z for the index. Compared to your formula the x and the y have been switched.
You computed the mapped index for out-of-bounds values of y.
You said height * width * depth= 12, and:
index = y * width * depth + x * depth + z
And we see in your table:
#.| Y | X | Z | index
--+---+---+---+------
1 | 0 | 1 | 0 | 2
2 | 1 | 0 | 0 | 6
This implies:
0 * width * depth + 1 * depth + 0 = 2 => depth = 2
1 * width * depth + 0 * depth + 0 = 6 => width * depth + 6 => width = 3
height * width * depth= 12 => height = 2
Thus:
y is in [0, 1]
x is in [0, 2]
z is in [0, 1]
The maximum index is at {x, y, z} = {2, 1, 1} and its value is 1 * 2 * 3 + 2 * 2 + 1 = 11.
Assuming from your example:
width = 2, height = 3, and depth = 2
x is in [0, width), y is in [0, height), z is in [0, depth)
Mapping second element should be:
1*2*2 + 0*2 + 0 = 4, but you get 6. I think the reason is that some of the dimensions or indices are swapped somewhere else in your code. Seems that width or depth is 3 in your case.
I have recently been trying to render a 3D sphere in OpenGL using triangles. I have been testing and modifying code from various websites and have finally found a winning combination. The only problem is that there are visible gaps in the sphere. Any thoughts on what would be causing this?
Code to render sphere
float Slices = 30;
float Stacks = 60;
float Radius = 20.0;
for (int i = 0; i <= Stacks; ++i){
float V = i / (float) Stacks;
float phi = V * glm::pi <float> ();
for (int j = 0; j <= Slices; ++j){
float U = j / (float) Slices;
float theta = U * (glm::pi <float> () * 4);
float x = cosf (theta) * sinf (phi);
float y = cosf (phi);
float z = sinf (theta) * sinf (phi);
x *= Radius;
y *= Radius;
z *= Radius;
Vertex *v = new Vertex {{x,y,z}, //Position
{255,0,0}}; //Color
screenToBuffer(v, 1);
delete []v;
}
}
Problem
Try and set it to GL_TRIANGLE_STRIP
What might be the problem is that it considers each group of three vertices to be only one triangle.
Like so
Indices: 0 1 2 3 4 5 ...
Triangles: {0 1 2} {3 4 5}
The GL_TRIAGLE_STRIP will do this.
Indices: 0 1 2 3 4 5 ...
Triangles: {0 1 2}
{1 2 3} drawing order is (2 1 3) to maintain proper winding
{2 3 4}
{3 4 5}
See this answer for a proper way to do it.
https://stackoverflow.com/a/7958376/1943599
Can someone explain why 1.000000 <= 1.0f is false?
The code:
#include <iostream>
#include <stdio.h>
using namespace std;
int main(int argc, char **argv)
{
float step = 1.0f / 10;
float t;
for(t = 0; t <= 1.0f; t += step)
{
printf("t = %f\n", t);
cout << "t = " << t << "\n";
cout << "(t <= 1.0f) = " << (t <= 1.0f) << "\n";
}
printf("t = %f\n", t );
cout << "t = " << t << "\n";
cout << "(t <= 1.0f) = " << (t <= 1.0f) << "\n";
cout << "\n(1.000000 <= 1.0f) = " << (1.000000 <= 1.0f) << "\n";
}
The result:
t = 0.000000
t = 0
(t <= 1.0f) = 1
t = 0.100000
t = 0.1
(t <= 1.0f) = 1
t = 0.200000
t = 0.2
(t <= 1.0f) = 1
t = 0.300000
t = 0.3
(t <= 1.0f) = 1
t = 0.400000
t = 0.4
(t <= 1.0f) = 1
t = 0.500000
t = 0.5
(t <= 1.0f) = 1
t = 0.600000
t = 0.6
(t <= 1.0f) = 1
t = 0.700000
t = 0.7
(t <= 1.0f) = 1
t = 0.800000
t = 0.8
(t <= 1.0f) = 1
t = 0.900000
t = 0.9
(t <= 1.0f) = 1
t = 1.000000
t = 1
(t <= 1.0f) = 0
(1.000000 <= 1.0f) = 1
As correctly pointed out in the comments, the value of t is not actually the same 1.00000 that you are defining in the line below.
Printing t with higher precision with std::setprecision(20) will reveal its actual value: 1.0000001192092895508.
The common way to avoid these kinds of issues is to compare not with 1, but with 1 + epsilon, where epsilon is a very small number, that is maybe one or two magnitudes greater than your floating point precision.
So you would write your for loop condition as
for(t = 0; t <= 1.000001f; t += step)
Note that in your case, epsilon should be atleast ten times greater than the maximum possible floating point error, as the float is added ten times.
As pointed out by Muepe and Alain, the reason for t != 1.0f is that 1/10 can not be precisely represented in binary floating point numbers.
Floating point types in C++ (and most other languages) are implemented using an approach that uses the available bytes (for example 4 or 8) for the following 3 components:
Sign
Exponent
Mantissa
Lets have a look at it for a 32 bit (4 byte) type which often is what you have in C++ for float.
The sign is just a simple bit beeing 1 or 0 where 0 could mean its positive and 1 that its negative. If you leave every standardization away that exists you could also say 0 -> negative, 1 -> positive.
The exponent could use 8 bits. Opposed to our daily life this exponent is not ment to be used to the base 10 but base 2. That means 1 as an exponent does not correspond to 10 but to 2, and the exponent 2 means 4 (=2^2) and not 100 (=10^2).
Another important part is, that for floating point variables we also might want to have negative exponents like 2^-1 beeing 0.5, 2^-2 for 0.25 and so on. Thus we define a bias value that gets subtracted from the exponent and yields the real value. In this case with 8 bits we'd choose 127 meaning that an exponent of 0 gives 2^-127 and an exponent of 255 means 2^128. But, there is an exception to this case. Usually two values of the exponent are used to mark NaN and infinity. Therefore the real exponent is from 0 to 253 giving a range from 2^-127 to 2^126.
The mantissa obviously now fills up the remaining 23 bits. If we see the mantissa as a series of 0 and 1 you can imagine its value to be like 1.m where m is the series of those bits, but not in powers of 10 but in powers of 2. So 1.1 would be 1 * 2^0 + 1 * 2^-1 = 1 + 0.5 = 1.5. As an example lets have a look at the following mantissa (a very short one):
m = 100101 -> 1.100101 to base 2 -> 1 * 2^0 + 1 * 2^-1 + 0 * 2^-2 + 0 * 2^-3 + 1 * 2^-4 + 0 * 2^-5 + 1 * 2^-6 = 1 * 1 + 1 * 0.5 + 1 * 1/16 + 1 * 1/64 = 1.578125
The final result of a float is then calculated using:
e * 1.m * (sign ? -1 : 1)
What exactly is going wrong in your loop: Your step is 0.1! 0.1 is a very bad number for floating point numbers to base 2, lets have a look why:
sign -> 0 (as its non-negative)
exponent -> The first value smaller than 0.1 is 2^-4. So the exponent should be -4 + 127 = 123
mantissa -> For this we check how many times the exponent is 0.1 and then try to convert the fraction to a mantissa. 0.1 / (2^-4) = 0.1/0.0625 = 1.6. Considering the mantissa gives 1.m our mantissa should be 0.6. So lets convert that to binary:
0.6 = 1 * 2^-1 + 0.1 -> m = 1
0.1 = 0 * 2^-2 + 0.1 -> m = 10
0.1 = 0 * 2^-3 + 0.1 -> m = 100
0.1 = 1 * 2^-4 + 0.0375 -> m = 1001
0.0375 = 1 * 2^-5 + 0.00625 -> m = 10011
0.00625 = 0 * 2^-6 + 0.00625 -> m = 100110
0.00625 = 0 * 2^-7 + 0.00625 -> m = 1001100
0.00625 = 1 * 2^-8 + 0.00234375 -> m = 10011001
We could continue like thiw until we have our 23 mantissa bits but i can tell you that you get:
m = 10011001100110011001...
Therefore 0.1 in a binary floating point environment is like 1/3 is in a base 10 system. Its a periodic infinite number. As the space in a float is limited there comes the 23rd bit where it just has to cut of, and therefore 0.1 is a tiny bit greater than 0.1 as there are not all infinite parts of the number in the float and after 23 bits there would be a 0 but it gets rounded up to a 1.
The reason is that 1.0/10.0 = 0.1 can not be represented exactly in binary, just as 1.0/3.0 = 0.333.. can not be represented exactly in decimals.
If we use
float step = 1.0f / 8;
for example, the result is as expected.
To avoid such problems, use a small offset as shown in the answer of mic_e.
I have given N points on a straight line, these are lets say- (x1,y1) , (x2, y2), .... (xn, yn) , these points represent a wire in 3D. I want this wire to bend to form shape of circle and ellipse. So these points will map to points on circle and ellipse. Tell about some mapping technique that maps points on straight line onto points on circle and ellipse.
Reduce the line points to scalar parametric coordinates 0 <= t <= 1.
Multiply the t coordinates by 2*pi (giving theta) and plug them into the parametric circle equation:
x = cos( theta )
y = sin( theta )
Example:
Given 4 points (0,0), (1,1), (5,5), and (10,10) convert to parametric coordinates like so:
length = | (10,10) - (0,0) | = sqrt( 10^2 + 10^2 ) = sqrt( 200 )
t0 = 0.0 = | (0,0) - (0,0) | / length = 0
t1 = 0.1 = | (1,1) - (0,0) | / length = sqrt( 2 ) / length
t2 = 0.5 = | (5,5) - (0,0) | / length = sqrt( 50 ) / length
t3 = 1.0 = | (10,10) - (0,0) | / length = sqrt( 200 ) / length
p0.x = cos( t0 * 2 * pi ) = 1
p0.y = sin( t0 * 2 * pi ) = 0
p1.x = cos( t1 * 2 * pi ) = 0.80901699437
p1.y = sin( t1 * 2 * pi ) = 0.58778525229
...