I'm using Fltk to render openGL graphs. currently I'm debugging a global array which is sorted by a heapsort function. My purpose is to see after each swap of elements in the heapsort function a graphical swap of elements. but I don't want to catch an event from FLTK event_handle for every time i need to redraw after I swapped and waiting at breakpoint. (the heapsort function and the opengl render part are running in 2 different threads (if that doesn't has to go without saying)).
So the first try I had was to use:
Fl::add_timeout(1.0, MyRedrawCallback, (void *)&myWindow);
Fl::run();
void MyRedrawCallback(void *myWindow)
{
MyWindow *pMyWindow;
pMyWindow = (MyWindow *) myWindow;
pMyWindow->redraw();
Fl::repeat_timeout(1.0, MyRedrawCallback, (void *)&pMyWindow);
}
But every Time the callback is called the 2nd time i get an "Access violation reading"
I'm suggesting that FL::run starts a different thread so maybe the first time is still in same thread so the address of redraw is still usable but after that I'm in a different thread and the function at address is not that what I'm expecting?!
But I already took a different way because I wasn't sure i cant even use the timeout on this way.
So i was looking for a way to get an event that's eq to "set amount of time passed" or "nothing is happening for..." but there isn't such a handle I'm right?
Finally is there a way to let FLTK execute commands even outside the eventloop? or is there another way to solve my problem?
Please take a look at the following example, taken from here: http://seriss.com/people/erco/fltk/#OpenGlInterp
#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/gl.h>
#include <math.h>
//
// Demonstrate interpolating shapes
// erco 06/10/05
//
class Playback : public Fl_Gl_Window {
int frame;
// Linear interpolation between two values based on 'frac' (0.0=a, 1.0=b)
float Linterp(float frac, float a, float b) {
return( a + ( frac * (b - a) ));
}
// Sinusoidal easein/easeout interpolation between two values based on 'frac' (0.0=a, 1.0=b)
float SinInterp(float frac, float a, float b) {
float pi = 3.14159;
frac = (sin(pi/2 + frac*pi ) + 1.0 ) / 2.0; // 0 ~ 1 -> 0 ~ 1
return(Linterp(frac,a,b));
}
// DRAW SIMPLE SHAPE INTERPOLATION
// Interpolation is based on the current frame number
//
void DrawShape(int frame) {
// Calculate a fraction that represents the frame# being shown
float frac = ( frame % 48 ) / 48.0 * 2;
if ( frac > 1.0 ) frac = 2.0-frac; // saw tooth wave: "/\/\/\"
static float a_xy[9][2] = {
{ -.5, -1. }, { 0.0, -.5 }, { -.5, -1. }, { 0.0, -.5 },
{ 0.0, 0.0 },
{ 0.0, -.5 }, { +.5, -1. }, { 0.0, -.5 }, { +.5, -1. },
};
static float b_xy[9][2] = {
{ -.25, -1. }, { -.50, -.75 }, { -.75, -1.0 }, { -.50, -.75 },
{ 0.0, 0.0 },
{ +.50, -.75 }, { +.75, -1.0 }, { +.50, -.75 }, { +.25, -1.0 }
};
// Linterp a and b to form new shape c
float c_xy[9][2];
for ( int i=0; i<9; i++ )
for ( int xy=0; xy<2; xy++ )
c_xy[i][xy] = SinInterp(frac, a_xy[i][xy], b_xy[i][xy]);
// Draw shape
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINE_STRIP);
for ( int i=0; i<9; i++ )
glVertex2f(c_xy[i][0], c_xy[i][1]);
glEnd();
}
// DRAW THE WIDGET
// Each time we're called, assume
//
void draw() {
if (!valid()) {
valid(1);
glLoadIdentity();
glViewport(0,0,w(),h());
}
glClear(GL_COLOR_BUFFER_BIT);
// Draw shape 4x, rotated at 90 degree positions
glPushMatrix();
DrawShape(frame); glRotatef(90.0, 0, 0, 1);
DrawShape(frame); glRotatef(90.0, 0, 0, 1);
DrawShape(frame); glRotatef(90.0, 0, 0, 1);
DrawShape(frame);
glPopMatrix();
// Advance frame counter
++frame;
}
// 24 FPS TIMER CALLBACK
// Called 24x per second to redraw the widget
//
static void Timer_CB(void *userdata) {
Playback *pb = (Playback*)userdata;
pb->redraw();
Fl::repeat_timeout(1.0/24.0, Timer_CB, userdata);
}
public:
// Constructor
Playback(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) {
frame = 0;
Fl::add_timeout(1.0/24.0, Timer_CB, (void*)this); // 24fps timer
end();
}
};
int main() {
Fl_Window win(500, 500);
Playback playback(10, 10, win.w()-20, win.h()-20);
win.resizable(&playback);
win.show();
return(Fl::run());
}
This example more/less does exactly what you want. Greg Ercolano has more FLTK examples on his web-site. I recommend taking a look at http://seriss.com/people/erco/fltk/ .
Related
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.
I have a Solar System that is running on a super low fps (about 26). When I run the program with the planets commented out I get about 1500-2000 fps. When I add any planet it drops down to about 400 fps. And then it only goes downhill from there with the more planets I add. The size of the pictures are not that big. The biggest one I have is about 150kb. Even when I reduce it, the fps still drops the same way.
Here is the code for the solar system.
Updated version using vectors
#include <Vrui/Application.h>
#include <iostream>
#include <vector>
#include "solarSystem.h"
#include "drawShape.h"
#include "planet.h"
#include "skybox.h"
using namespace std;
double orbitSpeed = 0.0;
double rotatSpeed = 0.0;
vector<Planet>planets;
/****************************************************
*
****************************************************/
SolarSystem::SolarSystem(int& argc,char**& argv)
:Vrui::Application(argc,argv)
{
//Vrui::setNavigationTransformation(Vrui::Point::origin,Vrui::Scalar(15));
}
/****************************************************
*
****************************************************/
void SolarSystem::frame(void)
{
Vrui::scheduleUpdate(Vrui::getApplicationTime()); // Aim for 125 FPS
}
/****************************************************
*
****************************************************/
void SolarSystem::createPlanets() const
{
planets.push_back(Planet("images/Sun.jpg", 696, 696, 2500, 0.0, 0.0));
planets.push_back(Planet("images/mercury.jpg", 200.44, 200.44, 57910.0, 45740.0, 0.0));
planets.push_back(Planet("images/venus.jpg", 600.05, 600.05, 108200.0, 107464.0, 177.3));
planets.push_back(Planet("images/earth.jpg", 600.37, 600.34, 149600.0, 147102.0, 23.5));
//planets.push_back(Planet("images/moon.jpg", 300.4, 300.4, 384.0, 363.0, 5.145));
planets.push_back(Planet("images/mars.jpg", 30000.39, 30000.37, 227940.0, 207425.0, 25.2));
planets.push_back(Planet("images/Jupiter.jpg", 69000.9, 65000.24, 778330.0, 740734.0, 3.1));
planets.push_back(Planet("images/neptune.jpg", 24.63, 24.08, 4504300.0, 4460608.0, 29.6));
planets.push_back(Planet("images/pluto.jpg", 10000.15, 10000.15, 5913520.0, 4475140.0, 29.6));
}
/****************************************************
*
****************************************************/
void SolarSystem::displayOrbitPath() const
{
glDisable(GL_LIGHTING);
//Orbit Path
glColor3f(1.0f, 1.0f, 1.0f);
//Mercury //1.5849
drawCircle(91781.559, 72493.326, 1, 200);
//Venus
drawCircle(171486.0, 170319.6936, 1, 200);
//Earth
drawCircle(237101.04, 233141.9598, 1, 200);
//Mars
drawCircle(361262.106, 328747.8825, 1, 200);
//Jupiter
drawCircle(1233575.217, 1173994.071, 1, 200);
//Saturn
drawCircle(1429400.0*1.5849, 1349353.0*1.5849, 1, 100);
//Uranus
drawCircle(2870990.0*1.5849, 2738637.0*1.5849, 1, 100);
//Neptune
drawCircle(7138865.07, 7069617.619, 1, 200);
//Pluto
drawCircle(5913520.0*1.5849, 4475140.0*1.5849, 1, 200);
}
/****************************************************
*
****************************************************/
void SolarSystem::display(GLContextData& contextData) const
{
displayOrbitPath();
glDisable(GL_LIGHTING);
for(std::vector<Planet>::iterator it = planets.begin();
it != planets.end();
++it)
{
double plOrbS = orbitSpeed;
double plRotS = rotatSpeed;
it->displayPlanet(0, plRotS, 0.0,0.0);
}
orbitSpeed+=1;
if (orbitSpeed > 359)
orbitSpeed = 0.0;
rotatSpeed+=3;
if (rotatSpeed > 1436.0)
rotatSpeed = 0.0;
}
/****************************************************
*
****************************************************/
int main(int argc,char* argv[])
{
SolarSystem app(argc, argv);
app.createPlanets();
app.run();
return 0;
}
This is what drops the fps considerably
Updated
planet.h
class Planet
{
public:
//Planet();
Planet(const char* fileName, double ER, double PR,
double orbitSMa, double orbitSmi, double angle);
~Planet() {};
void setOrbit(double orbitSpeed, double rotationSpeed,
double moonOrbitX, double moonOrbitY) ;
void displayPlanet(double orbitSpeed, double rotationSpeed,
double moonOrbitX, double moonOrbitY);
double getMajorAxis() {return majorAxis;};
double getMinorAxis() {return minorAxis;};
private:
const char* texture;
double equatRadius;
double polarRadius;
double orbitSemiMajor;
double orbitSemiMinor;
double majorAxis;
double minorAxis;
double orbitAngle;
Images::RGBImage surfaceImage;
};
planet.cpp Updated
#include "planet.h"
Planet::Planet(const char* fileName, double ER, double PR, double orbitSMa, double orbitSMi, double angle)
{
this->texture = fileName;
this->equatRadius = ER;
this->polarRadius = PR;
this->orbitSemiMajor = orbitSMa;
this->orbitSemiMinor = orbitSMi;
this->majorAxis = 0.0;
this->minorAxis = 0.0;
this->orbitAngle = angle;
surfaceImage=Images::readImageFile(this->texture);
}
void Planet::setOrbit(double orbitSpeed, double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
majorAxis = orbitSemiMajor * cos(orbitSpeed * 0.0055555556 * Math::Constants<double>::pi);
minorAxis = orbitSemiMinor * sin(orbitSpeed * 0.0055555556 * Math::Constants<double>::pi);
glTranslate(majorAxis+moonOrbitX, minorAxis+moonOrbitY, 0.0);
glRotatef(orbitAngle, 0.0, 1.0,1.0);
glRotatef(rotationSpeed, 0.0, 0.0, 1.0);
}
void Planet::displayPlanet(double orbitSpeed,double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
surfaceImage.glTexImage2D(GL_TEXTURE_2D,0,GL_RGB);
glPushMatrix();
setOrbit(orbitSpeed,rotationSpeed, moonOrbitX, moonOrbitY);
drawSolidPlanet(equatRadius, polarRadius, 1, 40, 40);
glPopMatrix();
}
I tried creating the planets using vectors, as you can see above, but I still keep getting low FPS when I run the program.
Here are the computer specs:
Video Card: NVIDIA Quadro FX 580 4GB
Computer: Intel Xeon(R) 3.2GHZ 12GB RAM
Have a list (e.g. std::vector<Planet> of planets in the solarsystem, and only create the planets once (you will need to move them, if you want your solarsystem to have movement.
Only read textures as part of the construction, as (I expect) the texture is "constant".
in SolarSystem::display() use the list of planets to call displayPlanet.
Does Images::readImageFile do file I/O? If so, do not call that every tic. Load it into a buffer/array somewhere one time and then grab the pointer every tic when displaying. You can do the rest of that function in the display, just not the load.
You are re-creating your planets every tic in display. Create them once in a create function, place them in a vector or array, and then call those buffered objects.
You also do not mention what the specs of your test computer are. A low end computer with no real graphics card might struggle with a somewhat complex textured model.
Edit from comment
// Within your Planet class add this where you have your texture stored:
Images::RGBImage surfaceImage;
// When the texture is setup in your constructor, add
surfaceImage=Images::readImageFile(this->texture);
// And remove it from the drawPlanet call
// Global or in a high visibility scope location
std::vector<Planet> planets;
// Call this outside of your main run loop
void createPlanets()
{
planets.push_back(Planet("images/pluto.jpg", 10000.15, 10000.15, 5913520.0, 4475140.0, 29.6));
... // Each planet
}
// And in your main draw loop:
for(std::vector<Planet>::iterator iter = planets.begin();
iter != planets.end();
++iter)
{
double plOrbS = orbitSpeed;
double plRotS = rotatSpeed;
iter->displayPlanet(plOrbS, plRotS, 0.0,0.0);
}
I know that OpenGL selection mode is deprecated and never was HW accelerated, except on a few SGI boxes and 3DLabs GPUs.But i can't get rid of it (not my code).Below its the C++ code:
void GLWidget::Selection(int x,int y) // This Is Where Selection Is Done
{
GLint viewport[4];
glSelectBuffer(BUFSIZE,selectBuf);
glRenderMode(GL_SELECT);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT,viewport);
gluPickMatrix(x,viewport[3]-y,5,5,viewport); //defining the picking matrix
gluPerspective(fov,ratio,0.1f,1000);
glMatrixMode(GL_MODELVIEW);
glInitNames();
glPushName(1); //Pushing names on the stack
glutSolidTorus(1, 2, 55, 55); //Some draw in GL_SELECT mode
glTranslatef(5.0f,1,5.0f);
glPopName();
glPushName(2);
glutSolidTorus(1, 2, 55, 55);
glTranslatef(5.0f,1,5.0f);
glPopName();
glPushName(3);
glutSolidTorus(RADIUS1, RADIUS2, complex1, complex2); //public members
glTranslatef(5.0f,1,5.0f);
glPopName();
int hits;
// restoring the original projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// returning to normal rendering mode
hits = glRenderMode(GL_RENDER);
// if there are hits process them
if (hits != 0){
qDebug() << "Found " << hits << " hit(s)";
processHits(hits,selectBuf);
}
}
This is the processHits method
void GLWidget::processHits (GLint hits, GLuint buffer[]) //Some prints
{
unsigned int i, j;
GLuint names, *ptr, minZ,*ptrNames, numberOfNames;
ptr = (GLuint *) buffer;
minZ = 0xffffffff;
for (i = 0; i < hits; i++) {
names = *ptr;
ptr++;
if (*ptr < minZ) {
numberOfNames = names;
minZ = *ptr;
ptrNames = ptr+2;
}
ptr += names+2;
}
qDebug() << "Nearest: ";
ptr = ptrNames;
for (j = 0; j < numberOfNames; j++,ptr++) {
qDebug() << *ptr ;
}
}
Selection() is invoked by using an *event (GLWidget derives from QGLWidget (QT 4.8)).
So,only when i click the right mousebutton I ""draw"" objects in the buffer and push their names on the stack.
void GLWidget::mousePressEvent(QMouseEvent *event)
{
lastPos = event->pos();
if (event->buttons() & GLUT_RIGHT_BUTTON){
Selection(event->x(),event->y());
}
}
While the paintGL() method is
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glViewport (0, 0, w_screen, h_screen);
gluLookAt(objCamera->mPos.x, objCamera->mPos.y, objCamera->mPos.z,
0, objCamera->mView.y, 0,
objCamera->mUp.x, objCamera->mUp.y, objCamera->mUp.z);
glutSolidTorus(1, 2, 55, 55); //draw some objects
glTranslatef(5.0f,1,5.0f);
glutSolidTorus(1, 2, 55, 55);
glTranslatef(5.0f,1,5.0f);
glutSolidTorus(RADIUS1, RADIUS2, complex1, complex2);
glTranslatef(5.0f,1,5.0f);
glTranslatef(-15.0f,-3,-15.0f);
}
At this time,with this code, I can select an object and retrieve its ID,and if there are more of them on the same xy coordinates i can retrieve the nearest one (by ID).
So,now I've got 3 objects with 3 different IDs (1-2-3).
The one with ID=3 has non fixed size.My question is:how to use the buffer to retrieve the third torus and change its size modifying RADIUS1, RADIUS2, complex1, complex2?
Could someone of you write a small example?
Have I,when there is a hit,simply use the name of the hit on the stack (given with glPushName),that must refers in some way to an object (maybe with a string public member wich contains the name),so i can change its properties?
You are going to have to store the properties of each object yourself. When you push a name onto the name stack, all you're doing is adding extra data to each fragment so you can effectively identify where it came from later.
You'll probably want to create a structure like { float rad1, rad2, complex1, complex2; } to store the values for each torus. Once you know the ID of the object selected, go into your array of said struct, and modify the values for the appropriate object. Each time you draw your scene, just run through this array of structs.
This is how I position my torus (satellite) upon a sphere, and then rotate it around the sphere:
int satellite_1_1_step = 0;
int &r_satellite_1_1_step = satellite_1_1_step;
float satellite_1_1_divider = 300;
float satellite_1_1_theta = 6.5;
float satellite_1_1_phi = 1;
float satellite_1_1_theta_increment = 20/satellite_1_1_divider;
float satellite_1_1_phi_increment = 20/satellite_1_1_divider;
void satellite_1_1 ()
{
float satellite_1_1_theta_math = (satellite_1_1_theta-(satellite_1_1_theta_increment * r_satellite_1_1_step))/10.0*M_PI;
float satellite_1_1_phi_math = (satellite_1_1_phi-(satellite_1_1_phi_increment * r_satellite_1_1_step))/10.0*2*M_PI;
r_satellite_1_1_x = radius_exodus_pos * sin(satellite_1_1_theta_math) * cos(satellite_1_1_phi_math);
r_satellite_1_1_y = radius_exodus_pos * sin(satellite_1_1_theta_math) * sin(satellite_1_1_phi_math);
r_satellite_1_1_z = radius_exodus_pos * cos(satellite_1_1_theta_math);
glPushMatrix();
glTranslatef(r_satellite_1_1_x,r_satellite_1_1_y,r_satellite_1_1_z);
glColor3f(1,0,0);
glutSolidTorus(0.04, 0.2, 10, 100);
glEnd();
glPopMatrix();
}
This is how I update and increment its position:
void satellite_1_1_increment()
{
if (r_satellite_1_1_step < satellite_1_1_divider)
{
++(r_satellite_1_1_step);
}
if (r_satellite_1_1_step >= satellite_1_1_divider)
{
r_satellite_1_1_step = 1;
}
}
So, my torus (satellite) moves around the sphere, ending back up in its starting position, and continues over again - which is great. However, the path it takes wobbles around the poles (I think) along the way - rather than simply circumnavigating the sphere.
Is there an improvement that can be made to my math which will cause the satellite to circumnavigate the sphere in a more circular path?
The first issue I see is this:
void satellite_1_1_increment()
{
if (r_satellite_1_1_step < satellite_1_1_divider)
{
++(r_satellite_1_1_step);
}
if (r_satellite_1_1_step >= satellite_1_1_divider)
{
r_satellite_1_1_step = 1;
}
}
What happens at the edge case when the step is incremented by the first test such that it satisfies the second test? It is immediately reset, thus missing the value. I think you want it written like this to avoid that problem:
void satellite_1_1_increment()
{
if (r_satellite_1_1_step >= satellite_1_1_divider)
r_satellite_1_1_step = 1;
else ++r_satellite_1_1_step;
}
Is 1 the correct reset value? Maybe it should be 0?
Changed the first two lines of:
void satellite_1_1 ()
float satellite_1_1_theta_math = (satellite_1_1_theta+(satellite_1_1_theta_increment* r_satellite_1_1_step))*M_PI;
float satellite_1_1_phi_math = (satellite_1_1_phi-(satellite_1_1_phi_increment* r_satellite_1_1_step))*M_PI/360;
Now the satellite orbits 360 degrees along the equator. Adding a glRotatef after my glPushMatrix lets me fine tune its axis.
Thanks again wallyk. - kropcke
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.