OpenGL:How to make a "Polyman's" mouth open - c++
I'm writing a program that has a polygon "man" walk from one side of the screen to the middle, open his mouth, jump up and do a flip, land, close his mouth, and walk left off the screen. I am a bit confused on how to make the lad's mouth open. I was thinking I could create a triangle of appropriate size the same color as the background and slowly translate it to where his mouth would be. What steps would I need to go through to make this possible, and where would I put the code to do so?
#include<Windows.h>
#include<GL/glut.h>
#include<stdlib.h>
#include<math.h>
#include<conio.h>
#include<stdio.h>
#include<iostream>
#include<iomanip>
#include<gl/glut.h>
using namespace std;
//***********************GLOBAL VALUES*********************************************
float theta=00.0; //global angular value for rotation
float scale1=1.0; //global scaling value
float dx=7.0,dy=-3.0;
int frame = 1;
void init(void); //This is a function to initialize the window clear color
void RenderScene(void); //This a function to draw polyman in an opened window
void loadicon(float[],float[],float[],float[], float[], float[]); //Load the polyman icon
void drawicon(float[],float[],float[],float[], float[], float[]); //Draw the icon the two first float for the square and the others for the line
void settrans(float[][3],float,float,float); //Sets the transformation matrix for desired scale, rotation, new pos
float xprime(float,float,float[][3]); //Calculates x' from x and transform
float yprime(float,float,float[][3]); //Calculates y' from y and transform
void transform(float[],float[],float[],float[], float[], float[], float[][3],float[],float[],float[],float[], float[], float[]); //performs the transformation on the icon pattern
void myidle(void);
void SetupRC(void); //Sets up the clear color
void TimerFunction(int); //This call back function is called each 30ms and changes the location, scale and rotation
//***********************MAIN PROGRAM**********************************************
int main(int argc, char** argv)
{
//Set up window title
char header[]="Polyman's journey";
glutInit(&argc,argv);
//Set up the display mode with two buffers and RGB colors
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
//Initialize window size and position
glutInitWindowSize(560,440);
glutInitWindowPosition(140,20);
//Initialize background color of the window
SetupRC();
//Open and label window
glutCreateWindow(header);
glutDisplayFunc(RenderScene);
glutTimerFunc(30,TimerFunction, 1); //Call the TimerFunction each 30s
//Now draw the scene
glutMainLoop();
return 0;
}
//*************************RenderScene Function*************************************
void RenderScene(void)
{
float xdel=0.25;
float px[7],py[7],plx[4],ply[4], pl2x[4], pl2y[4];// These variables hold the pattern for the icon square plus line
float pxp[7],pyp[7],plxp[4],plyp[4], pl2xp[4], pl2yp[4],t[3][3]; //These varables hold the pattern after transformation, t is the transformation matrix
//clear the window with the current background color
cout<<"in RenderScene"<<endl;
//set the current drawing color to white
glColor3f(1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//set the viewport to the window dimensions
glViewport(0,0,560,440);
//Establish the clipping volumn in user units, first clear all the translation matrices
glOrtho(-7.0,7.0,-7.0,7.0,1.0,-1.0);
loadicon(px,py,plx,ply, pl2x, pl2y);
//draw the icon untransformed
settrans(t,scale1,dx,dy);
transform(pxp,pyp,plxp,plyp,pl2xp,pl2yp, t,px,py,plx,ply, pl2x, pl2y);
//clear the window with the background color
glClear(GL_COLOR_BUFFER_BIT);
//set the current drawing color to white
glColor3f(1.0,1.0,1.0);
//now draw the figure
drawicon(pxp,pyp,plxp,plyp,pl2xp, pl2yp);
glEnd();
glutSwapBuffers();
return;
}//end of render scene
//************************LOAD ICON FUNCTION***********************************
void loadicon(float px[],float py[],float plx[],float ply[],float pl2x[],float pl2y[]) //Loads the polyman
{
//Set the coordinates of the square
px[0]=-0.625 ; py[0]=0.625 ;
px[1]=0.625 ; py[1]=0.625 ;
px[2]=1.0 ; py[2]=0.0 ;
px[3]=0.625 ; py[3]=-0.625 ;
px[4]=-0.625 ; py[4]=-0.625 ;
px[5]= -1.0 ; py[5]= 0.0 ;
px[6]=-0.625 ; py[6]=0.625 ;
//set the right foot
plx[0]= 0.25 ; ply[0]= -0.625 ;
plx[1]= 0.25 ; ply[1]= -0.875 ;
plx[2]= 0.0 ; ply[2]= -0.875 ;
plx[3] = 0.25 ; ply[3] = -0.875;
//set the left foot
pl2x[0]= -0.125 ; pl2y[0]= -0.375 ;
pl2x[1]= -0.125 ; pl2y[1]= -0.875 ;
pl2x[2]= -0.375 ; pl2y[2]= -0.875 ;
pl2x[3]= -0.125 ; pl2y[3]= -0.875 ;
return;
} //end of loadicon
//************************FUNCTION DRAWICON***********************************
void drawicon(float pxp[],float pyp[],float plxp[],float plyp[], float pl2xp[], float pl2yp[])
{
//draw the square icon at the transformed position
int i;
cout<<"in drawicon"<<endl;
glBegin(GL_LINE_STRIP);
//move to first point in the icon
glVertex2f(pxp[0],pyp[0]);
//now draw the rest of the box
for(i = 1; i <= 6; i++)
{
glVertex2f(pxp[i],pyp[i]);
}
glEnd();
//now draw the line
glBegin(GL_LINES);
glVertex2f(plxp[0],plyp[0]);
for (i=1; i <=3; i++)
{
glVertex2f(plxp[i],plyp[i]);
}//glVertex2f(plxp[2],plyp[2]);
glEnd();
glBegin(GL_LINES);
glVertex2f(pl2xp[0], pl2yp[0]);
for (i=1; i <=3; i++)
{
glVertex2f(pl2xp[i], pl2yp[i]);
}
glEnd();
//now fill the rectangle which is made by half of the square
//set the shading color to green
glColor3f(0.0,1.0,0.0);
glShadeModel(GL_FLAT);
//redraw the polygon
glBegin(GL_POLYGON);
//Firts point is where the line intersects the top of the square
glVertex2f(pxp[0], pyp[0]);
//rigth corner upper
glVertex2f(pxp[1],pyp[1]);
//right corner lower
glVertex2f(pxp[2],pyp[2]);
//left intersect
glVertex2f(pxp[3],pyp[3]);
glVertex2f(pxp[4],pyp[4]);
glVertex2f(pxp[5],pyp[5]);
glVertex2f(pxp[6],pyp[6]);
return;
} //end of draw icon
//************************FUNCTION SETTRANS***********************************
void settrans(float t[][3],float scale1,float dx,float dy)
{
cout<<"in settrans"<<endl;
int i,j;
float ts,ct,st;
double theta1;
//setup identity matrix
for(i=0;i<=2;i++)
{
for(j=0;j<=2;j++)
{
t[i][j]=0.0;
if(i==j) t[i][j]=1.0;
}
}
//set scale parameters
if(scale1!=-9.0)
{
t[0][0]=scale1;
t[1][1]=scale1;
}
if(theta!=-9.0)
{
theta1=(3.1416/180.0)*theta;
ct=cos(theta1);
st=sin(theta1);
ts=t[0][0];
t[0][0]=ts*ct;
t[0][1]=ts*st;
ts=t[1][1];
t[1][0]=-ts*st;
t[1][1]=ts*ct;
}
//translate the figure
if((dx+dy) != -18.0)
{
t[2][0]=dx;
t[2][1]=dy;
}
return;
}//end of settrans
//************************FUNCTION XPRIME***********************************
float xprime(float x1,float y1, float t[][3])
{
//this function pultiples the x vector by the transformation matrix
float xp1;
xp1=x1*t[0][0]+y1*t[1][0]+t[2][0];
return xp1;
}
//************************FUNCTION YPRIME***********************************
float yprime(float x1,float y1, float t[][3])
{
//this function pultiples the y vector by the transformation matrix
float yp1;
yp1=x1*t[0][1]+y1*t[1][1]+t[2][1];
return yp1;
}
//************************FUNCTION TRANSFORM***********************************
void transform(float pxp[],float pyp[],float plxp[],float plyp[],float pl2xp[],float pl2yp[],float t[][3],float px[],float py[],float plx[],float ply[], float pl2x[], float pl2y[])
{
int i;
cout<<"in transform"<<endl;
//transform the figure
for(i=0;i<=6;i++)
{
pxp[i] = xprime(px[i],py[i],t);
pyp[i] = yprime(px[i],py[i],t);
}
//transform the line
for(i=0;i<=3;i++)
{
plxp[i] = xprime(plx[i],ply[i],t);
plyp[i] = yprime(plx[i],ply[i],t);
}
for(i=0;i<=3;i++)
{
pl2xp[i] = xprime(pl2x[i],pl2y[i],t);
pl2yp[i] = yprime(pl2x[i],pl2y[i],t);
}
return;
}//end of transform
//************************ FUNCTION SetupRC***********************************
void SetupRC(void)
{
//sets the clear color of an open window and clears the open window
//set clear color to green
glClearColor(0.0,1.0,0.0,1.0);
return;
}//end of setupRC
//************************ FUNCTION Timer***********************************
void TimerFunction(int value)
{
//this call back function is called each 30ms and changes the location, scale and rotation
static float swc=0.1,sdx=0.1,sdy=0.1;
switch(frame)
{
case 1:
//theta+=5.0;
dx-=0.15;
if(dx<=0.0)
{
dx=0.0;
frame=2;
}
break;
case 2:
dy+=0.2;
if(dy>5.0)
{
dy=5.0;
frame=3;
}
break;
case 3:
theta+=5.0;
if(theta>360.0)
{
frame=4;
theta=0.0;
scale1=1.0;
}
break;
case 4:
dy-=0.2;
if(dy<=-3.0)
{
dy=-3.0;
frame=5;
}
break;
case 5:
dx-=0.15;
//theta+=5.0;
if(dx<=-8.0) dx=-8.0;
break;
}
//redraw the scene with new coordinate
glutPostRedisplay();
glutTimerFunc(33,TimerFunction,1);
}
Also, we aren't allowed to use any of the built in translate, rotate, or scale functions that OpenGL provides since it's our first assignment. Thanks for all the help, I really appreciate it.
Related
(SFML)Player constructor not updating with correct animation when key is pressed
My sprite moves to the left, right, up and down when the correct corresponding key is pressed but only the row 0 animation is used, but for some odd reason when I press two keys at the same time like (W,A) or (S, D) is transfer to opposite animation to which side it is moving. I tried moving the if statements directing the animation update to a nested if statement inside the key press if statements and that did nothing good, I then tried just having it update based off the key press with no nested if statement, that also did not work... I am new to SFML so this is really hurting my head to figure this out, also I do not mind criticism, please if you see something I could be doing better in terms of sprite movement, let me know! Thanks for your help. Below is my player class constructor #include "Player.h" Player::Player(Texture* texture, Vector2u imageCount, float switchTime, float speed) : // initializer list from animation.cpp animation(texture, imageCount, switchTime) { this->speed = speed; row = 0; body.setSize(Vector2f(100.0f, 150.0f)); body.setTexture(texture); //sets initial position for test sprite sheet body.setPosition(550.0f, 900.0f); } Player::~Player() { } void Player::Update(float deltaTime) { Vector2f movement(0.0f, 0.0f); if (Keyboard::isKeyPressed(Keyboard::A)) { //if A is pressed move to the left on the x axis movement.x -= speed * deltaTime; } if (Keyboard::isKeyPressed(Keyboard::D)) { //if D is pressed move to the right on the x axis movement.x += speed * deltaTime; } if (Keyboard::isKeyPressed(Keyboard::W)) { // if W is pressed move up on the y axis movement.y += speed * deltaTime; } if (Keyboard::isKeyPressed(Keyboard::S)) { // if S is pressed move down on the y axis movement.y -= speed * deltaTime; } if (movement.x == 0.0f || movement.y == 0.0f)//for idle animation { row = 0;//idle row for now just using walking until I get idle animation } else if(movement.x > 0.0f) { row = 1; //walking to the left animation } else if (movement.x < 0.0f ) { row = 3; //walking to the right animation } else if (movement.y > 0.0f) { row = 0; // walking to stright animation } else if (movement.y < 0.0f) { row = 2;// walking back animation } animation.Update(row, deltaTime); body.setTextureRect(animation.uvRect); body.move(movement); } void Player::Draw(RenderWindow& window) { window.draw(body); } Below is my player class initialization #pragma once #include <SFML/Graphics.hpp> #include "Animation.h" using namespace std; using namespace sf; class Player { public: Player(Texture* texture, Vector2u imageCount, float switchTime, float speed); ~Player(); void Update(float deltaTime); void Draw(RenderWindow& window); private: RectangleShape body; Animation animation; unsigned int row; float speed; }; Below Game while loop and the Player function call Player player(&playerTexture, Vector2u(9, 4), 0.09f, 100.0); //************************************************************* //clock & Time float deltaTime = 0.0f; Clock clock; while (window.isOpen()) { deltaTime = clock.restart().asSeconds(); //********************************************************* //Player Input if (Keyboard::isKeyPressed(Keyboard::Escape)) { window.close(); } //********************************************************** //draws everything player.Update(deltaTime); window.clear(); window.draw(spritestartingBG); player.Draw(window); window.display(); } return 0; }
if (movement.x == 0.0f || movement.y == 0.0f) will be true unless moving diagonally-- you probably want the || to be &&. Similarly, your left/right animations are reversed--you're moving left when movement.x is < 0.0, not > 0.0.
OpenGL ray OBB intersection
I want to implement object picking in 3D so I have a Ray from a point on the screen towards the scene using glm::unproject method "it returns the Y flipped so I use its negative value", the following code success always when the object is centered on the world origin but with another object that is transformed and the camera moved or rotated it may success and may not, i simulated the ray and it is already intersect the object, all coordinates are in the world space. bool Engine::IntersectBox(Ray& ray,BoundingBox* boundingBox,GLfloat& distance){ V3* v=boundingBox->getVertices(); glm::vec4 vec(v->x,v->y,v->z,1); vec=boundingBox->getMatrix()*vec; GLfloat minX=vec.x; GLfloat minY=vec.y; GLfloat minZ=vec.z; GLfloat maxX=vec.x; GLfloat maxY=vec.y; GLfloat maxZ=vec.z; for(int i=0;i<8;i++){ v++; vec=glm::vec4(v->x,v->y,v->z,1); vec=boundingBox->getMatrix()*vec; minX=minX<vec.x?minX:vec.x; minY=minY<vec.y?minY:vec.y; minZ=minZ<vec.z?minZ:vec.z; maxX=maxX>vec.x?maxX:vec.x; maxY=maxY>vec.y?maxY:vec.y; maxZ=maxZ>vec.z?maxZ:vec.z; } GLfloat tMin = 0.0f; GLfloat tMax = 100000.0f; glm::vec3 delta=glm::vec3(boundingBox->getMatrix()[3])-ray.getOrigin(); { glm::vec3 xAxis=boundingBox->getMatrix()[0]; GLfloat e = glm::dot(xAxis, delta); GLfloat f = glm::dot(ray.getDirection(), xAxis); if ( fabs(f) > 0.001f ) { // Standard case GLfloat min = (e+minX)/f; // Intersection with the "left" plane GLfloat max = (e+maxX)/f; // Intersection with the "right" plane if(min<max){ tMin=min; tMax=max; } else{ tMin=max; tMax=min; } if (tMax < tMin) return false; } else{ if(-e+minX > 0.0f || -e+maxX < 0.0f) return false; } } { glm::vec3 yAxis=boundingBox->getMatrix()[1]; GLfloat e = glm::dot(yAxis, delta); GLfloat f = glm::dot(ray.getDirection(), yAxis); if ( fabs(f) > 0.001f ){ GLfloat min = (e+minY)/f; GLfloat max = (e+maxY)/f; if(min<max){ tMin=glm::max(tMin,min); tMax=glm::min(tMax,max); } else{ tMin=glm::max(tMin,max); tMax=glm::min(tMax,min); } if (tMax < tMin) return false; }else{ if(-e+minY > 0.0f || -e+maxY < 0.0f) return false; } } { glm::vec3 zAxis=boundingBox->getMatrix()[2]; GLfloat e = glm::dot(zAxis, delta); GLfloat f = glm::dot(ray.getDirection(),zAxis); if ( fabs(f) > 0.001f ){ GLfloat min = (e+minZ)/f; GLfloat max = (e+maxZ)/f; if(min<max){ tMin=glm::max(tMin,min); tMax=glm::min(tMax,max); } else{ tMin=glm::max(tMin,max); tMax=glm::min(tMax,min); } if (tMax < tMin) return false; }else{ if(-e+minZ > 0.0f || -e+maxZ < 0.0f) return false; } } distance = tMin; return true; }
I am doing this using: OpenGL 3D-raypicking with high poly meshes The idea is to apart of rendering to screen also render index of each object into separate unseen buffer (color attachment, stencil, shadow,...) and than just pick pixel at mouse position from this buffer and depth ... which provides 3D position of the picked point and also index of object that it belongs to. This is very fast O(1) at almost no performance cost. Now You do not need OBB for your objects nor any intersection checking anymore. Instead have a local coordinate system in form of 4x4 homogenuous matrix with which you can easily convert the 3D position picked by mouse into object local coordinates making the manipulation like translation/rotation of the object really easy. Here is my older C++ approach of mine for this: Compute objects moving with arrows and mouse which does not require any additional libs and stuff. How ever I do it now using all above in fusion like this: //--------------------------------------------------------------------------- #ifndef _OpenGLctrl3D_h #define _OpenGLctrl3D_h //--------------------------------------------------------------------------- #include "gl/OpenGL3D_double.cpp" // vector and matrix math keyboard and mouse handler //--------------------------------------------------------------------------- static reper NULL_rep; AnsiString dbg=""; //--------------------------------------------------------------------------- class OpenGLctrl3D // arrow translation controls (you need one for each objet) { public: reper *rep; // points to bounded object model matrix double l[3],r0,r1,r2,a; // l - size of each straight arrow // r0 - tube radius // r1 - arrow radius // r2 - arced arrow radius // a - arrowhead size double a0,a1,aa; // start,end, cone size [rad] of the arced arrow OpenGLctrl3D() { rep=&NULL_rep; l[0]=3.5; r0=0.05; a0= 0.0*deg; a=0.10; l[1]=3.5; r1=0.25; a1=360.0*deg; l[2]=3.5; r2=0.50; aa= 15.0*deg; } OpenGLctrl3D(OpenGLctrl3D& a) { *this=a; } ~OpenGLctrl3D() {} OpenGLctrl3D* operator = (const OpenGLctrl3D *a) { *this=*a; return this; } //OpenGLctrl3D* operator = (const OpenGLctrl3D &a) { ...copy... return this; } void draw(int sel); // render arrows void mouse_select(void* sys); // handle [camera local] mouse events (no active button) void mouse_edit (void* sys); // handle [camera local] mouse events (active button) }; //--------------------------------------------------------------------------- class OpenGLctrls3D // arrow translation controls (you need one for each objet) { public: reper *eye; // camera matrix double per[16],ndc[16]; // perspective and viewport matrices TShiftState sh; double mw[3],ms[3]; // actual mouse [buttons],[world units],[camera units] bool _redraw; // redraw needed? int sel0,sel1,_sel; // actualy selected item ctrl[sel0].axis=sel1 the _sel is for iteration variable double psel[3]; // selected point [object local units] List<OpenGLctrl3D> ctrl; OpenGLctrls3D() { eye=&NULL_rep; matrix_one(per); matrix_one(ndc); ctrl.num=0; } OpenGLctrls3D(OpenGLctrls3D& a) { *this=a; } ~OpenGLctrls3D(){} OpenGLctrls3D* operator = (const OpenGLctrls3D *a) { *this=*a; return this; } //OpenGLctrls3D* operator = (const OpenGLctrls3D &a) { ...copy... return this; } void add(reper &rep,double *l,double r0,double r1,double r2,double a) // add new control bounded to rep { // l - size of each straight arrow // r0 - tube radius // r1 - arrow radius // r2 - arced arrow radius // a - arrowhead size ctrl.add(); OpenGLctrl3D *c=ctrl.dat+ctrl.num-1; c->rep=&rep; vector_copy(c->l,l); c->r0=r0; c->r1=r1; c->r2=r2; c->a=a; } void resize(int x0,int y0,int xs,int ys) { matrix_one(ndc); ndc[ 0]=+divide(2.0,double(xs)); ndc[ 5]=-divide(2.0,double(ys)); ndc[12]=-1.0; ndc[13]=+1.0; glGetDoublev(GL_PROJECTION_MATRIX,per); mouse_refresh(); } void draw() { int i; OpenGLctrl3D *c; for (c=ctrl.dat,i=0;i<ctrl.num;i++,c++) { glPushMatrix(); c->rep->use_rep(); glMatrixMode(GL_MODELVIEW); glMultMatrixd(c->rep->rep); if (i==sel0) c->draw(sel1); else c->draw(-1); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } } bool mouse(double mx,double my,TShiftState _sh) // handle mouse events return if redraw is needed { // mouse depth [camera units] ms[0]=mx; ms[1]=my; sh=_sh; ms[2]=glReadDepth(mx,divide(-2.0,ndc[5])-my-1,per); // mouse x,y [pixel] -> <-1,+1> NDC matrix_mul_vector(ms,ndc,ms); // mouse x,y <-1,+1> NDC -> [camera units] scr2world(mw,ms); return mouse_refresh(); } bool mouse_refresh() // call after any view change { _redraw=false; if (!sh.Contains(ssLeft)) { int _sel0=sel0; sel0=-1; int _sel1=sel1; sel1=-1; for (_sel=0;_sel<ctrl.num;_sel++) ctrl.dat[_sel].mouse_select(this); _redraw=((_sel0!=sel0)||(_sel1!=sel1)); } else{ if ((sel0>=0)&&(sel0<ctrl.num)) ctrl.dat[sel0].mouse_edit(this); } return _redraw; } void world2scr(double *s,double *w) { // camera [LCS] eye->g2l(s,w); // [camera units] -> <-1,+1> NDC s[0]=-divide(s[0]*per[0],s[2]); s[1]=-divide(s[1]*per[5],s[2]); } void scr2world(double *w,double *s) { // <-1,+1> NDC -> [camera units] w[0]=-divide(s[0]*s[2],per[0]); w[1]=-divide(s[1]*s[2],per[5]); w[2]=s[2]; // world [GCS] eye->l2g(w,w); } }; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void OpenGLctrl3D::draw(int sel) { if (sel==0) glColor3f(1.0,0.0,0.0); else glColor3f(0.5,0.0,0.0); glArrowx(0.0,0.0,0.0,r0,r1,l[0],a); if (sel==1) glColor3f(0.0,1.0,0.0); else glColor3f(0.0,0.5,0.0); glArrowy(0.0,0.0,0.0,r0,r1,l[1],a); if (sel==2) glColor3f(0.0,0.0,1.0); else glColor3f(0.0,0.0,0.5); glArrowz(0.0,0.0,0.0,r0,r1,l[2],a); if (sel==3) glColor3f(1.0,0.0,0.0); else glColor3f(0.5,0.0,0.0); glCircleArrowyz(0.0,0.0,0.0,r2,r0,r1,a0,a1,aa); if (sel==4) glColor3f(0.0,1.0,0.0); else glColor3f(0.0,0.5,0.0); glCircleArrowzx(0.0,0.0,0.0,r2,r0,r1,a0,a1,aa); if (sel==5) glColor3f(0.0,0.0,1.0); else glColor3f(0.0,0.0,0.5); glCircleArrowxy(0.0,0.0,0.0,r2,r0,r1,a0,a1,aa); } //--------------------------------------------------------------------------- void OpenGLctrl3D::mouse_select(void *_sys) { OpenGLctrls3D *sys=(OpenGLctrls3D*)_sys; int i,x,y,z; double p[3],q[3],pm[3],t,r; // mouse [object local units] rep->g2l(pm,sys->mw); // straight arrows for (i=0;i<3;i++) { t=pm[i]; pm[i]=0.0; r=vector_len(pm); pm[i]=t; t=divide(l[i]-t,a); if ((t>=0.0)&&(t<=1.0)&&(r<=r1*t)) // straight cone { sys->sel0=sys->_sel; sys->sel1=i; vector_ld(sys->psel,0.0,0.0,0.0); sys->psel[i]=pm[i]; } } // arced arrows for (i=0;i<3;i++) { if (i==0){ x=1; y=2; z=0; } if (i==1){ x=2; y=0; z=1; } if (i==2){ x=0; y=1; z=2; } t=atanxy(pm[x],pm[y]); p[x]=r2*cos(t); p[y]=r2*sin(t); p[z]=0.0; vector_sub(q,p,pm); r=vector_len(q); if (r<=r0*2.0) { sys->sel0=sys->_sel; sys->sel1=i+3; vector_copy(sys->psel,p); } } } //--------------------------------------------------------------------------- void OpenGLctrl3D::mouse_edit(void *_sys) { OpenGLctrls3D *sys=(OpenGLctrls3D*)_sys; // drag straight arrows (active button) if ((sys->sel1>=0)&&(sys->sel1<3)) { double z0,z1,z2,t0; double q[3],q0[3],q1[3],t; // q0 = mouse change in 2D screen space rep->l2g(q0,sys->psel); // selected point position sys->world2scr(q0,q0); vector_sub(q0,q0,sys->ms); q0[2]=0.0; // actual mouse position // q1 = selected axis step in 2D screen space rep->l2g(q,sys->psel); // selected point position sys->world2scr(q,q); vector_copy(q1,sys->psel); // axis step q1[sys->sel1]+=1.0; rep->l2g(q1,q1); sys->world2scr(q1,q1); vector_sub(q1,q1,q); q1[2]=0.0; // compute approx change t=-vector_mul(q0,q1); // dot(q0,q1) // enhance precision of t int i; double len0,len,dq[3]={0.0,0.0,0.0},dt; // selected arrow direction dq[sys->sel1]=1.0; // closest point on axis to psel for (len0=-1.0,dt=0.25*t;fabs(dt)>1e-5;t+=dt) { // position on axis p(t) = p0 + t*dp for (i=0;i<3;i++) q[i]=sys->psel[i]+(t*dq[i]); // len = distance to mouse rep->l2g(q,q); sys->world2scr(q,q); vector_sub(q,q,sys->ms); q[2]=0.0; len=vector_len2(q); // handle iteration step if (len0<-0.5) len0=len; if (len>len0) dt=-0.1*dt; len0=len; } // translate by change double m[16]= { 1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, 0.0,0.0,0.0,1.0, }; m[12+sys->sel1]=t; rep->use_rep(); matrix_mul(rep->rep,m,rep->rep); rep->_inv=0; sys->_redraw=true; } // rotate arced arrows (active button) if ((sys->sel1>=3)&&(sys->sel1<6)) { int i,x,y,z; double t,t0,tt,dt,len,len0,q[3]; if (sys->sel1==3){ x=1; y=2; z=0; } if (sys->sel1==4){ x=2; y=0; z=1; } if (sys->sel1==5){ x=0; y=1; z=2; } t0=atanxy(sys->psel[x],sys->psel[y]); // initial search for (i=10,t=0.0,dt=divide(1.0,i),len0=-1.0;i--;t+=dt) { q[x]=r2*cos(t0+t); q[y]=r2*sin(t0+t); q[z]=0.0; rep->l2g(q,q); sys->world2scr(q,q); vector_sub(q,q,sys->ms); q[2]=0.0; len=vector_len2(q); if ((len0<-0.5)||(len<len0)) { len0=len; tt=t; } } // closest angle to psel for (t=tt;fabs(dt)>0.1*deg;t+=dt) { q[x]=r2*cos(t0+t); q[y]=r2*sin(t0+t); q[z]=0.0; rep->l2g(q,q); sys->world2scr(q,q); vector_sub(q,q,sys->ms); q[2]=0.0; len=vector_len2(q); // handle iteration step if (len>len0) dt=-0.1*dt; else { tt=t; } len0=len; } // rotate if (sys->sel1==3) rep->lrotx(tt); if (sys->sel1==4) rep->lroty(tt); if (sys->sel1==5) rep->lrotz(tt); sys->_redraw=true; } } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- Unlike the example in the link above this uses a lot of stuff not provided (from my GL engine) so you can not use it directly however it should be enough to grasp the basics. Here some external stuff it uses (not all): I also use mine dynamic list template so: List<double> xxx; is the same as double xxx[]; xxx.add(5); adds 5 to end of the list xxx[7] access array element (safe) xxx.dat[7] access array element (unsafe but fast direct access) xxx.num is the actual used size of the array xxx.reset() clears the array and set xxx.num=0 xxx.allocate(100) preallocate space for 100 items Rendering: //--------------------------------------------------------------------------- void glArrowx(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r0,GLfloat r1,GLfloat l0,GLfloat l1) { double pos[3]={ x0, y0, z0}; double dir[3]={1.0,0.0,0.0}; glArrow3D(pos,dir,r0,r1,l0,l1); } //--------------------------------------------------------------------------- void glArrowy(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r0,GLfloat r1,GLfloat l0,GLfloat l1) { double pos[3]={ x0, y0, z0}; double dir[3]={0.0,1.0,0.0}; glArrow3D(pos,dir,r0,r1,l0,l1); } //--------------------------------------------------------------------------- void glArrowz(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r0,GLfloat r1,GLfloat l0,GLfloat l1) { double pos[3]={ x0, y0, z0}; double dir[3]={0.0,0.0,1.0}; glArrow3D(pos,dir,r0,r1,l0,l1); } //--------------------------------------------------------------------------- void glCircleArrowxy(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa) { double pos[3]={ x0, y0, z0}; double nor[3]={0.0,0.0,1.0}; double bin[3]={1.0,0.0,0.0}; glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa); } //--------------------------------------------------------------------------- void glCircleArrowyz(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa) { double pos[3]={ x0, y0, z0}; double nor[3]={1.0,0.0,0.0}; double bin[3]={0.0,1.0,0.0}; glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa); } //--------------------------------------------------------------------------- void glCircleArrowzx(GLfloat x0,GLfloat y0,GLfloat z0,GLfloat r,GLfloat r0,GLfloat r1,GLfloat a0,GLfloat a1,GLfloat aa) { double pos[3]={ x0, y0, z0}; double nor[3]={0.0,1.0,0.0}; double bin[3]={0.0,0.0,1.0}; glCircleArrow3D(pos,nor,bin,r,r0,r1,a0,a1,aa); } //--------------------------------------------------------------------------- void glArrow3D(double *pos,double *dir,double r0,double r1,double l0,double l1) { int i,n=_glCircleN; double nn=1.0,a,da=divide(pi2,n),p[3],dp[3],x[3],y[3],p0[3],p1[3],c,s,q; if (l0<0.0) { da=-da; nn=-nn; l1=-l1; } // TBN if (fabs(dir[0]-dir[1])>1e-6) vector_ld(x,dir[1],dir[0],dir[2]); else if (fabs(dir[0]-dir[2])>1e-6) vector_ld(x,dir[2],dir[1],dir[0]); else if (fabs(dir[1]-dir[2])>1e-6) vector_ld(x,dir[0],dir[2],dir[1]); else vector_ld(x,1.0,0.0,0.0); vector_one(dir,dir); vector_mul(x,x,dir); vector_mul(y,x,dir); vector_mul(p0,dir,l0-l1); vector_add(p0,pos,p0); vector_mul(p1,dir,l0 ); vector_add(p1,pos,p1); // disc r0, 0 vector_len(x,x,r0); vector_len(y,y,r0); glBegin(GL_TRIANGLE_FAN); vector_mul(p,dir,-nn); glNormal3dv(p); glVertex3dv(pos); for (a=0.0,i=0;i<=n;i++,a+=da) { vector_mul(dp,x,cos(a)); vector_add(p,pos,dp); vector_mul(dp,y,sin(a)); vector_add(p,p ,dp); glVertex3dv(p); } glEnd(); // tube r0, 0..l0-l1 q=divide(1.0,r0); glBegin(GL_QUAD_STRIP); for (a=0.0,i=0;i<=n;i++,a+=da) { vector_mul( p,x,cos(a)); vector_mul(dp,y,sin(a)); vector_add(dp,p ,dp); vector_add(p,pos,dp); vector_mul(dp,dp,q); glNormal3dv(dp); glVertex3dv(p); vector_sub(p,p,pos); vector_add(p,p,p0); glVertex3dv(p); } glEnd(); // disc r1, l0-l1 vector_len(x,x,r1); vector_len(y,y,r1); glBegin(GL_TRIANGLE_FAN); vector_mul(p,dir,-nn); glNormal3dv(p); glVertex3dv(p0); for (a=0.0,i=0;i<=n;i++,a+=da) { vector_mul(dp,x,cos(a)); vector_add(p,p0 ,dp); vector_mul(dp,y,sin(a)); vector_add(p,p ,dp); glVertex3dv(p); } glEnd(); // cone r1..0, l0-l1..l0 glBegin(GL_TRIANGLE_STRIP); q=divide(1.0,sqrt((l1*l1)+(r1*r1))); for (a=0.0,i=0;i<=n;i++,a+=da) { vector_mul( p,x,cos(a)); vector_mul(dp,y,sin(a)); vector_add(dp,p ,dp); vector_add(p,p0,dp); vector_mul(dp,dp,q); glNormal3dv(dp); glVertex3dv(p); glVertex3dv(p1); } glEnd(); } //--------------------------------------------------------------------------- void glCircleArrow3D(double *pos,double *nor,double *bin,double r,double r0,double r1,double a0,double a1,double aa) { int e,i,j,N=3*_glCircleN; double U[3],V[3],u,v; double a,b,da,db=pi2/double(_glCircleN-1),a2,rr; double *ptab,*p0,*p1,*n0,*n1,*pp,p[3],q[3],c[3],n[3],tan[3]; // buffers ptab=new double [12*_glCircleN]; if (ptab==NULL) return; p0=ptab+(0*_glCircleN); n0=ptab+(3*_glCircleN); p1=ptab+(6*_glCircleN); n1=ptab+(9*_glCircleN); // prepare angles a2=a1; da=db; aa=fabs(aa); if (a0>a1) { da=-da; aa=-aa; } a1-=aa; // compute missing basis vectors vector_copy(U,nor); // U is normal to arrow plane vector_mul(tan,nor,bin); // tangent is perpendicular to normal and binormal // arc interpolation a=<a0,a2> for (e=0,j=0,a=a0;e<5;j++,a+=da) { // end conditions if (e==0) // e=0 { if ((da>0.0)&&(a>=a1)) { a=a1; e++; } if ((da<0.0)&&(a<=a1)) { a=a1; e++; } rr=r0; } else{ // e=1,2,3,4 if ((da>0.0)&&(a>=a2)) { a=a2; e++; } if ((da<0.0)&&(a<=a2)) { a=a2; e++; } rr=r1*fabs(divide(a-a2,a2-a1)); } // compute actual tube segment center c[3] u=r*cos(a); v=r*sin(a); vector_mul(p,bin,u); vector_mul(q,tan,v); vector_add(c,p, q); vector_add(c,c,pos); // V is unit direction from arrow center to tube segment center vector_sub(V,c,pos); vector_one(V,V); // tube segment interpolation for (b=0.0,i=0;i<N;i+=3,b+=db) { u=cos(b); v=sin(b); vector_mul(p,U,u); // normal vector_mul(q,V,v); vector_add(n1+i,p,q); vector_mul(p,n1+i,rr); // vertex vector_add(p1+i,p,c); } if (e>1) // recompute normals for cone { for (i=3;i<N;i+=3) { vector_sub(p,p0+i ,p1+i); vector_sub(q,p1+i-3,p1+i); vector_mul(p,p,q); vector_one(n1+i,p); } vector_sub(p,p0 ,p1); vector_sub(q,p1+N-3,p1); vector_mul(p,q,p); vector_one(n1,p); if (da>0.0) for (i=0;i<N;i+=3) vector_neg(n1+i,n1+i); if (e== 3) for (i=0;i<N;i+=3) vector_copy(n0+i,n1+i); } // render base disc if (!j) { vector_mul(n,V,U); glBegin(GL_TRIANGLE_FAN); glNormal3dv(n); glVertex3dv(c); if (da<0.0) for (i= 0;i< N;i+=3) glVertex3dv(p1+i); else for (i=N-3;i>=0;i-=3) glVertex3dv(p1+i); glEnd(); } // render tube else{ glBegin(GL_QUAD_STRIP); if (da<0.0) for (i=0;i<N;i+=3) { glNormal3dv(n0+i); glVertex3dv(p0+i); glNormal3dv(n1+i); glVertex3dv(p1+i); } else for (i=0;i<N;i+=3) { glNormal3dv(n1+i); glVertex3dv(p1+i); glNormal3dv(n0+i); glVertex3dv(p0+i); } glEnd(); } // swap buffers pp=p0; p0=p1; p1=pp; pp=n0; n0=n1; n1=pp; // handle r0 -> r1 edge if (e==1) a-=da; if ((e==1)||(e==2)||(e==3)) e++; } // release buffers delete[] ptab; } //--------------------------------------------------------------------------- void glLinearArrow3D(double *pos,double *dir,double r0,double r1,double l,double al) { int e,i,N=3*_glCircleN; double U[3],V[3],W[3],u,v; double a,da=pi2/double(_glCircleN-1),r,t; double *ptab,*p0,*p1,*n1,*pp,p[3],q[3],c[3],n[3]; // buffers ptab=new double [9*_glCircleN]; if (ptab==NULL) return; p0=ptab+(0*_glCircleN); p1=ptab+(3*_glCircleN); n1=ptab+(6*_glCircleN); // compute basis vectors vector_one(W,dir); vector_ld(p,1.0,0.0,0.0); vector_ld(q,0.0,1.0,0.0); vector_ld(n,0.0,0.0,1.0); a=fabs(vector_mul(W,p)); pp=p; t=a; a=fabs(vector_mul(W,q)); if (t>a) { pp=q; t=a; } a=fabs(vector_mul(W,n)); if (t>a) { pp=n; t=a; } vector_mul(U,W,pp); vector_mul(V,U,W); vector_mul(U,V,W); for (e=0;e<4;e++) { // segment center if (e==0) { t=0.0; r= r0; } if (e==1) { t=l-al; r= r0; } if (e==2) { t=l-al; r= r1; } if (e==3) { t=l; r=0.0; } vector_mul(c,W,t); vector_add(c,c,pos); // tube segment interpolation for (a=0.0,i=0;i<N;i+=3,a+=da) { u=cos(a); v=sin(a); vector_mul(p,U,u); // normal vector_mul(q,V,v); vector_add(n1+i,p,q); vector_mul(p,n1+i,r); // vertex vector_add(p1+i,p,c); } if (e>2) // recompute normals for cone { for (i=3;i<N;i+=3) { vector_sub(p,p0+i ,p1+i); vector_sub(q,p1+i-3,p1+i); vector_mul(p,p,q); vector_one(n1+i,p); } vector_sub(p,p0 ,p1); vector_sub(q,p1+N-3,p1); vector_mul(p,q,p); vector_one(n1,p); } // render base disc if (!e) { vector_neg(n,W); glBegin(GL_TRIANGLE_FAN); glNormal3dv(n); glVertex3dv(c); for (i=0;i<N;i+=3) glVertex3dv(p1+i); glEnd(); } // render tube else{ glBegin(GL_QUAD_STRIP); for (i=0;i<N;i+=3) { glNormal3dv(n1+i); glVertex3dv(p0+i); glVertex3dv(p1+i); } glEnd(); } // swap buffers pp=p0; p0=p1; p1=pp; } // release buffers delete[] ptab; } //--------------------------------------------------------------------------- vector and matrix math: // cross product: W = U x V W.x=(U.y*V.z)-(U.z*V.y) W.y=(U.z*V.x)-(U.x*V.z) W.z=(U.x*V.y)-(U.y*V.x) // dot product: a = (U.V) a=U.x*V.x+U.y*V.y+U.z*V.z // abs of vector a = |U| a=sqrt((U.x*U.x)+(U.y*U.y)+(U.z*U.z)) vector_mul(a[3],b[3],c[3]) is cross product a = b x c a = vector_mul(b[3],c[3]) is dot product a = (b.c) vector_one(a[3],b[3]) is unit vector a = b/|b| vector_copy(a[3],b[3]) is just copy a = b vector_add(a[3],b[3],c[3]) is adding a = b + c vector_sub(a[3],b[3],c[3]) is substracting a = b - c vector_neg(a[3],b[3]) is negation a = -b vector_ld(a[3],x,y,z) is just loading a = (x,y,z) The reper class is just holding direct and inverse 4x4 matrix representing 3D coordinate system. Its implementation depends on your coordinate system and gfx notation (matrix row/column major order, multiplication order etc...) Everything you need to implement it is in the 4x4 homogenuous matrix link above. Now finally the usage: Here is my BDS2006 C++/VCL/OpenGL project source code: //--------------------------------------------------------------------------- #include <vcl.h> #include <math.h> #pragma hdrstop #include "Unit1.h" #include "OpenGLctrl3D.h" // only this is important //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; // this form/window //--------------------------------------------------------------------------- reper eye,obj; // camera and object matrices double perspective[16]; // projection matrix OpenGLscreen scr; // my GL engine can ignore this OpenGLctrls3D ctrl; // control component (important) bool _redraw=true; // need repaint ? //--------------------------------------------------------------------------- void gl_draw() // main rendering code { _redraw=false; scr.cls(); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_COLOR_MATERIAL); // set view glMatrixMode(GL_MODELVIEW); eye.use_inv(); glLoadMatrixd(eye.inv); // draw all controls ctrl.draw(); // draw all objects glPushMatrix(); obj.use_rep(); glMatrixMode(GL_MODELVIEW); glMultMatrixd(obj.rep); glColor3f(1.0,1.0,1.0); // glBox(0.0,0.0,0.0,1.0,1.0,1.0); glMatrixMode(GL_MODELVIEW); glPopMatrix(); scr.exe(); scr.rfs(); } //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner) { // application init scr.init(this); scr.views[0].znear=0.1; scr.views[0].zfar=100.0; scr.views[0].zang=60.0; // matrices eye.reset(); eye.gpos_set(vector_ld(0.0,0.0,+5.0)); eye.lrotz(25.0*deg); obj.reset(); obj.gpos_set(vector_ld(-1.0,-0.5,-1.0)); obj.lroty(-35.0*deg); // controls ctrl.eye=&eye; ctrl.add(obj,vector_ld(2.5,2.5,2.5),0.04,0.10,1.25,0.5); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormDestroy(TObject *Sender) { // application exit scr.exit(); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormResize(TObject *Sender) { // window resize scr.resize(); ctrl.resize(scr.x0,scr.y0,scr.xs,scr.ys); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormPaint(TObject *Sender) { // window repaint gl_draw(); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled) { // mouse wheel translates camera (like zoom) GLfloat dz=2.0; if (WheelDelta>0) dz=-dz; eye.lpos_set(vector_ld(0.0,0.0,dz)); ctrl.mouse_refresh(); _redraw=true; } //--------------------------------------------------------------------------- // mouse events void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y) { _redraw|=ctrl.mouse(X,Y,Shift); } void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,TShiftState Shift, int X, int Y) { _redraw|=ctrl.mouse(X,Y,Shift); } void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { _redraw|=ctrl.mouse(X,Y,Shift); } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { // double *p=ctrl.pm; Caption=AnsiString().sprintf("(%7.3lf,%7.3lf,%7.3lf)",p[0],p[1],p[2]); Caption=dbg; // obj.lroty(3.0*deg); ctrl.mouse_refresh(); _redraw=true; if (_redraw) gl_draw(); } //--------------------------------------------------------------------------- You can ignore the VCL and my engine related stuff. For each controlled object you should have its 4x4 transform matrix (reper) and a control component (OpenGLctrl3D). Then just mimic the events and add relevant calls to draw and key/mouse events for each. Here preview how it looks like: Sadly my GIF capturer does not capture the mouse cursor so you do not see where I click/drag ... But as you can see my control is rather complex and just OBB would not help much as the rings and arrows are intersecting a lot. The choppy ness is due to GIF capture encoding but when using logarithmic depth buffer you might expect chppyness also for object far from znear plane. To remedy that you can use: Linear depth buffer In my example I do not have any objects just single control but you get the idea ... so each object of yours should have its matrix (the same that is used for its rendering) so you just add a control referencing it. In case your objects are dynamicaly added and removed you need to add their add/removal to controls too... The most important stuff are the functions mouse_select and mouse_edit which converts the 3D global mouse position into objetc/control local one making very easy to detect stuff like inside cone, inside cylinder, angle of rotation and translation size etc ...
Visual Studio 2017 Exception Unhandled
I'm a novice programmer trying to follow a tuturial on recreating a game on Steam called Timber(I believe). The program was working fine and I had almost completed the tutrial, but I ran into trouble when I added the code: for (int i = 0 < NUM_BRANCHES; i++;) { branches[i].setTexture(textureBranch); branches[i].setPosition(-2000, -2000); // Set the sprite's origin to dead center // We can then spin it around without changing its position branches[i].setOrigin(220, 20); } Visual Studio says: branches[i].setPosition(-2000, -2000); Unhandled exception thrown: write access violation. this was 0x59AF28. occurred I'll also post the full code, apologies that it's a bit messy. #include "stdafx.h" #include <sstream> #include <SFML\Graphics.hpp> using namespace sf; // Function declaration void updateBranches(int seed); const int NUM_BRANCHES = 6; Sprite branches[NUM_BRANCHES]; // Where is the player/branch? // Left or right enum class side{ LEFT, RIGHT, NONE }; side branchPositions[NUM_BRANCHES]; int main() { // Creates a video mode object VideoMode vm(1920, 1080); // Creates and opens a window for the game RenderWindow window(vm, "Timber!!!", Style::Fullscreen); // Create a texture to hold a graphic on the GPU Texture textureBackground; // Load a graphic into the texture textureBackground.loadFromFile("graphics/background.png"); // Create a sprite Sprite spriteBackground; // Attach the texture to the sprite spriteBackground.setTexture(textureBackground); // Set the spriteBackground to cover the screen spriteBackground.setPosition(0, 0); // Make a tree sprite Texture textureTree; textureTree.loadFromFile("graphics/tree.png"); Sprite spriteTree; spriteTree.setTexture(textureTree); spriteTree.setPosition(810, 0); // Prepare the bee Texture textureBee; textureBee.loadFromFile("graphics/bee.png"); Sprite spriteBee; spriteBee.setTexture(textureBee); spriteBee.setPosition(0, 450); // Is the be currently moving? bool beeActive = false; // How fast can the bee fly float beeSpeed = 0.0f; // Make 3 cloud sprites from 1 texture Texture textureCloud; // Load 1 new texture textureCloud.loadFromFile("graphics/cloud.png"); // 3 new sprites with the same texture Sprite spriteCloud1; Sprite spriteCloud2; Sprite spriteCloud3; spriteCloud1.setTexture(textureCloud); spriteCloud2.setTexture(textureCloud); spriteCloud3.setTexture(textureCloud); // Position the clouds off screen spriteCloud1.setPosition(0, 0); spriteCloud2.setPosition(0, -150); spriteCloud3.setPosition(0, -300); // Are the clouds currently on the screen? bool cloud1Active = false; bool cloud2Active = false; bool cloud3Active = false; // How fast is each cloud? float cloud1Speed = 0.1f; float cloud2Speed = 0.2f; float cloud3Speed = 0.3f; // Variables to control time itself Clock clock; // Time bar RectangleShape timeBar; float timeBarStartWidth = 400; float timeBarHeight = 80; timeBar.setSize(Vector2f(timeBarStartWidth, timeBarHeight)); timeBar.setFillColor(Color::Red); timeBar.setPosition((1920 / 2) - timeBarStartWidth / 2, 980); Time gameTimeTotal; float timeRemaining = 6.0f; float timeBarWidthPerSecond = timeBarStartWidth / timeRemaining; // Track whether the game is running bool paused = true; // Draw some text int score = 0; sf::Text messageText; sf::Text scoreText; // Font Font font; font.loadFromFile("fonts/KOMIKAP_.ttf"); // Set the font of our message messageText.setFont(font); scoreText.setFont(font); // Assign the actual message messageText.setString("Press Enter to Start!"); scoreText.setString("score = 0"); // Make text really big messageText.setCharacterSize(75); scoreText.setCharacterSize(100); // Choose a color messageText.setFillColor(Color::White); scoreText.setFillColor(Color::Black); // Position the text FloatRect textRect = messageText.getLocalBounds(); messageText.setOrigin(textRect.left + textRect.width / 2.0f, textRect.top + textRect.height / 2.0f); messageText.setPosition(1920 / 2.0f, 1080 / 2.0f); scoreText.setPosition(20, 20); // Prepare 6 branches Texture textureBranch; textureBranch.loadFromFile("graphics/branch.png"); // Set the texture for each branch sprite for (int i = 0 < NUM_BRANCHES; i++;) { branches[i].setTexture(textureBranch); branches[i].setPosition(-2000, -2000); // Set the sprite's origin to dead center // We can then spin it around without changing its position branches[i].setOrigin(220, 20); } while (window.isOpen()) { /* ************** Handles the player input ************** */ if (Keyboard::isKeyPressed(Keyboard::Escape)) { window.close(); } // Start the game if (Keyboard::isKeyPressed(Keyboard::Return)) { paused = false; // Reset the time and the score score = 0; timeRemaining = 5; } /* ************** Update the scene ************** */ if (!paused) { // Measure time Time dt = clock.restart(); // Subtract from the amount of time remaining timeRemaining -= dt.asSeconds(); // size up the time bar timeBar.setSize(Vector2f(timeBarWidthPerSecond * timeRemaining, timeBarHeight)); if (timeRemaining <= 0.0f) { // Pause the game paused = true; // Change the message shown to the player messageText.setString("Out of time"); // Reposition the text base on its new size FloatRect textRect = messageText.getLocalBounds(); messageText.setOrigin(textRect.left + textRect.width / 2.0f, textRect.top + textRect.height / 2.0f); messageText.setPosition(1920 / 2.0f, 1080 / 2.0f); } // Setup the bee if (!beeActive) { // How fast is the bee srand((int)time(0) * 10); beeSpeed = (rand() % 400) + 350; // How high is the bee srand((int)time(0) * 10); float height = (rand() % 650) + 850; spriteBee.setPosition(1921, height); beeActive = true; } else // Move the bee { spriteBee.setPosition( spriteBee.getPosition().x - (beeSpeed * dt.asSeconds()), spriteBee.getPosition().y); // Has the bee reached the right hand edge of the screen? if (spriteBee.getPosition().x < -100) { // Set it up ready to be a whole new bee next frame beeActive = false; } } // Manage the clouds // Cloud 1 if (!cloud1Active) { // How fast is the cloud srand((int)time(0) * 10); cloud1Speed = (rand() % 150); // How high is the cloud srand((int)time(0) * 10); float height = (rand() % 200); spriteCloud1.setPosition(-300, height); cloud1Active = true; } else { spriteCloud1.setPosition( spriteCloud1.getPosition().x + (cloud1Speed * dt.asSeconds()), spriteCloud1.getPosition().y); // Has the cloud reached the right hand edge of the screen? if (spriteCloud1.getPosition().x > 1920) { // Set it up ready to be a whole new cloud next frame cloud1Active = false; } } // Cloud 2 if (!cloud2Active) { // How fast is the cloud srand((int)time(0) * 20); cloud2Speed = (rand() % 200); // How high is the cloud srand((int)time(0) * 20); float height = (rand() % 300); spriteCloud2.setPosition(-200, height); cloud2Active = true; } else { spriteCloud2.setPosition( spriteCloud2.getPosition().x + (cloud1Speed * dt.asSeconds()), spriteCloud2.getPosition().y); // Has the cloud reached the right hand edge of the screen? if (spriteCloud2.getPosition().x > 1920) { // Set it up ready to be a whole new cloud next frame cloud2Active = false; } } // Cloud 3 if (!cloud3Active) { // How fast is the cloud srand((int)time(0) * 30); cloud3Speed = (rand() % 250); // How high is the cloud srand((int)time(0) * 30); float height = (rand() % 150); spriteCloud3.setPosition(-100, height); cloud3Active = true; } else { spriteCloud3.setPosition( spriteCloud3.getPosition().x + (cloud1Speed * dt.asSeconds()), spriteCloud3.getPosition().y); // Has the cloud reached the right hand edge of the screen? if (spriteCloud3.getPosition().x > 1920) { // Set it up ready to be a whole new cloud next frame cloud3Active = false; } } // Update the score text std::stringstream ss; ss << "Score = " << score; scoreText.setString(ss.str()); // Update the branch sprites for (int i = 0; i < NUM_BRANCHES; i++) { float height = i * 150; if (branchPositions[i] == side::LEFT) { // Move the sprite to the left side branches[i].setPosition(610, height); // Flip the sprite around the other way branches[i].setRotation(180); } else if (branchPositions[i] == side::RIGHT) { // Move the sprite to the right side branches[i].setPosition(1330, height); // Set the sprite rotation to normal branches[i].setRotation(0); } else { // Hide the branch branches[i].setPosition(3000, height); } } } // End if(!paused) /* ************** Draw the scene ************** */ // Clear everything from the last frame window.clear(); // Draw our game scene here window.draw(spriteBackground); // Draw the clouds window.draw(spriteCloud1); window.draw(spriteCloud2); window.draw(spriteCloud3); // Draw the branches for (int i = 0; i < NUM_BRANCHES; i++) { window.draw(branches[i]); } // Draw the tree window.draw(spriteTree); // Draw the insect window.draw(spriteBee); // Draw the score window.draw(scoreText); //Draw the timebar window.draw(timeBar); if (paused) { // Draw our message window.draw(messageText); } // Show everyting we just drew window.display(); } return 0; } // Function definition void updateBranches(int seed) { // Move all the branches down on place for (int j = NUM_BRANCHES - 1; j > 0; j--) { branchPositions[j] = branchPositions[j - 1]; } // Spawn a new branch at postion 0 // LEFt, RIGHT, NONE srand((int)time(0) + seed); int r = (rand() % 5); switch (r) { case 0: branchPositions[0] = side::LEFT; break; case 1: branchPositions[0] = side::RIGHT; break; default: branchPositions[0] = side::NONE; break; } }
setPosition() requires an sf::Vector2f. So you could fix your code by changing that line to: branches[i].setPosition(sf::Vector2f(-2000, -2000))
3D Fireworks Effect in C/C++ using sine or cosine function
I am trying to implement fireworks effect in C. I have a cube with dimensions 10x10x10. A rocket starts from the ground, and when it reaches 8th floor it explodes. Here's the point I cannot do - the explosion. How can I implement this using sine or cosine function? so in point(5,0,7) //(x,y,z)// a rocket goes in the air for (j=0; j<9; j++) { setpoint(x, y, j); delay(100); clean(); //clears everything } Here comes the point to make the explosion. How this can be achieved? It can sparkle in random positions, too. Thanks in advance.
Heh I did find some time (done in 1.5 hod) and will for this funny stuff :) OK first some updates in the LED_cube class to support voxel point output and dimming the rest is the same as for the sphere from your another question ... //--------------------------------------------------------------------------- //--- LED cube class ver: 1.01 ---------------------------------------------- //--------------------------------------------------------------------------- #ifndef _LED_cube_h #define _LED_cube_h //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- const int _LED_cube_size=32; //--------------------------------------------------------------------------- class LED_cube { public: int n,map[_LED_cube_size][_LED_cube_size][_LED_cube_size]; LED_cube() { n=_LED_cube_size; } LED_cube(LED_cube& a) { *this=a; } ~LED_cube() { } LED_cube* operator = (const LED_cube *a) { *this=*a; return this; } //LED_cube* operator = (const LED_cube &a) { /*...copy...*/ return this; } void cls(int col); // clear cube with col 0x00BBGGRR void mul(int mul); // mull all channels by mul and then shr by 8 void point(int x,int y,int z,int col); // draws voxel with col 0x00BBGGRR void sphere(int x0,int y0,int z0,int r,int col); // draws sphere surface with col 0x00BBGGRR void glDraw(); // render cube by OpenGL as 1x1x1 cube at 0,0,0 }; //--------------------------------------------------------------------------- void LED_cube::cls(int col) { int x,y,z; for (x=0;x<n;x++) for (y=0;y<n;y++) for (z=0;z<n;z++) map[x][y][z]=col; } //--------------------------------------------------------------------------- void LED_cube::mul(int mul) { union { BYTE db[4]; int dd; } c; int x,y,z,i; for (x=0;x<n;x++) for (y=0;y<n;y++) for (z=0;z<n;z++) { c.dd=map[x][y][z]; i=c.db[0]; i=(i*mul)>>8; c.db[0]=i; i=c.db[1]; i=(i*mul)>>8; c.db[1]=i; i=c.db[2]; i=(i*mul)>>8; c.db[2]=i; map[x][y][z]=c.dd; } } //--------------------------------------------------------------------------- void LED_cube::point(int x,int y,int z,int col) { if ((x>=0)&&(x<n)) if ((y>=0)&&(y<n)) if ((z>=0)&&(z<n)) map[x][y][z]=col; } //--------------------------------------------------------------------------- void LED_cube::sphere(int x0,int y0,int z0,int r,int col) { int x,y,z,xa,ya,za,xb,yb,zb,xr,yr,zr,xx,yy,zz,rr=r*r; // bounding box xa=x0-r; if (xa<0) xa=0; xb=x0+r; if (xb>n) xb=n; ya=y0-r; if (ya<0) ya=0; yb=y0+r; if (yb>n) yb=n; za=z0-r; if (za<0) za=0; zb=z0+r; if (zb>n) zb=n; // project xy plane for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr) for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr) { zz=rr-xx-yy; if (zz<0) continue; zr=sqrt(zz); z=z0-zr; if ((z>0)&&(z<n)) map[x][y][z]=col; z=z0+zr; if ((z>0)&&(z<n)) map[x][y][z]=col; } // project xz plane for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr) for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr) { yy=rr-xx-zz; if (yy<0) continue; yr=sqrt(yy); y=y0-yr; if ((y>0)&&(y<n)) map[x][y][z]=col; y=y0+yr; if ((y>0)&&(y<n)) map[x][y][z]=col; } // project yz plane for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr) for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr) { xx=rr-zz-yy; if (xx<0) continue; xr=sqrt(xx); x=x0-xr; if ((x>0)&&(x<n)) map[x][y][z]=col; x=x0+xr; if ((x>0)&&(x<n)) map[x][y][z]=col; } } //--------------------------------------------------------------------------- void LED_cube::glDraw() { #ifdef __gl_h_ int x,y,z; float p[3],dp=1.0/float(n-1); glEnable(GL_BLEND); glBlendFunc(GL_ONE,GL_ONE); glPointSize(2.0); glBegin(GL_POINTS); for (p[0]=-0.5,x=0;x<n;x++,p[0]+=dp) for (p[1]=-0.5,y=0;y<n;y++,p[1]+=dp) for (p[2]=-0.5,z=0;z<n;z++,p[2]+=dp) { glColor4ubv((BYTE*)(&map[x][y][z])); glVertex3fv(p); } glEnd(); glDisable(GL_BLEND); glPointSize(1.0); #endif } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #endif //--------------------------------------------------------------------------- //-------------------------------------------------------------------------- the important stuff are: void mul(int mul); - used for dimming out the whole voxel map void point(int x,int y,int z,int col); - used to set collor of single voxel Now the particles //--------------------------------------------------------------------------- class particle { public: double x, y, z; // position double vx,vy,vz; // velocity double ax,ay,az; // acceleration driving force/m after update is reseted double i; // intensity particle() { x=0.0; y=0.0; z=0.0; vx=0.0; vy=0.0; vz=0.0; ax=0.0; ay=0.0; az=0.0; i=0.0; }; particle(particle& a){ *this=a; }; ~particle(){}; particle* operator = (const particle *a) { *this=*a; return this; }; // particle* operator = (const particle &a) { ...copy... return this; }; void update(double dt) { double c0,c; // gravity ay-=9.81; // friction in gass c=0.001; if (vx>0.0) c0=-c; else c0=+c; ax+=vx*vx*c0; if (vy>0.0) c0=-c; else c0=+c; ay+=vy*vy*c0; if (vz>0.0) c0=-c; else c0=+c; az+=vz*vz*c0; // friction in liquid c=0.0; ax-=vx*vx*vx*c; ay-=vy*vy*vy*c; az-=vz*vz*vz*c; // D'ALembert vx+=ax*dt; vy+=ay*dt; vz+=az*dt; x+=vx*dt; y+=vy*dt; z+=vz*dt; // reset acceleration ax=0.0; ay=0.0; az=0.0; } }; //--------------------------------------------------------------------------- List<particle> particles; // use any list/array you have at your disposal you need just function add and delete item //--------------------------------------------------------------------------- this is how to draw the scene: cube.mul(200); // dimm the voxel map insted of clearing it (intensity*=200/256) for (int i=0;i<particles.num;i++) { particle *p=&particles[i]; int j=double(255.0*p->i); if (j<0) j=0; if (j>255) j=255; cube.point(p->x,p->y,p->z,0x00010101*j); } cube.glDraw(); This is how to update simulation in some timer (double dt=timer interval in seconds !!!) double i0=1.0; // intensity at shoot start double i1=0.9*i0; // intensity after explosion double v0=0.6*double(_LED_cube_size); // shoot start speed double v1=0.5*v0,v1h=0.5*v1; // explosion speed if (particles.num==0) // shoot new particle if none in list { particle p; p.x=_LED_cube_size>>1; p.y=0.0; p.z=_LED_cube_size>>1; p.vy=v0; p.i=i0; particles.add(p); } for (int i=0;i<particles.num;i++) // update all particles in list { particle *p=&particles[i]; p->update(dt); if (fabs(p->i-i0)<1e-6) // intensity detect state before explosion { if (p->vy<=0.0) // explode near/after peak reached { particle q; q.x=p->x; // copy position q.y=p->y; q.z=p->z; q.i=i1; // new intensity particles.del(i); // remove old particle i--; for (int j=0;j<50;j++) // add new random particles { q.vx=v1*Random()-v1h; q.vy=v1*Random()-v1h; q.vz=v1*Random()-v1h; particles.add(q)-v1h; } continue; // avoid usage of p pointer after delete } } else{ // after explosion p->i*=0.95; // dimm intensity } if ((p->y<0.0)||(p->i<0.01))// remove particles below the ground or too dimmed out { particles.del(i); i--; continue; // avoid usage of p pointer after delete } } This is how it looks Sorry for the banner but I do not have anything solid for gif conversion and this site will not accept wmv ... You have to play with constants to match desired output on your LED cube size constants to play with: whole cube map dimm rate (cube.mul(200)) currently (200/256) per frame speeds,intensities v0,v1,i0,i1 number of new particles after explosion currently 50 particle intensity dimm rate after explosion currently 0.95 [Notes] List<> is just template for dynamic array can use anything from std:: or own array ... Do not forget to set dt constant to time elapsed between updates. Hope I did not forget to copy something. Hope it helps
It's better to do this using an upside down parabola instead of sin/cos. At the point of explosion give each particle a random horizontal speed. This speed is constant till the particle hits the ground. You also need to give each particle a random vertical speed. this time, however, you'll add to this speed an amount proportional to -0.5*g*dt^2 (strictly speaking, this is numerically wrong, but you won't notice unless you're doing scientific analysis). Here, g is the acceleration due to gravitation and dt is the time step. That's all.
C++ OpenGL: Ray Trace Shading Isn't Properly Shading
I'm a CS student and for our final we were told to construct the reflections on multiple spheres via ray tracing. That's almost literally what we got for directions except a picture for how it should look when finished. So I need spheres, with they're reflections (using ray tracing) mapped on them with the proper shading from a light. Well I have all of it working, except having multiple spheres and the fact that it doesn't look like the picture he gave us for a rubric. The multiple spheres thing I'm not too sure how to do, but I'd say I need to store them in a 2D array and modify a few sections of code. What I thought was modifying the sphere_intersect and find_reflect to include which sphere is being analyzed. Next, modify find_reflect so that when the new vector u is calculated its starting point (P0) is also updated. Then if the ray hits a sphere it will have to count how many times the ray has been reflected. At some point terminate (after 10 times maybe) and then I'll just draw the pixel. For an added touch I'd like to add solid colors to the spheres which would call for finding the normal of a sphere I believe. Anyways I'm going to attach a picture of his, a picture of mine, and the source code. Hopefully someone can help me out on this one. Thanks in advance! Professor's spheres My spheres #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <GL/glut.h> #include <math.h> #include <string> #define screen_width 750 #define screen_height 750 #define true 1 #define false 0 #define perpendicular 0 int gridXsize = 20; int gridZsize = 20; float plane[] = {0.0, 1.0, 0.0, -50.0,}; float sphere[] = {250.0, 270.0, -100.0, 100.0}; float eye[] = {0.0, 400.0, 550.0}; float light[] = {250.0, 550.0, -200.0}; float dot(float *u, float *v) { return u[0]*v[0] + u[1]*v[1] + u[2]*v[2]; } void norm(float *u) { float norm = sqrt(abs(dot(u,u))); for (int i =0; i <3; i++) { u[i] = u[i]/norm; } } float plane_intersect(float *u, float *pO) { float normt[3] = {plane[0], plane[1], plane[2]}; float s; if (dot(u,normt) == 0) { s = -10; } else { s = (plane[3]-(dot(pO,normt)))/(dot(u,normt)); } return s; } float sphere_intersect(float *u, float *pO) { float deltaP[3] = {sphere[0]-pO[0],sphere[1]-pO[1],sphere[2]-pO[2]}; float deltLen = sqrt(abs(dot(deltaP,deltaP))); float t=0; float answer; float det; if ((det =(abs(dot(u,deltaP)*dot(u,deltaP))- (deltLen*deltLen)+sphere[3]*sphere[3])) < 0) { answer = -10; } else { t =-1*dot(u,deltaP)- sqrt(det) ; if (t>0) { answer = t; } else { answer = -10; } } return answer; } void find_reflect(float *u, float s, float *pO) { float n[3] = {pO[0]+s *u[0]-sphere[0],pO[1]+s *u[1]-sphere[1],pO[2]+s *u[2]- sphere[2]}; float l[3] = {s *u[0],s *u[1],s *u[2]}; u[0] =(2*dot(l,n)*n[0])-l[0]; u[1] = (2*dot(l,n)*n[1])-l[1]; u[2] = (2*dot(l,n)*n[2])-l[2]; } float find_shade(float *u,float s, float *pO) { float answer; float lightVec[3] = {light[0]-(pO[0]+s *u[0]), light[1]-(pO[1]+s *u[1]), light[2]-(pO[2]+s *u[2])}; float n[3] = {pO[0]+s *u[0]-sphere[0],pO[1]+s *u[1]-sphere[1],pO[2]+s *u[2]-sphere[2]}; answer = -1*dot(lightVec,n)/(sqrt(abs(dot(lightVec,lightVec)))*sqrt(abs(dot(n,n)))); return answer; } void init() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,screen_width,0,screen_height); } void display() { glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); for (int i=0; i < screen_width; i++) { for (int j=0; j < screen_height; j++) { float ray[3] = {1*(eye[0]-i),-1*(eye[1]-j),1*eye[2]}; float point[3] = {i,j,0}; norm(ray); int plotted = false; while (!plotted) { float s_plane = plane_intersect(ray, point); float s_sphere = sphere_intersect(ray, point); if (s_plane <= 0 && s_sphere <=0) { glColor3f(0,0,0); glBegin(GL_POINTS); glVertex3f(i,j,0); glEnd(); plotted = true; } else if (s_sphere >= 0 && (s_plane <=0 || s_sphere <= s_plane)) { find_reflect(ray, s_sphere, point); } else if (s_plane >=0 && (s_sphere <=0 ||s_plane <= s_sphere)) { float shade = find_shade(ray, s_plane, point); float xx = s_plane*ray[0] + eye[0]; float z = s_plane*ray[2] + eye[2]; if (abs((int)xx/gridXsize)%2 == abs((int)z/gridZsize)%2) { glColor3f(shade,0,0); } else { glColor3f(shade,shade,shade); } glBegin(GL_POINTS); glVertex3f(i,j,0); glEnd(); plotted = true; } } } } glFlush(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutCreateWindow("Ray Trace with Sphere."); glutInitWindowSize(screen_width,screen_height); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutDisplayFunc(display); init(); glutMainLoop(); return 0; }
The professor did not tell you too much, because such a topic is covered thousands of time over the web, just check-out "Whitted Raytracing" ;) It's homework, and 5mn of googling around would solve the issue... Some clues to help without doing your homework for you Do it step by step, don't try to reproduce the picture in one step Get one sphere working, if hit the plane green pixel, the sphere red pixel, nothing, black. It's enough to get the intersections computing right. It looks like, from your picture, that you don't have the intersections right, for a start Same as previous, with several spheres. Same as one sphere : check intersection for all objects, keep the closest intersection from the point of view. Same as previous, but also compute the amount of light received for each intersection found, to have shade of red for spheres, and shade of green for the plane. (hint: dot product ^^) Texture for the plane Reflection for the spheres. Protip: a mirror don't reflect 100% of the light, just a fraction of it.