Creating multiple Bezier curves using GL_MAP1_VERTEX_3 function in OpenGL - c++

So I am trying to create an arbitrary curved shape using OpenGL and currently my code is only able to produce one curve between the specified control points, below is my OpenGL code:
#include <GL/glut.h>
#include <stdlib.h>
GLfloat controlPoints[18][3] =
{
{0.0, 8.0, 0.0},
{ -1.5, 3.0, 0.0}, //2
{-5.5, 4.0, 0.0},
{-5.5, 4.0, 0.0},
{-2.5, 0.0, 0.0}, //4
{-6.0, -4.0, 0.0},
{-6.0, -4.0, 0.0},
{-1.5, -3.0, 0.0}, //6
{0.0, -8.0, 0.0},
{0.0, -8.0, 0.0},
{1.0, -3.0, 0.0}, //8
{6.0, -5.0, 0.0},
{6.0, -5.0, 0.0},
{3.0, 0.0, 0.0}, //10
{6.5, 4.5, 0.0},
{6.5, 4.5, 0.0},
{1.5, 3.0, 0.0}, //12
{0.0, 8.0, 0.0}
};
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
for (int i = 0; (i + 3) < 3; i += 3)
{
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &controlPoints[i][0]);
}
//glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &controlPoints2[0][0]);
glEnable(GL_MAP1_VERTEX_3);
// The evaluator with a stride of 3 and an order of 4
}
void display(void)
{
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
//draw(controlPoints);
//draw(controlPoints2);
glBegin(GL_LINE_STRIP);
{
for (int i = 0; i <= 18; i++)
{
glEvalCoord1f((GLfloat)i / 18.0);
}
}
glEnd();
glBegin(GL_LINE_STRIP);
{
for (i = 0; i < 18; i++)
{
glVertex3fv(&controlPoints[i][0]);
}
}
glEnd();
glPointSize(6.0);
glColor3f(0.0, 0.0, 1.0);
glBegin(GL_POINTS);
{
for (i = 0; i < 18; i++)
{
glVertex3fv(&controlPoints[i][0]);
}
}
glEnd();
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
{
glOrtho(-10.0, 10.0, -10.0 * (GLfloat)h / (GLfloat)w, 10.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0);
}
else
{
glOrtho(-10.0 * (GLfloat)h / (GLfloat)w, 10.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0, -10.0, 10.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
exit(0);
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
How do I modify my init portion of the code such that able to produce 6 curves between the three control points totaling up to 18? and if not possible is there a way I can do it using GL_LINE_STRIP?
Below is what my current output looks like:

My advice - avoid openGL evaluators completely!
Aside from some SGI machines back in the 90's, no GPU vendor has ever added hardware support for them, so it falls back to a fairly inefficient software implementation.
Anyhow, there are a few problems in your code...
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3,
4, ///< this says you want 4 control points per curve
&controlPoints[i][0]);
However, there is something wrong here in the control points:
GLfloat controlPoints[18][3] =
{
{0.0, 8.0, 0.0},
{ -1.5, 3.0, 0.0}, //2
{-5.5, 4.0, 0.0}, ///< I'm assuming this is the last control point you want?
{-5.5, 4.0, 0.0}, ///< however this is duplicated here?
It looks as though you want a quadratic curve? (i.e. 3 control points per curve?)
// enable evaluators
glEnable(GL_MAP1_VERTEX_3);
// step through each triplet of CV's
for(int cv = 0; cv < 18; cv += 3) {
// specify the control point array
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0,
3, ///< each vertex has 3 floats.
3, ///< I assume you want 3? (as in 3x CV per curve)
&controlPoints[cv][0]);
// render this curve segment
glBegin(GL_LINE_STRIP);
{
// choose how many divisions you want
int NUM_DIVISIONS = 32;
for (int i = 0; i <= NUM_DIVISIONS; i++)
{
glEvalCoord1f((GLfloat)i / (GLfloat) NUM_DIVISIONS);
}
}
glEnd();
}
glDisable(GL_MAP1_VERTEX_3);
However, as I said above, GL evaluators are terrible.
It's actually just a lot easier to simply write the code yourself.
One option would be to simply tessellate each curve, and then render (This would work with your current control point layout)
void render_quadratic_curves(
GLfloat controlPoints[][3],
int num_curves,
int num_divisions) {
int out_size_of_each_curve = (num_divisions + 1) * 3;
// allocate enough memory to store a curves
GLfloat* temp = new GLfloat[out_size_of_each_curve];
// re-render from the same vertex array.
glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, temp);
glEnableClientState(GL_VERTEX_ARRAY);
for(int curve = 0; curve < num_curves; ++curve) {
// pointers to the control points for this curve
const GLfloat* P0 = controlPoints[3 * curve + 0];
const GLfloat* P1 = controlPoints[3 * curve + 1];
const GLfloat* P2 = controlPoints[3 * curve + 2];
for(int division = 0; division <= num_divisions; ++division) {
GLfloat t = (GLfloat) division / (GLfloat) NUM_DIVISIONS;
GLfloat inv_t = (1.0f - t);
// compute bezier coefficients for quadratic curve
GLfloat B0 = inv_t * inv_t;
GLfloat B1 = 2.0f * inv_t * t;
GLfloat B2 = t * t;
// compute XYZ coordinates
GLfloat x = P0[0] * B0 +
P1[0] * B1 +
P2[0] * B2;
GLfloat y = P0[1] * B0 +
P1[1] * B1 +
P2[1] * B2;
GLfloat z = P0[2] * B0 +
P1[2] * B1 +
P2[2] * B2;
// insert into the buffer for rendering
temp[3 * division + 0] = x;
temp[3 * division + 1] = y;
temp[3 * division + 2] = z;
}
// render this curve in one go as a strip
glDrawArrays(GL_LINE_STRIP, 0, num_divisions + 1);
}
// cleanup
glDisableClientState(GL_VERTEX_ARRAY);
delete [] temp;
}
However, in your case above you effectively have a loop, so this can be done in one go instead with GL_LINE_LOOP instead (This approach would nicely fit into a VBO)
void render_quadratic_curves_as_loop(
GLfloat controlPoints[][3],
int num_curves,
int num_divisions) {
// curves are 1 vertex smaller in size than previously,
// since the start vertex of one curve, is shared with the
// last vertex of the previous curve
int out_size_of_each_curve = num_divisions * 3;
// allocate enough memory to store all of the curves
GLfloat* temp = new GLfloat[out_size_of_each_curve * num_curves];
for(int curve = 0; curve < num_curves; ++curve) {
GLfloat* this_curve = temp + curve * out_size_of_each_curve;
// pointers to the control points for this curve
const GLfloat* P0 = controlPoints[3 * curve + 0];
const GLfloat* P1 = controlPoints[3 * curve + 1];
const GLfloat* P2 = controlPoints[3 * curve + 2];
// note! I am using less than here!
// the last vertex of each curve is simply the first
// vertex of the next one...
for(int division = 0; division < num_divisions; ++division) {
GLfloat t = (GLfloat) division / (GLfloat) NUM_DIVISIONS;
GLfloat inv_t = (1.0f - t);
// compute bezier coefficients for quadratic curve
GLfloat B0 = inv_t * inv_t;
GLfloat B1 = 2.0f * inv_t * t;
GLfloat B2 = t * t;
// compute XYZ coordinates
GLfloat x = P0[0] * B0 +
P1[0] * B1 +
P2[0] * B2;
GLfloat y = P0[1] * B0 +
P1[1] * B1 +
P2[1] * B2;
GLfloat z = P0[2] * B0 +
P1[2] * B1 +
P2[2] * B2;
// insert into the buffer for rendering
this_curve[3 * division + 0] = x;
this_curve[3 * division + 1] = y;
this_curve[3 * division + 2] = z;
}
}
// re-render from the same vertex array.
// This *could* be replaced with a VBO.
glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, temp);
glEnableClientState(GL_VERTEX_ARRAY);
// render all of the curves in one go.
glDrawArrays(GL_LINE_LOOP, 0, out_size_of_each_curve * num_curves);
// cleanup
glDisableClientState(GL_VERTEX_ARRAY);
delete [] temp;
}
// You'll now need to remove the duplicate CV's from your array
GLfloat controlPoints[12][3] =
{
{0.0, 8.0, 0.0},
{ -1.5, 3.0, 0.0}, //2
{-5.5, 4.0, 0.0},
{-2.5, 0.0, 0.0}, //4
{-6.0, -4.0, 0.0},
{-1.5, -3.0, 0.0}, //6
{0.0, -8.0, 0.0},
{1.0, -3.0, 0.0}, //8
{6.0, -5.0, 0.0},
{3.0, 0.0, 0.0}, //10
{6.5, 4.5, 0.0},
{1.5, 3.0, 0.0}, //12
};
render_quadratic_curves_as_loop(controlPoints, 6, 32);
If you actually want 4 CV's per curve, then you can easily extend this into a cubic bezier.
// obviously each curve will now need an additional CV
void render_cubic_curves_as_loop(
GLfloat controlPoints[][3],
int num_curves,
int num_divisions) {
// curves are 1 vertex smaller in size than previously,
// since the start vertex of one curve, is shared with the
// last vertex of the previous curve
int out_size_of_each_curve = num_divisions * 3;
// allocate enough memory to store all of the curves
GLfloat* temp = new GLfloat[out_size_of_each_curve * num_curves];
for(int curve = 0; curve < num_curves; ++curve) {
GLfloat* this_curve = temp + curve * out_size_of_each_curve;
// pointers to the control points for this curve
const GLfloat* P0 = controlPoints[4 * curve + 0];
const GLfloat* P1 = controlPoints[4 * curve + 1];
const GLfloat* P2 = controlPoints[4 * curve + 2];
const GLfloat* P3 = controlPoints[4 * curve + 2];
// note! I am using less than here!
// the last vertex of each curve is simply the first
// vertex of the next one...
for(int division = 0; division < num_divisions; ++division) {
GLfloat t = (GLfloat) division / (GLfloat) NUM_DIVISIONS;
GLfloat inv_t = (1.0f - t);
// compute bezier coefficients for cubic curve
GLfloat B0 = inv_t * inv_t * inv_t;
GLfloat B1 = 3.0f * inv_t * inv_t * t;
GLfloat B2 = 3.0f * inv_t * t * t;
GLfloat B2 = t * t;
// compute XYZ coordinates
GLfloat x = P0[0] * B0 +
P1[0] * B1 +
P2[0] * B2 +
P3[0] * B3;
GLfloat y = P0[1] * B0 +
P1[1] * B1 +
P2[1] * B2 +
P3[1] * B3;
GLfloat z = P0[2] * B0 +
P1[2] * B1 +
P2[2] * B2 +
P3[2] * B3;
// insert into the buffer for rendering
this_curve[3 * division + 0] = x;
this_curve[3 * division + 1] = y;
this_curve[3 * division + 2] = z;
}
}
// re-render from the same vertex array.
// This *could* be replaced with a VBO.
glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, temp);
glEnableClientState(GL_VERTEX_ARRAY);
// render all of the curves in one go.
glDrawArrays(GL_LINE_LOOP, 0, out_size_of_each_curve * num_curves);
// cleanup
glDisableClientState(GL_VERTEX_ARRAY);
delete [] temp;
}
NOTE: on modern hardware, if you have tessellation shaders available, that's usually the best option. Failing that, if you have hardware instancing, you can specify the basis coefficients as a shared vertex buffer, and the control points can be specified per instance.
generate a VBO to store the blending coefficients, and set the VBO to have a vertex divisor of 0.
void populate_shared_vertex_data_for_VBO(float* out, int NUM_DIVISIONS) {
for(int i = 0; i <= NUM_DIVISIONS; ++i) {
GLfloat t = (GLfloat) division / (GLfloat) (NUM_DIVISIONS + 1);
GLfloat inv_t = (1.0f - t);
// compute bezier coefficients for cubic curve
GLfloat B0 = inv_t * inv_t * inv_t;
GLfloat B1 = 3.0f * inv_t * inv_t * t;
GLfloat B2 = 3.0f * inv_t * t * t;
GLfloat B2 = t * t;
out[0] = B0;
out[1] = B1;
out[2] = B2;
out[3] = B3;
out += 4;
}
}
Load the control points for all curves into a single BIG VBO, set up the 4 per-instance attributes (i.e. specify 4 varying shader inputs, one for each CV, set each stride to sizeof(Cubic_Curve_CVS), and set the divisor to 1).
struct Cubic_Curve_CVS {
float P0[3];
float P1[3];
float P2[3];
float P3[3];
};
Cubic_Curve_CVS VBO_DATA[NUM_CURVES]; ///< load this
The vertex shader ends up being pretty simple to implement:
#version 450
uniform mat4 vs_mvp;
// share this buffer between all indices,
// i.e. glVertexAttribDivisor(0, 0);
layout(location = 0) in vec4 vs_coeffs;
// make these per-instance attributes
// i.e. :
// glVertexAttribDivisor(1, 1);
// glVertexAttribDivisor(2, 1);
// glVertexAttribDivisor(3, 1);
// glVertexAttribDivisor(4, 1);
layout(location = 1) in vec4 vs_CV0;
layout(location = 2) in vec4 vs_CV1;
layout(location = 3) in vec4 vs_CV2;
layout(location = 4) in vec4 vs_CV3;
void main()
{
float B0 = vs_coeffs.x;
float B1 = vs_coeffs.y;
float B2 = vs_coeffs.z;
float B3 = vs_coeffs.w;
vec4 V = vs_CV0 * B0 +
vs_CV1 * B1 +
vs_CV2 * B2 +
vs_CV3 * B3;
gl_Position = vs_mvp * V;
}
and then just render the whole lot in one go with glDrawArraysInstanced.

Related

Separating Triangle Strips in Circular Annulus

Given the problem description:
More specifically, the problem involves specifically the decorated annulus. The problem I am having is to separate the lightly shaded triangle from the dark shaded triangles.
I have produced code (based on a previous example) that produces a circular annulus. However, the triangles are together rather than separate, and produce the same color.
Here is the code that I have produced so far:
///////////////////////////////////////////////////////////////////////////////////////////
// circularAnnuluses.cpp
//
// This program draws three identical-looking circular annuluses in three different ways -
// see comments below.
//
// Interaction:
// Press the space bar to toggle between wirefrime and filled for the lower annulus.
//
// Sumanta Guha.
///////////////////////////////////////////////////////////////////////////////////////////
#include <cstdlib>
#include <cmath>
#include <iostream>
#ifdef __APPLE__
# include <GL/glew.h>
# include <GL/freeglut.h>
# include <OpenGL/glext.h>
#else
# include <GL/glew.h>
# include <GL/freeglut.h>
//# include <GL/glext.h>
#pragma comment(lib, "glew32.lib")
#endif
#define PI 3.14159265
#define N 6.0 // Number of vertices on the boundary of the disc.
using namespace std;
// Globals.
static int isWire = 0; // Is wireframe?
// Drawing routine.
void drawScene(void)
{
float angle;
int i;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the buffers including
// the depth buffer.
glPolygonMode(GL_FRONT, GL_FILL);
// Lower circular annulus: with a true hole.
if (isWire) glPolygonMode(GL_FRONT, GL_LINE); else glPolygonMode(GL_FRONT, GL_FILL);
glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i <= N; ++i)
{
angle = 2 * PI * i / N;
glColor3f(1.0, 0.0, 0.0);
glVertex3f(50 + cos(angle) * 10.0, 50 + sin(angle) * 10.0, 0.0);
glColor3f(0, 1, 0);
glVertex3f(50 + cos(angle) * 20.0, 50 + sin(angle) * 20.0, 0.0);
}
glEnd();
// Write labels.
glColor3f(0.0, 0.0, 0.0);
glFlush();
}
// Initialization routine.
void setup(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
}
// OpenGL window reshape routine.
void resize(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 100.0, 0.0, 100.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
switch (key)
{
case ' ':
if (isWire == 0) isWire = 1;
else isWire = 0;
glutPostRedisplay();
break;
case 27:
exit(0);
break;
default:
break;
}
}
// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
cout << "Interaction:" << endl;
cout << "Press the space bar to toggle between wirefrime and filled for the lower annulus." << endl;
}
// Main routine.
int main(int argc, char** argv)
{
printInteraction();
glutInit(&argc, argv);
glutInitContextVersion(4, 3);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("DecoratedAnnulus.cpp");
glutDisplayFunc(drawScene);
glutReshapeFunc(resize);
glutKeyboardFunc(keyInput);
glewExperimental = GL_TRUE;
glewInit();
setup();
glutMainLoop();
}
The section of code where the problem lies is in the 'drawscene' function. I believe there should be two different for loops to separate the triangles from one another, but whenever I try to split the for loop it produces a monster of a shape.
I'm not exactly sure where to begin to complete this last problem.
As mentioned in the other answer, a possibility is to switch to flat shading mode by glShadeModel.
But note, you've also to offset the vertex coordinates of the outer circle:
glShadeModel( GL_FLAT );
glBegin(GL_TRIANGLE_STRIP);
for (i = 0; i <= N; ++i)
{
angle1 = 2 * PI * i / N;
angle2 = 2 * PI * (i+0.5) / N;
glColor3f(1.0, 0.0, 0.0);
glVertex3f(50 + cos(angle1) * 10.0, 50 + sin(angle1) * 10.0, 0.0);
glColor3f(0, 1, 0);
glVertex3f(50 + cos(angle2) * 20.0, 50 + sin(angle2) * 20.0, 0.0);
}
glEnd();
The other possibility is to draw the inner and outer triangles with the primitive type GL_TRIANGLES in 2 separate loops:
glShadeModel( GL_SMOOTH );
glBegin(GL_TRIANGLES);
glColor3f(1.0, 0.0, 0.0);
for (i = 0; i <= N; ++i)
{
angle1 = 2 * PI * i / N;
angle2 = 2 * PI * (i+0.5) / N;
angle3 = 2 * PI * (i+1) / N;
glVertex3f(50 + cos(angle1) * 10.0, 50 + sin(angle1) * 10.0, 0.0);
glVertex3f(50 + cos(angle2) * 20.0, 50 + sin(angle2) * 20.0, 0.0);
glVertex3f(50 + cos(angle3) * 10.0, 50 + sin(angle3) * 10.0, 0.0);
}
glEnd();
glBegin(GL_TRIANGLES);
glColor3f(0, 1, 0);
for (i = 0; i <= N; ++i)
{
angle1 = 2 * PI * (i-0.5) / N;
angle2 = 2 * PI * i / N;
angle3 = 2 * PI * (i+0.5) / N;
glVertex3f(50 + cos(angle1) * 20.0, 50 + sin(angle1) * 20.0, 0.0);
glVertex3f(50 + cos(angle2) * 10.0, 50 + sin(angle2) * 10.0, 0.0);
glVertex3f(50 + cos(angle3) * 20.0, 50 + sin(angle3) * 20.0, 0.0);
}
glEnd();
Both methods generate the following image:
If you want a more "circular" look, then you've to tessellate the segments along the inner or outer circle. Use the primitive type GL_TRIANGLE_FAN (see Triangle primitives) to draw a single segment:
int N2 = 10;
glShadeModel( GL_SMOOTH );
# draw the red segments
glColor3f(1.0, 0.0, 0.0);
for (int i = 0; i <= N; ++i)
{
float angle1 = 2 * PI * i / N;
float angle2 = 2 * PI * (i+0.5) / N;
float angle3 = 2 * PI * (i+1) / N;
# draw a single red segment
glBegin(GL_TRIANGLE_FAN);
glVertex3f(50 + cos(angle2) * 20.0, 50 + sin(angle2) * 20.0, 0.0);
for (int j = 0; j <= N2; ++j)
{
float a = angle1 + (angle3 - angle1) * (float)j / (float)N2;
glVertex3f(50 + cos(a) * 10.0, 50 + sin(a) * 10.0, 0.0);
}
glEnd();
}
# draw the green sgements
glColor3f(0, 1, 0);
for (int i = 0; i <= N; ++i)
{
float angle1 = 2 * PI * (i-0.5) / N;
float angle2 = 2 * PI * i / N;
float angle3 = 2 * PI * (i+0.5) / N;
# draw a single green segment
glBegin(GL_TRIANGLE_FAN);
glVertex3f(50 + cos(angle2) * 10.0, 50 + sin(angle2) * 10.0, 0.0);
for (int j = 0; j <= N2; ++j)
{
float a = angle1 + (angle3 - angle1) * (float)j / (float)N2;
glVertex3f(50 + cos(a) * 20.0, 50 + sin(a) * 20.0, 0.0);
}
glEnd();
}

Drawing Circle with OpenGL

I'm trying to draw simple circle with C++/OpenGl
my code is:
#include <GL/glut.h>
#include <math.h>
void Draw() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glColor3f (0.0, 0.0, 0.0);
glVertex3f (0.1, 0.1, 0.0);
glVertex3f (0.9, 0.1, 0.0);
glVertex3f (0.9, 0.9, 0.0);
glVertex3f (0.1, 0.9, 0.0);
glEnd();
glFlush();
}
void DrawCircle(float cx, float cy, float r, int num_segments)
{
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
float theta = 2.0f * 3.1415926f * float(ii) / float(num_segments);//get the current angle
float x = r * cosf(theta);//calculate the x component
float y = r * sinf(theta);//calculate the y component
glVertex2f(x + cx, y + cy);//output vertex
}
glEnd();
}
void Initialize() {
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
int main(int iArgc, char** cppArgv) {
glutInit(&iArgc, cppArgv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(950, 500);
glutInitWindowPosition(200, 200);
glutCreateWindow("Universum");
Initialize();
glutDisplayFunc(Draw);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
DrawCircle(0.5, 0.5, 0.2, 5);
glutMainLoop();
return 0;
}
I'm beginner with OpenGL and now i'm starting to learn,
Can someone please explain me why i don't get the circle (i only see the black box),
Thanks!
It looks like immediately after you draw the circle, you go into the main glut loop, where you've set the Draw() function to draw every time through the loop. So it's probably drawing the circle, then erasing it immediately and drawing the square. You should probably either make DrawCircle() your glutDisplayFunc(), or call DrawCircle() from Draw().
#include <Windows.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define window_width 1080
#define window_height 720
void drawFilledSun(){
//static float angle;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -10);
int i, x, y;
double radius = 0.30;
//glColor3ub(253, 184, 19);
glColor3ub(255, 0, 0);
double twicePi = 2.0 * 3.142;
x = 0, y = 0;
glBegin(GL_TRIANGLE_FAN); //BEGIN CIRCLE
glVertex2f(x, y); // center of circle
for (i = 0; i <= 20; i++) {
glVertex2f (
(x + (radius * cos(i * twicePi / 20))), (y + (radius * sin(i * twicePi / 20)))
);
}
glEnd(); //END
}
void DrawCircle(float cx, float cy, float r, int num_segments) {
glBegin(GL_LINE_LOOP);
for (int ii = 0; ii < num_segments; ii++) {
float theta = 2.0f * 3.1415926f * float(ii) / float(num_segments);//get the current angle
float x = r * cosf(theta);//calculate the x component
float y = r * sinf(theta);//calculate the y component
glVertex2f(x + cx, y + cy);//output vertex
}
glEnd();
}
void main_loop_function() {
int c;
drawFilledSun();
DrawCircle(0, 0, 0.7, 100);
glutSwapBuffers();
c = getchar();
}
void GL_Setup(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glEnable(GL_DEPTH_TEST);
gluPerspective(45, (float)width / height, .1, 100);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitWindowSize(window_width, window_height);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("GLUT Example!!!");
glutIdleFunc(main_loop_function);
GL_Setup(window_width, window_height);
glutMainLoop();
}
This is what I did. I hope this helps. Two types of circle are here. Filled and unfilled.
There is another way to draw a circle - draw it in fragment shader.
Create a quad:
float right = 0.5;
float bottom = -0.5;
float left = -0.5;
float top = 0.5;
float quad[20] = {
//x, y, z, lx, ly
right, bottom, 0, 1.0, -1.0,
right, top, 0, 1.0, 1.0,
left, top, 0, -1.0, 1.0,
left, bottom, 0, -1.0, -1.0,
};
Bind VBO:
unsigned int glBuffer;
glGenBuffers(1, &glBuffer);
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*20, quad, GL_STATIC_DRAW);
and draw:
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
glEnableVertexAttribArray(ATTRIB_VERTEX);
glEnableVertexAttribArray(ATTRIB_VALUE);
glVertexAttribPointer(ATTRIB_VERTEX , 3, GL_FLOAT, GL_FALSE, 20, 0);
glVertexAttribPointer(ATTRIB_VALUE , 2, GL_FLOAT, GL_FALSE, 20, BUFFER_OFFSET(12));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
Vertex shader
attribute vec2 value;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
varying vec2 val;
void main() {
val = value;
gl_Position = projectionMatrix*viewMatrix*vertex;
}
Fragment shader
varying vec2 val;
void main() {
float R = 1.0;
float R2 = 0.5;
float dist = sqrt(dot(val,val));
if (dist >= R || dist <= R2) {
discard;
}
float sm = smoothstep(R,R-0.01,dist);
float sm2 = smoothstep(R2,R2+0.01,dist);
float alpha = sm*sm2;
gl_FragColor = vec4(0.0, 0.0, 1.0, alpha);
}
Don't forget to enable alpha blending:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
UPDATE: Read more
We will find the value of X and Y from this image. We know, sinθ=vertical/hypotenuse and cosθ=base/hypotenuse from the image we can say X=base and Y=vertical. Now we can write X=hypotenuse * cosθ and Y=hypotenuse * sinθ.
Now look at this code
void display(){
float x,y;
glColor3f(1, 1, 0);
for(double i =0; i <= 360;){
glBegin(GL_TRIANGLES);
x=5*cos(i);
y=5*sin(i);
glVertex2d(x, y);
i=i+.5;
x=5*cos(i);
y=5*sin(i);
glVertex2d(x, y);
glVertex2d(0, 0);
glEnd();
i=i+.5;
}
glEnd();
glutSwapBuffers();
}
glBegin(GL_POLYGON); // Middle circle
double radius = 0.2;
double ori_x = 0.0; // the origin or center of circle
double ori_y = 0.0;
for (int i = 0; i <= 300; i++) {
double angle = 2 * PI * i / 300;
double x = cos(angle) * radius;
double y = sin(angle) * radius;
glVertex2d(ori_x + x, ori_y + y);
}
glEnd();
Here is a code to draw a fill elipse, you can use the same method but replacing de xcenter and y center with radius
void drawFilledelipse(GLfloat x, GLfloat y, GLfloat xcenter,GLfloat ycenter) {
int i;
int triangleAmount = 20; //# of triangles used to draw circle
//GLfloat radius = 0.8f; //radius
GLfloat twicePi = 2.0f * PI;
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x, y); // center of circle
for (i = 0; i <= triangleAmount; i++) {
glVertex2f(
x + ((xcenter+1)* cos(i * twicePi / triangleAmount)),
y + ((ycenter-1)* sin(i * twicePi / triangleAmount))
);
}
glEnd();
}
I have done it using the following code,
glBegin(GL.GL_LINE_LOOP);
for(int i =0; i <= 300; i++){
double angle = 2 * Math.PI * i / 300;
double x = Math.cos(angle);
double y = Math.sin(angle);
gl.glVertex2d(x,y);
}
glEnd();
glBegin(GL_POLYGON);
double x = 2;
double y = 2;
for (int i = 0; i <= 360; i++) {
glVertex2d(x * sin(i), y * cos(i));
}
glEnd();

Can't get Gouraud Shading in OpenGL to work

I'm trying to get a shape to have some shading due to a light source but I'd like the shape to all be one colour.
My problem is that no matter how hard I try I cannot seem to get any shading on a singular colour model. I've simplified my model to a single triangle to make this example clearer:
#include <GL/glut.h>
#include <math.h>
#include <iostream>
#include<map>
#include<vector>
using namespace std;
/* Verticies for simplified demo */
float vertices[][3] = {
{0.1, 0.1, 0.1},
{0.2, 0.8, 0.3},
{0.3, 0.5, 0.5},
{0.8, 0.2, 0.1},
};
const int VERTICES_SIZE = 4;
/* Polygons for simplified demo */
int polygon[][3] = {
{0, 1, 3},
{0, 2, 1},
{0, 3, 2},
{1, 2, 3},
};
const int POLYGON_SIZE = 4;
/* Average point for looking at */
float av_point[3];
/*
* Holds the normal for each vertex calculated by averaging the
* planar normals that each vertex is connected to.
* It holds {index_of_vertex_in_vertices : normal}
*/
map<int, float*> vertex_normals;
/*
* Calculates average point in list of vertices
* Stores in result
*/
void averagePoint(float vertices[][3], int length, float result[3]) {
for(int i = 0; i < length; i++) {
result[0] += vertices[i][0];
result[1] += vertices[i][1];
result[2] += vertices[i][2];
}
result[0] /= length;
result[1] /= length;
result[2] /= length;
}
/*
* Performs inplace normalisation of vector v
*/
void normalise(float v[3]) {
GLfloat length = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] /= length;
v[1] /= length;
v[2] /= length;
}
/*
* Performs cross product of vectors u and v and stores
* result in result
* Normalises result.
*/
void crossProduct(float u[], float v[], float result[]) {
result[0] = u[1] * v[2] - u[2] * v[1];
result[1] = u[2] * v[0] - u[0] * v[2];
result[2] = u[0] * v[1] - u[1] * v[0];
}
/*
* Calculates normal for plane
*/
void calculate_normal(int polygon[3], float vertices[][3], float normal[3]) {
GLfloat u[3], v[3];
for (int i = 0; i < 3; i++) {
u[i] = vertices[polygon[0]][i] - vertices[polygon[1]][i];
v[i] = vertices[polygon[2]][i] - vertices[polygon[1]][i];
}
crossProduct(u, v, normal);
normalise(normal);
}
/*
* Populates vertex_normal with it's averaged face normal
*/
void calculate_vertex_normals (map<int, float*> &vertex_normal){
map<int, vector<int> > vertex_to_faces;
map<int, float*> faces_to_normal;
// Loop over faces
for (int i = 0; i < POLYGON_SIZE; i++) {
float* normal = new float[3];
calculate_normal(polygon[i], vertices, normal);
for (int j = 0; j < 3; j++) {
vertex_to_faces[polygon[i][j]].push_back(i);
}
faces_to_normal[i] = normal;
}
vertex_normal.clear();
// Loop over vertices
for (int v = 0; v < VERTICES_SIZE; v++) {
vector<int> faces = vertex_to_faces[v];
int faces_count = 0;
float* normal = new float[3];
for (vector<int>::iterator it = faces.begin(); it != faces.end(); ++it){
normal[0] += faces_to_normal[*it][0];
normal[1] += faces_to_normal[*it][1];
normal[2] += faces_to_normal[*it][2];
faces_count++;
}
normal[0] /= faces_count;
normal[1] /= faces_count;
normal[2] /= faces_count;
vertex_normal[v] = normal;
}
// Delete normal declared in first loop
for (int i = 0; i < POLYGON_SIZE; i++) {
delete faces_to_normal[i];
}
}
/*
* Draws polygons in polygon array.
*/
void draw_polygon() {
for(int i = 0; i < POLYGON_SIZE; i++) {
glBegin(GL_POLYGON);
for(int j = 0; j < 3; j++) {
glNormal3fv(vertex_normals[polygon[i][j]]);
glVertex3fv(vertices[polygon[i][j]]);
}
glEnd();
}
}
/*
* Sets up lighting and material properties
*/
void init()
{
// Calculate average point for looking at
averagePoint(vertices, VERTICES_SIZE, av_point);
// Calculate vertices average normals
calculate_vertex_normals(vertex_normals);
glClearColor (0.0, 0.0, 0.0, 0.0);
cout << "init" << endl;
// Intialise and set lighting parameters
GLfloat light_pos[] = {1.0, 1.0, 1.0, 0.0};
GLfloat light_ka[] = {0.2, 0.2, 0.2, 1.0};
GLfloat light_kd[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_ks[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ka);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_kd);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_ks);
// Initialise and set material parameters
GLfloat material_ka[] = {1.0, 1.0, 1.0, 1.0};
GLfloat material_kd[] = {0.43, 0.47, 0.54, 1.0};
GLfloat material_ks[] = {0.33, 0.33, 0.52, 1.0};
GLfloat material_ke[] = {0.0, 0.0, 0.0, 0.0};
GLfloat material_se[] = {10.0};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material_ka);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material_kd);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material_ks);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material_ke);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material_se);
// Smooth shading
glShadeModel(GL_SMOOTH);
// Enable lighting
glEnable (GL_LIGHTING);
glEnable (GL_LIGHT0);
// Enable Z-buffering
glEnable(GL_DEPTH_TEST);
}
/*
* Free's resources
*/
void destroy() {
for (int i = 0; i < VERTICES_SIZE; i++) {
delete vertex_normals[i];
}
}
/*
* Display simple polygon
*/
void display (){
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_polygon();
glutSwapBuffers();
}
/*
* Sets up camera perspective and view point
* Looks at average point in model.
*/
void reshape (int w, int h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, 1.0, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 1, av_point[0], av_point[1], av_point[2], 0, 0.5, 0);
}
int main (int argc, char **argv)
{
// Initialize graphics window
glutInit(&argc, argv);
glutInitWindowSize(256, 256);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE);
// Initialize OpenGL
init();
glutCreateWindow("Rendering");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop ();
destroy();
return 1;
}
I'm really new to OpenGL so I'm hoping that it's something simple. Since I've remembered to set my normals so I'm not sure what else is going wrong.
The end aim is to render a face with Gouraud shading (and then textures) for my coursework however we've almost been left to figure out OpenGL (1.4 - course requirement) for ourselves, and we aren't allowed to use shaders.
I'm trying to create something similar to this picture (taken from Google):
with my triangle.
shading due to a light source but I'd like the shape to all be one colour.
Aren't those two requirements mutually exclusive? What exactly is your desired outcome. Can you draw a picture what you're imagining? When it comes to implementing, using shaders is a lot easier than juggling with a gazillion of OpenGL state machine switches.
Update
Anyway here's my revised version of OPs code that draws a single triangle subject to Gourad illumination. This code compiles and draw a single triangle with a hint of a specular reflex.
Let's go through what I did. First there's your original setup of the triangle. Nothing special here and nothing changed either (except a few includes) (EDIT) on second look I did a change. The use of a std::map was totally unaccounted for. We know the number of vertices and can just preallocate the normals' memory.
#include <GL/glut.h>
#include <math.h>
// for memcpy
#include <string.h>
#include <map>
#include <vector>
#include <iostream>
using namespace::std;
/* Verticies for simplified demo */
const int VERTICES_SIZE = 4;
float vertices[VERTICES_SIZE][3] = {
{0.1, 0.1, 0.1},
{0.2, 0.8, 0.3},
{0.3, 0.5, 0.5},
{0.8, 0.2, 0.1},
};
// this is now a plain array
float vertex_normals[VERTICES_SIZE][3];
/* Polygons for simplified demo */
const int POLYGON_SIZE = 4;
int polygon[POLYGON_SIZE][3] = {
{0, 1, 3},
{0, 2, 1},
{0, 3, 2},
{1, 2, 3},
};
/* Average point for looking at */
float av_point[3];
/*
* Calculates average point in list of vertices
* Stores in result
*/
void averagePoint(float vertices[][3], int length, float result[3]) {
for(int i = 0; i < length; i++) {
result[0] += vertices[i][0];
result[1] += vertices[i][1];
result[2] += vertices[i][2];
}
result[0] /= length;
result[1] /= length;
result[2] /= length;
}
/*
* Performs inplace normalisation of vector v
*/
void normalise(float v[3]) {
GLfloat length = sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] /= length;
v[1] /= length;
v[2] /= length;
}
/*
* Performs cross product of vectors u and v and stores
* result in result
* Normalises result.
*/
void crossProduct(float u[], float v[], float result[]) {
result[0] = u[1] * v[2] - u[2] * v[1];
result[1] = u[2] * v[0] - u[0] * v[2];
result[2] = u[0] * v[1] - u[1] * v[0];
}
/*
* Calculates normal for plane
*/
void calculate_normal(int polygon[3], float vertices[][3], float normal[3]) {
GLfloat u[3], v[3];
for (int i = 0; i < 3; i++) {
u[i] = vertices[polygon[0]][i] - vertices[polygon[1]][i];
v[i] = vertices[polygon[2]][i] - vertices[polygon[1]][i];
}
crossProduct(u, v, normal);
normalise(normal);
}
EDIT: My next change was here. See the comment
/*
* Populates normals with it's averaged face normal
*
* Passing the normal output buffer as a parameter was a bit
* pointless, as this procedure accesses global variables anyway.
* Either pass everything as parameters or noting at all,
* be consequent. And doing it mixed is pure evil.
*/
void calculate_vertex_normals()
{
// We love RAII, no need for new and delete!
vector< vector<int> > vertex_to_faces(POLYGON_SIZE);
vector< vector<float> > faces_to_normal(POLYGON_SIZE);
// Loop over faces
for (int i = 0; i < POLYGON_SIZE; i++) {
vector<float> normal(3);
calculate_normal(polygon[i], vertices, &normal[0]);
for (int j = 0; j < 3; j++) {
vertex_to_faces[polygon[i][j]].push_back(i);
}
faces_to_normal[i] = normal;
}
// Loop over vertices
for (int v = 0; v < VERTICES_SIZE; v++) {
// avoid a copy here by using a reference
vector<int> &faces = vertex_to_faces[v];
int faces_count = 0;
float normal[3];
for (vector<int>::iterator it = faces.begin(); it != faces.end(); ++it){
normal[0] += faces_to_normal[*it][0];
normal[1] += faces_to_normal[*it][1];
normal[2] += faces_to_normal[*it][2];
faces_count++;
}
// dividing a vector obtained by a number of unit length vectors
// summed by the number of unit vectors summed does not normalize
// it. You need to normalize it properly!
normalise(normal);
// memcpy is really be best choice here
memcpy(vertex_normals[v], normal, sizeof(normal));
}
}
draw_polygon is a rather unhappy name for this function. It draws a triangulated mesh. *EDIT: Also it can be written much nicer by employing vertex arrays (available since 1994 with OpenGL-1.1).
/*
* Draws polygons in polygon array.
*/
void draw_polygon() {
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, &vertices[0][0]);
glNormalPointer(GL_FLOAT, 0, &vertex_normals[0][0]);
glDrawElements(GL_TRIANGLES, POLYGON_SIZE*3, GL_UNSIGNED_INT, polygon);
}
Here it's getting interesting. A common misconception is, that people think OpenGL is "initialized". That's not the case. What you initialize is data. In your case your geometry data
/*
* Sets up lighting and material properties
*/
void init_geometry()
{
// Calculate average point for looking at
averagePoint(vertices, VERTICES_SIZE, av_point);
// Calculate vertices average normals
calculate_vertex_normals(vertex_normals);
}
Here comes the tricky part: OpenGL fixed function illumination is a state as everything else. When you call glLightfv it will set internal parameters based on state when being called. The position is transformed by the modelview when calling this. But without a proper modelview being set up, you can't setup the illumination. Hence I put it into its own function, which we call right after setting up modelview in the drawing function.
void setup_illumination()
{
// Intialise and set lighting parameters
GLfloat light_pos[] = {1.0, 1.0, 1.0, 0.0};
GLfloat light_ka[] = {0.2, 0.2, 0.2, 1.0};
GLfloat light_kd[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_ks[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ka);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_kd);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_ks);
// Initialise and set material parameters
GLfloat material_ka[] = {1.0, 1.0, 1.0, 1.0};
GLfloat material_kd[] = {0.43, 0.47, 0.54, 1.0};
GLfloat material_ks[] = {0.33, 0.33, 0.52, 1.0};
GLfloat material_ke[] = {0.0, 0.0, 0.0, 0.0};
GLfloat material_se[] = {10.0};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material_ka);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material_kd);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material_ks);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material_ke);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, material_se);
// Smooth shading
glShadeModel(GL_SMOOTH);
// Enable lighting
glEnable (GL_LIGHTING);
glEnable (GL_LIGHT0);
}
For the drawing function a few things were changed. See the comments in the code
/*
* Display simple polygon
*/
void display (void)
{
// float window sizes are usefull for view volume calculations
//
// requesting the window dimensions for each drawing iteration
// is just two function calls. Compare this to the number of function
// calls a typical application will do for the actual rendering
// Trying to optimize away those two calls is a fruitless microoptimization
float const window_width = glutGet(GLUT_WINDOW_WIDTH);
float const window_height = glutGet(GLUT_WINDOW_HEIGHT);
float const window_aspect = window_width / window_height;
// glViewport operates independent of the projection --
// another reason to put it into the drawing code
glViewport(0, 0, window_width, window_height);
glClearDepth(1.);
glClearColor (0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// It's a often made mistake to setup projection in the window resize
// handler. Projection is a drawing state, hence should be set in
// the drawing code. Also in most programs you will have multiple
// projections mixed throughout rendering a single frame so there you
// actually **must** set projection in drawing code, otherwise it
// wouldn't work.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70, window_aspect, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, -3, av_point[0], av_point[1], av_point[2], 0, 1, 0);
// Fixed function pipeline light position setup calls operate on the current
// modelview matrix, so we must setup the illumination parameters with the
// modelview matrix at least after the view transformation (look-at) applied.
setup_illumination();
// Enable depth testing (z buffering would be enabled/disabled with glDepthMask)
glEnable(GL_DEPTH_TEST);
draw_polygon();
glutSwapBuffers();
}
int main (int argc, char **argv)
{
// Initialize graphics window
glutInit(&argc, argv);
glutInitWindowSize(256, 256);
glutInitDisplayMode (GLUT_DEPTH | GLUT_DOUBLE);
// we actually have to create a window
glutCreateWindow("illuination");
// Initialize geometry
init_geometry();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
You seem to have an array called vertices (which is the correct spelling), and another array called verticies, in several places (calculate_normal is the most obvious example). Is this a mistake? It could be messing up your normal calculations where you take one co-ordinate from the first array but the second co-ordinate from a different, unrelated array.

Rotation of my cube based on arcball quaternion rotation matrix slightly off

Im trying to rotate my cube using quaternion to matrix rotation based on arcball mouse movement. My cube is rendering, and it has movement/rotation, but it isnt simply just rotating around an axis, it is also moving in the direction of my mouse, so i think that either the data that im getting from my trackball is a bit off, or the way im transforming my quaternion into a rotation matrix is slightly off. trackball_ptov is where i translate mouse location to an arcball. mouseMotion() is where im creating the rotation matrix from the quaternion.
The entirety of my main:
#include "Angel.h"
#include <gl/glew.h>
#include <glut.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
using namespace std;
#define bool int /* if system does not support bool type */
#define false 0
#define true 1
#define M_PI 3.14159265358 /* if not in math.h */
int winWidth, winHeight;
float angle = 0.0, axis[3], trans[3];
bool trackingMouse = false;
float lastPos[3] = {0.0, 0.0, 0.0};
float aspect = 1.0;
int curx, cury;
int startX, startY;
int modelInit=1;
//the program object
GLuint program = 0;
glm::mat4 model;
typedef Angel::vec4 color4;
typedef Angel::vec4 point4;
const int NumVertices = 36; //(6 faces)(2 triangles/face)(3 vertices/triangle)
point4 points[NumVertices];
color4 colors[NumVertices];
enum { Xaxis = 0, Yaxis = 1, Zaxis = 2, NumAxes = 3 };
int Axis = Xaxis;
GLuint mvpUniform;
GLuint shaderaxis;
int Index = 0;
// Vertices of a unit cube centered at origin, sides aligned with axes
point4 vertices[8]={
point4(-0.5, -0.5, 0.5, 1.0),
point4(-0.5, 0.5, 0.5, 1.0),
point4(0.5, 0.5, 0.5, 1.0),
point4(0.5, -0.5, 0.5, 1.0),
point4(-0.5, -0.5, -0.5, 1.0),
point4(-0.5, 0.5, -0.5, 1.0),
point4(0.5, 0.5, -0.5, 1.0),
point4(0.5, -0.5, -0.5, 1.0)
};
// RGBA colors
color4 vertex_colors[8] = {
color4(0.0, 0.0, 0.0, 1.0), // black
color4(1.0, 0.0, 0.0, 1.0), // red
color4(1.0, 1.0, 0.0, 1.0), // yellow
color4(0.0, 1.0, 0.0, 1.0), // green
color4(0.0, 0.0, 1.0, 1.0), // blue
color4(1.0, 0.0, 1.0, 1.0), // magenta
color4(1.0, 1.0, 1.0, 1.0), // white
color4(0.0, 1.0, 1.0, 1.0) // cyan
};
// quad generates two triangles for each face and assigns colors to the vertices
void quad(int a, int b, int c, int d) {
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[b]; points[Index] = vertices[b]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[a]; points[Index] = vertices[a]; Index++;
colors[Index] = vertex_colors[c]; points[Index] = vertices[c]; Index++;
colors[Index] = vertex_colors[d]; points[Index] = vertices[d]; Index++;
}
// generate 12 triangles: 36 vertices and 36 colors
void colorcube(void) {
quad(1, 0, 3, 2);
quad(2, 3, 7, 6);
quad(3, 0, 4, 7);
quad(6, 5, 1, 2);
quad(4, 5, 6, 7);
quad(5, 4, 0, 1);
}
// OpenGL initialization
void init(void) {
colorcube();
// Load shaders and use the resulting shader program
GLuint program = InitShader("vshader36.glsl", "fshader36.glsl");
glUseProgram(program);
// Create a vertex array object
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and initialize a buffer object
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(colors), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(points), points);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(points), sizeof(colors), colors);
// set up vertex arrays
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
model = glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, -5.0));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(points)));
mvpUniform = glGetUniformLocation(program, "mvp");
glEnable(GL_DEPTH_TEST);
glClearColor(1.0, 1.0, 1.0, 1.0);
}
void trackball_ptov(int x, int y, int width, int height, float v[3]) {
float d, a;
/* project x, y onto a hemisphere centered within width, height , note z is up here*/
v[0] = (2.0*x - width) / width;
v[1] = (height - 2.0F*y) / height;
d = sqrt(v[0]*v[0] + v[1]*v[1]);
v[2] = cos((M_PI/2.0) * ((d < 1.0) ? d : 1.0));
a = 1.0 / sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] *= a;
v[1] *= a;
v[2] *= a;
}
void display() {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glm::mat4 proj = glm::perspective(90.F, 1.F, 0.1F, 100.F);
glm::mat4 view = glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, 0.0)); //apply mouse translation
//view = glm::rotate(view, 0.2*mousediff.x, glm::vec3(0.0, 1.0, 0.0)); //apply mouse rotation
//view = glm::rotate(view, 0.2*mousediff.y, glm::vec3(1.0, 0.0, 0.0));
//model = glm::translate(glm::mat4(1.0), glm::vec3(0.0, 0.0, -5.0));
//glUniformMatrix4fv(mvpUniform, 1, false, glm::value_ptr(proj));
glUniformMatrix4fv(mvpUniform, 1, false, glm::value_ptr(proj*view*model));
//glUniformMatrix4fv(mvpUniform, 1, false, glm::value_ptr(model*view*proj));
glDrawArrays(GL_TRIANGLES, 0, NumVertices);
glutSwapBuffers();
}
void keyboard(unsigned char key, int x, int y) {
switch(key) {
case 033: // Escape Key
case 'q': case 'Q':
exit(EXIT_SUCCESS);
break;
}
}
void mouseButton(int button, int state, int x, int y) {
if(button==GLUT_RIGHT_BUTTON) exit(0);
/* holding down left button allows user to rotate cube */
if(button==GLUT_LEFT_BUTTON)
switch(state) {
case GLUT_DOWN:
trackingMouse = true;
startX = x;
startY = y;
curx = x;
cury = y;
trackball_ptov(x, y, 512, 512, lastPos);
break;
case GLUT_UP:
trackingMouse = false;
angle = 0.0;
break;
}
}
void mouseMotion(int x, int y) {
float curPos[3], dx, dy, dz;
/* compute position on hemisphere */
if(trackingMouse) {
/* compute the change in position on the hemisphere */
trackball_ptov(x, y, 512, 512, curPos);
dx = curPos[0] - lastPos[0];
dy = curPos[1] - lastPos[1];
dz = curPos[2] - lastPos[2];
if (dx || dy || dz) {
/* compute theta and cross product */
angle = 90.0 * sqrt(dx*dx + dy*dy + dz*dz);
axis[0] = lastPos[1]*curPos[2] - lastPos[2]*curPos[1];
axis[1] = lastPos[2]*curPos[0] - lastPos[0]*curPos[2];
axis[2] = lastPos[0]*curPos[1] - lastPos[1]*curPos[0];
/* update position */
lastPos[0] = curPos[0];
lastPos[1] = curPos[1];
lastPos[2] = curPos[2];
}
float w = angle;
float x = axis[0];
float y = axis[1];
float z = axis[2];
glm::mat4 xform = glm::mat4((1.F - (2.F * ( y*y + z*z ))),(2.F * ( x*y - z*w )),( x*z + y*w ),0.F,
(2.F * ( x*y + z*w )),(1.F - (2.F * ( x*x + z*z ))),(2.F * ( y*z - x*w )),0.F,
(2.F * ( x*z - y*w )),(2.F * ( y*z + x*w )),(1.F - (2.F * ( x*x + y*y ))),0.F,
0.F,0.F,0.F,1.F);
model = xform*model;
}
glutPostRedisplay();
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(512, 512);
glutCreateWindow("Color Cube");
glewInit();
init();
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutIdleFunc(display);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion);
glutMainLoop();
return 0;
}
Here is the fshader36
#version 150
in vec4 color;
out vec4 fColor;
void main()
{
fColor = color;
}
here is VSHADER
#version 330
uniform mat4 mvp;
layout(location=0) in vec4 vPosition;
layout(location=1) in vec4 vColor;
out vec4 color;
void main() {
color = vColor;
gl_Position = mvp * vPosition;
}

lighting the sun giving absurd results

I am trying to develop space simulator. I am trying to use sun as the light source. My problem is that the lighting dosent work as expected. Maybe i am using the wrong calculation for the normals. I am using a single "createsphere" function to create a sphere, and then use different coordinates and sizes to display them. The problem is that all the spheres on the screen show almost the same effect(i.e i've applied only one light source but it seems to have been implemented to all the spheres) .and also the light rotates along with them. I am not sure where the problem is ...i am posting my code ...
the code for sphere display
void DisplaySphere_sun (double R, GLuint texture)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int b,m = 0;
glScalef (0.0125 * R, 0.0125 * R, 0.0125 * R);
glBindTexture (GL_TEXTURE_2D, texture);
glBegin (GL_TRIANGLE_STRIP);
for ( b = 0; b <VertexCount; b++)
{
/*if((b%3)==0)
{
glNormal3f(normal[m].x,normal[m].y,normal[m].z);
m++;
}*/
glTexCoord2f (VERTEX[b].U, VERTEX[b].V);
/*glNormal3f(-VERTEX[b].X, -VERTEX[b].Y, -VERTEX[b].Z);*/
glVertex3f (VERTEX[b].Y, VERTEX[b].X, -VERTEX[b].Z);
}
m = 0;
for ( b = 0; b <VertexCount; b++)
{
/*if((b%3)==0)
{
glNormal3f(normal[m].x,normal[m].y,normal[m].z);
m++;
}*/
glTexCoord2f (VERTEX[b].U, -VERTEX[b].V);
/* glNormal3f(-VERTEX[b].X, -VERTEX[b].Y, -VERTEX[b].Z);*/
glVertex3f (VERTEX[b].Y, VERTEX[b].X, VERTEX[b].Z);
}
glEnd();
//glRotatef(120,0,0,0);
}
the code for creating a sphere
void CreateSphere (double R, double X, double Y, double Z) {
int n,m;
double a;
double b;
n = 0;
m = 0;
for( b = 0; b <= 90 - space; b+=space){
for( a = 0; a <= 360 - space; a+=space)
{
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b) / 180 * PI) - X;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b) / 180 * PI) + Y;
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a) / 360;
n++;
VERTEX[n].X = R * sin((a) / 180 * PI) * sin((b + space) / 180 * PI) - X;
VERTEX[n].Y = R * cos((a) / 180 * PI) * sin((b + space) / 180 * PI) + Y;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a) / 360;
n++;
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b) / 180 * PI) - X;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b) / 180 * PI) + Y;
VERTEX[n].Z = R * cos((b) / 180 * PI) - Z;
VERTEX[n].V = (2 * b) / 360;
VERTEX[n].U = (a + space) / 360;
n++;
VERTEX[n].X = R * sin((a + space) / 180 * PI) * sin((b + space) /180 * PI) - X;
VERTEX[n].Y = R * cos((a + space) / 180 * PI) * sin((b + space) /180 * PI) + Y;
VERTEX[n].Z = R * cos((b + space) / 180 * PI) - Z;
VERTEX[n].V = (2 * (b + space)) / 360;
VERTEX[n].U = (a + space) / 360;
n++;
}
}
}
and code for lighting the sun
glPushMatrix();
gluLookAt (0.0, 10.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); //defines a viewing transformation.
// Now translate to the sun
glTranslatef(0.0, -7.0, 3.0);
/* For LIGHT0 */
GLfloat lightZeroPosition[] = {0.0f, 0.0f, 0.0f, 1.0f};
/*GLfloat lightvec[] = {0.5f, 0.2f, 0.0f, 1.0f};*/
GLfloat lightZeroColor[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat amb[] = {1, 1, 1, 1};
GLfloat spec[] = {0.3, 0.3, 0.3, 1};
glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
glEnable(GL_LIGHT0);
glRotatef(angle,0,0,1);
DisplaySphere(5,textures);
// function to display the sun
glPopMatrix();
I'm a bit puzzled, why you don't draw the sun at the orign of the solar system? The sun is a star, and stars carry over 95% of their stellar systems mass, so the center of gravity of the whole thing is within the sun for most planets (only Jupiter has so much mass, that it shifts the center of gravity slightly outside the sun's photosphere radius).
As for your lighting problem, one normally doesn't illuminate light sources. Just switch off lighting when drawing the sun. Then when drawing the planets place the light source within the sun. OpenGL is not a global renderer, i.e. after you've drawn something, it completely forgets about it, i.e. you won't get any lighting interactions between the things you draw (means also, no shadows for free).
This is how I'd draw a solar system (pseudocode):
draw_solar_system():
glPushMatrix()
glDisable(GL_LIGHTING)
draw_origin_sphere(sun_radius)
glEnable(GL_LIGHTING)
glLightfv(GL_LIGHT0, GL_POSITION, (0., 0., 0., 1.))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (1., 1., 1., 1.))
glLightfv(GL_LIGHT0, GL_AMBIENT, (0., 0., 0., 1.))
for p in planets:
glPushMatrix()
glRotatef(p.orbital_inclination, p.axis_of_orbital_inclination)
glRotatef(p.orbital_angle, 0., 1., 0.)
glTranslatef(p.orbit_radius, 1., 0. 0.)
glRotate(p.axial_of_inclination, p.axis_of_axis_inclination)
glRotate(p.time_of_day, 0., 1., 0.)
draw_origin_sphere(p.radius)
glPopMatrix()
glPopMatrix()