Hello.
I have the need to combine up to 10 repeating texture patterns on a geometry with alpha channel for each texture pattern. However, the GSG’s getNumTextureStages() reports that I can have only 4 texture stages, with one texture and alpha channel each. This why I have to try to program a custom shader so I can upload 10 textures and alpha channels to do splatting.
Thus far the only thing I’ve managed to get working is splatting 10 textures with 4 alpha textures (with up to 3 channels each). However, this looks really bad because there is no shading and no shadows. For starters I need shading to work so I can at least get my project really started.
The model I am using is a GeoMipTerrain constructed from a heightfield.
I tried to combine some snippets from the net to get shading to work. I got the fragment shader code from the following snippet: [url]Lights inputs in GLSL shaders]
The problem is that when shader output picture on screen, the picture is full of black patches:
These black patches move and strech as I move the camera. Maybe I am using wrong types of input coordinates or something?
I can recite much of the the jargon regarding the math behind shading, but I have no real understanding what it all means. This is all just like reading religious scripture with a foreign language, just rehearsed and imitated rote. Thus, if some code snippet does not work, I have no means to figure out why it is broken.
So now I ask help. Can somebody figure out what am I doing wrong with the shading part?
EDIT: I tried loading a model from egg file instead of the GeoMipTerrain, and the shading is done properly. Thus it seems like GeoMipTerrain does not properly generate normals or something. What can be done? Can I somehow correct the normals in GeoMipTerrain?
Shader inputs via Python:
dlight = DirectionalLight('dlight')
self.dlight = self.render.attachNewNode(dlight)
self.dlight.setHpr(0, -60, 0)
self.render.setLight(self.dlight)
self.terrain = GeoMipTerrain('test')
...
root = self.terrain.getRoot()
shader = Shader.load(Shader.SL_GLSL, vertex='terrainv.glsl', fragment='terrainf.glsl')
root.setShader(shader)
for i in xrange(0, 10):
root.setShaderInput("tex%d" % i, loader.loadTexture("splat/tex%d.jpg" % i))
root.setShaderInput('alpha012', loader.loadTexture('splat/alpha012.png'))
root.setShaderInput('alpha345', loader.loadTexture('splat/alpha345.png'))
root.setShaderInput('alpha678', loader.loadTexture('splat/alpha678.png'))
root.setShaderInput('alpha9', loader.loadTexture('splat/alpha9.png'))
root.setShaderInput('tiling', 128)
root.setShaderInput('customLight', self.dlight)
...
Note that self.terrain is a GeoMipTerrain node constructed from a heightmap.
Vertex shader:
#version 330
// Uniform inputs
uniform mat4 p3d_ModelViewProjectionMatrix;
uniform mat4 p3d_ModelViewMatrix;
uniform mat3 p3d_NormalMatrix;
// Vertex inputs
in vec4 p3d_Vertex;
in vec3 p3d_Normal;
in vec2 p3d_MultiTexCoord0;
// Output things to fragment shader
out vec2 texCoord; // texture coordinate
out vec3 vpos; // vertex position in relation to camera???
out vec3 norm; // vertex normal in camera space???
void main() {
gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
texCoord = p3d_MultiTexCoord0;
vpos = vec3(p3d_ModelViewMatrix * p3d_Vertex);
norm = normalize(p3d_NormalMatrix * p3d_Normal);
}
Fragment shader:
#version 330 compatibility
// Texture layer alpha textures
uniform sampler2D alpha012;
uniform sampler2D alpha345;
uniform sampler2D alpha678;
uniform sampler2D alpha9;
// Texture layers
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform sampler2D tex3;
uniform sampler2D tex4;
uniform sampler2D tex5;
uniform sampler2D tex6;
uniform sampler2D tex7;
uniform sampler2D tex8;
uniform sampler2D tex9;
// Tiling multiplier
uniform float tiling = 4.0;
// Custom light shader input, works on all light types except AmbientLight
uniform gl_LightSourceParameters customLight;
uniform struct {
// Sum of all ambient lights
vec4 ambient;
} p3d_LightModel;
struct P3DMaterial {
vec4 ambient;
vec4 diffuse;
vec3 specular;
float shininess;
};
uniform P3DMaterial p3d_Material;
in vec3 vpos;
in vec3 norm;
in vec4 texCoord;
//ApplyShading(vec4 texColor, )
void main(void)
{
// This is the code I was able to understand, texture splatting
vec4 a0 = texture2D(alpha012, texCoord.xy);
vec4 a1 = texture2D(alpha345, texCoord.xy);
vec4 a2 = texture2D(alpha678, texCoord.xy);
vec4 a3 = texture2D(alpha9, texCoord.xy);
vec4 rgb0 = texture2D(tex0, texCoord.xy * tiling); // Tile
vec4 rgb1 = texture2D(tex1, texCoord.xy * tiling); // Tile
vec4 rgb2 = texture2D(tex2, texCoord.xy * tiling); // Tile
vec4 rgb3 = texture2D(tex3, texCoord.xy * tiling); // Tile
vec4 rgb4 = texture2D(tex4, texCoord.xy * tiling); // Tile
vec4 rgb5 = texture2D(tex5, texCoord.xy * tiling); // Tile
vec4 rgb6 = texture2D(tex6, texCoord.xy * tiling); // Tile
vec4 rgb7 = texture2D(tex7, texCoord.xy * tiling); // Tile
vec4 rgb8 = texture2D(tex8, texCoord.xy * tiling); // Tile
vec4 rgb9 = texture2D(tex9, texCoord.xy * tiling); // Tile
rgb0 *= a0.r;
rgb1 = mix(rgb0, rgb1, a0.g);
rgb2 = mix(rgb1, rgb2, a0.b);
rgb3 = mix(rgb2, rgb3, a1.r);
rgb4 = mix(rgb3, rgb4, a1.g);
rgb5 = mix(rgb4, rgb5, a1.b);
rgb6 = mix(rgb5, rgb6, a2.r);
rgb7 = mix(rgb6, rgb7, a2.g);
rgb8 = mix(rgb7, rgb8, a2.b);
vec4 texDiffuse = mix(rgb8, rgb9, a3.r);
// Here is the Pong-shading thing, I don't understand what this code does :( pls halp
gl_FragColor = p3d_LightModel.ambient * p3d_Material.ambient;
vec3 diff = customLight.position.xyz - vpos * customLight.position.w;
vec3 L = normalize(diff);
vec3 E = normalize(-vpos);
vec3 R = normalize(-reflect(L, norm));
vec4 diffuse = clamp(texDiffuse * p3d_Material.diffuse * customLight.diffuse * max(dot(norm, L), 0), 0, 1);
vec4 specular = vec4(p3d_Material.specular, 1) * customLight.specular * pow(max(dot(R, E), 0), p3d_Material.shininess);
float spotEffect = dot(normalize(customLight.spotDirection), -L);
if (spotEffect > customLight.spotCosCutoff) {
gl_FragColor += (diffuse + specular) / (customLight.constantAttenuation + customLight.linearAttenuation * length(diff) + customLight.quadraticAttenuation * length(diff) * length(diff));
}
}