GLSL Shader Crash bei Array Nutzung
Verfasst: 22.03.2014, 19:11
Ich entwickel zur Zeit einen "Übershader" zur Behandlung von Lichtquellen. Für Direktionale-Lichtquellen läuft alles hervorragend. Nun bin ich dabei das ganze um Punkt-Lichtquellen zu erweitern und habe hier ein Fehlerverhalten beim Zugriff auf Array Werte, den ich mir absolut nicht erklären kann. Hier ersteinmal der gesamte Shader Quellcode:
Vertexshader:
Fragmentshader:
Ich habe inzwischen 2 Tage mit Debuggen verbracht und alle Werte zum Shader überprüft. Sie sind in Ordnung und werden korrekt übergeben. Beim Testen im Shader bin ich auf folgende Stelle gestoßen, die zum Fehlverhalten führt:
Das ganze läuft korrekt und fehlerfrei, wenn ich den Zugriff auf das Array mit einem konstanten Index mache : vec3 dir = vTest2[0]; Nutze ich jedoch wie im Snipped eine Variable mit dem Laufindexwert: vec3 dir = vTest2[k]; dann tickt der Shader aus. D.h. es wird um das x-fache langsamer gerendert (Beleuchtung sieht nach wie vor korrekt aus) und ich habe im Wechsel immer ein Bild und einen schwarzen Bildschirm. Unter Linux führt das ganze z.T. zu einem so harten Crash, dass nix mehr geht. D.h. ich kann dann nicht mal mehr die Konsole öffen um einen Prozess zu killen, sondern muss durchstarten. Unter Windows habe ich nur das gleiche Fehlverhalten. Der GDB meldet keinen Fehler, Valgrind schmiert zusammen mit dem Prozess ab :o(
Für mich sieht es so aus, als ob irgendwo ein Speicherzugriff daneben geht. Aber ich verstehe nicht wie das passieren kann und sehe auch keine Möglichkeit das zu debuggen, da das bei Shadern ja nicht geht. Ich habe im Test mal den Laufindex überprüft indem ich wie man im Snipped sehen kann, den diffusen Lichtwert in Anbhängigkeit zum Index manipuliere, der scheint i.O. zu sein, es wird immer rot gerendert. D.h. der Laufindex der Schleife ist 0 bei einer Lichtquelle und somit richtig.
Hat jemand eine Idee was hier schief laufen könnte oder wie ich möglicherweise weiter die Fehlerquelle eingrenzen kann, bin inzwischen völlig ratlos und verstehe die Welt nicht mehr.
Vertexshader:
Code: Alles auswählen
#version 130
uniform mat4 MVPMatrix; // combined model/view/projection matrix.
uniform mat4 NMatrix; // normal matrix.
uniform mat4 MVMatrix; // model/view matrix.
// Per-Vertex informations we will pass in
in vec3 vertex;
in vec2 texCoord0;
in vec3 normal;
// Those values will be passed into the fragment shader.
out vec2 vTexCoord0;
out vec3 vNormal;
#ifndef MAX_LIGHT_COUNT
#define MAX_LIGHT_COUNT 8
// The number of lights which should be created
uniform int uCountDirectionalLights;
uniform int uCountPointLights;
// The directional light value arrays
uniform vec3 uDirectionalLightDirection[MAX_LIGHT_COUNT];
out vec3 vDirectionalLightDirection[MAX_LIGHT_COUNT];
// The point light value arrays
uniform vec3 uPointLightPosition[MAX_LIGHT_COUNT];
out vec3 vPointLightDirection[MAX_LIGHT_COUNT];
uniform vec3 uCameraPosition; // Position of the camera in view space.
out vec3 vCameraDirection;
flat out int vCountDirectionalLights;
flat out int vCountPointLights;
out vec3 vTest2[MAX_LIGHT_COUNT];
void createLights(vec4 position)
{
for(int i=0; i<uCountDirectionalLights; i++){
vDirectionalLightDirection[i] = uDirectionalLightDirection[i];
}
for(int i=0; i<uCountPointLights; i++){
vTest2[i] = uPointLightPosition[i] - position.xyz;
}
// Compute camera direction for specular lighting
vCameraDirection = uCameraPosition - position.xyz;
vCountDirectionalLights = uCountDirectionalLights;
vCountPointLights = uCountPointLights;
}
void main( void )
{
//transform vertex position to clip space.
gl_Position = MVPMatrix * vec4(vertex, 1.0);
// transform normal to view space.
vec3 eNormal = vec3(NMatrix * vec4(normal, 0.0));
eNormal = eNormal / length(eNormal);
vNormal = eNormal;
// create lights using world view position values.
createLights(MVMatrix * vec4(vertex, 1.0));
vTexCoord0 = texCoord0;
}
Code: Alles auswählen
#version 130
#ifdef GLES2
//Set the default precision to medium. We don't need as high of a precision in the fragment shader.
precision mediump float;
#endif
uniform sampler2D texture;
in vec3 vNormal;
in vec2 vTexCoord0;
out vec4 outColor;
#ifndef MAX_LIGHT_COUNT
#define MAX_LIGHT_COUNT 8
struct Material {
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
uniform Material uMaterial;
uniform bool uUseLighting;
uniform vec4 uSceneAmbientColor;
uniform vec4 uDirectionalLightDiffuseColor[MAX_LIGHT_COUNT];
uniform vec4 uDirectionalLightSpecularColor[MAX_LIGHT_COUNT];
flat in int vCountDirectionalLights;
in vec3 vDirectionalLightDirection[MAX_LIGHT_COUNT];
uniform vec4 uPointLightDiffuseColor[MAX_LIGHT_COUNT];
uniform vec4 uPointLightSpecularColor[MAX_LIGHT_COUNT];
uniform float uPointLightInverseRange[MAX_LIGHT_COUNT];
flat in int vCountPointLights;
in vec3 vPointLightDirection[MAX_LIGHT_COUNT];
in vec3 vCameraDirection;
in vec3 vTest;
in vec3 vTest2[MAX_LIGHT_COUNT];
vec4 computeLighting(vec3 normalVector, vec3 lightDirection, float attenuation, vec3 cameraDirection, vec4 diffuseColor, vec4 specularColor)
{
vec4 LightWeighting = vec4(1.0, 1.0, 1.0, 1.0);
if(uUseLighting)
{
// do light calculations
float dotNormalLightDirection = max(dot(normalVector, lightDirection), 0.0);
vec4 ambientLight = uSceneAmbientColor * uMaterial.ambient;
vec4 diffuseLight = dotNormalLightDirection * diffuseColor * uMaterial.diffuse;
// Specular
vec3 halfVector = normalize(lightDirection + cameraDirection);
float dotHalfLightDirection = max(dot(normalVector, halfVector), 0.0);
vec4 specularLight = vec4(0.0);
if(dotHalfLightDirection > 0.0){
specularLight = pow(dotHalfLightDirection, uMaterial.shininess)* specularColor * uMaterial.specular;
}
LightWeighting = ambientLight + diffuseLight + specularLight;
}
return LightWeighting;
}
vec4 computeLights(vec3 normal)
{
vec4 combinedLightWeights = vec4(0.0, 0.0, 0.0, 0.0);
if(uUseLighting)
{
// normalize camer a for specular lighting
vec3 cameraDirection = normalize(vCameraDirection);
for(int i=0; i<vCountDirectionalLights; i++){
vec3 lightDirection = normalize(vDirectionalLightDirection[i]);
combinedLightWeights += computeLighting(normal, -lightDirection, 1.0, cameraDirection, uDirectionalLightDiffuseColor[i], uDirectionalLightSpecularColor[i]);
}
for(int n=0; n<1; n++){
/* Calculate the light attenuation based on light radius algorithm.
@see http://www.ozone3d.net/tutorials/glsl_lighting_phong_p4.php
*/
//vec3 ldir = vPointLightDirection[i] * uPointLightInverseRange[i];
//float attenuation = clamp(1.0 - dot(ldir, ldir), 0.0, 1.0);
vec4 color = vec4(1.0, 1.0, 0.0, 1.0);
if(n==0){
color = vec4(1.0, 0.0, 0.0, 1.0);
}
if(n>0){
color = vec4(0.0, 1.0, 0.0, 1.0);
}
int k = 0;
vec3 dir = vTest2[k];
//combinedLightWeights += computeLighting(normal, normalize(vPointLightDirection[i]), attenuation, cameraDirection, uPointLightDiffuseColor[i], uPointLightSpecularColor[i]);
combinedLightWeights += computeLighting(normal, normalize(dir), 1.0, cameraDirection, color, uPointLightSpecularColor[n]);
}
}
return combinedLightWeights;
}
void main(void)
{
// Normalize the vectors.
vec3 normal = normalize(vNormal);
vec4 lightWeighting = computeLights(normal);
vec4 textureColor = texture2D(texture, vTexCoord0);
outColor = vec4(textureColor.xyz * lightWeighting.xyz, textureColor.a);
}
Code: Alles auswählen
int k = 0;
vec3 dir = vTest2[k];
//combinedLightWeights += computeLighting(normal, normalize(vPointLightDirection[i]), attenuation, cameraDirection, uPointLightDiffuseColor[i], uPointLightSpecularColor[i]);
combinedLightWeights += computeLighting(normal, normalize(dir), 1.0, cameraDirection, color, uPointLightSpecularColor[n]);
Für mich sieht es so aus, als ob irgendwo ein Speicherzugriff daneben geht. Aber ich verstehe nicht wie das passieren kann und sehe auch keine Möglichkeit das zu debuggen, da das bei Shadern ja nicht geht. Ich habe im Test mal den Laufindex überprüft indem ich wie man im Snipped sehen kann, den diffusen Lichtwert in Anbhängigkeit zum Index manipuliere, der scheint i.O. zu sein, es wird immer rot gerendert. D.h. der Laufindex der Schleife ist 0 bei einer Lichtquelle und somit richtig.
Hat jemand eine Idee was hier schief laufen könnte oder wie ich möglicherweise weiter die Fehlerquelle eingrenzen kann, bin inzwischen völlig ratlos und verstehe die Welt nicht mehr.