From cd1f604ffe6130fd7d3a8358a8cebd7f821f9a11 Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sun, 2 Dec 2012 14:24:58 +0200 Subject: [PATCH] Handle day-night transition in shader and make light sources brighter when shaders are used --- .../shaders/test_shader_1/opengl_vertex.glsl | 45 ++++++++++++++--- .../shaders/test_shader_2/opengl_vertex.glsl | 37 +++++++++++++- src/content_mapblock.cpp | 21 ++++---- src/game.cpp | 18 ++++--- src/itemdef.cpp | 7 ++- src/mapblock_mesh.cpp | 49 +++++++++++-------- src/mapblock_mesh.h | 5 +- 7 files changed, 132 insertions(+), 50 deletions(-) diff --git a/client/shaders/test_shader_1/opengl_vertex.glsl b/client/shaders/test_shader_1/opengl_vertex.glsl index 498085053..e24f58c09 100644 --- a/client/shaders/test_shader_1/opengl_vertex.glsl +++ b/client/shaders/test_shader_1/opengl_vertex.glsl @@ -2,6 +2,7 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform float dayNightRatio; varying vec3 vPosition; @@ -11,15 +12,43 @@ void main(void) vPosition = (mWorldViewProj * gl_Vertex).xyz; - if(gl_Normal.y > 0.5) - gl_FrontColor = gl_BackColor = gl_Color; - else - gl_FrontColor = gl_BackColor = gl_Color * 0.7; + vec4 color; + //color = vec4(1.0, 1.0, 1.0, 1.0); - /*if(gl_Normal.y > 0.5) - gl_FrontColor = gl_BackColor = vec4(1.0, 1.0, 1.0, 1.0); - else - gl_FrontColor = gl_BackColor = vec4(1.0, 1.0, 1.0, 1.0) * 0.7;*/ + 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.0; // 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; + + if(gl_Normal.y <= 0.5) + color *= 0.7; + + color.a = gl_Color.a; + + gl_FrontColor = gl_BackColor = color; gl_TexCoord[0] = gl_MultiTexCoord0; } diff --git a/client/shaders/test_shader_2/opengl_vertex.glsl b/client/shaders/test_shader_2/opengl_vertex.glsl index 6286fc0d7..80fd6d427 100644 --- a/client/shaders/test_shader_2/opengl_vertex.glsl +++ b/client/shaders/test_shader_2/opengl_vertex.glsl @@ -2,6 +2,7 @@ uniform mat4 mWorldViewProj; uniform mat4 mInvWorld; uniform mat4 mTransWorld; +uniform float dayNightRatio; varying vec3 vPosition; @@ -13,8 +14,40 @@ void main(void) vPosition = (mWorldViewProj * gl_Vertex).xyz; - gl_FrontColor = gl_BackColor = gl_Color; - //gl_FrontColor = gl_BackColor = vec4(1.0, 1.0, 1.0, 1.0); + 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.0; // 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; + + color.a = gl_Color.a; + + gl_FrontColor = gl_BackColor = color; gl_TexCoord[0] = gl_MultiTexCoord0; } diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 68895c396..aa3c061d6 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -171,7 +171,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, continue; u16 l = getInteriorLight(n, 0, data); - video::SColor c = MapBlock_LightColor(f.alpha, l); + video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source)); video::S3DVertex vertices[4] = { @@ -226,7 +226,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, // Otherwise use the light of this node (the liquid) else l = getInteriorLight(n, 0, data); - video::SColor c = MapBlock_LightColor(f.alpha, l); + video::SColor c = MapBlock_LightColor(f.alpha, l, decode_light(f.light_source)); // Neighbor liquid levels (key = relative position) // Includes current node @@ -544,7 +544,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 1, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); for(u32 j=0; j<6; j++) { @@ -604,7 +604,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, AtlasPointer pa_leaves = tile_leaves.texture; u16 l = getInteriorLight(n, 1, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); v3f pos = intToFloat(p, BS); aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2); @@ -638,7 +638,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data, AtlasPointer ap = tile.texture; - video::SColor c(255,255,255,255); + u16 l = getInteriorLight(n, 1, data); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); // Wall at X+ of node video::S3DVertex vertices[4] = @@ -683,7 +684,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 0, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); float d = (float)BS/16; // Wall at X+ of node @@ -730,7 +731,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 1, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); for(u32 j=0; j<4; j++) { @@ -793,7 +794,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, tile.texture.id) + "^[transformR90"); u16 l = getInteriorLight(n, 1, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); const f32 post_rad=(f32)BS/8; const f32 bar_rad=(f32)BS/16; @@ -996,7 +997,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, AtlasPointer ap = tile.texture; u16 l = getInteriorLight(n, 0, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); float d = (float)BS/64; @@ -1045,7 +1046,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, } u16 l = getInteriorLight(n, 0, data); - video::SColor c = MapBlock_LightColor(255, l); + video::SColor c = MapBlock_LightColor(255, l, decode_light(f.light_source)); v3f pos = intToFloat(p, BS); diff --git a/src/game.cpp b/src/game.cpp index 0c1a21370..fc780a808 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -841,13 +841,15 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter Sky *m_sky; bool *m_force_fog_off; f32 *m_fog_range; + Client *m_client; public: GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off, - f32 *fog_range): + f32 *fog_range, Client *client): m_sky(sky), m_force_fog_off(force_fog_off), - m_fog_range(fog_range) + m_fog_range(fog_range), + m_client(client) {} ~GameGlobalShaderConstantSetter() {} @@ -873,10 +875,12 @@ public: if(*m_force_fog_off) fog_distance = 10000*BS; services->setPixelShaderConstant("fogDistance", &fog_distance, 1); - } -private: - IrrlichtDevice *m_device; + // Day-night ratio + u32 daynight_ratio = m_client->getEnv().getDayNightRatio(); + float daynight_ratio_f = (float)daynight_ratio / 1000.0; + services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1); + } }; void the_game( @@ -1307,8 +1311,8 @@ void the_game( /* Shader constants */ - shsrc->addGlobalConstantSetter( - new GameGlobalShaderConstantSetter(sky, &force_fog_off, &fog_range)); + shsrc->addGlobalConstantSetter(new GameGlobalShaderConstantSetter( + sky, &force_fog_off, &fog_range, &client)); /* Main loop diff --git a/src/itemdef.cpp b/src/itemdef.cpp index 9ce064ea4..260baadc0 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -30,6 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "tile.h" #endif #include "log.h" +#include "main.h" // g_settings +#include "settings.h" #include "util/serialize.h" #include "util/container.h" #include "util/thread.h" @@ -356,7 +358,10 @@ public: scene::IMesh *node_mesh = mapblock_mesh.getMesh(); assert(node_mesh); - setMeshColor(node_mesh, video::SColor(255, 255, 255, 255)); + video::SColor c(255, 255, 255, 255); + if(g_settings->getS32("enable_shaders") != 0) + c = MapBlock_LightColor(255, 0xffff, decode_light(f.light_source)); + setMeshColor(node_mesh, c); /* Scale and translate the mesh so it's a unit cube diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index a9f14f8f0..b2870509b 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -435,7 +435,7 @@ struct FastFace }; static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3, - v3f p, v3s16 dir, v3f scale, core::array &dest) + v3f p, v3s16 dir, v3f scale, u8 light_source, core::array &dest) { FastFace face; @@ -477,16 +477,16 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3, float h = tile.texture.size.Y; face.vertices[0] = video::S3DVertex(vertex_pos[0], normal, - MapBlock_LightColor(alpha, li0), + MapBlock_LightColor(alpha, li0, light_source), core::vector2d(x0+w*abs_scale, y0+h)); face.vertices[1] = video::S3DVertex(vertex_pos[1], normal, - MapBlock_LightColor(alpha, li1), + MapBlock_LightColor(alpha, li1, light_source), core::vector2d(x0, y0+h)); face.vertices[2] = video::S3DVertex(vertex_pos[2], normal, - MapBlock_LightColor(alpha, li2), + MapBlock_LightColor(alpha, li2, light_source), core::vector2d(x0, y0)); face.vertices[3] = video::S3DVertex(vertex_pos[3], normal, - MapBlock_LightColor(alpha, li3), + MapBlock_LightColor(alpha, li3, light_source), core::vector2d(x0+w*abs_scale, y0)); face.tile = tile; @@ -658,7 +658,8 @@ static void getTileInfo( v3s16 &p_corrected, v3s16 &face_dir_corrected, u16 *lights, - TileSpec &tile + TileSpec &tile, + u8 &light_source ) { VoxelManipulator &vmanip = data->m_vmanip; @@ -688,18 +689,20 @@ static void getTileInfo( tile = tile0; p_corrected = p; face_dir_corrected = face_dir; + light_source = ndef->get(n0).light_source; } else { tile = tile1; p_corrected = p + face_dir; face_dir_corrected = -face_dir; + light_source = ndef->get(n1).light_source; } // eg. water and glass if(equivalent) tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; - + if(data->m_smooth_lighting == false) { lights[0] = lights[1] = lights[2] = lights[3] = @@ -743,9 +746,10 @@ static void updateFastFaceRow( v3s16 face_dir_corrected; u16 lights[4] = {0,0,0,0}; TileSpec tile; + u8 light_source = 0; getTileInfo(data, p, face_dir, makes_face, p_corrected, face_dir_corrected, - lights, tile); + lights, tile, light_source); for(u16 j=0; javg("Meshgen: faces drawn by tiling", 0); @@ -873,6 +879,7 @@ static void updateFastFaceRow( lights[2] = next_lights[2]; lights[3] = next_lights[3]; tile = next_tile; + light_source = next_light_source; } p = p_next; @@ -1058,18 +1065,20 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data): os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0"; p.tile.texture = tsrc->getTexture(os.str()); } - // - Lighting - for(u32 j = 0; j < p.vertices.size(); j++) + // - Classic lighting (shaders handle this by themselves) + if(!enable_shaders) { - video::SColor &vc = p.vertices[j].Color; - u8 day = vc.getRed(); - u8 night = vc.getGreen(); - finalColorBlend(vc, day, night, 1000); - if(day != night) - m_daynight_diffs[i][j] = std::make_pair(day, night); + for(u32 j = 0; j < p.vertices.size(); j++) + { + video::SColor &vc = p.vertices[j].Color; + u8 day = vc.getRed(); + u8 night = vc.getGreen(); + finalColorBlend(vc, day, night, 1000); + if(day != night) + m_daynight_diffs[i][j] = std::make_pair(day, night); + } } - // Create material video::SMaterial material; material.setFlag(video::EMF_LIGHTING, false); diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index 82268efd2..c23b6cc5a 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -160,9 +160,10 @@ struct MeshCollector // alpha in the A channel of the returned SColor // day light (0-255) in the R channel of the returned SColor // night light (0-255) in the G channel of the returned SColor -inline video::SColor MapBlock_LightColor(u8 alpha, u16 light) +// light source (0-255) in the B channel of the returned SColor +inline video::SColor MapBlock_LightColor(u8 alpha, u16 light, u8 light_source=0) { - return video::SColor(alpha, (light & 0xff), (light >> 8), 0); + return video::SColor(alpha, (light & 0xff), (light >> 8), light_source); } // Compute light at node