glRotate+glTranslate in glLoadMatrix



  • Die ViewMatrix ist doch die Matrix, welche die Kameraposition/Ausrichtung beschreibt.

    Diese berechnest du doch bereits. Du nennst sie hier glaube Modelmatrix, was ja 'eigentlich' die Position/Ausrichtung von den einezelnen 3D-Objekten ist (Jedes 3D-Objekt hat seine eigene ModelMatrix)



  • Hallo XMA Man,

    dachte ich eigentlich auch, dass ich alles berechnet hätte.

    In GLSL im VertexShader gibt es wie schon gesagt das veraltete "Matrixprodukt" gl_ModelViewProjectionMatrix.

    Hier sieht man im 5. Codefenster (der lange Code unten 🤡 ), dass der Programmierer die viewMatrix mit den Daten von der gluLookAt-Funktion füttert. Die brauche ich aber im Prinzip nicht.

    Hier nochmal der alte und der neue Vertex-Shader:
    Alt

    #version 450 compatibility // schlecht...
    layout(location=0)in vec3 VAO_position;
    layout(location=1)in vec3 VAO_normals;
    layout(location=2)in vec3 VAO_tex;
    layout(binding=2)buffer Matrices{
    		mat4 modelM;
    		mat4 projM;
    };
    void main(){
    		vec3 pos=VAO_position+vec3(gl_InstanceID*10.0f,0.0f,0.0f);
    		gl_Position=gl_ModelViewProjectionMatrix*vec4(VAO_position+pos,1.0f); // gl_ModelViewProjectionMatrix ist deprecated und möchte ich ersetzen
    };
    

    Funktioniert einwandfrei, aber halt mit einer deprecated Funktion.

    Neu

    #version 450
    layout(location=0)in vec3 VAO_position;
    layout(location=1)in vec3 VAO_normals;
    layout(location=2)in vec3 VAO_tex;
    layout(binding=2)buffer Matrices{
    		mat4 modelM;
    		mat4 projM;
    };
    void main(){
    		vec3 pos=VAO_position+vec3(gl_InstanceID*10.0f,0.0f,0.0f);
    		gl_Position=projM*modelM*vec4(VAO_position+pos,1.0f); // hier berechne ich die Position ohne gl_ModelViewProjectionMatrix
    };
    

    Der Code funktioniert halt nicht so, wie er soll => es werden keine Objekte angezeigt (s. Bilder).

    ohne_deprecated
    mit_deprecated

    In einem Forum habe ich auch schonmal gelesen, dass Funktionen wie glLoadMatrix, glMultMatrix, glPush/PopMatrix und glMatrixMode etc. eigentlich nicht mehr verwendet werden sollten. Der Anwender soll "selber mehr berechnen".

    In der neuen Vulkan API werden diese Funktionen vllt. gar nicht mehr existieren...

    Ist ja im Prinzip egal. Nur warum wird bei mir nichts angezeigt?

    Wäre dankbar für jeden Tipp. Oder einen Komplettcode oder Beispielcode etc.

    Mit freundlichen Grüßen
    PHBU



  • Um die Shader-Variable gl_ModelViewProjectionMatrix zu befüllen, nutzt du doch OpenGL::glLoadMatrixf(ssbo.projM); und das funktioniert ja offentsichtlich.

    Kannst du irgentwie sichersstellen, dass die verwendeten Matrizen zur neuen Schreibweise wirklich gleich sind?

    Das hier ist erstmal richtig. Das mache ich auch so:

    gl_Position=projM*modelM*vec4(VAO_position+pos,1.0f);

    Im Nofall kannst du ja die Matrizen abfragen und dann fest im Shader schreiben, nur um zu sehen, ob der richtige Inhalt dort ankommt.



  • Hallo XMAMan,

    hast du gerade den Code von dir parat?

    Mich würde v.a. interessieren, wie du die Daten zum Shader schreibst.

    Ich verwende SSBOs (später schreibe ich nämlich mehr Daten rein).

    Vertex-Shader

    #version 450
    layout(location=0)in vec3 VAO_position;
    layout(location=1)in vec3 VAO_normals;
    layout(location=2)in vec2 VAO_tex;
    layout(binding=1)buffer Matrices{
    		mat4 modelM;
    		mat4 projM;
    };
    out vec2 TexCoord;
    void main(){
    	vec3 pos=VAO_position+vec3(gl_InstanceID*10.0f,0.0f,0.0f);
    	gl_Position=projM*modelM*vec4(VAO_position+pos,1.0f);
    	TexCoord=VAO_tex;
    }
    

    Fragment-Shader

    #version 450
    layout(binding=0)uniform sampler2D tex;
    in vec2 TexCoord;
    out vec4 outColor;
    void main(){
    		outColor=texture2D(tex,TexCoord);
    }
    

    Shader-Klasse

    class Shader{
    	public:
    		/* öffentliche Strukturen, Aufzählungen */
    		enum ShaderType:unsigned char{
    			Fragment,
    			Geometry,
    			Vertex
    		};
    		/* öffentliche Deklarationen */
    		signed char add(const char*,ShaderType);
    		signed char compile();
    		void freeResources();
    		template<typename T>T*getStorageAddress(const string&,unsigned int,unsigned int);
    		signed char setUniform(const char*,int);
    		void use();
    		/* öffentliche Variablen/Konstanten */
    
    	private:
    		/* private Strukturen, Aufzählungen */
    		struct storage{
    			void*address;
    			unsigned int blockIndex;
    			unsigned int ID;
    		};
    		/* private Deklarationen */
    
    		/* private Variablen/Konstanten */
    		static unsigned int actProgramID;
    		unsigned char isCompiled=false;
    		unsigned int programID=0;
    		vector<int>shaderIDs;
    		map<string,storage>storages;
    };
    

    Hier ist wahrscheinlich die Funktion getStorageAddress am Wichtigsten

    template<typename T>T*Shader::getStorageAddress(const string&name,unsigned int binding,unsigned int size){
    	if(this->isCompiled==false)return NULL; // wenn Programm noch nicht kompiliert wurde
    	if(this->storages.count(name)==0){ // wenn Storage noch nicht erfragt wurde
    		storage&actElement=this->storages[name];
    
    		if(Shader::actProgramID!=this->programID){
    			OpenGL::glUseProgram(this->programID);
    			Shader::actProgramID=this->programID;
    		}
    		if((actElement.blockIndex=OpenGL::glGetProgramResourceIndex(this->programID,OpenGL::GL_SHADER_STORAGE_BLOCK,name.c_str()))!=OpenGL::GL_INVALID_INDEX){ // wenn Storage existiert
    			OpenGL::glGenBuffers(1,&actElement.ID);
    			OpenGL::glBindBuffer(OpenGL::GL_SHADER_STORAGE_BUFFER,actElement.ID);
    			OpenGL::glBufferData(OpenGL::GL_SHADER_STORAGE_BUFFER,size,NULL,OpenGL::GL_DYNAMIC_DRAW); // Speicher allokieren
    			actElement.address=OpenGL::glMapBuffer(OpenGL::GL_SHADER_STORAGE_BUFFER,OpenGL::GL_WRITE_ONLY);
    			OpenGL::glShaderStorageBlockBinding(this->programID,actElement.blockIndex,binding);
    			OpenGL::glBindBufferBase(OpenGL::GL_SHADER_STORAGE_BUFFER,binding,actElement.ID);
    		}else{
    			this->storages.erase(name);
    			cerr<<"Storage \""<<name<<"\" existiert nicht"<<endl;
    			return NULL;
    		}
    	}
    	return reinterpret_cast<T*>(this->storages[name].address);
    }
    

    Diese gibt mir nicht NULL zurück. Müsste also funktionieren.

    display-Funktion

    void display(){
    	const static float scale_factor=0.01f;
    
    	OpenGL::glClear(OpenGL::GL_COLOR_BUFFER_BIT|OpenGL::GL_DEPTH_BUFFER_BIT);
    	// Modellmatrix
    	OpenGL::glMatrixMode(OpenGL::GL_MODELVIEW);
    	{
    		ssbo.modelM[0]=scale_factor*cos(loc.yaw*PI/180.0f);
    		ssbo.modelM[1]=scale_factor*sin(loc.pitch*PI/180.0f)*sin(loc.yaw*PI/180.0f);
    		ssbo.modelM[2]=-scale_factor*cos(loc.pitch*PI/180.0f)*sin(loc.yaw*PI/180.0f);
    		ssbo.modelM[3]=0;
    		ssbo.modelM[4]=0;
    		ssbo.modelM[5]=scale_factor*cos(loc.pitch*PI/180.0f);
    		ssbo.modelM[6]=scale_factor*sin(loc.pitch*PI/180.0f);
    		ssbo.modelM[7]=0;
    		ssbo.modelM[8]=scale_factor*sin(loc.yaw*PI/180.0f);
    		ssbo.modelM[9]=-scale_factor*sin(loc.pitch*PI/180.0f)*cos(loc.yaw*PI/180.0f);
    		ssbo.modelM[10]=scale_factor*cos(loc.pitch*PI/180.0f)*cos(loc.yaw*PI/180.0f);
    		ssbo.modelM[11]=0;
    		ssbo.modelM[12]=loc.x*cos(loc.yaw*PI/180.0f)+loc.z*sin(loc.yaw*PI/180.0f);
    		ssbo.modelM[13]=loc.x*sin(loc.pitch*PI/180.0f)*sin(loc.yaw*PI/180.0f)-loc.z*sin(loc.pitch*PI/180.0f)*cos(loc.yaw*PI/180.0f)+loc.y*cos(loc.pitch*PI/180.0f);
    		ssbo.modelM[14]=-loc.x*cos(loc.pitch*PI/180.0f)*sin(loc.yaw*PI/180.0f)+loc.z*cos(loc.pitch*PI/180.0f)*cos(loc.yaw*PI/180.0f)+loc.y*sin(loc.pitch*PI/180.0f);
    		ssbo.modelM[15]=1;
    	}
    	OpenGL::glLoadMatrixf(ssbo.modelM);
    	{
    		OpenGL::glBindVertexArray(VAOs[0]->ID); // VAO von GPU binden
    		OpenGL::glActiveTexture(OpenGL::GL_TEXTURE_0);
    		OpenGL::glBindTexture(OpenGL::GL_TEXTURE_2D,VAOs[0]->VBO.picID); // Textur von GPU binden
    		OpenGL::glBindBuffer(OpenGL::GL_ELEMENT_ARRAY_BUFFER,VAOs[0]->VBO.indID); // Index-Array von GPU binden
    		blockShader.use();
    		OpenGL::glDrawElementsInstanced(OpenGL::GL_TRIANGLES,VAOs[0]->VBO.indSize,OpenGL::GL_UNSIGNED_BYTE,NULL,20);
    		OpenGL::glBindBuffer(OpenGL::GL_ELEMENT_ARRAY_BUFFER,0);
    		OpenGL::glBindVertexArray(0);
    	}
    	OpenGL::glutSwapBuffers();
    	return;
    }
    

    initShaderStorage-Funktion, die die Adresse des SSBO "Matrices" ermittelt

    signed char initShaderStorage(){
    	ssbo.modelM=blockShader.getStorageAddress<float>("Matrices",1,4*4*sizeof(float)+4*4*sizeof(float));
    	if(ssbo.modelM==NULL){
    		cerr<<"Matrices can't be loaded."<<endl;
    		return -1;
    	}
    	ssbo.projM=ssbo.modelM+4*4*sizeof(float);
    	return 0;
    }
    

    Rufst Du bei dir auch glLoadMatrix o.ä. auf?

    Falls Du/Ihr mehr Code benötigen solltet/solltest, schreibt. Ich komm da wirklich nicht weiter.

    Mit freundlichen Grüßen
    PHBU



  • Ok, so sehen die Matrizen bei mir im Vertexshader aus:

    #version 450
    
    uniform mat4 projection_matrix;
    uniform mat4 modelview_matrix;
    

    So lege ich die Variable erstmal an

    int id1 = GetUniformLocation(shaderProgrameId, "projection_matrix");
    int id2 = GetUniformLocation(shaderProgrameId, "modelview_matrix");
    

    So übergebe ich dann die Daten an den Shader

    Matrix4  projectionMatrix = ...;
    Matrix4 modelViewMatrix = ...;
    UniformMatrix4(id1, false, ref projectionMatrix);
    UniformMatrix4(id2, false, ref modelViewMatrix);
    

    Ich nutze OpenTK als Framework.

    Ich muss schon zugeben, dass sieht etwas anders aus als glGetProgramResourceIndex. Ist das auch für Uniform-Variablen?



  • Hallo,

    glGetProgramResourceIndex geht auch für Uniforms (GL_UNIFORM statt GL_SHADER_STORAGE_BLOCK).

    Also nutzt Du nicht glLoadMatrix!?

    MfG
    PHBU



  • Nein, glLoadMatrix nutze ich nicht. Ich denke mal, dass macht nur Sinn, wenn man gl_ModelViewProjectionMatrix im Shader verwenden will. Vielleicht klappt das auch nur mit alten OpenGL-Versionen.



  • Hallo nochmal,

    wenn ich im Vertex-Shader folgenden Code verwende,

    #version 450\n
    layout(location=0)in vec3 VAO_position;
    layout(location=1)in vec3 VAO_normals;
    layout(location=2)in vec2 VAO_tex;
    layout(binding=1)uniform ModelMatrix{mat4 modelM;};
    layout(binding=2)uniform ProjectionMatrix{mat4 projM;};
    out vec2 TexCoord;
    void main(){
    		vec3 pos=VAO_position+vec3(gl_InstanceID*10.0f,0.0f,0.0f);
    		gl_Position=projM*modelM*vec4(VAO_position+pos,1.0f);
    		TexCoord=VAO_tex;
    }
    

    (benutze jetzt doch wieder Uniforms) dann würde es mit den Funktionsaufrufen

    ubo.modelM=blockShader.getUniformAddress<float>("ModelMatrix",1u);
    ubo.projM=blockShader.getUniformAddress<float>("ProjectionMatrix",2u);
    

    funktionieren (ubo.modelM und ubo.projM sind vom Typ float*).

    Hier nochmal die Funktion getUniformAddress:

    template<typename T>T*Shader::getUniformAddress(const string&name,unsigned int binding){
    	if(this->isCompiled==false)return NULL; // wenn Programm noch nicht kompiliert wurde
    	if(this->uniforms.count(name)==0){ // wenn Storage noch nicht erfragt wurde
    		uniform&actElement=this->uniforms[name];
    
    		if(Shader::actProgramID!=this->programID){
    			OpenGL::glUseProgram(this->programID);
    			Shader::actProgramID=this->programID;
    		}
    		if((actElement.blockIndex=OpenGL::glGetUniformBlockIndex(this->programID,name.c_str()))!=OpenGL::GL_INVALID_INDEX){ // wenn Storage existiert
    			int size;
    
    			OpenGL::glGetActiveUniformBlockiv(this->programID,actElement.blockIndex,OpenGL::GL_UNIFORM_BLOCK_DATA_SIZE,&size);
    			OpenGL::glGenBuffers(1,&actElement.ID);
    			OpenGL::glBindBuffer(OpenGL::GL_UNIFORM_BUFFER,actElement.ID);
    			OpenGL::glBufferData(OpenGL::GL_UNIFORM_BUFFER,size,NULL,OpenGL::GL_DYNAMIC_DRAW); // Speicher allokieren
    			actElement.address=OpenGL::glMapBuffer(OpenGL::GL_UNIFORM_BUFFER,OpenGL::GL_WRITE_ONLY);
    			OpenGL::glUniformBlockBinding(this->programID,actElement.blockIndex,binding);
    			OpenGL::glBindBufferBase(OpenGL::GL_UNIFORM_BUFFER,binding,actElement.ID);
    		}else{
    			this->uniforms.erase(name);
    			cerr<<"Uniform \""<<name<<"\" existiert nicht"<<endl;
    			return NULL;
    		}
    	}
    	return reinterpret_cast<T*>(this->uniforms[name].address);
    }
    

    Und spaßenshalber nochmal die komplette "Klassendeklaration":

    class Shader{
    	public:
    		/* öffentliche Strukturen, Aufzählungen */
    		enum ShaderType:unsigned char{
    			Fragment,
    			Geometry,
    			Vertex
    		};
    		/* öffentliche Deklarationen */
    		signed char add(const char*,ShaderType);
    		signed char compile();
    		void freeResources();
    		template<typename T>T*getUniformAddress(const string&,unsigned int);
    		signed char setUniformi(const char*,int);
    		void use();
    		/* öffentliche Variablen/Konstanten */
    
    	private:
    		/* private Strukturen, Aufzählungen */
    		struct uniform{
    			void*address;
    			unsigned int blockIndex;
    			unsigned int ID;
    		};
    		/* private Deklarationen */
    
    		/* private Variablen/Konstanten */
    		static unsigned int actProgramID;
    		unsigned char isCompiled=false;
    		unsigned int programID=0;
    		vector<int>shaderIDs;
    		map<string,uniform>uniforms;
    };
    

    Irgendwie finde ich nicht die Vorgehensweise (code o.ä.), wie man auf Member einer Uniform/ShaderStorage-Blocks vom Hauptprogramm zugreifen kann...
    Es wäre jetzt mit Uniforms nicht schlimm, da diese ja nur mindestens (hoffe das ist richtig) 16 kB auf dem VRAM einnehmen. Aber es wäre halt verschwendeter Platz...

    Falls Ihr noch Tipps habt, schreibt 🙂 .

    Mit freundlichen Grüßen
    PHBU



  • Der Code sieht ja grauenvoll aus 😮


  • Mod

    roflo schrieb:

    Der Code sieht ja grauenvoll aus 😮

    der beitrag ist von seiner nuetzlichkeit auch grauenvoll 😛
    vielleicht kannst du deinen beitrag aufwerten indem du ihm zeigst wie er seinen code aufwertet.


Anmelden zum Antworten