diff --git a/components/renderers/cpp/src/splat_render.cpp b/components/renderers/cpp/src/splat_render.cpp
index a7e796dc97d86d65c8f4082beadbd801f3cf9ca0..f108404e77e4d4faaca59642e82d4a3d5007079c 100644
--- a/components/renderers/cpp/src/splat_render.cpp
+++ b/components/renderers/cpp/src/splat_render.cpp
@@ -467,6 +467,8 @@ bool Splatter::render(ftl::rgbd::VirtualSource *src, ftl::rgbd::Frame &out) {
 		Eigen::Matrix4f matrix = transform.matrix() * src->getPose().cast<float>();
 		params.m_viewMatrix = MatrixConversion::toCUDA(matrix.inverse());
 		params.m_viewMatrixInverse = MatrixConversion::toCUDA(matrix);
+
+		params.camera = src->parameters(Channel::Right);
 		
 		out.create<GpuMat>(Channel::Right, Format<uchar4>(camera.width, camera.height));
 		out.get<GpuMat>(Channel::Right).setTo(background_, cvstream);
diff --git a/components/rgbd-sources/src/sources/net/net.cpp b/components/rgbd-sources/src/sources/net/net.cpp
index dd97e961812d186572052ccd44ac5af13678e661..5956114d57bc2b9bc0a0b10bee48fd7a29d6b470 100644
--- a/components/rgbd-sources/src/sources/net/net.cpp
+++ b/components/rgbd-sources/src/sources/net/net.cpp
@@ -107,12 +107,20 @@ bool NetSource::_getCalibration(Universe &net, const UUID &peer, const string &s
 
 				LOG(INFO) << "Calibration received: " << p.cx << ", " << p.cy << ", " << p.fx << ", " << p.fy;
 
-				// Put calibration into config manually
-				host_->getConfig()["focal"] = p.fx;
-				host_->getConfig()["centre_x"] = p.cx;
-				host_->getConfig()["centre_y"] = p.cy;
-				host_->getConfig()["baseline"] = p.baseline;
-				host_->getConfig()["doffs"] = p.doffs;
+				if (chan == Channel::Left) {
+					// Put calibration into config manually
+					host_->getConfig()["focal"] = p.fx;
+					host_->getConfig()["centre_x"] = p.cx;
+					host_->getConfig()["centre_y"] = p.cy;
+					host_->getConfig()["baseline"] = p.baseline;
+					host_->getConfig()["doffs"] = p.doffs;
+				} else {
+					host_->getConfig()["focal_right"] = p.fx;
+					host_->getConfig()["centre_x_right"] = p.cx;
+					host_->getConfig()["centre_y_right"] = p.cy;
+					host_->getConfig()["baseline_right"] = p.baseline;
+					host_->getConfig()["doffs_right"] = p.doffs;
+				}
 				
 				return true;
 			} else {
@@ -138,6 +146,7 @@ NetSource::NetSource(ftl::rgbd::Source *host)
 	temperature_ = host->value("temperature", 6500);
 	default_quality_ = host->value("quality", 0);
 	last_bitrate_ = 0;
+	params_right_.width = 0;
 
 	decoder_c1_ = nullptr;
 	decoder_c2_ = nullptr;
@@ -156,6 +165,16 @@ NetSource::NetSource(ftl::rgbd::Source *host)
 		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/focal", host_->getConfig()["focal"].dump());
 	});
 
+	host->on("centre_x", [this,host](const ftl::config::Event&) {
+		params_.cx = host_->value("centre_x", 0.0);
+		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/centre_x", host_->getConfig()["centre_x"].dump());
+	});
+
+	host->on("centre_y", [this,host](const ftl::config::Event&) {
+		params_.cy = host_->value("centre_y", 0.0);
+		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/centre_y", host_->getConfig()["centre_y"].dump());
+	});
+
 	host->on("doffs", [this,host](const ftl::config::Event&) {
 		params_.doffs = host_->value("doffs", params_.doffs);
 		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/doffs", host_->getConfig()["doffs"].dump());
@@ -166,11 +185,25 @@ NetSource::NetSource(ftl::rgbd::Source *host)
 		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/baseline", host_->getConfig()["baseline"].dump());
 	});
 
-	host->on("doffs", [this,host](const ftl::config::Event&) {
-		params_.doffs = host_->value("doffs", params_.doffs);
-		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/doffs", host_->getConfig()["doffs"].dump());
+	// Right parameters
+
+	host->on("focal_right", [this,host](const ftl::config::Event&) {
+		params_right_.fx = host_->value("focal_right", 0.0);
+		params_right_.fy = params_right_.fx;
+		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/focal_right", host_->getConfig()["focal_right"].dump());
+	});
+
+	host->on("centre_x_right", [this,host](const ftl::config::Event&) {
+		params_right_.cx = host_->value("centre_x_right", 0.0);
+		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/centre_x_right", host_->getConfig()["centre_x_right"].dump());
 	});
 
+	host->on("centre_y_right", [this,host](const ftl::config::Event&) {
+		params_right_.cy = host_->value("centre_y_right", 0.0);
+		host_->getNet()->send(peer_, "update_cfg", host_->getURI() + "/centre_y_right", host_->getConfig()["centre_y_right"].dump());
+	});
+
+
 	host->on("quality", [this,host](const ftl::config::Event&) {
 		default_quality_ = host->value("quality", 0);
 	});
@@ -356,12 +389,13 @@ void NetSource::setPose(const Eigen::Matrix4d &pose) {
 
 ftl::rgbd::Camera NetSource::parameters(ftl::codecs::Channel chan) {
 	if (chan == ftl::codecs::Channel::Right) {
-		auto uri = host_->get<string>("uri");
-		if (!uri) return params_;
+		if (params_right_.width == 0) {
+			auto uri = host_->get<string>("uri");
+			if (!uri) return params_;
 
-		ftl::rgbd::Camera params;
-		_getCalibration(*host_->getNet(), peer_, *uri, params, chan);
-		return params;
+			_getCalibration(*host_->getNet(), peer_, *uri, params_right_, chan);
+		}
+		return params_right_;
 	} else {
 		return params_;
 	}
@@ -386,6 +420,7 @@ void NetSource::_updateURI() {
 		peer_ = *p;
 
 		has_calibration_ = _getCalibration(*host_->getNet(), peer_, *uri, params_, ftl::codecs::Channel::Left);
+		_getCalibration(*host_->getNet(), peer_, *uri, params_right_, ftl::codecs::Channel::Right);
 
 		host_->getNet()->bind(*uri, [this](short ttimeoff, const ftl::codecs::StreamPacket &spkt, const ftl::codecs::Packet &pkt) {
 			//if (chunk == -1) {
diff --git a/components/rgbd-sources/src/sources/net/net.hpp b/components/rgbd-sources/src/sources/net/net.hpp
index 0f867a9ab08fee843ba229ba47636938ef04abfa..469902a5709f1ce9674d4fcafb0b36b957b5f7a4 100644
--- a/components/rgbd-sources/src/sources/net/net.hpp
+++ b/components/rgbd-sources/src/sources/net/net.hpp
@@ -58,6 +58,7 @@ class NetSource : public detail::Source {
 	int maxN_;
 	int default_quality_;
 	ftl::codecs::Channel prev_chan_;
+	ftl::rgbd::Camera params_right_;
 
 	ftl::rgbd::detail::ABRController abr_;
 	int last_bitrate_;
diff --git a/components/rgbd-sources/src/sources/virtual/virtual.cpp b/components/rgbd-sources/src/sources/virtual/virtual.cpp
index afea7e17c485b7a1a6ae050c02e61372bb5d4604..17ce33638fbc1cfc934beb93243399cf93151118 100644
--- a/components/rgbd-sources/src/sources/virtual/virtual.cpp
+++ b/components/rgbd-sources/src/sources/virtual/virtual.cpp
@@ -3,12 +3,26 @@
 using ftl::rgbd::VirtualSource;
 using ftl::rgbd::Source;
 using ftl::codecs::Channel;
+using ftl::rgbd::Camera;
 
 class VirtualImpl : public ftl::rgbd::detail::Source {
 	public:
 	explicit VirtualImpl(ftl::rgbd::Source *host, const ftl::rgbd::Camera &params) : ftl::rgbd::detail::Source(host) {
 		params_ = params;
+
+		params_right_.width = host->value("width", 1280);
+		params_right_.height = host->value("height", 720);
+		params_right_.fx = host->value("focal_right", 700.0f);
+		params_right_.fy = params_right_.fx;
+		params_right_.cx = host->value("centre_x_right", -(double)params_.width / 2.0);
+		params_right_.cy = host->value("centre_y_right", -(double)params_.height / 2.0);
+		params_right_.minDepth = host->value("minDepth", 0.1f);
+		params_right_.maxDepth = host->value("maxDepth", 20.0f);
+		params_right_.doffs = 0;
+		params_right_.baseline = host->value("baseline", 0.0f);
+
 		capabilities_ = ftl::rgbd::kCapVideo | ftl::rgbd::kCapStereo;
+
 		if (!host->value("locked", false)) capabilities_ |= ftl::rgbd::kCapMovable;
 		host->on("baseline", [this](const ftl::config::Event&) {
 			params_.baseline = host_->value("baseline", 0.0f);
@@ -19,6 +33,27 @@ class VirtualImpl : public ftl::rgbd::detail::Source {
 			params_.fy = params_.fx;
 		});
 
+		host->on("centre_x", [this](const ftl::config::Event&) {
+			params_.cx = host_->value("centre_x", 0.0f);
+		});
+
+		host->on("centre_y", [this](const ftl::config::Event&) {
+			params_.cy = host_->value("centre_y", 0.0f);
+		});
+
+		host->on("focal_right", [this](const ftl::config::Event&) {
+			params_right_.fx = host_->value("focal_right", 700.0f);
+			params_right_.fy = params_right_.fx;
+		});
+
+		host->on("centre_x_right", [this](const ftl::config::Event&) {
+			params_right_.cx = host_->value("centre_x_right", 0.0f);
+		});
+
+		host->on("centre_y_right", [this](const ftl::config::Event&) {
+			params_right_.cy = host_->value("centre_y_right", 0.0f);
+		});
+
 	}
 
 	~VirtualImpl() {
@@ -65,14 +100,32 @@ class VirtualImpl : public ftl::rgbd::detail::Source {
 		return true;
 	}
 
+	Camera parameters(ftl::codecs::Channel c) {
+		return (c == Channel::Left) ? params_ : params_right_;
+	}
+
 	bool isReady() override { return true; }
 
 	std::function<void(ftl::rgbd::Frame &)> callback;
 	ftl::rgbd::Frame frame;
+
+	ftl::rgbd::Camera params_right_;
 };
 
 VirtualSource::VirtualSource(ftl::config::json_t &cfg) : Source(cfg) {
 	auto params = params_;
+
+	params_.width = value("width", 1280);
+	params_.height = value("height", 720);
+	params_.fx = value("focal", 700.0f);
+	params_.fy = params_.fx;
+	params_.cx = value("centre_x", -(double)params_.width / 2.0);
+	params_.cy = value("centre_y", -(double)params_.height / 2.0);
+	params_.minDepth = value("minDepth", 0.1f);
+	params_.maxDepth = value("maxDepth", 20.0f);
+	params_.doffs = 0;
+	params_.baseline = value("baseline", 0.0f);
+
 	impl_ = new VirtualImpl(this, params);
 }