Add texture bumpmapping feature.

This commit is contained in:
RealBadAngel 2013-07-04 02:36:32 +02:00
parent b850f0f038
commit 3f6f327cb9
11 changed files with 602 additions and 2 deletions

@ -0,0 +1 @@
trans_alphach

@ -0,0 +1,47 @@
uniform sampler2D myTexture;
uniform sampler2D normalTexture;
uniform vec4 skyBgColor;
uniform float fogDistance;
varying vec3 vPosition;
varying vec3 viewVec;
void main (void)
{
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
float alpha = col.a;
vec2 uv = gl_TexCoord[0].st;
vec4 base = texture2D(myTexture, uv);
vec4 final_color = vec4(0.2, 0.2, 0.2, 1.0) * base;
vec3 vVec = normalize(viewVec);
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
vec3 R = reflect(-vVec, bump);
vec3 lVec = normalize(vec3(0.0, -0.4, 0.5));
float diffuse = max(dot(lVec, bump), 0.0);
vec3 color = diffuse * texture2D(myTexture, gl_TexCoord[0].st).rgb;
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
vec4 vSpecular = 0.2*specular * diffuse;
color += vSpecular;
col = vec4(color.r, color.g, color.b, alpha);
col *= gl_Color;
col = col * col; // SRGB -> Linear
col *= 1.8;
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
col = sqrt(col); // Linear -> SRGB
if(fogDistance != 0.0){
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
alpha = mix(alpha, 0.0, d);
}
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
}

@ -0,0 +1,98 @@
uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform float dayNightRatio;
varying vec3 vPosition;
varying vec3 viewVec;
void main(void)
{
gl_Position = mWorldViewProj * gl_Vertex;
vPosition = (mWorldViewProj * gl_Vertex).xyz;
vec3 tangent;
vec3 binormal;
vec3 c1 = cross( gl_Normal, vec3(0.0, 0.0, 1.0) );
vec3 c2 = cross( gl_Normal, vec3(0.0, 1.0, 0.0) );
if( length(c1)>length(c2) )
{
tangent = c1;
}
else
{
tangent = c2;
}
tangent = normalize(tangent);
//binormal = cross(gl_Normal, tangent);
//binormal = normalize(binormal);
vec4 color;
//color = vec4(1.0, 1.0, 1.0, 1.0);
float day = gl_Color.r;
float night = gl_Color.g;
float light_source = gl_Color.b;
/*color.r = mix(night, day, dayNightRatio);
color.g = color.r;
color.b = color.r;*/
float rg = mix(night, day, dayNightRatio);
rg += light_source * 1.5; // Make light sources brighter
float b = rg;
// Moonlight is blue
b += (day - night) / 13.0;
rg -= (day - night) / 13.0;
// Emphase blue a bit in darker places
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
// Artificial light is yellow-ish
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
color.r = rg;
color.g = rg;
color.b = b;
// Make sides and bottom darker than the top
color = color * color; // SRGB -> Linear
if(gl_Normal.y <= 0.5)
color *= 0.6;
//color *= 0.7;
color = sqrt(color); // Linear -> SRGB
color.a = gl_Color.a;
gl_FrontColor = gl_BackColor = color;
gl_TexCoord[0] = gl_MultiTexCoord0;
vec3 n1 = normalize(gl_NormalMatrix * gl_Normal);
vec4 tangent1 = vec4(tangent.x, tangent.y, tangent.z, 0);
//vec3 t1 = normalize(gl_NormalMatrix * tangent1);
//vec3 b1 = cross(n1, t1);
vec3 v;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 vVec = -vVertex;
//v.x = dot(vVec, t1);
//v.y = dot(vVec, b1);
//v.z = dot(vVec, n1);
//viewVec = vVec;
viewVec = normalize(vec3(0.0, -0.4, 0.5));
//Vector representing the 0th texture coordinate passed to fragment shader
//gl_TexCoord[0] = vec2(gl_MultiTexCoord0);
// Transform the current vertex
//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

@ -0,0 +1 @@
trans_alphach_ref

@ -0,0 +1,46 @@
uniform sampler2D myTexture;
uniform sampler2D normalTexture;
uniform vec4 skyBgColor;
uniform float fogDistance;
varying vec3 vPosition;
varying vec3 viewVec;
void main (void)
{
vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
float alpha = col.a;
vec2 uv = gl_TexCoord[0].st;
vec4 base = texture2D(myTexture, uv);
vec4 final_color = vec4(0.2, 0.2, 0.2, 1.0) * base;
vec3 vVec = normalize(viewVec);
vec3 bump = normalize(texture2D(normalTexture, uv).xyz * 2.0 - 1.0);
vec3 R = reflect(-vVec, bump);
vec3 lVec = normalize(vec3(0.0, -0.4, 0.5));
float diffuse = max(dot(lVec, bump), 0.0);
vec3 color = diffuse * texture2D(myTexture, gl_TexCoord[0].st).rgb;
float specular = pow(clamp(dot(R, lVec), 0.0, 1.0),1.0);
vec4 vSpecular = 0.2*specular * diffuse;
color += vSpecular;
col = vec4(color.r, color.g, color.b, alpha);
col *= gl_Color;
col = col * col; // SRGB -> Linear
col *= 1.8;
col.r = 1.0 - exp(1.0 - col.r) / exp(1.0);
col.g = 1.0 - exp(1.0 - col.g) / exp(1.0);
col.b = 1.0 - exp(1.0 - col.b) / exp(1.0);
col = sqrt(col); // Linear -> SRGB
if(fogDistance != 0.0){
float d = max(0.0, min(vPosition.z / fogDistance * 1.5 - 0.6, 1.0));
col = mix(col, skyBgColor, d);
}
gl_FragColor = vec4(col.r, col.g, col.b, alpha);
}

@ -0,0 +1,98 @@
uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform float dayNightRatio;
varying vec3 vPosition;
varying vec3 viewVec;
void main(void)
{
gl_Position = mWorldViewProj * gl_Vertex;
vPosition = (mWorldViewProj * gl_Vertex).xyz;
vec3 tangent;
vec3 binormal;
vec3 c1 = cross( gl_Normal, vec3(0.0, 0.0, 1.0) );
vec3 c2 = cross( gl_Normal, vec3(0.0, 1.0, 0.0) );
if( length(c1)>length(c2) )
{
tangent = c1;
}
else
{
tangent = c2;
}
tangent = normalize(tangent);
//binormal = cross(gl_Normal, tangent);
//binormal = normalize(binormal);
vec4 color;
//color = vec4(1.0, 1.0, 1.0, 1.0);
float day = gl_Color.r;
float night = gl_Color.g;
float light_source = gl_Color.b;
/*color.r = mix(night, day, dayNightRatio);
color.g = color.r;
color.b = color.r;*/
float rg = mix(night, day, dayNightRatio);
rg += light_source * 1.5; // Make light sources brighter
float b = rg;
// Moonlight is blue
b += (day - night) / 13.0;
rg -= (day - night) / 13.0;
// Emphase blue a bit in darker places
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
// Artificial light is yellow-ish
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
color.r = rg;
color.g = rg;
color.b = b;
// Make sides and bottom darker than the top
color = color * color; // SRGB -> Linear
if(gl_Normal.y <= 0.5)
color *= 0.6;
//color *= 0.7;
color = sqrt(color); // Linear -> SRGB
color.a = gl_Color.a;
gl_FrontColor = gl_BackColor = color;
gl_TexCoord[0] = gl_MultiTexCoord0;
vec3 n1 = normalize(gl_NormalMatrix * gl_Normal);
vec4 tangent1 = vec4(tangent.x, tangent.y, tangent.z, 0);
//vec3 t1 = normalize(gl_NormalMatrix * tangent1);
//vec3 b1 = cross(n1, t1);
vec3 v;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
vec3 vVec = -vVertex;
//v.x = dot(vVec, t1);
//v.y = dot(vVec, b1);
//v.z = dot(vVec, n1);
//viewVec = vVec;
viewVec = normalize(vec3(0.0, -0.4, 0.5));
//Vector representing the 0th texture coordinate passed to fragment shader
//gl_TexCoord[0] = vec2(gl_MultiTexCoord0);
// Transform the current vertex
//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

@ -172,6 +172,8 @@
# (1: low level shaders; not implemented) # (1: low level shaders; not implemented)
# 2: enable high level shaders # 2: enable high level shaders
#enable_shaders = 2 #enable_shaders = 2
# Set to true to enable textures bumpmapping. Requires shaders enabled.
#enable_bumpmapping = false
# The time in seconds it takes between repeated # The time in seconds it takes between repeated
# right clicks when holding the right mouse button # right clicks when holding the right mouse button
#repeat_rightclick_time = 0.25 #repeat_rightclick_time = 0.25

@ -127,6 +127,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("trilinear_filter", "false"); settings->setDefault("trilinear_filter", "false");
settings->setDefault("preload_item_visuals", "true"); settings->setDefault("preload_item_visuals", "true");
settings->setDefault("enable_shaders", "2"); settings->setDefault("enable_shaders", "2");
settings->setDefault("enable_bumpmapping", "false");
settings->setDefault("repeat_rightclick_time", "0.25"); settings->setDefault("repeat_rightclick_time", "0.25");
settings->setDefault("enable_particles", "true"); settings->setDefault("enable_particles", "true");

@ -804,6 +804,10 @@ public:
u32 daynight_ratio = m_client->getEnv().getDayNightRatio(); u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
float daynight_ratio_f = (float)daynight_ratio / 1000.0; float daynight_ratio_f = (float)daynight_ratio / 1000.0;
services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1); services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
// Normal map texture layer
int layer = 1;
services->setPixelShaderConstant("normalTexture" , (irr::f32*)&layer, 1);
} }
}; };

@ -1072,12 +1072,18 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
Also store animation info Also store animation info
*/ */
bool enable_shaders = (g_settings->getS32("enable_shaders") > 0); bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()-> video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()->
getShader("test_shader_1").material; getShader("test_shader_1").material;
video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()-> video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()->
getShader("test_shader_2").material; getShader("test_shader_2").material;
video::E_MATERIAL_TYPE shadermat3 = m_gamedef->getShaderSource()-> video::E_MATERIAL_TYPE shadermat3 = m_gamedef->getShaderSource()->
getShader("test_shader_3").material; getShader("test_shader_3").material;
video::E_MATERIAL_TYPE bumpmaps1 = m_gamedef->getShaderSource()->
getShader("bumpmaps_solids").material;
video::E_MATERIAL_TYPE bumpmaps2 = m_gamedef->getShaderSource()->
getShader("bumpmaps_liquids").material;
for(u32 i = 0; i < collector.prebuffers.size(); i++) for(u32 i = 0; i < collector.prebuffers.size(); i++)
{ {
PreMeshBuffer &p = collector.prebuffers[i]; PreMeshBuffer &p = collector.prebuffers[i];
@ -1154,8 +1160,33 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
material.MaterialType material.MaterialType
= video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.setTexture(0, p.tile.texture); material.setTexture(0, p.tile.texture);
if(enable_shaders) if (enable_shaders)
p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3); {
if (enable_bumpmapping)
{
ITextureSource *tsrc = data->m_gamedef->tsrc();
std::string basename,normal,replace;
replace = "_normal.png";
basename = tsrc->getTextureName(p.tile.texture_id);
unsigned pos = basename.find(".");
normal = basename.substr (0, pos) + replace;
if (tsrc->isKnownSourceImage(normal))
{
// look for image extension and replace it
for(std::string::size_type i = 0; (i = basename.find(".", i)) != std::string::npos;)
{
basename.replace(i, 4, replace);
i += replace.length();
}
material.setTexture(1, tsrc->getTexture(basename));
p.tile.applyMaterialOptionsWithShaders(material, bumpmaps1,bumpmaps2, shadermat3);
}
else
p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3);
}
else
p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3);
}
else else
p.tile.applyMaterialOptions(material); p.tile.applyMaterialOptions(material);
@ -1217,6 +1248,9 @@ MapBlockMesh::~MapBlockMesh()
bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio) bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
{ {
bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
if(!m_has_animation) if(!m_has_animation)
{ {
m_animation_force_timer = 100000; m_animation_force_timer = 100000;
@ -1271,6 +1305,19 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame; os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
// Set the texture // Set the texture
buf->getMaterial().setTexture(0, tsrc->getTexture(os.str())); buf->getMaterial().setTexture(0, tsrc->getTexture(os.str()));
if (enable_shaders && enable_bumpmapping)
{
std::string basename,normal;
basename = tsrc->getTextureName(tile.texture_id);
unsigned pos;
pos = basename.find(".");
normal = basename.substr (0, pos);
normal += "_normal.png";
os.str("");
os<<normal<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
if (tsrc->isKnownSourceImage(normal))
buf->getMaterial().setTexture(1, tsrc->getTexture(os.str()));
}
} }
// Day-night transition // Day-night transition

255
util/generate-texture-normals.sh Executable file

@ -0,0 +1,255 @@
#!/bin/bash
# This script generates normalmaps using The GIMP to do the heavy lifting.
# give any unrecognized switch (say, -h) for usage info.
rm /tmp/normals_filelist.txt
numprocs=6
skiptools=false
skipinventory=false
invresolution=64
dryrun=false
pattern="*.png *.jpg"
filter=0
scale=8
wrap=0
heightsource=0
conversion=0
invertx=0
inverty=0
while test -n "$1"; do
case "$1" in
--scale|-s)
if [ -z "$2" ] ; then echo "Missing scale parameter"; exit 1; fi
scale=$2
shift
shift
;;
--pattern|-p)
if [ -z "$2" ] ; then echo "Missing pattern parameter"; exit 1; fi
pattern=$2
shift
shift
;;
--skiptools|-t)
skiptools=true
shift
;;
--skipinventory|-i)
if [[ $2 =~ ^[0-9]+$ ]]; then
invresolution=$2
shift
fi
skipinventory=true
shift
;;
--filter|-f)
if [ -z "$2" ] ; then echo "Missing filter parameter"; exit 1; fi
case "$2" in
sobel3|1)
filter=1
;;
sobel5|2)
filter=2
;;
prewitt3|3)
filter=3
;;
prewitt5|4)
filter=4
;;
3x3|5)
filter=5
;;
5x5|6)
filter=6
;;
7x7|7)
filter=7
;;
9x9|8)
filter=8
;;
*)
filter=0
;;
esac
shift
shift
;;
--heightalpha|-a)
heightsource=1
shift
;;
--conversion|-c)
if [ -z "$2" ] ; then echo "Missing conversion parameter"; exit 1; fi
case "$2" in
biased|1)
conversion=1
;;
red|2)
conversion=2
;;
green|3)
conversion=3
;;
blue|4)
conversion=4
;;
maxrgb|5)
conversion=5
;;
minrgb|6)
conversion=6
;;
colorspace|7)
conversion=7
;;
normalize-only|8)
conversion=8
;;
heightmap|9)
conversion=9
;;
*)
conversion=0
;;
esac
shift
shift
;;
--wrap|-w)
wrap=1
shift
;;
--invertx|-x)
invertx=1
shift
;;
--inverty|-y)
inverty=1
shift
;;
--dryrun|-d)
dryrun=true
shift
;;
*)
echo -e "\nUsage:\n"
echo "`basename $0` [--scale|-s <value>] [--filter|-f <string>]"
echo " [--wrap|-w] [--heightalpha|-a] [--invertx|-x] [--inverty|-y]"
echo " [--conversion|-c <string>] [--skiptools|-t] [--skipinventory|-i [<value>]]"
echo " [--dryrun|-d] [--pattern|-p <pattern>]"
echo -e "\nDefaults to a scale of 8, checking all files in the current directory, and not"
echo "skipping apparent tools or inventory images. Filter, if specified, may be one"
echo "of: sobel3, sobel5, prewitt3, prewitt5, 3x3, 5x5, 7x7, or 9x9, or a value 1"
echo "through 8 (1=sobel3, 2=sobel5, etc.). Defaults to 0 (four-sample). The height"
echo "source is taken from the image's alpha channel if heightalpha is specified.\n"
echo ""
echo "If inventory skip is specified, an optional resolution may also be included"
echo "(default is 64). Conversion can be one of: biased, red, green, blue, maxrgb,"
echo "minrgb, colorspace, normalize-only, heightmap or a value from 1 to 9"
echo "corresponding respectively to those keywords. Defaults to 0 (simple"
echo "normalize) if not specified. Wrap, if specified, enables wrapping of the"
echo "normalmap around the edges of the texture (defaults to no). Invert X/Y"
echo "reverses the calculated gradients for the X and/or Y dimensions represented"
echo "by the normalmap (both default to non-inverted)."
echo ""
echo "The pattern, can be an escaped pattern string such as \*apple\* or"
echo "default_\*.png or similar (defaults to all PNG and JPG images in the current"
echo "directory that do not contain \"_normal\" or \"_specular\" in their filenames)."
echo ""
echo "If set for dry-run, the actions this script will take will be printed, but no"
echo "images will be generated. Passing an invalid value to a switch will generally"
echo "cause that switch to revert to its default value."
echo ""
exit 1
;;
esac
done
echo -e "\nProcessing files based on pattern \"$pattern\" ..."
normalMap()
{
out=`echo "$1" | sed 's/.png/_normal.png/' | sed 's/.jpg/_normal.png/'`
echo "Launched process to generate normalmap: \"$1\" --> \"$out\"" >&2
gimp -i -b "
(define
(normalMap-fbx-conversion fileName newFileName filter nscale wrap heightsource conversion invertx inverty)
(let*
(
(image (car (gimp-file-load RUN-NONINTERACTIVE fileName fileName)))
(drawable (car (gimp-image-get-active-layer image)))
(drawable (car (gimp-image-flatten image)))
)
(if (> (car (gimp-drawable-type drawable)) 1)
(gimp-convert-rgb image) ()
)
(plug-in-normalmap
RUN-NONINTERACTIVE
image
drawable
filter
0.0
nscale
wrap
heightsource
0
conversion
0
invertx
inverty
0
0.0
drawable)
(gimp-file-save RUN-NONINTERACTIVE image drawable newFileName newFileName)
(gimp-image-delete image)
)
)
(normalMap-fbx-conversion \"$1\" \"$out\" $2 $3 $4 $5 $6 $7 $8)" -b '(gimp-quit 0)'
}
export -f normalMap
for file in `ls $pattern |grep -v "_normal.png"|grep -v "_specular"` ; do
invtest=`file "$file" |grep "$invresolution x $invresolution"`
if $skipinventory && [ -n "$invtest" ] ; then
echo "Skipped presumed "$invresolution"px inventory image: $file" >&2
continue
fi
tooltest=`echo "$file" \
| grep -v "_tool" \
| grep -v "_shovel" \
| grep -v "_pick" \
| grep -v "_axe" \
| grep -v "_sword" \
| grep -v "_hoe" \
| grep -v "bucket_"`
if $skiptools && [ -z "$tooltest" ] ; then
echo "Skipped presumed tool image: $file" >&2
continue
fi
if $dryrun ; then
echo "Would have generated a normalmap for $file" >&2
continue
else
echo \"$file\" $filter $scale $wrap $heightsource $conversion $invertx $inverty
fi
done | xargs -P $numprocs -n 8 -I{} bash -c normalMap\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}\ \{\}