The triangles are mostly ok but one or 2 triangles would have a missing pixel between them
which probably means theres a issue with edge cases but i cant figure it out
the white spaces only happen on the edge of the triangles so i assume there is something wrong with either my edge equation or my top left rule but im really lost on what is
wrong with it
struct EdgeEqn {
float a, b, c;
bool tl;
};
GLPbo::EdgeEqn construct(const glm::vec3 a, const glm::vec3& b) {
GLPbo::EdgeEqn x = { a.y - b.y,b.x - a.x,(b.y - a.y) * a.x - (b.x - a.x) * a.y };
if (x.a > 0) {
x.tl = true;
}
else if (x.a < 0) {
x.tl = false;
}
else if (x.b < 0) {
x.tl = true;
}
else {
x.tl = false;
}
return x;
}
bool edgeFunction(GLPbo::EdgeEqn x, const glm::vec2& c, float& line_eval)
{
float eval = x.a * c.x + x.b * c.y + x.c;
line_eval = eval;
return (eval > 0.f || (eval == 0.f && x.tl))
? true : false;
}
bool Topleft_increase(GLPbo::EdgeEqn x, float eval) {
return (eval > 0.f || (eval == 0.f && x.tl))
? true : false;
}
bool GLPbo::render_triangle(glm::vec3 const& p0, glm::vec3 const& p1,
glm::vec3 const& p2, glm::vec3 clr) {
if (((p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y)) < 0) {
culling++;
return false;
}
GLPbo::Color random = { static_cast<GLubyte>(clr.r), static_cast<GLubyte>(clr.g)
, static_cast<GLubyte>(clr.b), 255 };
int min_x = static_cast<int>(std::min({ p0.x, p1.x, p2.x }));
int min_y = static_cast<int>(std::min({ p0.y, p1.y, p2.y }));
int max_x = static_cast<int>(std::max({ p0.x, p1.x, p2.x }));
int max_y = static_cast<int>(std::max({ p0.y, p1.y, p2.y }));
GLPbo::EdgeEqn l0 = construct(p1, p2);
GLPbo::EdgeEqn l1 = construct(p2, p0);
GLPbo::EdgeEqn l2 = construct(p0, p1);
float ev0 = 0, ev1 = 0, ev2 = 0;
bool e0 = edgeFunction(l0, glm::vec2(min_x + 0.5, min_y + 0.5), ev0);
bool e1 = edgeFunction(l1, glm::vec2(min_x + 0.5, min_y + 0.5), ev1);
bool e2 = edgeFunction(l2, glm::vec2(min_x + 0.5, min_y + 0.5), ev2);
for (int y = min_y; y <= max_y; ++y) {
bool hE0 = e0; bool hE1 = e1; bool hE2 = e2;
float hEv0 = ev0; float hEv1 = ev1; float hEv2 = ev2;
for (int x = min_x; x <= max_x; ++x) {
if (hE0 == true && hE1 == true && hE2 == true) {
set_pixel(x, y, random);
}
hEv0 += l0.a;
hEv1 += l1.a;
hEv2 += l2.a;
hE0 = Topleft_increase(l0, hEv0);
hE1 = Topleft_increase(l1, hEv1);
hE2 = Topleft_increase(l2, hEv2);
}
ev0 += l0.b;
ev1 += l1.b;
ev2 += l2.b;
e0 = Topleft_increase(l0, ev0);
e1 = Topleft_increase(l1, ev1);
e2 = Topleft_increase(l2, ev2);
}
return true;
}
Can i get rotation(yaw , pitch,roll) from this matrix algorithm ?
thanks
matrix[0][0] = cos(pitch)*cos(yaw);
matrix[0][2] = cos(pitch)*sin(yaw);
matrix[0][1] = sin(pitch);
matrix[0][3] = 0;
matrix[1][0] = -cos(roll)*sin(pitch)*cos(yaw)+sin(roll)*sin(yaw);
matrix[1][1] = cos(roll)*cos(pitch);
matrix[1][2] = -cos(roll)*sin(pitch)*sin(yaw)-sin(roll)*cos(yaw);
matrix[1][3] = 0;
matrix[2][0] = -sin(roll)*sin(pitch)*cos(yaw)-cos(roll)*sin(yaw);
matrix[2][1] = sin(roll)*cos(pitch);
matrix[2][2] = cos(roll)*cos(yaw)-sin(roll)*sin(pitch)*sin(yaw);
matrix[2][3] = 0;
matrix[3][0] = 0;
matrix[3][1] = 0;
matrix[3][2] = 0;
matrix[3][3] = 1;
edit : i used this code but it not working :
D3DXMATRIX matrix2 = D3DXMATRIX(matrix);
yaw = atan2(matrix2._13, matrix2._11);
pitch = asin(matrix2._12);
roll = atan2(matrix2._32, matrix2._22);
Edit 3:
this is my old function , it works but not 100%
VECTOR getAnglefromMatrix(float* m)
{
float pitch, yaw, roll;
D3DXMATRIX matrix = D3DXMATRIX(m);
if (matrix._11 == 1.0f)
{
yaw = todegree(atan2f(matrix._13, matrix._34));
pitch = 0;
roll = 0;
}
else if (matrix._11 == -1.0f)
{
yaw = todegree(atan2f(matrix._13, matrix._34));
pitch = 0;
roll = 0;
}
else
{
yaw = todegree(atan2(-matrix._31,matrix._11));
pitch = todegree(asin(matrix._21));
roll = todegree(atan2(-matrix._23,matrix._22));
}
return vector3d(yaw,pitch,roll);
}
i did something wrong ?
We can go through the entries and find some that are nice for back-calculations:
matrix[0][0] = cos(pitch)*cos(yaw);
matrix[0][2] = cos(pitch)*sin(yaw);
This gives us:
yaw = atan2(matrix[0][2], matrix[0][0])
For the pitch:
matrix[0][1] = sin(pitch);
This gives us:
pitch = asin(matrix[0][1]) //this assumes pitch is between -pi/2 and +pi/2
Then
matrix[1][1] = cos(roll)*cos(pitch);
matrix[2][1] = sin(roll)*cos(pitch);
This gives us:
roll = atan2(matrix[2][1], matrix[1][1])
I omitted the cases where the arguments to atan2 become zero. I am confident you can figure them out. In these cases, the Euler angles are not uniquely defined.
I am working on soft body simulation. I am trying to do it with OpenGL in c++. However, I have some problems and I could not find anything on the internet. I am using the mass-spring method.
First, I did the simulation in 2d and it worked without a problem. There was a code available. However, when I directly applied it to 3d, it did not and I cannot find the problem. Is it UV sphere? People are using icosahedron sphere, I am aware, however, I cannot figure out how to initialize springs. Since the direction of the springs matter; when I changed the directions in 2d, it does not work. Or it may be the directions of the springs in the UV sphere. Also, I suspect force accumulation and Euler integrator. It may be normals, however, the simulation does not work in the first part where I apply pressure. So to be sure, I changed the normals as vectors from origin to the midpoint of the springs since the ball is located at the origin initially but it fails again. It's been a while since I took a physics course. I put the code below, I know it is not efficient and not well written, but I am interested in making the simulation work, but regardless I appreciate all comments. Anyways, thanks for reading thus far. I wish you all a wonderful day.
mass point initialization
void
InitPoints()
{
float dxy = (360.0 * DegreesToRadians) / CircleVertices;
float dz = (360.0 * DegreesToRadians) / NumCirclesx2;
points[0] = vec4( 0.0, 1.0, 0.0, 1.0);
for(int j=1;j<NumCirclesx2/2;j++){
for(int i=0;i<CircleVertices;i++){
points[(j-1)*CircleVertices + i+1] = vec4(BALLRADIUS * sin(i * dxy)*sin(j*dz), BALLRADIUS *cos(j*dz), BALLRADIUS *cos(i * dxy)*sin(j*dz), 1.0);
}
}
points[NumVertices-1] = vec4( 0.0, -1.0, 0.0, 1.0);
}
Springs initialization
void
InitEdges(){
int k = 0;
for(int j=0;j<CircleVertices;j++){
edges[4*j] = points[1+j];
edges[4*j+1] = points[0];
spring[k].p1 = 0;
spring[k].p2 = 1+j;
spring[k].index = 4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[4*j+2] = points[(1+j)];
spring[k].p1 = 1+j;
spring[k].index = 4*j+2;
if(2+j == CircleVertices){
edges[4*j+3] = points[(2+j)];
spring[k].p2 = 2+j;
}
else{
edges[4*j+3] = points[(2+j)%(CircleVertices)];
spring[k].p2 = (2+j)%(CircleVertices);
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
for(int i=1;i<NumCirclesx2/2-1;i++){
for(int j=0;j<CircleVertices;j++){
edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].p2 = (i-1)*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j+2;
if(2+j == CircleVertices){
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
spring[k].p2 = i*CircleVertices+(2+j);
}
else {
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
spring[k].p2 = i*CircleVertices+(2+j)%CircleVertices;
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
}
for(int j=0;j<CircleVertices;j++){
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j] = points[NumVertices-1];
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
spring[k].p1 = (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1;
spring[k].p2 = NumVertices-1;
spring[k].index = (NumCirclesx2/2-1)*CircleVertices*4+2*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
}
volume of the ball
float VolumeBall(){
float minx = 100000,miny = 100000,minz = 100000, maxx = -100000, maxy = -100000, maxz = -100000;
for(int i = 0; i<NumVertices; i++){
if(points[i].x < minx) minx = points[i].x;
if(points[i].y < miny) miny = points[i].y;
if(points[i].z < minz) minz = points[i].z;
if(points[i].x > maxx) maxx = points[i].x;
if(points[i].y > maxy) maxy = points[i].y;
if(points[i].z > maxz) maxz = points[i].z;
}
return (maxx - minx) * (maxz - minz) * (maxy - miny);
}
force accumulator
void AccumulateForces(){
vec3 point1, point2,point3,point4;
float r12;
vec3 v12;
float f;
vec3 F;
vec3 norm;
bool flag = true;
float volume=0;
float pressurev;
for(int i =0; i<NumVertices; i++){
mass[i].f.x = 0;
mass[i].f.z = 0;
mass[i].f.y = 0;
if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
}
for(int i=0; i<NumEdges/2; i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1, point2);
if(r12 != 0){
v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
F = (point1-point2)/r12 * f;
mass[spring[i].p1].f -= F;
mass[spring[i].p2].f += F;
}
spring[i].n = normalize(point1-point2);
}
volume = VolumeBall();
for(int i=0;i<NumEdges/2;i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1,point2);
pressurev = r12 * Pressure * (1.0f/volume);
mass[spring[i].p1].f += spring[i].n * pressurev;
mass[spring[i].p2].f += spring[i].n * pressurev;
}
}void AccumulateForces(){
vec3 point1, point2,point3,point4;
float r12;
vec3 v12;
float f;
vec3 F;
vec3 norm;
bool flag = true;
float volume=0;
float pressurev;
for(int i =0; i<NumVertices; i++){
mass[i].f.x = 0;
mass[i].f.z = 0;
mass[i].f.y = 0;
if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
}
for(int i=0; i<NumEdges/2; i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1, point2);
if(r12 != 0){
v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
F = (point1-point2)/r12 * f;
mass[spring[i].p1].f -= F;
mass[spring[i].p2].f += F;
}
spring[i].n = normalize(point1-point2);
}
volume = VolumeBall();
for(int i=0;i<NumEdges/2;i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1,point2);
pressurev = r12 * Pressure * (1.0f/volume);
mass[spring[i].p1].f += spring[i].n * pressurev;
mass[spring[i].p2].f += spring[i].n * pressurev;
}
}
euler integrator
void IntegrateEuler(){
float dry,drx,drz;
for(int i=0;i<NumVertices;i++){
mass[i].v.x = mass[i].v.x + (mass[i].f.x/Mass) * DT;
drx = mass[i].v.x * DT;
if(points[i].x + drx < -SCRSIZE){
drx = -SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].x + drx > SCRSIZE){
drx = SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].x = points[i].x + drx;
mass[i].v.y = mass[i].v.y + (mass[i].f.y/Mass) * DT;
dry = mass[i].v.y * DT;
if(points[i].y + dry < -SCRSIZE){
dry = -SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].y + dry > SCRSIZE){
dry = SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].y = points[i].y + dry;
mass[i].v.z = mass[i].v.z + (mass[i].f.z/Mass) * DT;
drz = mass[i].v.z * DT;
if(points[i].z + drz < -SCRSIZE){
drz = -SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
if(points[i].z + drz > SCRSIZE){
drz = SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
points[i].z = points[i].z + drz;
if(points[i].x > SCRSIZE)
points[i].x = SCRSIZE;
if(points[i].y > SCRSIZE)
points[i].y = SCRSIZE;
if(points[i].z > SCRSIZE)
points[i].z = SCRSIZE;
if(points[i].x < -SCRSIZE)
points[i].x = -SCRSIZE;
if(points[i].y < -SCRSIZE)
points[i].y = -SCRSIZE;
if(points[i].z < -SCRSIZE)
points[i].z = -SCRSIZE;
}
}
if you are interested, whole code with shaders.
#include "Angel.h"
#define Mass 1.0f
#define KS 1755.0f
#define KD 35.0f
#define GY -10.0f
#define BALLRADIUS 0.516f
#define DT 0.011f
#define FINAL_PRESSURE 85.0f
#define SCRSIZE 7
typedef Angel::vec4 color4;
typedef Angel::vec4 point4;
const int CircleVertices = 8;
const int NumCirclesx2 = 20;
const int NumVertices = CircleVertices * (NumCirclesx2/2-1) + 2;
const int NumEdges = (NumVertices-2)*4+CircleVertices*2;
point4 points[NumVertices];
GLfloat w = 512, h = 512;
//-----------------------------------------------------------------
float xLeft = -2.0;
float xRight = 2.0;
float yBottom = -2.0;
float yTop = 2.0;
float zNear = -4.0;
float zFar = 4.0;
float aspectx = 1;
float aspecty = 1;
//-----------------------------------------------------------------
GLuint vModel;
GLuint vProjection;
GLuint vView;
//------------------------------------------------------------------
typedef struct {
vec3 v;
vec3 f;
} PointMass;
typedef struct {
int p1,p2;
int index;
float length;
vec3 n;
} Spring;
PointMass mass[NumVertices];
Spring spring[NumEdges/2];
float Pressure = 0;
//------------------------------------------------------------------
point4 edges[NumEdges];
point4 b[5];
point4 c[5];
static int k = 0;
//view angle
const float dr = 5.0 * DegreesToRadians;
float theta = 0;
float phi = 0;
float distance(vec4 a, vec4 b){
return sqrt((a.x - b.x) * (a.x - b.x)+(a.y - b.y) * (a.y - b.y)+(a.z - b.z) * (a.z - b.z));
}
float distance(vec3 a, vec3 b){
return sqrt((a.x - b.x) * (a.x - b.x)+(a.y - b.y) * (a.y - b.y)+(a.z - b.z) * (a.z - b.z));
}
float innerprod(vec3 a, vec3 b){
vec3 c = a * b;
return c.x+c.y+c.z;
}
void
InitPoints()
{
float dxy = (360.0 * DegreesToRadians) / CircleVertices;
float dz = (360.0 * DegreesToRadians) / NumCirclesx2;
points[0] = vec4( 0.0, 1.0, 0.0, 1.0);
for(int j=1;j<NumCirclesx2/2;j++){
for(int i=0;i<CircleVertices;i++){
points[(j-1)*CircleVertices + i+1] = vec4(BALLRADIUS * sin(i * dxy)*sin(j*dz), BALLRADIUS *cos(j*dz), BALLRADIUS *cos(i * dxy)*sin(j*dz), 1.0);
}
}
points[NumVertices-1] = vec4( 0.0, -1.0, 0.0, 1.0);
}
void
InitEdges(){
int k = 0;
for(int j=0;j<CircleVertices;j++){
edges[4*j] = points[1+j];
edges[4*j+1] = points[0];
spring[k].p1 = 0;
spring[k].p2 = 1+j;
spring[k].index = 4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[4*j+2] = points[(1+j)];
spring[k].p1 = 1+j;
spring[k].index = 4*j+2;
if(2+j == CircleVertices){
edges[4*j+3] = points[(2+j)];
spring[k].p2 = 2+j;
}
else{
edges[4*j+3] = points[(2+j)%(CircleVertices)];
spring[k].p2 = (2+j)%(CircleVertices);
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
for(int i=1;i<NumCirclesx2/2-1;i++){
for(int j=0;j<CircleVertices;j++){
edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].p2 = (i-1)*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
spring[k].p1 = i*CircleVertices+1+j;
spring[k].index = i*CircleVertices*4+4*j+2;
if(2+j == CircleVertices){
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
spring[k].p2 = i*CircleVertices+(2+j);
}
else {
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
spring[k].p2 = i*CircleVertices+(2+j)%CircleVertices;
}
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
}
}
for(int j=0;j<CircleVertices;j++){
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j] = points[NumVertices-1];
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
spring[k].p1 = (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1;
spring[k].p2 = NumVertices-1;
spring[k].index = (NumCirclesx2/2-1)*CircleVertices*4+2*j;
spring[k].length = distance(points[spring[k].p1],points[spring[k].p2]);
k++;
cout << NumVertices-1 << " " << (NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1 << endl;
}
}
void updateEdge(){
for(int j=0;j<CircleVertices;j++){
edges[4*j] = points[1+j];
edges[4*j+1] = points[0];
edges[4*j+2] = points[(1+j)];
if(2+j == CircleVertices){
edges[4*j+3] = points[(2+j)];
}
else{
edges[4*j+3] = points[(2+j)%(CircleVertices)];
}
}
for(int i=1;i<NumCirclesx2/2-1;i++){
for(int j=0;j<CircleVertices;j++){
edges[i*CircleVertices*4+4*j] = points[i*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+1] = points[(i-1)*CircleVertices+1+j];
edges[i*CircleVertices*4+4*j+2] = points[i*CircleVertices+1+j];
if(2+j == CircleVertices){
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)];
}
else {
edges[i*CircleVertices*4+4*j+3] = points[i*CircleVertices+(2+j)%CircleVertices];
}
}
}
for(int j=0;j<CircleVertices;j++){
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j] = points[NumVertices-1];
edges[(NumCirclesx2/2-1)*CircleVertices*4+2*j+1] = points[(NumCirclesx2/2-1)*CircleVertices-CircleVertices+j+1];
}
}
float VolumeBall(){
float minx = 100000,miny = 100000,minz = 100000, maxx = -100000, maxy = -100000, maxz = -100000;
for(int i = 0; i<NumVertices; i++){
if(points[i].x < minx) minx = points[i].x;
if(points[i].y < miny) miny = points[i].y;
if(points[i].z < minz) minz = points[i].z;
if(points[i].x > maxx) maxx = points[i].x;
if(points[i].y > maxy) maxy = points[i].y;
if(points[i].z > maxz) maxz = points[i].z;
}
return (maxx - minx) * (maxz - minz) * (maxy - miny);
}
void AccumulateForces(){
vec3 point1, point2,point3,point4;
float r12;
vec3 v12;
float f;
vec3 F;
vec3 norm;
bool flag = true;
float volume=0;
float pressurev;
for(int i =0; i<NumVertices; i++){
mass[i].f.x = 0;
mass[i].f.z = 0;
mass[i].f.y = 0;
if(Pressure - FINAL_PRESSURE >= 0) mass[i].f.y = Mass * GY;
}
for(int i=0; i<NumEdges/2; i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1, point2);
if(r12 != 0){
v12 = mass[spring[i].p1].v - mass[spring[i].p2].v;
f = (r12 - spring[i].length) * KS + innerprod(v12,point1 - point2) * KD / r12;
F = (point1-point2)/r12 * f;
mass[spring[i].p1].f -= F;
mass[spring[i].p2].f += F;
}
spring[i].n = normalize(point1-point2);
// if(flag){
// point3 = vec3(points[spring[i+1].p1].x,points[spring[i+1].p1].y,points[spring[i+1].p1].z);
// point4 = vec3(points[spring[i+1].p2].x,points[spring[i+1].p2].y,points[spring[i+1].p2].z);
// norm = cross(point1-point2, point3-point4);
// norm = normalize(norm);
// spring[i].n = norm;
// flag = false;
// }
// else{
// spring[i].n = norm;
// flag = true;
// }
}
// for(int i=0; i< NumEdges/2; i++){
// point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
// point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
// r12 = distance(point1, point2);
// volume += 0.5 * abs(point1.x-point2.x) * abs(spring[i].n.x) * r12;
// }
volume = VolumeBall();
for(int i=0;i<NumEdges/2;i++){
point1 = vec3(points[spring[i].p1].x,points[spring[i].p1].y,points[spring[i].p1].z);
point2 = vec3(points[spring[i].p2].x,points[spring[i].p2].y,points[spring[i].p2].z);
r12 = distance(point1,point2);
pressurev = r12 * Pressure * (1.0f/volume);
mass[spring[i].p1].f += spring[i].n * pressurev;
mass[spring[i].p2].f += spring[i].n * pressurev;
}
}
void IntegrateEuler(){
float dry,drx,drz;
for(int i=0;i<NumVertices;i++){
mass[i].v.x = mass[i].v.x + (mass[i].f.x/Mass) * DT;
drx = mass[i].v.x * DT;
if(points[i].x + drx < -SCRSIZE){
drx = -SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].x + drx > SCRSIZE){
drx = SCRSIZE - points[i].x;
mass[i].v.x = -0.1 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].x = points[i].x + drx;
mass[i].v.y = mass[i].v.y + (mass[i].f.y/Mass) * DT;
dry = mass[i].v.y * DT;
if(points[i].y + dry < -SCRSIZE){
dry = -SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
if(points[i].y + dry > SCRSIZE){
dry = SCRSIZE - points[i].y;
mass[i].v.y = -0.1 * mass[i].v.y;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.z = 0.95 * mass[i].v.z;
}
points[i].y = points[i].y + dry;
mass[i].v.z = mass[i].v.z + (mass[i].f.z/Mass) * DT;
drz = mass[i].v.z * DT;
if(points[i].z + drz < -SCRSIZE){
drz = -SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
if(points[i].z + drz > SCRSIZE){
drz = SCRSIZE - points[i].z;
mass[i].v.z = -0.1 * mass[i].v.z;
mass[i].v.x = 0.95 * mass[i].v.x;
mass[i].v.y = 0.95 * mass[i].v.y;
}
points[i].z = points[i].z + drz;
if(points[i].x > SCRSIZE)
points[i].x = SCRSIZE;
if(points[i].y > SCRSIZE)
points[i].y = SCRSIZE;
if(points[i].z > SCRSIZE)
points[i].z = SCRSIZE;
if(points[i].x < -SCRSIZE)
points[i].x = -SCRSIZE;
if(points[i].y < -SCRSIZE)
points[i].y = -SCRSIZE;
if(points[i].z < -SCRSIZE)
points[i].z = -SCRSIZE;
}
}
// OpenGL initialization
void
init()
{
InitPoints();
InitEdges();
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and initialize a buffer object put all of the object in the same buffer to speed things up
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(edges), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(edges), edges);
// Load shaders and use the resulting shader program
GLuint program = InitShader("vshader.glsl", "fshader.glsl");
glUseProgram(program);
// set up vertex arrays
GLuint vPosition = glGetAttribLocation(program, "vPosition");
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 4, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0));
// uniform variables in the shader
GLuint vColor = glGetUniformLocation(program, "vColor");
glUniform4fv(vColor, 1, color4(1.0,0.0,0.0,1.0));
vView = glGetUniformLocation(program, "vView");
vProjection = glGetUniformLocation(program, "vProjection");
//glEnable(GL_DEPTH_TEST);
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
//----------------------------------------------------------------------------
void
display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
point4 at( 0.0, 0.0, 0.0, 1.0 );
point4 eye( 0.5*sin(theta)*cos(phi), 0.5*sin(phi), -cos(theta)*0.5*cos(phi), 1.0 );
vec4 up( 0.0, 1.0, 0.0, 0.0 );
updateEdge();
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(edges), edges);
mat4 view = LookAt( eye, at, up );
glUniformMatrix4fv(vView, 1, GL_TRUE, view);
glUniformMatrix4fv(vProjection, 1, GL_TRUE,
Ortho( -SCRSIZE, SCRSIZE, -SCRSIZE, SCRSIZE, zNear, zFar ));
// Ortho( aspectx*xLeft, aspectx*xRight, aspecty*yBottom, aspecty*yTop, zNear, zFar ));
glDrawArrays(GL_LINES, 0, NumEdges);
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void
keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'i':
case 'I': aspectx=aspectx*0.9;aspecty=aspecty*0.9;break;
case 'o':
case 'O': aspectx=aspectx*1.1;aspecty=aspecty*1.1;break;
case 033: // Escape Key
// 'q' exits
case 'q': case 'Q': exit(EXIT_SUCCESS); break;
}
}
//----------------------------------------------------------------------------
//special keyboard function catches special keyboard inputs such as arrow keys.
void SpecialKeyboard(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT: theta += dr; break;
case GLUT_KEY_RIGHT: theta -= dr; break;
case GLUT_KEY_UP: phi += dr; break;
case GLUT_KEY_DOWN: phi -= dr; break;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
void timer(int)
{
AccumulateForces();
IntegrateEuler();
if(Pressure < FINAL_PRESSURE)
{
Pressure += FINAL_PRESSURE/100.0f;
printf("Pressure = %4.4f\n",Pressure);
}
glutPostRedisplay();
glutTimerFunc(1000, timer, 0);
}
// void
// idle(void)
// {
// AccumulateForces();
// IntegrateEuler();
// if(Pressure < FINAL_PRESSURE)
// {
// Pressure += FINAL_PRESSURE/100.0f;
// printf("Pressure = %4.4f\n",Pressure);
// }
// glutPostRedisplay();
// }
//----------------------------------------------------------------------------
void reshape(GLsizei ww, GLsizei hh)
{
glViewport( 0, 0, ww, hh );
aspectx = (GLfloat)ww/w;
aspecty = (GLfloat)hh/h;
w = ww;
h = hh;
}
int
main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(512, 512);
glutInitContextVersion(3, 2);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow("Free Fall");
glewExperimental = GL_TRUE;
glewInit();
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutSpecialFunc(SpecialKeyboard);
glutTimerFunc(1000.0/60.0, timer, 0);
// glutIdleFunc(idle);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
#version 150
in vec4 vPosition;
uniform vec4 vColor;
uniform mat4 vView;
uniform mat4 vProjection;
out vec4 color;
void main()
{
gl_Position = vProjection*vView*vPosition;
color = vColor;
}
#version 150
in vec4 color;
out vec4 fColor;
void main()
{
fColor = color;
}
Recently i implemented a simple Opengl program that composes of a scene of objects, i've applied most of the transformation & projection matrices, in such away that i am able to rotate transform & scale objects, move my camera through z & x coordinates and applied perspective projection however when it comes to camera rotation things get weird, my rotation matrix for my camera is simply a rotation matrix that rotates the world uniformly, however when i rotate the world so that i look in the up direction;+y; and when i move forward, the camera doesn't seem to advance in the direction where it is looking at;as it is the case in FPS games my camera moves relative to the world space, i know that i am missing the vectors that specify directions in x,y,z coordinates, but i am unable to incorporate these vectors with my camera (view Transformation) matrix, most of the tutorial on internet either describes it in a block diagram or uses the conventional gluLookAt() function, i really need a brief explanation about view Transformations and specifically camera rotation and how i should implement it in my matrices, my my final matrix is as follows:
resultTransform = perspectiveTrans * cameraTrans * modelTrans;
where:
perspectiveTrans = applies only a perspective projection transformation
cameraTrans = is a combination of rotate,translate matrices that affect all obj.s in the scene
modelTrans =is the transformation that is applied to the models
Matrix4X4.cpp file:
#include "Matrix4X4.h"
using namespace std;
////////////////////////////////// Constructor Declerations ////////////////////////////////
Matrix4X4::Matrix4X4()
{
setIdentity();
}
Matrix4X4::Matrix4X4(float value)
{
for(int i = 0 ; i < 4; i++)
for ( int j = 0; j < 4; j++)
Matrix[i][j] = value;
}
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////// Destructor Decleration //////////////////////////////
Matrix4X4::~Matrix4X4()
{
}
///////////////////////////////////////////////////////////////////////////////////
/////////////////////// Set Identity Matrix /////////////////////////////////////////
void Matrix4X4::setIdentity()
{
Matrix[0][0] =1; Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = 0;
Matrix[1][0] =0; Matrix[1][1] = 1; Matrix[1][2] = 0; Matrix[1][3] = 0;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = 1; Matrix[2][3] = 0;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0; Matrix[3][3] = 1;
}
///////////////////////////////////////////////////////////////////////////////////
///////////////////////// Set Translation Matrix //////////////////////////////////
Matrix4X4 Matrix4X4::setTranslation(float x,float y,float z)
{
Matrix[0][0] =1; Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = x;
Matrix[1][0] =0; Matrix[1][1] = 1; Matrix[1][2] = 0; Matrix[1][3] = y;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = 1; Matrix[2][3] = z;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0; Matrix[3][3] = 1;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Set Rotation Matrix ///////////////////////////////////////////
Matrix4X4 Matrix4X4::setRotation(float x,float y,float z)
{
Matrix4X4 xRot;
Matrix4X4 yRot;
Matrix4X4 zRot;
x = (float)x * 3.14/ 180.0;
y = (float)y * 3.14/ 180.0;
z = (float)z * 3.14/ 180.0;
xRot.Matrix[0][0] =1; xRot.Matrix[0][1] = 0; xRot.Matrix[0][2] = 0; xRot.Matrix[0][3] = 0;
xRot.Matrix[1][0] =0; xRot.Matrix[1][1] = cosf(x); xRot.Matrix[1][2] = -sinf(x); xRot.Matrix[1][3] = 0;
xRot.Matrix[2][0] =0; xRot.Matrix[2][1] = sinf(x); xRot.Matrix[2][2] = cosf(x); xRot.Matrix[2][3] = 0;
xRot.Matrix[3][0] =0; xRot.Matrix[3][1] = 0; xRot.Matrix[3][2] = 0; xRot.Matrix[3][3] = 1;
yRot.Matrix[0][0] = cosf(y); yRot.Matrix[0][1] = 0; yRot.Matrix[0][2] = -sinf(y); yRot.Matrix[0][3] = 0;
yRot.Matrix[1][0] =0; yRot.Matrix[1][1] = 1; yRot.Matrix[1][2] = 0; yRot.Matrix[1][3] = 0;
yRot.Matrix[2][0] = sinf(y); yRot.Matrix[2][1] = 0; yRot.Matrix[2][2] = cosf(y); yRot.Matrix[2][3] = 0;
yRot.Matrix[3][0] =0; yRot.Matrix[3][1] = 0; yRot.Matrix[3][2] = 0; yRot.Matrix[3][3] = 1;
zRot.Matrix[0][0] = cosf(z); zRot.Matrix[0][1] = -sinf(z); zRot.Matrix[0][2] = 0; zRot.Matrix[0][3] = 0;
zRot.Matrix[1][0] = sinf(z); zRot.Matrix[1][1] = cosf(z); zRot.Matrix[1][2] = 0; zRot.Matrix[1][3] = 0;
zRot.Matrix[2][0] =0; zRot.Matrix[2][1] = 0; zRot.Matrix[2][2] = 1; zRot.Matrix[2][3] = 0;
zRot.Matrix[3][0] =0; zRot.Matrix[3][1] = 0; zRot.Matrix[3][2] = 0; zRot.Matrix[3][3] = 1;
return (zRot * yRot * xRot) ;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////// Set Scale Matrix //////////////////////////////////////////
Matrix4X4 Matrix4X4::setScale(float x,float y,float z)
{
Matrix[0][0] =x; Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = 0;
Matrix[1][0] =0; Matrix[1][1] = y; Matrix[1][2] = 0; Matrix[1][3] = 0;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = z; Matrix[2][3] = 0;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 0; Matrix[3][3] = 1;
return *this;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Set Perspective Projection ///////////////////////////////////////
void Matrix4X4::setPerspective(float fov,float aRatio,float zNear,float zFar)
{
fov = (fov/2) * 3.14 / 180.0;
float tanHalfFOV = tanf(fov);
float zRange = zNear - zFar;
Matrix[0][0] =1.0f / (tanHalfFOV * aRatio); Matrix[0][1] = 0; Matrix[0][2] = 0; Matrix[0][3] = 0;
Matrix[1][0] =0; Matrix[1][1] = 1.0f / tanHalfFOV; Matrix[1][2] = 0; Matrix[1][3] = 0;
Matrix[2][0] =0; Matrix[2][1] = 0; Matrix[2][2] = (-zNear - zFar)/ zRange; Matrix[2][3] = 2* zFar * zNear / zRange;
Matrix[3][0] =0; Matrix[3][1] = 0; Matrix[3][2] = 1; Matrix[3][3] = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// Getters & Setters ////////////////////////////////////////////
float * Matrix4X4::getMat()
{
return (float *) Matrix;
}
float Matrix4X4::getMember(int x, int y) const
{
return Matrix[x][y];
}
void Matrix4X4::setMat(int row,int col,float value)
{
Matrix[row][col] = value;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// (*) Operator Overload //////////////////////////////////////
Matrix4X4 operator * (const Matrix4X4 & lhs,const Matrix4X4 & rhs)
{
Matrix4X4 result;
for(int i = 0 ; i < 4; i++)
for ( int j = 0; j < 4; j++)
result.setMat(i, j, lhs.getMember(i,0) * rhs.getMember(0, j) +
lhs.getMember(i,1) * rhs.getMember(1, j) +
lhs.getMember(i,2) * rhs.getMember(2, j) +
lhs.getMember(i,3) * rhs.getMember(3, j));
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
the Transformation code i use in my main block:
SDL_PumpEvents();
for (int x = 0; x< 256; x++)
{
if (state[x] == 1 )
{
if(x == 26)
tranForward -= 0.001;
if (x == 22)
tranForward += 0.001;
if (x == 4)
tranRight += 0.0009;
if (x == 7)
tranRight -= 0.0009;
if (x == 82)
lookUp += 0.02;
if (x == 81)
lookUp -= 0.02;
if (x == 80)
lookRight -= 0.02;
if (x == 79)
lookRight += 0.02;
}
}
modelTrans = Translation.setTranslation(0, 0, 5) * Scale.setScale(0.5, 0.5, 0.5);
camTrans = Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward);
Projection.setPerspective(70, win.getWidth()/win.getHeight(), 0.1, 1000);
result = Projection * camTrans * modelTrans;
glUniformMatrix4fv(uniformloc, 1, GL_TRUE, result.getMat());
The matrix multiplication does not have the same rules as the scalar multiplication and in your case A*B does NOT equal B*A when multiplying the matrices. If rest of the code is good your solution might simply be turning
result = Projection * camTrans * modelTrans;
into
result = Projection * (modelTrans * camTrans);
Do alway watch out for both, multiplication order and parentheses when dealing with anything but scalar values.
In general when you are combining a translation and rotation matrix you need to think in matrix own space coordinate system, that means like playing a FPS:
Multiplying rotation*translation means the object will rotate first and then translate meaning the object position will depend on the rotation being already applied and a 180 degrees rotation will translate the object backwards from the 3rd view perspective.
Multiplying translation*rotation means the object will translate first and then rotate meaning it will in fact be moved into the same direction no matter the rotation, only the direction of where the object is facing will be changed by rotation matrix.
Just a nice example, if you want to present a movement of earth around sun (the earth is circling the sun while rotating around its own axis being on some radius):
Matrix4X4 orbitRotation; //rotation matrix for where in orbit the object is
Matrix4X4 objectRotation; //object rotation around its own axis
Matrix4X4 orbitRadius; //object orbit radius
Matrix4X4 result = (orbitRotation*orbitRadius)*objectRotation;
my code seemed to ignore the previous matrix calculation and re calculated the transformations with respect to my scene's initial state, the desired world rotation & Translation is achieved by using a fixed value for rotation & Translation, the modified code blocks are as follows:
for (int x = 0; x< 256; x++)
{
if (state[x] == 1 )
{
if(x == 26)
tranForward = -0.001;
if (x == 22)
tranForward = 0.001;
if (x == 4)
tranRight = 0.0009;
if (x == 7)
tranRight = -0.0009;
if (x == 82)
lookUp = 0.02;
if (x == 81)
lookUp = -0.02;
if (x == 80)
lookRight = -0.02;
if (x == 79)
lookRight = 0.02;
}
}
camTrans = Rotation.setRotation(lookUp, lookRight, 0) * Translation.setTranslation(tranRight, 0, tranForward);
result = camTrans * result;
modelTrans = Projection * result;
tranForward = 0.0;
tranRight = 0.0;
lookUp = 0.0;
lookRight = 0.0;
glUniformMatrix4fv(uniformloc, 1, GL_TRUE, modelTrans.getMat());
note that result matrix keeps track of the previous state and the current state transformations are applied with respect to it.