From 062de11b4cff30861dd4e9eb56f131d821f34b51 Mon Sep 17 00:00:00 2001 From: Novatux Date: Sun, 26 Jan 2014 11:40:21 +0100 Subject: [PATCH] Fix rendering glitches when far from the center of the map --- src/camera.cpp | 16 ++++++++++++++-- src/camera.h | 8 ++++++++ src/client.cpp | 2 +- src/client.h | 4 ++++ src/clientmap.cpp | 4 ++++ src/clientmap.h | 4 +++- src/clientobject.h | 1 + src/clouds.cpp | 4 +++- src/clouds.h | 6 ++++++ src/content_cao.cpp | 9 +++++---- src/environment.h | 5 +++++ src/game.cpp | 28 +++++++++++++++++++++------- src/itemdef.cpp | 2 +- src/mapblock_mesh.cpp | 14 ++++++++++++-- src/mapblock_mesh.h | 7 ++++++- src/particles.cpp | 25 +++++++++++++------------ src/particles.h | 8 +++++--- 17 files changed, 112 insertions(+), 35 deletions(-) diff --git a/src/camera.cpp b/src/camera.cpp index 937ba38af..783ae84c4 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -36,6 +36,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "util/numeric.h" #include "util/mathconstants.h" +#include "constants.h" + +#define CAMERA_OFFSET_STEP 200 Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, IGameDef *gamedef): @@ -53,6 +56,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, m_camera_position(0,0,0), m_camera_direction(0,0,0), + m_camera_offset(0,0,0), m_aspect(1.0), m_fov_x(1.0), @@ -348,11 +352,19 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, v3f abs_cam_up; m_headnode->getAbsoluteTransformation().rotateVect(abs_cam_up, rel_cam_up); + // Update offset if too far away from the center of the map + m_camera_offset.X += CAMERA_OFFSET_STEP* + (((s16)(m_camera_position.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP); + m_camera_offset.Y += CAMERA_OFFSET_STEP* + (((s16)(m_camera_position.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP); + m_camera_offset.Z += CAMERA_OFFSET_STEP* + (((s16)(m_camera_position.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP); + // Set camera node transformation - m_cameranode->setPosition(m_camera_position); + m_cameranode->setPosition(m_camera_position-intToFloat(m_camera_offset, BS)); m_cameranode->setUpVector(abs_cam_up); // *100.0 helps in large map coordinates - m_cameranode->setTarget(m_camera_position + 100 * m_camera_direction); + m_cameranode->setTarget(m_camera_position-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction); // Get FOV setting f32 fov_degrees = g_settings->getFloat("fov"); diff --git a/src/camera.h b/src/camera.h index aa9139148..df40e3b9f 100644 --- a/src/camera.h +++ b/src/camera.h @@ -79,6 +79,12 @@ public: { return m_camera_direction; } + + // Get the camera offset + inline v3s16 getOffset() const + { + return m_camera_offset; + } // Horizontal field of view inline f32 getFovX() const @@ -144,6 +150,8 @@ private: v3f m_camera_position; // Absolute camera direction v3f m_camera_direction; + // Camera offset + v3s16 m_camera_offset; // Field of view and aspect ratio stuff f32 m_aspect; diff --git a/src/client.cpp b/src/client.cpp index fb3f9b861..4d6c0cb99 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -179,7 +179,7 @@ void * MeshUpdateThread::Thread() ScopeProfiler sp(g_profiler, "Client: Mesh making"); - MapBlockMesh *mesh_new = new MapBlockMesh(q->data); + MapBlockMesh *mesh_new = new MapBlockMesh(q->data, m_camera_offset); if(mesh_new->getMesh()->getMeshBufferCount() == 0) { delete mesh_new; diff --git a/src/client.h b/src/client.h index 52d285ac4..01cd3a01c 100644 --- a/src/client.h +++ b/src/client.h @@ -119,6 +119,8 @@ public: MutexedQueue m_queue_out; IGameDef *m_gamedef; + + v3s16 m_camera_offset; }; enum ClientEventType @@ -406,6 +408,8 @@ public: // Including blocks at appropriate edges void addUpdateMeshTaskWithEdge(v3s16 blockpos, bool ack_to_server=false, bool urgent=false); void addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server=false, bool urgent=false); + + void updateCameraOffset(v3s16 camera_offset){ m_mesh_update_thread.m_camera_offset = camera_offset; } // Get event from queue. CE_NONE is returned if queue is empty. ClientEvent getClientEvent(); diff --git a/src/clientmap.cpp b/src/clientmap.cpp index df6c2822c..20a59f266 100644 --- a/src/clientmap.cpp +++ b/src/clientmap.cpp @@ -175,6 +175,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver) v3f camera_position = m_camera_position; v3f camera_direction = m_camera_direction; f32 camera_fov = m_camera_fov; + v3s16 camera_offset = m_camera_offset; m_camera_mutex.Unlock(); // Use a higher fov to accomodate faster camera movements. @@ -250,6 +251,9 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver) if not seen on display */ + if (block->mesh != NULL) + block->mesh->updateCameraOffset(m_camera_offset); + float range = 100000 * BS; if(m_control.range_all == false) range = m_control.wanted_range * BS; diff --git a/src/clientmap.h b/src/clientmap.h index f36e6127c..e695411be 100644 --- a/src/clientmap.h +++ b/src/clientmap.h @@ -86,12 +86,13 @@ public: ISceneNode::drop(); } - void updateCamera(v3f pos, v3f dir, f32 fov) + void updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset) { JMutexAutoLock lock(m_camera_mutex); m_camera_position = pos; m_camera_direction = dir; m_camera_fov = fov; + m_camera_offset = offset; } /* @@ -146,6 +147,7 @@ private: v3f m_camera_position; v3f m_camera_direction; f32 m_camera_fov; + v3s16 m_camera_offset; JMutex m_camera_mutex; std::map m_drawlist; diff --git a/src/clientobject.h b/src/clientobject.h index fb5cb29f4..613c635a2 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -65,6 +65,7 @@ public: virtual bool isLocalPlayer(){return false;} virtual void setAttachments(){} virtual bool doShowSelectionBox(){return true;} + virtual void updateCameraOffset(v3s16 camera_offset){}; // Step object in time virtual void step(float dtime, ClientEnvironment *env){} diff --git a/src/clouds.cpp b/src/clouds.cpp index 55ec8965a..1bf6dc9c1 100644 --- a/src/clouds.cpp +++ b/src/clouds.cpp @@ -35,7 +35,8 @@ Clouds::Clouds( scene::ISceneNode(parent, mgr, id), m_seed(seed), m_camera_pos(0,0), - m_time(0) + m_time(0), + m_camera_offset(0,0,0) { m_material.setFlag(video::EMF_LIGHTING, false); //m_material.setFlag(video::EMF_BACK_FACE_CULLING, false); @@ -318,6 +319,7 @@ void Clouds::render() } v3f pos(p0.X, m_cloud_y, p0.Y); + pos -= intToFloat(m_camera_offset, BS); for(u16 i=0; i<4; i++) v[i].Pos += pos; diff --git a/src/clouds.h b/src/clouds.h index 8f8b19faf..d718e56bf 100644 --- a/src/clouds.h +++ b/src/clouds.h @@ -66,6 +66,11 @@ public: void step(float dtime); void update(v2f camera_p, video::SColorf color); + + void updateCameraOffset(v3s16 camera_offset) + { + m_camera_offset = camera_offset; + } private: video::SMaterial m_material; @@ -76,6 +81,7 @@ private: u32 m_seed; v2f m_camera_pos; float m_time; + v3s16 m_camera_offset; }; diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 840103cc7..84ec3e143 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -1058,23 +1058,24 @@ public: if(getParent() != NULL) return; + v3s16 camera_offset = m_env->getCameraOffset(); if(m_meshnode){ - m_meshnode->setPosition(pos_translator.vect_show); + m_meshnode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS)); v3f rot = m_meshnode->getRotation(); rot.Y = -m_yaw; m_meshnode->setRotation(rot); } if(m_animated_meshnode){ - m_animated_meshnode->setPosition(pos_translator.vect_show); + m_animated_meshnode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS)); v3f rot = m_animated_meshnode->getRotation(); rot.Y = -m_yaw; m_animated_meshnode->setRotation(rot); } if(m_spritenode){ - m_spritenode->setPosition(pos_translator.vect_show); + m_spritenode->setPosition(pos_translator.vect_show-intToFloat(camera_offset, BS)); } } - + void step(float dtime, ClientEnvironment *env) { if(m_visuals_expired && m_smgr && m_irr){ diff --git a/src/environment.h b/src/environment.h index 9e282476f..8cc0bcd7e 100644 --- a/src/environment.h +++ b/src/environment.h @@ -500,6 +500,10 @@ public: { m_player_names.push_back(name); } void removePlayerName(std::string name) { m_player_names.remove(name); } + void updateCameraOffset(v3s16 camera_offset) + { m_camera_offset = camera_offset; } + v3s16 getCameraOffset() + { return m_camera_offset; } private: ClientMap *m_map; @@ -515,6 +519,7 @@ private: IntervalLimiter m_drowning_interval; IntervalLimiter m_breathing_interval; std::list m_player_names; + v3s16 m_camera_offset; }; #endif diff --git a/src/game.cpp b/src/game.cpp index 196d1e316..18e69c132 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -228,6 +228,7 @@ PointedThing getPointedThing(Client *client, v3f player_position, core::line3d shootline, f32 d, bool liquids_pointable, bool look_for_object, + v3s16 camera_offset, std::vector &hilightboxes, ClientActiveObject *&selected_object) { @@ -258,8 +259,8 @@ PointedThing getPointedThing(Client *client, v3f player_position, v3f pos = selected_object->getPosition(); hilightboxes.push_back(aabb3f( - selection_box->MinEdge + pos, - selection_box->MaxEdge + pos)); + selection_box->MinEdge + pos - intToFloat(camera_offset, BS), + selection_box->MaxEdge + pos - intToFloat(camera_offset, BS))); } mindistance = (selected_object->getPosition() - camera_position).getLength(); @@ -361,8 +362,8 @@ PointedThing getPointedThing(Client *client, v3f player_position, i2 != boxes.end(); i2++) { aabb3f box = *i2; - box.MinEdge += npf + v3f(-d,-d,-d); - box.MaxEdge += npf + v3f(d,d,d); + box.MinEdge += npf + v3f(-d,-d,-d) - intToFloat(camera_offset, BS); + box.MaxEdge += npf + v3f(d,d,d) - intToFloat(camera_offset, BS); hilightboxes.push_back(box); } } @@ -2541,6 +2542,8 @@ void the_game( Update camera */ + v3s16 old_camera_offset = camera.getOffset(); + LocalPlayer* player = client.getEnv().getLocalPlayer(); float full_punch_interval = playeritem_toolcap.full_punch_interval; float tool_reload_ratio = time_from_last_punch / full_punch_interval; @@ -2554,10 +2557,19 @@ void the_game( v3f camera_position = camera.getPosition(); v3f camera_direction = camera.getDirection(); f32 camera_fov = camera.getFovMax(); + v3s16 camera_offset = camera.getOffset(); + + bool camera_offset_changed = (camera_offset != old_camera_offset); if(!disable_camera_update){ client.getEnv().getClientMap().updateCamera(camera_position, - camera_direction, camera_fov); + camera_direction, camera_fov, camera_offset); + if (camera_offset_changed){ + client.updateCameraOffset(camera_offset); + client.getEnv().updateCameraOffset(camera_offset); + if (clouds) + clouds->updateCameraOffset(camera_offset); + } } // Update sound listener @@ -2600,6 +2612,7 @@ void the_game( &client, player_position, camera_direction, camera_position, shootline, d, playeritem_def.liquids_pointable, !ldown_for_dig, + camera_offset, // output hilightboxes, selected_object); @@ -3030,7 +3043,7 @@ void the_game( Update particles */ - allparticles_step(dtime, client.getEnv()); + allparticles_step(dtime); allparticlespawners_step(dtime, client.getEnv()); /* @@ -3249,7 +3262,8 @@ void the_game( */ update_draw_list_timer += dtime; if(update_draw_list_timer >= 0.2 || - update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2){ + update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2 || + camera_offset_changed){ update_draw_list_timer = 0; client.getEnv().getClientMap().updateDrawList(driver); update_draw_list_last_cam_dir = camera_direction; diff --git a/src/itemdef.cpp b/src/itemdef.cpp index d5e03f7b3..0187c7387 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -398,7 +398,7 @@ public: MeshMakeData mesh_make_data(gamedef); MapNode mesh_make_node(id, param1, 0); mesh_make_data.fillSingleNode(&mesh_make_node); - MapBlockMesh mapblock_mesh(&mesh_make_data); + MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); scene::IMesh *node_mesh = mapblock_mesh.getMesh(); assert(node_mesh); video::SColor c(255, 255, 255, 255); diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index afea3dcce..ef05acbb7 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -1030,7 +1030,7 @@ static void updateAllFastFaceRows(MeshMakeData *data, MapBlockMesh */ -MapBlockMesh::MapBlockMesh(MeshMakeData *data): +MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): m_mesh(new scene::SMesh()), m_gamedef(data->m_gamedef), m_animation_force_timer(0), // force initial animation @@ -1248,11 +1248,13 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data): &p.indices[0], p.indices.size()); } + m_camera_offset = camera_offset; + /* Do some stuff to the mesh */ - translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS)); + translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS)); if(m_mesh) { @@ -1415,6 +1417,14 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat return true; } +void MapBlockMesh::updateCameraOffset(v3s16 camera_offset) +{ + if (camera_offset != m_camera_offset) { + translateMesh(m_mesh, intToFloat(m_camera_offset-camera_offset, BS)); + m_camera_offset = camera_offset; + } +} + /* MeshCollector */ diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index c75984021..021309d99 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -81,7 +81,7 @@ class MapBlockMesh { public: // Builds the mesh given - MapBlockMesh(MeshMakeData *data); + MapBlockMesh(MeshMakeData *data, v3s16 camera_offset); ~MapBlockMesh(); // Main animation function, parameters: @@ -107,6 +107,8 @@ public: if(m_animation_force_timer > 0) m_animation_force_timer--; } + + void updateCameraOffset(v3s16 camera_offset); private: scene::SMesh *m_mesh; @@ -133,6 +135,9 @@ private: u32 m_last_daynight_ratio; // For each meshbuffer, maps vertex indices to (day,night) pairs std::map > > m_daynight_diffs; + + // Camera offset info -> do we have to translate the mesh? + v3s16 m_camera_offset; }; diff --git a/src/particles.cpp b/src/particles.cpp index 19bdaf121..5a3056c32 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -66,6 +66,7 @@ Particle::Particle( { // Misc m_gamedef = gamedef; + m_env = &env; // Texture m_material.setFlag(video::EMF_LIGHTING, false); @@ -95,7 +96,7 @@ Particle::Particle( this->setAutomaticCulling(scene::EAC_OFF); // Init lighting - updateLight(env); + updateLight(); // Init model updateVertices(); @@ -134,7 +135,7 @@ void Particle::render() scene::EPT_TRIANGLES, video::EIT_16BIT); } -void Particle::step(float dtime, ClientEnvironment &env) +void Particle::step(float dtime) { m_time += dtime; if (m_collisiondetection) @@ -143,7 +144,7 @@ void Particle::step(float dtime, ClientEnvironment &env) v3f p_pos = m_pos*BS; v3f p_velocity = m_velocity*BS; v3f p_acceleration = m_acceleration*BS; - collisionMoveSimple(&env, m_gamedef, + collisionMoveSimple(m_env, m_gamedef, BS*0.5, box, 0, dtime, p_pos, p_velocity, p_acceleration); @@ -158,13 +159,13 @@ void Particle::step(float dtime, ClientEnvironment &env) } // Update lighting - updateLight(env); + updateLight(); // Update model updateVertices(); } -void Particle::updateLight(ClientEnvironment &env) +void Particle::updateLight() { u8 light = 0; try{ @@ -173,11 +174,11 @@ void Particle::updateLight(ClientEnvironment &env) floor(m_pos.Y+0.5), floor(m_pos.Z+0.5) ); - MapNode n = env.getClientMap().getNode(p); - light = n.getLightBlend(env.getDayNightRatio(), m_gamedef->ndef()); + MapNode n = m_env->getClientMap().getNode(p); + light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef()); } catch(InvalidPositionException &e){ - light = blend_light(env.getDayNightRatio(), LIGHT_SUN, 0); + light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0); } m_light = decode_light(light); } @@ -199,6 +200,7 @@ void Particle::updateVertices() m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0, c, tx0, ty0); + v3s16 camera_offset = m_env->getCameraOffset(); for(u16 i=0; i<4; i++) { if (m_vertical) { @@ -209,17 +211,16 @@ void Particle::updateVertices() m_vertices[i].Pos.rotateXZBy(m_player->getYaw()); } m_box.addInternalPoint(m_vertices[i].Pos); - m_vertices[i].Pos += m_pos*BS; + m_vertices[i].Pos += m_pos*BS - intToFloat(camera_offset, BS); } } - /* Helpers */ -void allparticles_step (float dtime, ClientEnvironment &env) +void allparticles_step (float dtime) { for(std::vector::iterator i = all_particles.begin(); i != all_particles.end();) @@ -232,7 +233,7 @@ void allparticles_step (float dtime, ClientEnvironment &env) } else { - (*i)->step(dtime, env); + (*i)->step(dtime); i++; } } diff --git a/src/particles.h b/src/particles.h index 7c89a79bf..101fc49ce 100644 --- a/src/particles.h +++ b/src/particles.h @@ -67,19 +67,20 @@ class Particle : public scene::ISceneNode virtual void OnRegisterSceneNode(); virtual void render(); - void step(float dtime, ClientEnvironment &env); + void step(float dtime); bool get_expired () { return m_expiration < m_time; } private: - void updateLight(ClientEnvironment &env); + void updateLight(); void updateVertices(); video::S3DVertex m_vertices[4]; float m_time; float m_expiration; + ClientEnvironment *m_env; IGameDef *m_gamedef; core::aabbox3d m_box; core::aabbox3d m_collisionbox; @@ -94,6 +95,7 @@ private: u8 m_light; bool m_collisiondetection; bool m_vertical; + v3s16 m_camera_offset; }; class ParticleSpawner @@ -144,7 +146,7 @@ class ParticleSpawner bool m_vertical; }; -void allparticles_step (float dtime, ClientEnvironment &env); +void allparticles_step (float dtime); void allparticlespawners_step (float dtime, ClientEnvironment &env); void delete_particlespawner (u32 id);