# OpenGL / GLUT - my approach to lighting?

I am asking to make a simple Propeller using `GL_TRIANGLE_STRIP`

. Writing the structure wasn't easy, however, but for the lighting to work properly I am giving me problems as I am using `GL_TRIANGLE_STRIP`

. Before I used `GL_POLYGON`

and made lighting for shapes (like rectangles) it was very easy as I just specified `glNormal3f`

once for each shape.

Question: Based on some internet search, apparently I need to specify a normal vortex vector for not every shape. So is my current lighting correct (the way I specify normal vectors)? ``````#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>

#define PI 3.14159265

static GLfloat lpos[] = { 0.0, 0.0, 4.0, 1.0 };
static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
static GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 };
static GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 };
static GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 };
static float alpha = 0.0;
static float beta = PI / 6.0;
static float zoom = 10.0;
static bool lightSource = true;
float twistConstant = 0;
float rotateConstant = 0;
float numberOfObj = 3;
float numberOfTriangles = 1;
static GLdouble cpos;

void DrawTopTriangleSet(){
glMaterialfv(GL_FRONT, GL_EMISSION, black);
glMaterialfv(GL_BACK, GL_EMISSION, black);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
glBegin(GL_TRIANGLE_STRIP);

for (int i = 180; i >= 0; i = i - numberOfTriangles){
glNormal3f(0, cos(i*PI / 180), sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
}

glEnd();
}

void DrawBottomTriangleSet(){
glMaterialfv(GL_FRONT, GL_EMISSION, black);
glMaterialfv(GL_BACK, GL_EMISSION, black);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
glBegin(GL_TRIANGLE_STRIP);

for (int i = 180; i >= 0; i = i - numberOfTriangles){
glNormal3f(0, -cos(i*PI / 180), sin(i*PI / 180));
glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
}

glEnd();
}

void DrawBackTriangleSet(){
glMaterialfv(GL_FRONT, GL_EMISSION, black);
glMaterialfv(GL_BACK, GL_EMISSION, black);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, yellow);
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, yellow);
glBegin(GL_TRIANGLE_STRIP);

for (int i = 180; i >= 0; i = i - numberOfTriangles){
glNormal3f(0, -cos(i*PI / 180), -sin(i*PI / 180));
glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
}

glEnd();
}

void DrawInsideTriangleSet(){
glMaterialfv(GL_FRONT, GL_EMISSION, black);
glMaterialfv(GL_BACK, GL_EMISSION, black);
glBegin(GL_TRIANGLE_STRIP);

for (int i = 180; i >= 0; i = i - numberOfTriangles){
glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
}

glEnd();
}

void writemessage()
{
printf(" X => x++ <= Move light source in direction of +X\n");
printf(" Y => y++ <= Move light source in direction of +Y\n");
printf(" Z => z++ <= Move light source in direction of +Z\n");
printf("\n");
printf("^X => x-- <= Move light source in direction of -X\n");
printf("^Y => y-- <= Move light source in direction of -Y\n");
printf("^Z => z-- <= Move light source in direction of -Z\n");
printf("\n");
printf(" ^ => Move camera up\n");
printf(" > => Move camera right\n");
printf(" < => Move camera left\n");
printf(" down arrow => Move camera down\n");
printf("\n");
printf(" t => More Twist\n");
printf(" f => Less Twist\n");
printf("\n");
printf(" q => More Propeller\n");
printf(" f => Less Propeller\n");
printf("\n");
printf(" w => More Triangles\n");
printf(" s => Less Triangles\n");
printf("\n");
printf(" 0 => Toggling light source\n");
printf("\n");
printf(" r => Rotates Propeller\n");
printf("\n");
printf(" You can not move the light source when the light source is off !!!");
}

void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.01, 20.0);
glMatrixMode(GL_MODELVIEW);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
cpos = zoom * cos(beta) * sin(alpha);
cpos = zoom * sin(beta);
cpos = zoom * cos(beta) * cos(alpha);
gluLookAt(cpos, cpos, cpos, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
if (lightSource == true){
glLightfv(GL_LIGHT0, GL_POSITION, lpos);
glMaterialfv(GL_FRONT, GL_EMISSION, white);
glPushMatrix();
glTranslatef(lpos, lpos, lpos);
glutSolidSphere(0.1, 10, 8);
glPopMatrix();
glMaterialfv(GL_FRONT, GL_EMISSION, black);
}
glRotatef(rotateConstant, 0, 0, 1);

for (int i = 0; i < numberOfObj; i++){
glPushMatrix();
glRotatef(i * 360 / numberOfObj, 0, 0, 1);

DrawTopTriangleSet();
DrawBottomTriangleSet();
DrawBackTriangleSet();
DrawInsideTriangleSet();

glPopMatrix();
}

// Cone
glMaterialfv(GL_FRONT, GL_EMISSION, black);
glMaterialfv(GL_BACK, GL_EMISSION, black);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, red);
glPushMatrix();
glTranslated(0, 0, -1.5);
glutSolidCone(1, 2, 50, 50);
glPopMatrix();

// Back of Cone
glMaterialfv(GL_FRONT, GL_EMISSION, black);
glMaterialfv(GL_BACK, GL_EMISSION, black);
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, red);
glBegin(GL_POLYGON);
glNormal3f(0, 0, 1);
for (int i = 0; i <= 360; i++)
{
glVertex3f(cos(i*PI / 180) * 1, sin(i*PI / 180) * 1, -1.5);
}

glEnd();

glutSwapBuffers();
glFlush();
}

void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 27:
exit(0);
break;
case 'x':
if (lightSource == true)
lpos = lpos + 0.2;
glutPostRedisplay();
break;
case 'X':
if (lightSource == true)
lpos = lpos - 0.2;
glutPostRedisplay();
break;
case 'y':
if (lightSource == true)
lpos = lpos + 0.2;
glutPostRedisplay();
break;
case 'Y':
if (lightSource == true)
lpos = lpos - 0.2;
glutPostRedisplay();
break;
case 'z':
if (lightSource == true)
lpos = lpos + 0.2;
glutPostRedisplay();
break;
case 'Z':
if (lightSource == true)
lpos = lpos - 0.2;
glutPostRedisplay();
break;

case '+':
if (zoom != 1.5)zoom = zoom - 0.5;
glutPostRedisplay();
break;
case '-':
if (zoom != 15)zoom = zoom + 0.5;
glutPostRedisplay();
break;
case '0':
if (lightSource == true){
glDisable(GL_LIGHT0);
lightSource = false;
}
else{
glEnable(GL_LIGHT0);
lightSource = true;
}
glutPostRedisplay();
break;
case 't':
if (twistConstant <= 1){
twistConstant = twistConstant + 0.05;
glutPostRedisplay();
}
break;
case 'f':
if (twistConstant >= 0){
twistConstant = twistConstant - 0.05;
glutPostRedisplay();
}
break;
case 'r':
rotateConstant = rotateConstant + 2;
glutPostRedisplay();

break;
case 'q':
if (numberOfObj <= 6){
numberOfObj++;
glutPostRedisplay();
}

break;
case 'a':
if (numberOfObj >= 0){
numberOfObj--;
glutPostRedisplay();
}

break;
case 's':
if (numberOfTriangles <90){
numberOfTriangles++;
glutPostRedisplay();
}

break;
case 'w':
if (numberOfTriangles > 1){
numberOfTriangles--;
glutPostRedisplay();
}

break;
default:
break;
}
}

void specialkey(GLint key, int x, int y)
{
switch (key) {
case GLUT_KEY_RIGHT:
alpha = alpha + PI / 180;
if (alpha > 2 * PI) alpha = alpha - 2 * PI;
glutPostRedisplay();
break;
case GLUT_KEY_LEFT:
alpha = alpha - PI / 180;
if (alpha < 0) alpha = alpha + 2 * PI;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
if (beta < 0.45*PI) beta = beta + PI / 180;
glutPostRedisplay();
break;
case GLUT_KEY_DOWN:
if (beta > -0.05*PI) beta = beta - PI / 180;
glutPostRedisplay();
break;

default:
break;
}
}

int main(int argc, char** argv)
{
writemessage();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(1200, 800);
glutInitWindowPosition(0, 0);
glutCreateWindow(argv);

glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);

glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glEnable(GL_LIGHT0);

glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 5.0, 10.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0);

glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutSpecialFunc(specialkey);

glutMainLoop();
return 0;
}
```

```
+3

source to share

I don't think your normals are quite correct. For example, for this piece of geometry:

``````glNormal3f(0, cos(i*PI / 180), sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
```

```

Since it `twistConstant`

is part of the computation of the vertex coordinates, it looks very suspicious that it is also not part of the normal computation. I don't think that a normal value cannot depend on a constant value if it changes the order in which vertices are evaluated.

Let's try to calculate the normal for this case. This is just to illustrate the process, it is likely that I won't get it for sure without trying to implement it.

For parameterized surfaces, you usually compute the normal as the cross product of two gradient vectors (one for each parameter). Using `a`

short for the angle value `I * PI / 180`

and `c`

short for `twistConstant`

, the two vertices from the above code:

``````     | a            |         | a            |
v1 = | 0            |    v2 = | 0.5 * sin(a) |
| 0.5 * sin(a) |         | - c * sin(a) |
```

```

The gradient for the parameter `a`

at the vertex is `v1`

as follows:

``````           | 1            |
dv1 / da = | 0            |
| 0.5 * cos(a) |
```

```

As I read your code, the surface is flat in the direction between these two vertices, so we can use the difference between the two vectors as the second gradient:

``````          | 0                    |
v2 - v1 = | 0.5 * sin(a)         |
| - (c + 0.5) * sin(a) |
```

```

Cross product between these two gradient vectors:

``````| 1            |   | 0                    |   | -0.25 * sin(a) * cos(a) |
| 0            | x | 0.5 * sin(a)         | = | (c + 0.5) * sin(a)      |
| 0.5 * cos(a) |   | - (c + 0.5) * sin(a) |   | 0.5 * sin(a)            |
```

```

Then it will be the normal at the vertex `v1`

. The normal at `v2`

will be different, which makes sense because the blade is twisted.

Besides math, you also don't need to specify normals in `DrawInsideTriangleSet()`

:

``````glVertex3f(i*PI / 180, 0.5*sin(i*PI / 180), twistConstant*-sin(i*PI / 180));
glVertex3f(i*PI / 180, 0, 0.5*sin(i*PI / 180));
glVertex3f(i*PI / 180, -0.5*sin(i*PI / 180), twistConstant*sin(i*PI / 180));
```

```

The first call should probably have been `glNormal3f()`

instead `glVertex3f()`

.

+4

source

All Articles
{"ft_lang_label":"__label__en","ft_lang_prob":0.5088633,"math_prob":0.99560964,"size":10519,"snap":"2021-21-2021-25","text_gpt3_token_len":3494,"char_repetition_ratio":0.16737993,"word_repetition_ratio":0.22959523,"special_character_ratio":0.36609945,"punctuation_ratio":0.25536993,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9935974,"pos_list":[0,1,2,3,4],"im_url_duplicate_count":[null,1,null,1,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2021-05-16T08:59:24Z\",\"WARC-Record-ID\":\"<urn:uuid:b0d7ba89-5208-4bc5-87fb-25dc742310e5>\",\"Content-Length\":\"64619\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:1939eadc-8d2f-4943-9768-6694a5e56787>\",\"WARC-Concurrent-To\":\"<urn:uuid:8483bfec-a9f1-4aa5-9f4b-527d27b0d22e>\",\"WARC-IP-Address\":\"157.245.84.7\",\"WARC-Target-URI\":\"https://daily-blog.netlify.app/questions/2168722/index.html\",\"WARC-Payload-Digest\":\"sha1:E5QG4FBFED3GR3JMVT6DBP65NGOLNTPR\",\"WARC-Block-Digest\":\"sha1:PWOFPO3ZMIBVUFE6K2PI2LKMCSD7JNXT\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2021/CC-MAIN-2021-21/CC-MAIN-2021-21_segments_1620243992516.56_warc_CC-MAIN-20210516075201-20210516105201-00057.warc.gz\"}"}