Toon posts:

[C & OpenGL] Smooth Shademodel

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb een probleem met een OpenGL programma dat ik aan het maken ben. Ik heb het probleem terug gebracht tot de volgende situatie: ik probeer een vierkant (QUAD) te tekenen met een verloop van kleuren (Rood in de ene hoek, groen in de ander, etc.).

Dit doe ik door de shademodel op smooth te zetten, zodat ik voor elk punt van de quad een aparte kleur kan definieren. De code ziet er dan zo uit:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  glShadeModel (GL_SMOOTH);

  (...)

  glBegin (GL_QUADS);
    glNormal3f (0.0, 1.0, 0.0);

    glColor3f (1.0, 0.0, 0.0);
    glVertex3f (10.0, 50.0, 10.0);

    glColor3f (0.0, 1.0, 0.0);
    glVertex3f (90.0, 50.0, 10.0);

    glColor3f (0.0, 0.0, 1.0);
    glVertex3f (90.0, 50.0, 90.0);

    glColor3f (0.0, 0.0, 0.0);
    glVertex3f (10.0, 50.0, 90.0);
  glEnd ();


Het resultaat ziet er dan als volgt uit:

Afbeeldingslocatie: http://img512.imageshack.us/img512/8429/colorshm7.th.png

Het probleem is echter dat ik in mijn programma ook licht nodig heb en dat het bovenstaande niet meer werkt op het moment dat ik het licht 'aanzet' door glEnable (GL_LIGHTING) aan te roepen. Op het moment dat ik dat doe, krijg ik het volgende:

Afbeeldingslocatie: http://img505.imageshack.us/img505/4823/blackjs1.th.png

De quad blijft dan geheel zwart. Omdat ik dacht dat het probleem kwam doordat ik nog geen lichtbronnen had gedefinieerd, heb ik deze ook toegevoegd, maar dit hielp geheel niet. Deze code staat (als commentaar) nog wel in mijn code, maar helpt dus niet.

Ik heb het programma zo klein mogelijk gemaakt, zodat het makkelijk te begrijpen is. Het bestaat nu enkel uit een main en een display functie. Download het hier.

Kan iemand mij vertellen wat ik hier fout doe?

[ Voor 4% gewijzigd door Verwijderd op 01-02-2007 16:51 ]


  • TweakerNummer
  • Registratie: September 2001
  • Niet online
Ik gok dat je geen normals heb gedefinieerd.

[edit]Hier is wat code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void createCubeList(void)
{
    GLfloat A[3] = {-1.0,-1.0, 1.0};
    GLfloat B[3] = { 1.0,-1.0, 1.0};
    GLfloat E[3] = {-1.0, 1.0, 1.0};
    GLfloat F[3] = { 1.0, 1.0, 1.0};

    glShadeModel(primitive_shading); // is default GL_SMOOTH

    glNewList(CUBE, GL_COMPILE);
        glBegin(GL_POLYGON);
            glColor3fv(green);
            glMaterialfv(GL_FRONT, GL_DIFFUSE, green); // static const GLfloat green[] = {0.0, 1.0, 0.0};
            glMaterialfv(GL_FRONT, GL_SPECULAR, green);
            glMaterialf(GL_FRONT, GL_SHININESS, 12); 
            glNormal3f(0.0,0.0,1.0);
            glVertex3fv(A);
            glVertex3fv(B);
            glVertex3fv(F);
            glVertex3fv(E);
        glEnd();
                // hier komen de andere punten om de cube te creeeren
    glEndList();
}

[ Voor 103% gewijzigd door TweakerNummer op 01-02-2007 16:52 ]


Verwijderd

Topicstarter
TweakerNummer schreef op donderdag 01 februari 2007 @ 16:46:
Ik gok dat je geen normals heb gedefinieerd.

(...)
Ik heb het licht als volgt gedefinieerd (staat ook in code, maar dan als commentaar, omdat het geen effect lijkt te hebben):

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  GLfloat LightAmbient[]  = { 0.5f,  0.5f, 0.5f, 1.0f };
  GLfloat LightDiffuse[]  = { 1.0f,  1.0f, 1.0f, 1.0f };
  GLfloat LightPosition[] = { 0.0f,  1.0f, 0.0f, 0.0f };  // Directional light from above

  glLightfv (GL_LIGHT0, GL_AMBIENT,  LightAmbient);
  glLightfv (GL_LIGHT0, GL_DIFFUSE,  LightDiffuse);
  glLightfv (GL_LIGHT0, GL_POSITION, LightPosition);

  /* Apply the object properties */
  float pAmbient[4] = {0.5, 0.5, 0.5, 0.0};
  float pDiffuse[4] = {0.6, 0.2, 0.0, 0.0};
  float pSpecular[4] = {0.8, 0.3, 0.0, 0.0};
  float pShininess = 1.0;

  glMaterialfv(GL_FRONT, GL_AMBIENT,   pAmbient);
  glMaterialfv(GL_FRONT, GL_DIFFUSE,   pDiffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR,  pSpecular);
  glMaterialf (GL_FRONT, GL_SHININESS, pShininess);


Het licht komt hier dus van bovenaf. De normal van de quad heb ik gedefinieerd als:

code:
1
glNormal3f (0.0, 1.0, 0.0);


Dat zou toch goed moeten zijn?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

Normal specificeer je per vertex he, niet per quad. Nou pakt ie voor iedere vertex automatisch de normal van de vorige als je er geen hebt gespecificeerd, dus daar zit de fout denk ik niet, maar hou daar rekening mee.

Heb je je belichting wel zo ingesteld dat hij de kleuren van de vertices meeneemt? Dat zie ik niet echt af aan je code namelijk (je stelt namelijk een diffuse color voor een light in, en een diffuse color voor een material, maar je zegt nergens dat ie de diffuse color van je vertex af moet halen)

[ Voor 68% gewijzigd door .oisyn op 01-02-2007 18:49 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
.oisyn schreef op donderdag 01 februari 2007 @ 18:47:
Normal specificeer je per vertex he, niet per quad. Nou pakt ie voor iedere vertex automatisch de normal van de vorige als je er geen hebt gespecificeerd, dus daar zit de fout denk ik niet, maar hou daar rekening mee.
Volgens mij is een normaal toch per definitie voor het gehele vlak, of niet? Maar goed, dat is volgens mij het probleem niet.
.oisyn schreef op donderdag 01 februari 2007 @ 18:47:
Heb je je belichting wel zo ingesteld dat hij de kleuren van de vertices meeneemt? Dat zie ik niet echt af aan je code namelijk (je stelt namelijk een diffuse color voor een light in, en een diffuse color voor een material, maar je zegt nergens dat ie de diffuse color van je vertex af moet halen)
Hoe zou ik dat laatste moeten doen dan?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op donderdag 01 februari 2007 @ 22:08:
[...]

Volgens mij is een normaal toch per definitie voor het gehele vlak, of niet?
Nope, hoe kun je anders een mooie bol maken zonder dat je de vlakken duidelijk ziet? :). Het idee is nou juist dat de belichting per vertex berekend wordt, en dat de kleuren over het vlak geïnterpoleerd worden. Dat is de traditionele Gouraud shading. Tegenwoordig gebeurt dit natuurlijk door slechts de normalen te interpoleren en per pixel de belichting te doen mbv vertex- en pixelshaders.
Maar goed, dat is volgens mij het probleem niet.
Is het ook niet, maar ik wilde dat misverstand even uit de weg helpen ;)
Hoe zou ik dat laatste moeten doen dan?
Geen idee, OpenGL is voor mij te lang geleden. In d3d moet je de material diffuse source op vertex zetten, wellicht dat je met die info iets kan (open een opengl handleiding, ga naar de glMaterial functie en vandaar wordt je vast wel doorverwezen naar aanverwante zaken)

[ Voor 18% gewijzigd door .oisyn op 01-02-2007 22:15 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • The Fox NL
  • Registratie: Oktober 2004
  • Laatst online: 10:15
Misschien dat Nehe tutorials je kunnen helpen bij de belichting: http://nehe.gamedev.net/

  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Met GL_LIGHTING enabled worden de uiteindelijke kleuren van je polygonen bepaald door ofwel de material properties (als GL_COLOR_MATERIAL disabled is), ofwel door een combinatie van glColor() calls voor de componenten die door glColorMaterial() getracked worden en gewone glMaterial() calls voor de overige componenten, maar om die kleuren te berekenen moet OGL in beide situaties weten wat de vertex normals zijn (anders krijg je heel veel zwart) en die geef je niet goed op. Verder doe je een aantal dingen die maar 1 keer gedaan hoeven worden telkens opnieuw, maar dat is op zich niet erg.

Hieronder je programmaatje in een wat logischere (goede ;)) vorm gegoten zodat je het effect van in- en uitschakelen van de belichting en het veranderen van de normals beter kunt zien:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define WINPOS_X     200
#define WINPOS_Y     50

static int frameWidth  = 700;
static int frameHeight = 700;


void InitGL() {
    // enable lighting
    glEnable(GL_LIGHTING);
    // turn on light 0
    glEnable(GL_LIGHT0);

    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
    glCullFace(GL_BACK);

//  glColorMaterial(GL_FRONT, GL_DIFFUSE);
//  glEnable(GL_COLOR_MATERIAL);
    glShadeModel(GL_SMOOTH);


    GLfloat LightAmbient[]  = { 0.5f,  0.5f, 0.5f, 1.0f };
    GLfloat LightDiffuse[]  = { 1.0f,  1.0f, 1.0f, 1.0f };
    GLfloat LightPosition[] = { 0.0f,  1.0f, 0.0f, 0.0f };
    // define light 0
    glLightfv(GL_LIGHT0, GL_AMBIENT,  LightAmbient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  LightDiffuse);
    glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
}

void progDisplay3D (void) {
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluPerspective(90, (float) frameWidth / frameHeight, 1.0, 1000.0);

    /* Draw the background in the default color. */
    glClearColor(0.0, 0.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    gluLookAt(100.0, 100.0, 100.0,   0.0,  0.0,  0.0,   0.0,   1.0,   0.0);


    float pAmbient[4] = {0.5, 0.5, 0.5, 0.0};
    float pDiffuse[4] = {0.6, 0.2, 0.0, 0.0};
    float pSpecular[4] = {0.8, 0.3, 0.0, 0.0};
    float pShininess = 1.0;
    /* apply the material properties */
    glMaterialfv(GL_FRONT, GL_AMBIENT,   pAmbient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   pDiffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR,  pSpecular);
    glMaterialf(GL_FRONT, GL_SHININESS, pShininess);


    /* Draw the quad */
    glBegin (GL_QUADS);
        glNormal3f(0.0, 1.0, 0.0);
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(10.0, 50.0, 10.0);

        glNormal3f(0.0, 1.0, 0.0);
        glColor3f(0.0, 1.0, 0.0);
        glVertex3f(90.0, 50.0, 10.0);

        glNormal3f(0.0, 0.0, 1.0);
        glColor3f(0.0, 0.0, 1.0);
        glVertex3f(90.0, 50.0, 90.0);

        glNormal3f(1.0, 0.0, 0.0);
        glColor3f(0.0, 0.0, 0.0);
        glVertex3f(10.0, 50.0, 90.0);
    glEnd ();

    glutSwapBuffers ();
}


int main (int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(frameWidth, frameHeight); 
    glutInitWindowPosition(WINPOS_X, WINPOS_Y);

    glutCreateWindow("Example");

    InitGL();

    glutDisplayFunc(progDisplay3D);
    glutMainLoop();

    return 0;
}

Verwijderd

Topicstarter
DroogKloot schreef op vrijdag 02 februari 2007 @ 01:43:
Verder doe je een aantal dingen die maar 1 keer gedaan hoeven worden telkens opnieuw, maar dat is op zich niet erg.
Klopt, maar in mijn programma (dus niet het boven geplaatste fragment) moet het programma afwisselen tussen 2D (ortho) en 3D, dus één init() functie zou niet voldoende zijn geweest. Maar goed, dan maak ik er wel 2 van :-)
DroogKloot schreef op vrijdag 02 februari 2007 @ 01:43:
Hieronder je programmaatje in een wat logischere (goede ;)) vorm gegoten zodat je het effect van in- en uitschakelen van de belichting en het veranderen van de normals beter kunt zien:
Bedankt, dit werkt idd! Nu vraag ik me alleen af hoe ik in mijn programma de normals van een gegeven vertex kan berekenen. Ik probeer nu zoiets te maken:

Afbeeldingslocatie: http://www.ics.uci.edu/~dvd/images/normpdf.gif

Oftewel, ik heb dus een 2-dimensionale array met waarden, en ik moet deze omzetten in een soort height map. In het bovenstaande plaatje is dus een bell curve weergegeven, maar in mijn geval kunnen er dus meerdere bergen en dalen zijn. De horizontale assen (X en Z) zijn dan de dimensies van de array en op de Y-as komen dan de waarden uit de array.

Stel nou dat ik de volgende array heb:

1.0 1.0 1.0
1.0 2.0 1.0
1.0 1.0 1.0

Dan zou er in het midden een piek/berg zijn. Dit doe ik nu door van elke set van vier coordinaten een quad te maken. Dit voorbeeld zou dus 4 quads opleveren. Maar hoe bereken ik dan de normaal van de vertices van een zo'n quad?

Laten we als voorbeeld de quad met deze coordinaten even nemen:

1.0 1.0 1.0
1.0 2.0 1.0
1.0 1.0 1.0

Kan iemand mij even helpen bij dit voorbeeld? Hoe bereken ik de normalen van deze 4 vertices?

(Als ik het op een andere manier beter kan doen hoor ik het overigens ook graag.)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:52

.oisyn

Moderator Devschuur®

Demotivational Speaker

Sowieso moet je, wederom, per vertex werken, en niet per quad. Die quad die je eruit pakt is dus niet interessant - voor elke vertex in de matrix moet je de normaal berekenen.

Hoe je de normaal bepaald hangt een beetje af van hoe je het oppervlak approximeert. Een naieve maar snelle implementatie is gewoon (vr - vl) × (vo - vb) en dat genormaliseerd, waarbij vr de vertex rechts van v is, vl de vertex links van v, vo de vertex eronder en vb de vertex erboven is. Voor de vertices aan de rand zou je kunnen stellen dat het virtuele vertex dat naast hun ligt dezelfde hoogte heeft.

[ Voor 9% gewijzigd door .oisyn op 02-02-2007 14:59 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1