g3n / engine

Go 3D Game Engine (http://g3n.rocks)
https://discord.gg/NfaeVr8zDg
BSD 2-Clause "Simplified" License
2.8k stars 295 forks source link

GLSL 3.30 does not allow indexing texture sampler with non constant values – crash #139

Closed capnm closed 5 years ago

capnm commented 5 years ago

Related to #2, I'm not sure where that comes from:

https://github.com/g3n/engine/blame/master/renderer/shaders/sources.go#L137 or renderer/shaders/include/material.glsl:35: vec4 texColor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));

./g3nd 04:34:03.453577:I:G3ND:G3N Demo v0.6 starting 04:34:03.453624:I:G3ND:OpenGL version: 4.5 (Core Profile) Mesa 19.2.0-devel - padoka PPA 04:34:03.458111:I:G3ND:Using data directory:g3nd/data

panic: error compiling Vertex Shader: 0:58(26): error: sampler arrays indexed with non-constant expressions are forbidden in GLSL 1.30 and later
001:#version 330 core
...
051:// GLSL 3.30 does not allow indexing texture sampler with non constant values.
052:// This function is used to mix the texture with the specified index with the material color.
053:// It should be called for each texture index. It uses two externally defined variables:
054:// vec4 texColor
055:// vec4 texMixed
056:vec4 MIX_TEXTURE(vec4 texMixed, vec2 FragTexcoord, int i) {
057:    if (MatTexVisible(i)) {
058:        vec4 texColor = texture(MatTexture[i], FragTexcoord * MatTexRepeat(i) + MatTexOffset(i));
059:        if (i == 0) {
060:            texMixed = texColor;
061:        } else {
062:            texMixed = mix(texMixed, texColor, texColor.a);
063:        }
064:    }
065:    return texMixed;
066:}
...

goroutine 1 [running, locked to thread]:
github.com/g3n/g3nd/app.(*App).Update(0xc0000a6460, 0xc000226580, 0xa9cb781)
    g3nd/app/app.go:633 +0x2c8
github.com/g3n/engine/app.(*Application).Run(0xc0000922a0, 0xc0000dbf28)
    pkg/mod/github.com/g3n/engine@v0.1.1-0.20190916152255-1cfa5d780099/app/app-desktop.go:87 +0x15b
github.com/g3n/g3nd/app.(*App).Run(0xc0000a6460)
    g3nd/app/app.go:614 +0x9f
main.main()
    g3nd/main.go:24 +0x27
danaugrs commented 5 years ago

Hi @capnm, thanks for reporting this. I think https://github.com/g3n/engine/commit/973727e925428878318641974704a26dd2ac92e6 might have fixed your issue - could you get latest and try again?

breiting commented 5 years ago

Hi @danaugrs , I just tested the latest master with this fix, but still get an error once using the Material with textures:

panic: error compiling Vertex Shader: 0:56(26): error: sampler arrays indexed with non-constant expressions are forbidden in GLSL 1.30 and later
001:#version 330 core

After some research I found a "fix" which at least let my program work again with textures. I don't know if that is a valid fix?!

In shaders/sources.go:135

vec4 MIX_TEXTURE(vec4 texMixed, vec2 FragTexcoord, int i) {
    vec4 texColor = texture(MatTex(0), FragTexcoord * MatTexRepeat(0) + MatTexOffset(0));
    if (MatTexVisible(i)) {
        if (i == 0) {
            texMixed = texColor;
        } else {
            texMixed = mix(texMixed, texColor, texColor.a);
        }
    }
    return texMixed;
}
danaugrs commented 5 years ago

Hi @breiting! Thanks for the attempt, but that's not a valid solution because it always uses the first texture (with index 0) but materials can have more than one texture.

I pushed the following fix: https://github.com/g3n/engine/commit/a6db6017ca1ef64e9b849213430ba60d0e70f896. @capnm and @breiting please let me know if it works for you! πŸ˜„

breiting commented 5 years ago

Well the one error got fixed, but your commits triggered another error :-)

panic: error compiling Fragment Shader: 0:242(12): warning: extension `GL_OES_standard_derivatives' unsupported in fragment shader
0:195(2): error: #extension directive is not allowed in the middle of a shader
001:#version 330 core

this introduced the problem

241:    // Workaround for gl_FrontFacing
242:    #extension GL_OES_standard_derivatives : enable
243:    vec3 fdx = dFdx(Position.xyz);
244:    vec3 fdy = dFdy(Position.xyz);

When I comment out the extension, everything works fine again.

danaugrs commented 5 years ago

Interesting - apparently the extension declaration isn't necessary. Fixed in https://github.com/g3n/engine/commit/643d63832dcc4ae661271d1755683a0be5204234. Thanks for the help!

capnm commented 5 years ago

Hi @danaugrs I've updated to the current master (7efde9ba89b1501e4aaff108f084b976551e7e2e) now the compiler complains about this fragment shader. Sorry, I don't have time right now to see what's going on :-/

./g3nd β†’ texture β†’ box

19:39:15.688350:I:G3ND:G3N Demo v0.6 starting
19:39:15.688483:I:G3ND:OpenGL version: 4.5 (Core Profile) Mesa 19.2.0-devel - padoka PPA
19:39:15.690470:I:G3ND:Using data directory:g3nd/data
panic: error compiling Fragment Shader: 0:242(12): warning: extension `GL_OES_standard_derivatives' unsupported in fragment shader
0:195(2): error: #extension directive is not allowed in the middle of a shader

001:#version 330 core
002:#define AMB_LIGHTS 1
003:#define DIR_LIGHTS 3
004:#define POINT_LIGHTS 0
005:#define SPOT_LIGHTS 0
006:#define MAT_TEXTURES 2
007:precision highp float;
008:
009:// Inputs from vertex shader
010:in vec4 Position;     // Fragment position in camera coordinates
011:in vec3 Normal;       // Fragment normal in camera coordinates
012:in vec2 FragTexcoord; // Fragment texture coordinates
013:
014:
015://
016:// Lights uniforms
017://
018:
019:#if AMB_LIGHTS>0
020:    // Ambient lights color uniform
021:    uniform vec3 AmbientLightColor[AMB_LIGHTS];
022:#endif
023:
024:#if DIR_LIGHTS>0
025:    // Directional lights uniform array. Each directional light uses 2 elements
026:    uniform vec3 DirLight[2*DIR_LIGHTS];
027:    // Macros to access elements inside the DirectionalLight uniform array
028:    #define DirLightColor(a)        DirLight[2*a]
029:    #define DirLightPosition(a)     DirLight[2*a+1]
030:#endif
031:
032:#if POINT_LIGHTS>0
033:    // Point lights uniform array. Each point light uses 3 elements
034:    uniform vec3 PointLight[3*POINT_LIGHTS];
035:    // Macros to access elements inside the PointLight uniform array
036:    #define PointLightColor(a)          PointLight[3*a]
037:    #define PointLightPosition(a)       PointLight[3*a+1]
038:    #define PointLightLinearDecay(a)    PointLight[3*a+2].x
039:    #define PointLightQuadraticDecay(a) PointLight[3*a+2].y
040:#endif
041:
042:#if SPOT_LIGHTS>0
043:    // Spot lights uniforms. Each spot light uses 5 elements
044:    uniform vec3  SpotLight[5*SPOT_LIGHTS];
045:    // Macros to access elements inside the PointLight uniform array
046:    #define SpotLightColor(a)           SpotLight[5*a]
047:    #define SpotLightPosition(a)        SpotLight[5*a+1]
048:    #define SpotLightDirection(a)       SpotLight[5*a+2]
049:    #define SpotLightAngularDecay(a)    SpotLight[5*a+3].x
050:    #define SpotLightCutoffAngle(a)     SpotLight[5*a+3].y
051:    #define SpotLightLinearDecay(a)     SpotLight[5*a+3].z
052:    #define SpotLightQuadraticDecay(a)  SpotLight[5*a+4].x
053:#endif
054:
055://
056:// Material properties uniform
057://
058:
059:// Material parameters uniform array
060:uniform vec3 Material[6];
061:// Macros to access elements inside the Material array
062:#define MatAmbientColor     Material[0]
063:#define MatDiffuseColor     Material[1]
064:#define MatSpecularColor    Material[2]
065:#define MatEmissiveColor    Material[3]
066:#define MatShininess        Material[4].x
067:#define MatOpacity          Material[4].y
068:#define MatPointSize        Material[4].z
069:#define MatPointRotationZ   Material[5].x
070:
071:#if MAT_TEXTURES > 0
072:    // Texture unit sampler array
073:    uniform sampler2D MatTexture[MAT_TEXTURES];
074:    // Texture parameters (3*vec2 per texture)
075:    uniform vec2 MatTexinfo[3*MAT_TEXTURES];
076:    // Macros to access elements inside the MatTexinfo array
077:    #define MatTexOffset(a)     MatTexinfo[(3*a)]
078:    #define MatTexRepeat(a)     MatTexinfo[(3*a)+1]
079:    #define MatTexFlipY(a)      bool(MatTexinfo[(3*a)+2].x)
080:    #define MatTexVisible(a)    bool(MatTexinfo[(3*a)+2].y)
081:    // Alpha compositing (see here: https://ciechanow.ski/alpha-compositing/)
082:    vec4 Blend(vec4 texMixed, vec4 texColor) {
083:        texMixed.rgb *= texMixed.a;
084:        texColor.rgb *= texColor.a;
085:        texMixed = texColor + texMixed * (1 - texColor.a);
086:        if (texMixed.a > 0.0) {
087:            texMixed.rgb /= texMixed.a;
088:        }
089:        return texMixed;
090:    }
091:#endif
092:
093:/***
094: phong lighting model
095: Parameters:
096:    position:   input vertex position in camera coordinates
097:    normal:     input vertex normal in camera coordinates
098:    camDir:     input camera directions
099:    matAmbient: input material ambient color
100:    matDiffuse: input material diffuse color
101:    ambdiff:    output ambient+diffuse color
102:    spec:       output specular color
103: Uniforms:
104:    AmbientLightColor[]
105:    DiffuseLightColor[]
106:    DiffuseLightPosition[]
107:    PointLightColor[]
108:    PointLightPosition[]
109:    PointLightLinearDecay[]
110:    PointLightQuadraticDecay[]
111:    MatSpecularColor
112:    MatShininess
113:*****/
114:void phongModel(vec4 position, vec3 normal, vec3 camDir, vec3 matAmbient, vec3 matDiffuse, out vec3 ambdiff, out vec3 spec) {
115:
116:    vec3 ambientTotal  = vec3(0.0);
117:    vec3 diffuseTotal  = vec3(0.0);
118:    vec3 specularTotal = vec3(0.0);
119:
120:    bool noLights = true;
121:
122:#if AMB_LIGHTS>0
123:    noLights = false;
124:    // Ambient lights
125:    for (int i = 0; i < AMB_LIGHTS; ++i) {
126:        ambientTotal += AmbientLightColor[i] * matAmbient;
127:    }
128:#endif
129:
130:#if DIR_LIGHTS>0
131:    noLights = false;
132:    // Directional lights
133:    for (int i = 0; i < DIR_LIGHTS; ++i) {
134:        vec3 lightDirection = normalize(DirLightPosition(i)); // Vector from fragment to light source
135:        float dotNormal = max(dot(lightDirection, normal), 0.0); // Dot product between light direction and fragment normal
136:        if (dotNormal > 0.0) { // If the fragment is lit
137:            diffuseTotal += DirLightColor(i) * matDiffuse * dotNormal;
138:            specularTotal += DirLightColor(i) * MatSpecularColor * pow(max(dot(reflect(-lightDirection, normal), camDir), 0.0), MatShininess);
139:        }
140:    }
141:#endif
142:
143:#if POINT_LIGHTS>0
144:    noLights = false;
145:    // Point lights
146:    for (int i = 0; i < POINT_LIGHTS; ++i) {
147:        vec3 lightDirection = PointLightPosition(i) - vec3(position); // Vector from fragment to light source
148:        float lightDistance = length(lightDirection); // Distance from fragment to light source
149:        lightDirection = lightDirection / lightDistance; // Normalize lightDirection
150:        float dotNormal = max(dot(lightDirection, normal), 0.0);  // Dot product between light direction and fragment normal
151:        if (dotNormal > 0.0) { // If the fragment is lit
152:            float attenuation = 1.0 / (1.0 + PointLightLinearDecay(i) * lightDistance + PointLightQuadraticDecay(i) * lightDistance * lightDistance);
153:            vec3 attenuatedColor = PointLightColor(i) * attenuation;
154:            diffuseTotal += attenuatedColor * matDiffuse * dotNormal;
155:            specularTotal += attenuatedColor * MatSpecularColor * pow(max(dot(reflect(-lightDirection, normal), camDir), 0.0), MatShininess);
156:        }
157:    }
158:#endif
159:
160:#if SPOT_LIGHTS>0
161:    noLights = false;
162:    for (int i = 0; i < SPOT_LIGHTS; ++i) {
163:        // Calculates the direction and distance from the current vertex to this spot light.
164:        vec3 lightDirection = SpotLightPosition(i) - vec3(position); // Vector from fragment to light source
165:        float lightDistance = length(lightDirection); // Distance from fragment to light source
166:        lightDirection = lightDirection / lightDistance; // Normalize lightDirection
167:        float angleDot = dot(-lightDirection, SpotLightDirection(i));
168:        float angle = acos(angleDot);
169:        float cutoff = radians(clamp(SpotLightCutoffAngle(i), 0.0, 90.0));
170:        if (angle < cutoff) { // Check if fragment is inside spotlight beam
171:            float dotNormal = max(dot(lightDirection, normal), 0.0); // Dot product between light direction and fragment normal
172:            if (dotNormal > 0.0) { // If the fragment is lit
173:                float attenuation = 1.0 / (1.0 + SpotLightLinearDecay(i) * lightDistance + SpotLightQuadraticDecay(i) * lightDistance * lightDistance);
174:                float spotFactor = pow(angleDot, SpotLightAngularDecay(i));
175:                vec3 attenuatedColor = SpotLightColor(i) * attenuation * spotFactor;
176:                diffuseTotal += attenuatedColor * matDiffuse * dotNormal;
177:                specularTotal += attenuatedColor * MatSpecularColor * pow(max(dot(reflect(-lightDirection, normal), camDir), 0.0), MatShininess);
178:            }
179:        }
180:    }
181:#endif
182:    if (noLights) {
183:        diffuseTotal = matDiffuse;
184:    }
185:    // Sets output colors
186:    ambdiff = ambientTotal + MatEmissiveColor + diffuseTotal;
187:    spec = specularTotal;
188:}
189:// Final fragment color
190:out vec4 FragColor;
191:
192:void main() {
193:
194:    // Compute final texture color
195:    vec4 texMixed = vec4(1);
196:    #if MAT_TEXTURES > 0
197:        bool firstTex = true;
198:        if (MatTexVisible(0)) {
199:            vec4 texColor = texture(MatTexture[0], FragTexcoord * MatTexRepeat(0) + MatTexOffset(0));
200:            if (firstTex) {
201:                texMixed = texColor;
202:                firstTex = false;
203:            } else {
204:                texMixed = Blend(texMixed, texColor);
205:            }
206:        }
207:        #if MAT_TEXTURES > 1
208:            if (MatTexVisible(1)) {
209:                vec4 texColor = texture(MatTexture[1], FragTexcoord * MatTexRepeat(1) + MatTexOffset(1));
210:                if (firstTex) {
211:                    texMixed = texColor;
212:                    firstTex = false;
213:                } else {
214:                    texMixed = Blend(texMixed, texColor);
215:                }
216:            }
217:            #if MAT_TEXTURES > 2
218:                if (MatTexVisible(2)) {
219:                    vec4 texColor = texture(MatTexture[2], FragTexcoord * MatTexRepeat(2) + MatTexOffset(2));
220:                    if (firstTex) {
221:                        texMixed = texColor;
222:                        firstTex = false;
223:                    } else {
224:                        texMixed = Blend(texMixed, texColor);
225:                    }
226:                }
227:            #endif
228:        #endif
229:    #endif
230:
231:    // Combine material with texture colors
232:    vec4 matDiffuse = vec4(MatDiffuseColor, MatOpacity) * texMixed;
233:    vec4 matAmbient = vec4(MatAmbientColor, MatOpacity) * texMixed;
234:
235:    // Normalize interpolated normal as it may have shrinked
236:    vec3 fragNormal = normalize(Normal);
237:
238:    // Calculate the direction vector from the fragment to the camera (origin)
239:    vec3 camDir = normalize(-Position.xyz);
240:
241:    // Workaround for gl_FrontFacing
242:    #extension GL_OES_standard_derivatives : enable
243:    vec3 fdx = dFdx(Position.xyz);
244:    vec3 fdy = dFdy(Position.xyz);
245:    vec3 faceNormal = normalize(cross(fdx,fdy));
246:    if (dot(fragNormal, faceNormal) < 0.0) { // Back-facing
247:        fragNormal = -fragNormal;
248:    }
249:
250:    // Calculates the Ambient+Diffuse and Specular colors for this fragment using the Phong model.
251:    vec3 Ambdiff, Spec;
252:    phongModel(Position, fragNormal, camDir, vec3(matAmbient), vec3(matDiffuse), Ambdiff, Spec);
253:
254:    // Final fragment color
255:    FragColor = min(vec4(Ambdiff + Spec, matDiffuse.a), vec4(1.0));
256:}
257:

goroutine 1 [running, locked to thread]:
github.com/g3n/g3nd/app.(*App).Update(0xc00008c460, 0xc00053b080, 0xa69e9a2)
    g3nd/app/app.go:633 +0x2c8
github.com/g3n/engine/app.(*Application).Run(0xc000064300, 0xc0000bff28)
    GOPATH/pkg/mod/github.com/g3n/engine@v0.1.1-0.20190920151355-4fba891551e6/app/app-desktop.go:87 +0x15b
github.com/g3n/g3nd/app.(*App).Run(0xc00008c460)
    g3nd/app/app.go:614 +0x9f
main.main()
    g3nd/main.go:24 +0x27
danaugrs commented 5 years ago

@capnm I forgot to update g3nd to use the latest version (did so now in https://github.com/g3n/g3nd/commit/6c8ff52178c0e4e9906778effe962c6e9c2dfb0f). Should work now!

capnm commented 5 years ago

Should work now!

Almost ;-)

Could you probably print the shader path? Why there the 2 shader copies?

./g3nd 
20:15:02.677858:I:G3ND:G3N Demo v0.6 starting
20:15:02.678016:I:G3ND:OpenGL version: 4.5 (Core Profile) Mesa 19.2.0-devel - padoka PPA
20:15:02.680563:I:G3ND:Using data directory:g3nd/data
panic: error compiling Fragment Shader: 0:51(159): error: sampler arrays indexed with non-constant expressions are forbidden in GLSL 1.30 and later
01:#version 330 core
02:#define AMB_LIGHTS 1
03:#define DIR_LIGHTS 0
04:#define POINT_LIGHTS 0
05:#define SPOT_LIGHTS 0
06:#define MAT_TEXTURES 1
07:precision highp float;
08:
09:
10://
11:// Material properties uniform
12://
13:
14:// Material parameters uniform array
15:uniform vec3 Material[6];
16:// Macros to access elements inside the Material array
17:#define MatAmbientColor      Material[0]
18:#define MatDiffuseColor     Material[1]
19:#define MatSpecularColor    Material[2]
20:#define MatEmissiveColor    Material[3]
21:#define MatShininess        Material[4].x
22:#define MatOpacity          Material[4].y
23:#define MatPointSize        Material[4].z
24:#define MatPointRotationZ   Material[5].x
25:
26:#if MAT_TEXTURES > 0
27:    // Texture unit sampler array
28:    uniform sampler2D MatTexture[MAT_TEXTURES];
29:    // Texture parameters (3*vec2 per texture)
30:    uniform vec2 MatTexinfo[3*MAT_TEXTURES];
31:    // Macros to access elements inside the MatTexinfo array
32:    #define MatTexOffset(a)      MatTexinfo[(3*a)]
33:    #define MatTexRepeat(a)      MatTexinfo[(3*a)+1]
34:    #define MatTexFlipY(a)       bool(MatTexinfo[(3*a)+2].x)
35:    #define MatTexVisible(a) bool(MatTexinfo[(3*a)+2].y)
36:    // Alpha compositing (see here: https://ciechanow.ski/alpha-compositing/)
37:    vec4 Blend(vec4 texMixed, vec4 texColor) {
38:        texMixed.rgb *= texMixed.a;
39:        texColor.rgb *= texColor.a;
40:        texMixed = texColor + texMixed * (1 - texColor.a);
41:        if (texMixed.a > 0.0) {
42:            texMixed.rgb /= texMixed.a;
43:        }
44:        return texMixed;
45:    }
46:#endif
47:// GLSL 3.30 does not allow indexing texture sampler with non constant values.
48:// This macro is used to mix the texture with the specified index with the material color.
49:// It should be called for each texture index.
50:#if MAT_TEXTURES > 0
51:vec4 MIX_POINT_TEXTURE(vec4 texMixed, mat2 rotation, int i) {                                                           \
52:    if (MatTexVisible(i)) {                                                                                      \
53:        vec2 pt = gl_PointCoord - vec2(0.5);                                                                     \
54:        vec4 texColor = texture(MatTexture[i], (rotation * pt + vec2(0.5)) * MatTexRepeat(i) + MatTexOffset(i)); \
55:        if (i == 0) {                                                                                            \
56:            texMixed = texColor;                                                                                 \
57:        } else {                                                                                                 \
58:            texMixed = mix(texMixed, texColor, texColor.a);                                                      \
59:        }                                                                                                        \
60:    }
61:    return texMixed;
62:}
63:#endif
64:
danaugrs commented 5 years ago

@capnm thanks! That was another shader with a similar issue that I forgot to modify. Updated g3nd and all should be golden now. Please let me know if it isn't πŸ˜„

capnm commented 5 years ago

Do you know some magic how to use the new go mod for a library development?

I'd tried go mod vendor, but it doesn't clones the (g3n) repository, it just copies the old tip files (which is useless …)

danaugrs commented 5 years ago

Hey @capnm yeah - It was tricky to find info about this when I started using go modules! You can add a line like replace your/library/package => local/library/path to the end of the go.mod file for the application that uses your library. E.g. when developing the engine I modify the g3nd go.mod to be:

module github.com/g3n/g3nd

go 1.12

require (
    github.com/g3n/engine v0.1.1-0.20190920210015-bf87e32ba567
    github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
)

replace github.com/g3n/engine => ../engine

Hope this helps!

capnm commented 5 years ago

Cool, that's exactly what i needed, thanks! I clicked through all the demos and the shader compiler seems happy now :-)

breiting commented 5 years ago

@capnm, you can easily switch to a different version of a module by using go get <module>@<commitID>