Shiny materials, shader reorganisation

This implements the proposal made in the forum for "shiny" materials -
material can now determine the angle at which the most light is reflected.
Shiny materials might set this lower to approximate a "reflection" effect,
and increase the "spottiness" at the same time. To compensate for the
lack of brightness without light, "emittance" can be used.

Not sure this is the most elegant way to model this - the "proper" way
here would be to have emittance, shading and specular as three separate
light parameters instead of molding one into the other and using the third
to compensate.

Furthermore, this reorganises shaders in a major way: We reduce the
number of shader files down to three, pushing a number of possible
configurations into preprocessor. I believe this should be easier to
understand, which for the moment trumps theoretical extensibility
benefits.
lights3
Peter Wortmann 2015-09-20 14:50:22 +01:00
parent 88ef1d40fa
commit 480ade634d
20 changed files with 380 additions and 398 deletions

View File

@ -1,40 +0,0 @@
// Ambient light calculation
#ifdef HAVE_LIGHT
uniform sampler2D ambientTex;
uniform mat3x2 ambientTransform;
uniform float ambientBrightness;
#endif
//uniform float cullMode; // 0 if backface culling is enabled, 1 if it is disabled
// Already declared in LightShader.glsl
slice(texture+6)
{
#ifdef HAVE_LIGHT
// Ambient light
// Extra .xy since some old intel drivers return a vec3
float ambient = texture2D(ambientTex, (ambientTransform * vec3(gl_FragCoord.xy, 1.0)).xy).r * ambientBrightness;
#else
// Lighting disabled: Ambient light everywhere
float ambient = 1.0;
#endif
}
slice(light+1)
{
// Add ambience to brightness
#ifdef LANDSCAPE
// For landscape, ambient brightness is coming from top
vec3 ambientDir = vec3(0.0, -1.0, 0.0);
light = mix(light, 1.0 + 1.0 * dot(normal, ambientDir), ambient);
#ifdef HAVE_2PX
light2 = mix(light2, 1.0 + 1.0 * dot(normal2, ambientDir), ambient);
#endif
#else
// For objects, ambient brightness is coming from the front
vec3 ambientDir = vec3(0.0, 0.0, 1.0);
light = mix(light, max(max(dot(normal, ambientDir), 0.0), cullMode * max(dot(-normal, ambientDir), 0.0)), ambient);
#endif
}

View File

@ -0,0 +1,162 @@
// uncomment the following lines for debugging light directions:
// yellow: light up, blue: light down, turqoise: light right, pink: light left
// brightness: light strength
//#define LIGHT_DEBUG
// uncomment the following lines for debugging light color:
// the light will always come from the front and have a uniform brightness.
//#define LIGHT_DEBUG_COLOR
// uncomment the following lines to set the light color to pink for all lights for debugging:
//#define LIGHT_DEBUG_PINK
// At what point of light intensity we set the "darkness" point. This
// is to compensate for the fact that the engine "smoothes" the light
// and therefore will often never arrive at 0 light intensity.
const float lightDarknessLevel = 8.0 / 256.0;
#ifdef HAVE_LIGHT
uniform sampler2D ambientTex;
uniform mat3x2 ambientTransform;
uniform float ambientBrightness;
uniform sampler2D lightTex;
#endif
// Gamma uniforms
uniform vec3 gamma;
// 0 if backface culling is enabled, 1 if it is disabled
uniform float cullMode;
// Light dot product, taking cull mode into account
float lightDot(vec3 normal, vec3 lightDir) {
return abs(max(-cullMode, dot(normalize(normal), lightDir)));
}
vec3 extend_normal(vec2 v)
{
// the higher the second value, the further away the light source from the landscape
return normalize(vec3(v, 0.45));
}
// Converts the pixel range 0.0..1.0 into the integer range 0..255
int f2i(float x) {
return int(x * 255.9);
}
slice(texture+5)
{
#ifdef HAVE_LIGHT
// Query light texture
vec2 lightDirCoord = lightCoord.st;
vec4 lightPx = texture2D(lightTex, lightDirCoord);
float lightBright = 2.0*max(0.0, lightPx.a-lightDarknessLevel);
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
// Query light color texture (part of the light texture)
vec2 lightColorCoord = lightCoord.st - vec2(0.0, 0.5); // subtract offset for the color texture
vec3 lightColor = texture2D(lightTex, lightColorCoord.st).rgb;
// Normalise light colour
#ifdef LIGHT_DEBUG_COLOR
lightBright = 0.5;
lightColor = vec4(1.0, 0.0, 1.0, 1.0);
#endif
#else
// When lighting is disabled, put a light source coming from the camera.
// Note that in most cases this does not actually matter, since in the
// case with lighting disabled, ambient lighting takes fully over.
float lightBright = 0.5;
vec3 lightDir = vec3(0.0, 0.0, 1.0);
vec3 lightColor = vec3(1.0, 1.0, 1.0);
#endif
#ifdef HAVE_LIGHT
// Ambient light
// Extra .xy since some old intel drivers return a vec3
float ambient = texture2D(ambientTex, (ambientTransform * vec3(gl_FragCoord.xy, 1.0)).xy).r * ambientBrightness;
#else
// Lighting disabled: Ambient light everywhere
float ambient = 1.0;
#endif
}
slice(light)
{
// Light dot product, taking backface culling into account
normal = normalize(normal);
float light = lightDot(normal, lightDir);
// Amount of reflection, depending on the angle where material reflects most
light = min(light / matAngle, 2.0 - light / matAngle);
#ifdef LANDSCAPE
normal2 = normalize(normal2);
float light2 = lightDot(normal2, lightDir);
light2 = min(light2 / matAngle2, 2.0 - light2 / matAngle2);
#endif
}
slice(light+1)
{
#ifdef LANDSCAPE
// For landscape, ambient brightness is coming from top
vec3 ambientDir = normalize(vec3(0.0, -1.0, 1.0));
#else
// For objects, ambient brightness is coming from the front
vec3 ambientDir = vec3(0.0, 0.0, 1.0);
#endif
// Add ambience to brightness
lightBright = mix(lightBright, 1.0, ambient);
light = mix(light, 0.5 * (ambient + lightDot(normal, ambientDir)), ambient);
#ifdef LANDSCAPE
light2 = mix(light2, 0.5 * (ambient + lightDot(normal2, ambientDir)), ambient);
#endif
lightColor = mix(lightColor, vec3(1.0,1.0,1.0), ambient);
}
slice(color+5)
{
// Normalize light colour
vec3 lightColorNorm = sqrt(3.0) * normalize(lightColor);
// Add light. Depending on material properties, we make it more
// "spotty" and allow the material to self-illuminate. The light
// brightness overrules everything though (= FoW is last factor).
vec3 spotLight = pow(vec3(light,light,light), matSpot);
color.rgb = lightBright * color.rgb * (matEmit + lightColorNorm * spotLight);
#ifdef LANDSCAPE
vec3 spotLight2 = pow(vec3(light2,light2,light2), matSpot2);
color2.rgb = lightBright * color2.rgb * (matEmit2 + lightColorNorm * spotLight2);
#endif
}
slice(finish+5)
{
#ifdef LIGHT_DEBUG
#ifdef HAVE_LIGHT
float lightYDir = lightPx.b - 1.0/3.0;
float lightXDir = lightPx.g - 1.0/3.0;
float lightStrength = lightPx.a;
color =
vec4(lightStrength * vec3(1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
1.0-1.5*max(0.0, -lightYDir)),
1.0);
#else
color = vec4(0.0, 0.0, 0.0, 0.0); // invisible
#endif
#endif
}
slice(finish+10) {
color = vec4(pow(color.rgb, gamma), color.a);
}

View File

@ -1,7 +0,0 @@
// Gamma uniforms
uniform vec3 gamma;
slice(finish+10) {
color = vec4(pow(color.rgb, gamma), color.a);
}

View File

@ -1,5 +1,4 @@
// Input textures
uniform sampler2D landscapeTex[2];
uniform sampler2D scalerTex;
@ -11,11 +10,7 @@ uniform vec2 resolution;
// Center position
uniform vec2 center;
// Texture map
#ifndef NO_BROKEN_ARRAYS_WORKAROUND
uniform sampler1D matMapTex;
#else
uniform float matMap[256];
#endif
uniform int materialDepth;
uniform vec2 materialSize;
@ -25,20 +20,15 @@ const vec2 scalerStepY = vec2(0.0, 1.0 / 32.0);
const vec2 scalerOffset = scalerStepX / 3.0 + scalerStepY / 3.0;
const vec2 scalerPixel = vec2(scalerStepX.x, scalerStepY.y) / 3.0;
// Parameters
// How much % the normals from the normal map are added up to the
// landscape normal. The higher the strength, the more structure
// within the material is visible but also the less the borders
// between the different materials stand out.
const float normalMapStrength = 0.20;
// how much % the normals from the normal map are added up to the landscape normal. The higher the strength, the more
// structure within the material is visible but also the less the borders between the different materials stand out.
const float normalMapStrength = 0.75;
float queryMatMap(int pix)
vec4 queryMatMap(int pix)
{
#ifndef NO_BROKEN_ARRAYS_WORKAROUND
int idx = f2i(texture1D(matMapTex, float(pix) / 256.0 + 0.5 / 256.0).r);
return float(idx) / 256.0 + 0.5 / float(materialDepth);
#else
return matMap[pix];
#endif
return texture1D(matMapTex, float(pix) / 2.0 / 256.0 + 0.5 / 2.0 / 256.0);
}
slice(coordinate)
@ -63,44 +53,74 @@ slice(texture)
// our pixel color (without/with interpolation)
vec4 landscapePx = texture2D(landscapeTex[0], centerCoo);
vec4 realLandscapePx = texture2D(landscapeTex[0], texCoo);
// find scaler coordinate
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
int iScaler = f2i(landscapePx.a), iRow = iScaler / 8;
scalerCoo.x += float(iScaler - iRow * 8) / 8.0;
scalerCoo.y += float(iScaler / 8) / 32.0;
// query scaler texture
vec4 scalerPx = texture2D(scalerTex, scalerCoo);
// Get "second" landscape pixel
vec2 centerCoo2 = centerCoo + fullStep * floor(vec2(-0.5, -0.5) +
scalerPx.gb * 255.0 / 64.0);
vec4 landscapePx2 = texture2D(landscapeTex[0], centerCoo2);
}
slice(material)
{
// Get material pixels
float materialIx = queryMatMap(f2i(landscapePx.r));
// Get material properties from material map
int matMapIx = f2i(landscapePx.r);
vec4 matMap = queryMatMap(2*matMapIx);
vec4 matMapX = queryMatMap(2*matMapIx+1);
float materialIx = float(f2i(matMap.a)) / 256.0 + 0.5 / float(materialDepth);
vec3 matEmit = matMap.rgb;
vec3 matSpot = matMapX.rgb * 255.9f / 16.0f;
float matAngle = matMapX.a;
// Query material texture pixels
vec4 materialPx = texture3D(materialTex, vec3(materialCoo, materialIx));
vec4 normalPx = texture3D(materialTex, vec3(materialCoo, materialIx+0.5));
// Same for second pixel, but we'll simply use the first normal
#ifdef HAVE_2PX
float materialIx2 = queryMatMap(f2i(landscapePx2.r));
// Same for second pixel
int matMapIx2 = f2i(landscapePx2.r);
vec4 matMap2 = queryMatMap(2*matMapIx2);
vec4 matMapX2 = queryMatMap(2*matMapIx2+1);
float materialIx2 = float(f2i(matMap2.a)) / 256.0 + 0.5 / float(materialDepth);
vec3 matEmit2 = matMap2.rgb;
vec3 matSpot2 = matMapX2.rgb * 255.9f / 16.0f;
float matAngle2 = matMapX2.a;
// Query material texture pixels
vec4 materialPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2));
vec4 normalPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2+0.5));
#endif
}
slice(normal)
{
// Normal calculation
vec3 normal = extend_normal(mix(realLandscapePx.yz, landscapePx.yz, scalerPx.a)
- vec2(0.5, 0.5));
vec3 normal = extend_normal(1.5 * (mix(realLandscapePx.yz, landscapePx.yz, scalerPx.a)
- vec2(0.5, 0.5)));
vec3 textureNormal = normalPx.xyz - vec3(0.5,0.5,0.5);
normal = normal + textureNormal * normalMapStrength;
normal = mix(textureNormal, normal, normalMapStrength);
#ifdef HAVE_2PX
vec3 normal2 = extend_normal(landscapePx2.yz - vec2(0.5, 0.5));
vec3 textureNormal2 = normalPx2.xyz - vec3(0.5,0.5,0.5);
normal2 = normal2 + textureNormal2 * normalMapStrength;
#endif
normal2 = mix(textureNormal2, normal2, normalMapStrength);
}
slice(color) {
#define color gl_FragColor
color = materialPx;
#ifdef HAVE_2PX
vec4 color2 = materialPx2;
#endif
}
slice(color+10) {
// Mix second color into main color according to scaler
color = mix(color2, color, scalerPx.r);
}

View File

@ -1,99 +0,0 @@
// Base light calculations
#ifdef HAVE_LIGHT
uniform sampler2D lightTex;
#endif
uniform float cullMode; // 0 if backface culling is enabled, 1 if it is disabled
// uncomment the following lines for debugging light directions:
// yellow: light up, blue: light down, turqoise: light right, pink: light left
// brightness: light strength
//#define LIGHT_DEBUG
// uncomment the following lines for debugging light color:
// the light will always come from the front and have a uniform brightness.
//#define LIGHT_DEBUG_COLOR
// uncomment the following lines to set the light color to pink for all lights for debugging:
//#define LIGHT_DEBUG_PINK
// At what point of light intensity we set the "darkness" point. This
// is to compensate for the fact that the engine "smoothes" the light
// and therefore will often never arrive at 0 light intensity.
const float lightDarknessLevel = 8.0 / 256.0;
slice(texture+5)
{
#ifdef HAVE_LIGHT
// Query light texture
vec2 lightDirCoord = lightCoord.st;
vec4 lightPx = texture2D(lightTex, lightDirCoord);
float lightBright = max(0.0, lightPx.a-lightDarknessLevel);
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
// Query light color texture (part of the light texture)
vec2 lightColorCoord = lightCoord.st - vec2(0.0, 0.5); // subtract offset for the color texture
vec4 lightColor = texture2D(lightTex, lightColorCoord.st);
#ifdef LIGHT_DEBUG_COLOR
lightBright = 0.5;
lightDir = vec3(0.0, 0.0, 1.0);
#endif
#else
// When lighting is disabled, put a light source coming from the camera.
// Note that in most cases this does not actually matter, since in the
// case with lighting disabled, ambient lighting takes fully over.
float lightBright = 0.5;
vec3 lightDir = vec3(0.0, 0.0, 1.0);
vec4 lightColor = vec4(1.0, 1.0, 1.0, 1.0);
#endif
}
slice(light)
{
float light = 2.0 * lightBright * max(max(dot(normal, lightDir), 0.0), cullMode * max(dot(-normal, lightDir), 0.0));
#ifdef HAVE_2PX
float light2 = 2.0 * lightBright * max(max(dot(normal2, lightDir), 0.0), cullMode * max(dot(-normal2, lightDir), 0.0));
#endif
}
slice(color+5)
{
// pink shade for debugging!
#ifdef LIGHT_DEBUG_PINK
lightColor = vec4(1.0, 0.0, 1.0, 1.0);
#endif
lightColor.rgb = sqrt(3.0) * normalize(lightColor.rgb);
// Add light
color.rgb = light * color.rgb * lightColor.rgb;
#ifdef HAVE_2PX
color2.rgb = light2 * color2.rgb * lightColor.rgb;
#endif
}
slice(finish+5)
{
#ifdef LIGHT_DEBUG
#ifdef HAVE_LIGHT
float lightYDir = lightPx.b - 1.0/3.0;
float lightXDir = lightPx.g - 1.0/3.0;
float lightStrength = lightPx.a;
color =
vec4(lightStrength * vec3(1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
1.0-1.5*max(0.0, -lightYDir)),
1.0);
#else
color = vec4(0.0, 0.0, 0.0, 0.0); // invisible
#endif
#endif
}

View File

@ -1,35 +0,0 @@
uniform vec4 clrMod;
slice(init)
{
#define color gl_FragColor
#ifdef MESH
// TODO: Add emission part of the material. Note we cannot just
// add this to the color, but it would need to be handled separately,
// such that it is independent from the incident light direction.
color = gl_FrontMaterial.diffuse;
#else
vec4 baseColor = gl_Color;
color = baseColor;
#endif
}
slice(color)
{
// TODO: Instead of a conditional, we could compute the color as
// color = A + B*color + C*clrMod + D*color*clrMod;
// Then, mod2 would be A=-0.5, B=1, C=1, D=0
// and default would be A=0,B=0,C=0,D=1
// Would allow to avoid conditionsals and #ifdefs, but need 4 uniforms...
// Could also try some sort of 3x3 matrix:
// out = (color, clrmod, 1) * (A,B,C,D,E,F,0,0,G) * (color, clrmod, 1)
#ifdef CLRMOD_MOD2
color = clamp(color + clrMod - 0.5, 0.0, 1.0);
#else
color = color * clrMod;
#endif
}

View File

@ -1,43 +0,0 @@
uniform mat3x2 lightTransform;
#ifdef HAVE_NORMALMAP
uniform sampler2D normalTex;
#endif
#ifdef MESH
varying vec3 normalDir;
#endif
slice(texture+4)
{
#ifdef HAVE_LIGHT
// prepare texture coordinate for light lookup in LightShader.c
// Extra .xy since some old intel drivers return a vec3
vec2 lightCoord = (lightTransform * vec3(gl_FragCoord.xy, 1.0)).xy;
#endif
}
slice(normal)
{
#ifdef HAVE_NORMALMAP
vec4 normalPx = texture2D(normalTex, texcoord.xy);
vec3 normalPxDir = 2.0 * (normalPx.xyz - vec3(0.5, 0.5, 0.5));
#ifdef MESH
// For meshes, the normal matrix is typically provided in Clonk
// coordinates, but the normal matrix incorporates a component that
// transforms from Ogre to Clonk coordinates. Therefore, we need to
// reverse that transformation for meshes.
// TODO: This could be optimized since the matrix is so simple that
// we don't need to do a full matrix multiplication.
mat3 c2o = mat3(0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0);
vec3 normal = normalize(c2o * gl_NormalMatrix * normalPxDir);
#else
vec3 normal = normalize(gl_NormalMatrix * normalPxDir);
#endif
#else
#ifdef MESH
vec3 normal = normalDir; // Normal matrix is already applied in vertex shader
#else
vec3 normal = vec3(0.0, 0.0, 1.0);
#endif
#endif
}

View File

@ -0,0 +1,109 @@
uniform mat3x2 lightTransform;
#ifdef HAVE_NORMALMAP
uniform sampler2D normalTex;
#endif
#ifdef MESH
varying vec3 normalDir;
#endif
uniform vec4 clrMod;
#ifdef HAVE_BASE
uniform sampler2D baseTex;
#endif
#ifdef HAVE_OVERLAY
uniform vec4 overlayClr;
uniform sampler2D overlayTex;
#endif
slice(material)
{
// Default material properties. TODO: Populate them?
vec3 matEmit = vec3(0.0,0.0,0.0);
vec3 matSpot = vec3(1.0,1.0,1.0);
float matAngle = 1.0;
}
slice(texture)
{
#define color gl_FragColor
#ifdef MESH
// TODO: Add emission part of the material. Note we cannot just
// add this to the color, but it would need to be handled separately,
// such that it is independent from the incident light direction.
color = gl_FrontMaterial.diffuse;
#else
vec4 baseColor = gl_Color;
color = baseColor;
#endif
#ifdef HAVE_BASE
color = baseColor * texture2D(baseTex, texcoord.xy);
#endif
#ifdef HAVE_OVERLAY
// Get overlay color from overlay texture
vec4 overlay = baseColor * overlayClr * texture2D(overlayTex, texcoord.xy);
// Mix overlay with texture
float alpha0 = 1.0 - (1.0 - color.a) * (1.0 - overlay.a);
color = vec4(mix(color.rgb, overlay.rgb, overlay.a / alpha0), alpha0);
#endif
}
slice(texture+4)
{
#ifdef HAVE_LIGHT
// prepare texture coordinate for light lookup in LightShader.c
// Extra .xy since some old intel drivers return a vec3
vec2 lightCoord = (lightTransform * vec3(gl_FragCoord.xy, 1.0)).xy;
#endif
}
slice(normal)
{
#ifdef HAVE_NORMALMAP
vec4 normalPx = texture2D(normalTex, texcoord.xy);
vec3 normalPxDir = 2.0 * (normalPx.xyz - vec3(0.5, 0.5, 0.5));
#ifdef MESH
// For meshes, the normal matrix is typically provided in Clonk
// coordinates, but the normal matrix incorporates a component that
// transforms from Ogre to Clonk coordinates. Therefore, we need to
// reverse that transformation for meshes.
// TODO: This could be optimized since the matrix is so simple that
// we don't need to do a full matrix multiplication.
mat3 c2o = mat3(0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0);
vec3 normal = normalize(c2o * gl_NormalMatrix * normalPxDir);
#else
vec3 normal = normalize(gl_NormalMatrix * normalPxDir);
#endif
#else
#ifdef MESH
vec3 normal = normalDir; // Normal matrix is already applied in vertex shader
#else
vec3 normal = vec3(0.0, 0.0, 1.0);
#endif
#endif
}
slice(color)
{
// TODO: Instead of a conditional, we could compute the color as
// color = A + B*color + C*clrMod + D*color*clrMod;
// Then, mod2 would be A=-0.5, B=1, C=1, D=0
// and default would be A=0,B=0,C=0,D=1
// Would allow to avoid conditionsals and #ifdefs, but need 4 uniforms...
// Could also try some sort of 3x3 matrix:
// out = (color, clrmod, 1) * (A,B,C,D,E,F,0,0,G) * (color, clrmod, 1)
#ifdef HAVE_MOD2
color = clamp(color + clrMod - 0.5, 0.0, 1.0);
#else
color = color * clrMod;
#endif
}

View File

@ -1,49 +0,0 @@
#define HAVE_2PX
slice(texture+5)
{
// find scaler coordinate
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
#ifdef SCALER_IN_GPU
if(texture2D(landscapeTex[0], centerCoo - fullStepX - fullStepY).r == landscapePx.r)
scalerCoo += scalerStepX;
if(texture2D(landscapeTex[0], centerCoo - fullStepY).r == landscapePx.r)
scalerCoo += 2.0 * scalerStepX;
if(texture2D(landscapeTex[0], centerCoo + fullStepX - fullStepY).r == landscapePx.r)
scalerCoo += 4.0 * scalerStepX;
if(texture2D(landscapeTex[0], centerCoo - fullStepX ).r == landscapePx.r)
scalerCoo += scalerStepY;
if(texture2D(landscapeTex[0], centerCoo + fullStepX ).r == landscapePx.r)
scalerCoo += 2.0 * scalerStepY;
if(texture2D(landscapeTex[0], centerCoo - fullStepX + fullStepY).r == landscapePx.r)
scalerCoo += 4.0 * scalerStepY;
if(texture2D(landscapeTex[0], centerCoo + fullStepY).r == landscapePx.r)
scalerCoo += 8.0 * scalerStepY;
if(texture2D(landscapeTex[0], centerCoo + fullStepX + fullStepY).r == landscapePx.r)
scalerCoo += 16.0 * scalerStepY;
#else
int iScaler = f2i(landscapePx.a), iRow = iScaler / 8;
scalerCoo.x += float(iScaler - iRow * 8) / 8.0;
scalerCoo.y += float(iScaler / 8) / 32.0;
#endif
// Note: scalerCoo will jump around a lot, causing some GPUs to
// apparantly get confused with the level-of-detail
// calculation. We therefore try to disable LOD.
vec4 scalerPx = texture2DLod(scalerTex, scalerCoo, 0.0);
// gen3 other coordinate calculation. Still struggles a bit with 3-ways
vec2 centerCoo2 = centerCoo + fullStep * floor(vec2(-0.5, -0.5) +
scalerPx.gb * 255.0 / 64.0);
vec4 landscapePx2 = texture2D(landscapeTex[0], centerCoo2);
}
slice(color+10) {
// Mix second color into main color according to scaler
color = mix(color2, color, scalerPx.r);
}

View File

@ -1,11 +0,0 @@
uniform vec4 overlayClr;
uniform sampler2D overlayTex;
slice(texture+1)
{
// Get overlay color from overlay texture
vec4 overlay = baseColor * overlayClr * texture2D(overlayTex, texcoord.xy);
// Mix overlay with texture
float alpha0 = 1.0 - (1.0 - color.a) * (1.0 - overlay.a);
color = vec4(mix(color.rgb, overlay.rgb, overlay.a / alpha0), alpha0);
}

View File

@ -1,6 +0,0 @@
uniform sampler2D baseTex;
slice(texture)
{
color = baseColor * texture2D(baseTex, texcoord.xy);
}

View File

@ -1,17 +0,0 @@
// #ifdef NO_TEXTURE_LOD_IN_FRAGMENT
#define texture1DLod(t,c,l) texture1D(t,c)
#define texture2DLod(t,c,l) texture2D(t,c)
// #endif
vec3 extend_normal(vec2 v)
{
// the higher the second value, the further away the light source from the landscape
return normalize(vec3(v, 0.45));
}
// Converts the pixel range 0.0..1.0 into the integer range 0..255
int f2i(float x) {
return int(x * 255.9);
}

View File

@ -9,4 +9,7 @@ Blast2ObjectRatio=100
MaxAirSpeed=100
MaxSlide=1
Placement=50
TextureOverlay=gold
TextureOverlay=gold
LightEmit=0,215,255
LightSpot=64,64,64
LightAngle=220

View File

@ -598,22 +598,15 @@ bool CStdGL::CreateSpriteShader(C4Shader& shader, const char* name, int ssc, C4G
shader.AddTexCoord("texcoord");
// Then load slices for fragment shader
shader.AddFragmentSlice(-1, "#define OPENCLONK");
if (ssc & C4SSC_MOD2) shader.AddFragmentSlice(-1, "#define CLRMOD_MOD2");
shader.AddFragmentSlice(-1, "#define OPENCLONK\n#define SPRITE");
if (ssc & C4SSC_MOD2) shader.AddFragmentSlice(-1, "#define HAVE_MOD2");
if (ssc & C4SSC_NORMAL) shader.AddFragmentSlice(-1, "#define HAVE_NORMALMAP");
if (ssc & C4SSC_LIGHT) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT");
shader.LoadSlices(pGroups, "UtilShader.glsl");
shader.LoadSlices(pGroups, "ObjectBaseShader.glsl");
if (ssc & C4SSC_BASE) shader.AddFragmentSlice(-1, "#define HAVE_BASE");
if (ssc & C4SSC_OVERLAY) shader.AddFragmentSlice(-1, "#define HAVE_OVERLAY");
if (ssc & C4SSC_BASE) shader.LoadSlices(pGroups, "SpriteTextureShader.glsl");
if (ssc & C4SSC_OVERLAY) shader.LoadSlices(pGroups, "SpriteOverlayShader.glsl");
// In case light is disabled, these shaders use a default light source
// (typically ambient light everywhere).
shader.LoadSlices(pGroups, "ObjectLightShader.glsl");
shader.LoadSlices(pGroups, "LightShader.glsl");
shader.LoadSlices(pGroups, "AmbientShader.glsl");
shader.LoadSlices(pGroups, "GammaShader.glsl");
shader.LoadSlices(pGroups, "CommonShader.glsl");
shader.LoadSlices(pGroups, "ObjectShader.glsl");
if (!shader.Init(name, uniformNames))
{

View File

@ -537,15 +537,11 @@ bool C4LandscapeRenderGL::LoadShader(C4GroupSet *pGroups, C4Shader& shader, cons
if(ssc & C4SSC_LIGHT) hLightTexCoord = shader.AddTexCoord("lightCoord");
// Then load slices for fragment shader
shader.AddFragmentSlice(-1, "#define LANDSCAPE");
shader.AddFragmentSlice(-1, "#define OPENCLONK\n#define LANDSCAPE");
if(ssc & C4SSC_LIGHT) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT"); // sample light from light texture
shader.LoadSlices(pGroups, "UtilShader.glsl");
shader.LoadSlices(pGroups, "CommonShader.glsl");
shader.LoadSlices(pGroups, "LandscapeShader.glsl");
shader.LoadSlices(pGroups, "LightShader.glsl");
shader.LoadSlices(pGroups, "AmbientShader.glsl");
shader.LoadSlices(pGroups, "ScalerShader.glsl");
shader.LoadSlices(pGroups, "GammaShader.glsl");
// Initialise!
if (!shader.Init(name, UniformNames)) {
@ -578,7 +574,6 @@ bool C4LandscapeRenderGL::LoadShaders(C4GroupSet *pGroups)
UniformNames[C4LRU_Gamma] = "gamma";
UniformNames[C4LRU_Resolution] = "resolution";
UniformNames[C4LRU_Center] = "center";
UniformNames[C4LRU_MatMap] = "matMap";
UniformNames[C4LRU_MatMapTex] = "matMapTex";
UniformNames[C4LRU_MaterialDepth] = "materialDepth";
UniformNames[C4LRU_MaterialSize] = "materialSize";
@ -800,7 +795,7 @@ void C4LandscapeRenderGL::AddTexturesFromMap(C4TextureMap *pMap)
}
void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
void C4LandscapeRenderGL::BuildMatMap(uint32_t *pTex)
{
// TODO: Still merely an inefficient placeholder for things to come...
@ -812,8 +807,8 @@ void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
if(!pEntry->GetTextureName())
{
// Undefined textures transparent
if(pFMap) pFMap[pix] = 0.5 / iMaterialTextureDepth;
if(pIMap) pIMap[pix] = 0;
pTex[2*pix] = 0;
pTex[2*pix+1] = RGBA(0,0,0,255);
continue;
}
@ -821,8 +816,13 @@ void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
int iPhases = 1; const char *p = pEntry->GetTextureName();
while((p = strchr(p, '-'))) { p++; iPhases++; }
// Hard-coded hack. Fix me!
const int iPhaseLength = 300;
float phase = (iPhases == 1 ? 0 : float(C4TimeMilliseconds::Now().AsInt() % (iPhases * iPhaseLength)) / iPhaseLength);
C4Material *pMaterial = pEntry->GetMaterial();
const int iPhaseLength = pMaterial->AnimationSpeed;
float phase = 0;
if (iPhases > 1) {
phase = C4TimeMilliseconds::Now().AsInt() % (iPhases * iPhaseLength);
phase /= iPhaseLength;
}
// Find our transition
const char *pFrom = pEntry->GetTextureName();
@ -851,8 +851,17 @@ void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
}
// Assign texture
if(pFMap) pFMap[pix] = (gTexCoo + 0.5) / iMaterialTextureDepth;
if(pIMap) pIMap[pix] = int((gTexCoo * 256.0 / iMaterialTextureDepth) + 0.5);
int iTexCoo = int((gTexCoo * 256.0 / iMaterialTextureDepth) + 0.5);
pTex[2*pix] = RGBA(
Clamp(pMaterial->LightEmit[0], 0, 255),
Clamp(pMaterial->LightEmit[1], 0, 255),
Clamp(pMaterial->LightEmit[2], 0, 255),
iTexCoo);
pTex[2*pix+1] = RGBA(
Clamp(pMaterial->LightSpot[0], 0, 255),
Clamp(pMaterial->LightSpot[1], 0, 255),
Clamp(pMaterial->LightSpot[2], 0, 255),
Clamp(pMaterial->LightAngle, 0, 255));
}
}
@ -889,12 +898,6 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
ShaderCall.SetUniform2f(C4LRU_Center,
centerX / float(Surfaces[0]->Wdt),
centerY / float(Surfaces[0]->Hgt));
if (shader->HaveUniform(C4LRU_MatMap))
{
GLfloat MatMap[256];
BuildMatMap(MatMap, NULL);
ShaderCall.SetUniform1fv(C4LRU_MatMap, 256, MatMap);
}
ShaderCall.SetUniform1i(C4LRU_MaterialDepth, iMaterialTextureDepth);
ShaderCall.SetUniform2f(C4LRU_MaterialSize,
float(iMaterialWidth) / ::Game.C4S.Landscape.MaterialZoom,
@ -960,9 +963,9 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
}
if(ShaderCall.AllocTexUnit(C4LRU_MatMapTex, GL_TEXTURE_1D))
{
GLubyte MatMap[256];
BuildMatMap(NULL, MatMap);
glTexImage1D(GL_TEXTURE_1D, 0, 1, 256, 0, GL_RED, GL_UNSIGNED_BYTE, MatMap);
uint32_t MatMap[2*256];
BuildMatMap(MatMap);
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, 2*256, 0, GL_RGBA, GL_UNSIGNED_BYTE, MatMap);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}

View File

@ -45,7 +45,6 @@ enum C4LR_Uniforms
C4LRU_Gamma,
C4LRU_Resolution,
C4LRU_Center,
C4LRU_MatMap,
C4LRU_MatMapTex,
C4LRU_MaterialDepth,
C4LRU_MaterialSize,
@ -150,7 +149,7 @@ private:
void AddTextureTransition(const char *szFrom, const char *szTo);
void AddTextureAnim(const char *szTextureAnim);
void AddTexturesFromMap(C4TextureMap *pMap);
void BuildMatMap(GLfloat *pFMap, GLubyte *pIMap);
void BuildMatMap(uint32_t *pTex);
};
#endif

View File

@ -267,6 +267,12 @@ void C4MaterialCore::Clear()
MinHeightCount = 0;
SplashRate=10;
KeepSinglePixels=false;
AnimationSpeed = 20;
LightAngle = 255;
for (int i = 0; i < 3; i++) {
LightEmit[i] = 0;
LightSpot[i] = 16;
}
}
void C4MaterialCore::Default()
@ -304,7 +310,6 @@ void C4MaterialCore::CompileFunc(StdCompiler *pComp)
if (pComp->isCompiler()) Clear();
pComp->Name("Material");
pComp->Value(mkNamingAdapt(toC4CStr(Name), "Name", ""));
pComp->Value(mkNamingAdapt(ColorAnimation, "ColorAnimation", 0));
const StdEnumEntry<C4MaterialCoreShape> Shapes[] =
{
@ -368,6 +373,10 @@ void C4MaterialCore::CompileFunc(StdCompiler *pComp)
pComp->Value(mkNamingAdapt(MinHeightCount, "MinHeightCount", 0));
pComp->Value(mkNamingAdapt(SplashRate, "SplashRate", 10));
pComp->Value(mkNamingAdapt(KeepSinglePixels, "KeepSinglePixels", false));
pComp->Value(mkNamingAdapt(AnimationSpeed, "AnimationSpeed", 100));
pComp->Value(mkNamingAdapt(LightAngle, "LightAngle", 255));
pComp->Value(mkNamingAdapt(mkArrayAdaptDM(LightEmit, 0), "LightEmit"));
pComp->Value(mkNamingAdapt(mkArrayAdaptDM(LightSpot, 16),"LightSpot"));
pComp->NameEnd();
// material reactions
pComp->Value(mkNamingAdapt(mkSTLContainerAdapt(CustomReactionList),

View File

@ -180,6 +180,10 @@ public:
int32_t MinHeightCount; // minimum material thickness in order for it to be counted
int32_t SplashRate;
bool KeepSinglePixels; // if true, single pixels are not destroyed (for vehicle)
int32_t AnimationSpeed; // frames per animation phase
int32_t LightAngle; // light angle at which we have maximum reflection
int32_t LightEmit[3]; // amount the material lights up itself
int32_t LightSpot[3]; // spot strength
void Clear();
void Default();

View File

@ -854,7 +854,6 @@ bool StdMeshMaterialProgram::AddParameterNames(const StdMeshMaterialShaderParame
bool StdMeshMaterialProgram::CompileShader(StdMeshMaterialLoader& loader, C4Shader& shader, int ssc)
{
// Add standard slices
shader.AddFragmentSlice(-1, "#define MESH");
loader.AddShaderSlices(shader, ssc);
// Add our slices
shader.AddVertexSlice(-1, "varying vec2 texcoord;");

View File

@ -61,27 +61,15 @@ public:
{
#ifndef USE_CONSOLE
// Add mesh-independent slices
shader.AddFragmentSlice(-1, "#define OPENCLONK");
shader.AddVertexSlice(-1, "#define OPENCLONK");
if (ssc & C4SSC_MOD2) shader.AddFragmentSlice(-1, "#define CLRMOD_MOD2");
shader.AddFragmentSlice(-1, "#define OPENCLONK\n#define MESH");
shader.AddVertexSlice(-1, "#define OPENCLONK\n#define MESH");
if (ssc & C4SSC_MOD2) shader.AddFragmentSlice(-1, "#define HAVE_MOD2");
if (ssc & C4SSC_LIGHT) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT");
if (ssc & C4SSC_BASE) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT");
if (ssc & C4SSC_OVERLAY) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT");
shader.LoadSlices(&::GraphicsResource.Files, "UtilShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "ObjectBaseShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "MeshShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "GammaShader.glsl");
// Note that these shader slices are always loaded, even if lighting
// is disabled. The shaders then assume a default light if HAVE_LIGHT
// is not defined. This avoids completely flat shading for meshes
// that are shown as picture graphics for example.
shader.LoadSlices(&::GraphicsResource.Files, "ObjectLightShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "LightShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "AmbientShader.glsl");
if (ssc & C4SSC_BASE) shader.LoadSlices(&::GraphicsResource.Files, "SpriteTextureShader.glsl");
if (ssc & C4SSC_OVERLAY) shader.LoadSlices(&::GraphicsResource.Files, "SpriteOverlayShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "CommonShader.glsl");
shader.LoadSlices(&::GraphicsResource.Files, "ObjectShader.glsl");
#endif
}