Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

1

25.10.2013, 12:45

Mehrere Lichtquellen an GLSL Shader senden

Hi,

ich bin mir gerade nicht sicher wie ich meine Lichtquellen am besten an meinen Shader sende (stelle aktuell auf ein Entity Component System um).
Alle Lichtquellen liegen als Objekte vor:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
class Light:public Component{ // Basisklasse, wird noch Entity damit ich Shadowmaps als Komponente binden kann
    public:
        vec3 m_position;
        color m_diffuse, m_specular;

        Light();
        Light(const vec3 &position, const color &diffuse, const color &specular);
};

// DirectionalLight, PointLight, SpotLight abgeleitet von Light


Der 3D renderer hat 3 vectoren für jeweils eine Sorte Lichtquelle:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Renderer3D:public bb::System{
    public:
        Camera* m_camera;
        bb::Shader* m_shader;
        bb::color m_ambient;
        std::vector<bb::DirectionalLight*> m_directionalLights; // <--
        std::vector<bb::PointLight*> m_pointLights;
        std::vector<bb::SpotLight*> m_spotLights;

        Renderer3D();
        Renderer3D(Camera* camera, bb::Shader* shader);
        virtual ~Renderer3D();

        void update(const float deltaTime);
};


Im Shader liegen die Lichtquellen dann als structs vor und werden als array angenommen, z.B.:

Quellcode

1
2
3
4
5
6
struct DirectionalLight{
    vec3 direction;
    vec4 diffuse, specular;
};

uniform DirectionalLight directionalLight[10];


Übergeben werden sie dann aktuell so:

C-/C++-Quelltext

1
2
3
4
5
for(std::vector<bb::DirectionalLight*>::iterator i = m_directionalLights.begin(); i != m_directionalLights.end(); i++){
            m_shader->sendUniform("directionalLight[0].direction", (*i)->m_position.x, (*i)->m_position.y, (*i)->m_position.z);
            m_shader->sendUniform("directionalLight[0].diffuse", (*i)->m_diffuse.r, (*i)->m_diffuse.g, (*i)->m_diffuse.b, (*i)->m_diffuse.a);
            m_shader->sendUniform("directionalLight[0].specular", (*i)->m_specular.r, (*i)->m_specular.g, (*i)->m_specular.b, (*i)->m_specular.a);
        }


Wie übergebe ich dann jetzt am besten alle Lichtquellen? Momentan habe ich das erstmal fest an die 0 gebunden. Das soll natürlich nicht so bleiben und stringstream ist langsam. Außerdem wüsste ich gerne ob ich die arrays im Shader dynamisch groß machen kann, oder muss ich dann jedes mal neu compilieren?
Könnte ich wenn ich die Daten in den Klassen als struct speichere diese in einem sendUniforms1fv übergeben?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

25.10.2013, 13:02

Ich würd einfach alle Lichtquellen in einen Constant Buffer packen...

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

3

25.10.2013, 13:09

Uhhh das sieht gut aus. Kannte ich noch nicht. Danke guck ich mir an :)

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

4

26.10.2013, 15:30

Also das Prinzip müsste ich verstanden haben (wie bei allen anderen Buffern). Aber ich kann mir gerade nicht erklären warum ich nicht an den Index komme.
Ich teste gerade mit einem ganz einfachem Shader:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
// (fragment shader, im vertex steht nur die main)

#version 150

precision highp float;

uniform TestABC{ // <- will ich haben
    vec4 a;
};

void main(){

}


C-/C++-Quelltext

1
2
3
4
5
6
bb::Shader* sh = new bb::Shader("res/shader/test.vsh", "res/shader/test.fsh"); // läd, compiliert, linkt (funktionert garantiert)
std::cout<<glGetError()<<std::endl; // nur zur Sicherheit
std::cout<<sh->getID()<<std::endl;
std::cout<<glGetError()<<std::endl;
std::cout<<glGetUniformBlockIndex(sh->getID(), "TestABC")<<std::endl;
std::cout<<glGetError()<<std::endl;


Ausgabe davon:

Quellcode

1
2
3
4
5
0
7
0
4294967295
0


Die Shader ID stimmt soweit. Aber warum bekomme ich jetzt keinen vernünftigen Wert für "TestABC"?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

26.10.2013, 16:50

Dein Shader verwendet den Uniform Block ja nicht, daher wird er auch nicht active sein... ;)

LukasBanana

Alter Hase

Beiträge: 1 097

Beruf: Shader Tools Programmer

  • Private Nachricht senden

6

26.10.2013, 19:05

Ja, die Shader Compiler optimieren manchmal etwas sehr groß zügig. Zumindest hatte ich schon des Öffteren das Problem, dass beim Wegoptimieren von Ressourcen, Samplern usw. die Slots verschoben wurden.
Das ist während des Entwicklungsprozesses sehr unschön. Ich glaube aber in D3D11 sollte das kein Problem mehr sein, weil man da ja die Register Slots im Shader genau festlegen kann.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

7

26.10.2013, 19:49

Du kannst, analog zu Direct3D, die Slots auch in OpenGL genau festlegen (layout(location = ...)). Ansonsten gibt es keine Garantie, welche Ressourcen welche Slots bekommen und der Driver darf tun, was auch immer er will. Dass ungenutzte Ressourcen wegoptimiert werden, ist in OpenGL sogar so vorgesehen...

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

8

27.10.2013, 12:18

Danke das macht Sinn :)

DeKugelschieber

Community-Fossil

  • »DeKugelschieber« ist der Autor dieses Themas

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

9

27.10.2013, 14:01

Ok irgendwas mach ich wohl gerade falsch...

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
glGenBuffers(1, &m_ubo);
glBindBuffer(GL_UNIFORM_BUFFER, m_ubo);
glBufferData(GL_UNIFORM_BUFFER, sizeof(float), 0, GL_DYNAMIC_DRAW); // <- muss das gemacht werden?

unsigned int index = glGetUniformBlockIndex(m_shader->getID(), "test"); // <- gibt mir 0
glUniformBlockBinding(m_shader->getID(), index, 0);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, index);

float f[] = {1.0f};
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(float), f);
glBindBuffer(GL_UNIFORM_BUFFER, 0);


Fragment Shader:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
// ...

uniform test{
    float a;
};

// ...

void main(){
    if(a == 1.0){
        gl_FragColor = color*texture(texture0, texCoord);
    }
}


EDIT

Habs, kommt davon wenn man unaufmerksam die Doku liest...

C-/C++-Quelltext

1
glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_ubo); // <- bindet den _Buffer_ an den Port, nicht den Index an den Port :P


Was ich noch nicht weiß: kann ich die UBOs quasi als array nutzen? Wie greife ich nachher auf meine Lichtquellen zu?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »DeKugelschieber« (27.10.2013, 14:10)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

10

27.10.2013, 18:44

Na du packst einfach ein Array in dein UBO... ;)

Werbeanzeige