国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Godot 4 源碼分析 - Path2D與PathFollow2D

這篇具有很好參考價(jià)值的文章主要介紹了Godot 4 源碼分析 - Path2D與PathFollow2D。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

學(xué)習(xí)演示項(xiàng)目dodge_the_creeps,發(fā)現(xiàn)里面多了一個(gè)Path2D與PathFollow2D

Godot 4 源碼分析 - Path2D與PathFollow2D,godot,游戲引擎

?研究GDScript代碼發(fā)現(xiàn),它主要用于隨機(jī)生成Mob

	var mob_spawn_location = get_node(^"MobPath/MobSpawnLocation")
	mob_spawn_location.progress = randi()

	# Set the mob's direction perpendicular to the path direction.
	var direction = mob_spawn_location.rotation + PI / 2

	# Set the mob's position to a random location.
	mob.position = mob_spawn_location.position

	# Add some randomness to the direction.
	direction += randf_range(-PI / 4, PI / 4)
	mob.rotation = direction

	# Choose the velocity for the mob.
	var velocity = Vector2(randf_range(150.0, 250.0), 0.0)
	mob.linear_velocity = velocity.rotated(direction)

這個(gè)有這么大的作用,不明覺(jué)厲

但不知道如何下手

查看源碼,有編輯器及類源碼

Godot 4 源碼分析 - Path2D與PathFollow2D,godot,游戲引擎

先從應(yīng)用角度,到B站上找找有沒(méi)有視頻,結(jié)果發(fā)現(xiàn)這個(gè)

Godot塔防游戲 - 01 -核心路徑制作 Path2D_嗶哩嗶哩_bilibili

看了之后,就知道使用方法了:

  • 添加Path2D
  • 在編輯器中設(shè)置路徑各關(guān)鍵點(diǎn),形成路徑

Godot 4 源碼分析 - Path2D與PathFollow2D,godot,游戲引擎

  • 在Path2D下增加PathFollow2D

這就OK了。剩下的就是使用

所謂使用,輸入為PathFollow2D的progress,輸出為路徑上的點(diǎn)信息(position, rotation...),然后用戶再根據(jù)這些信息去確定相應(yīng)的屬性

比如演示項(xiàng)目中,Path2D定制了一個(gè)外框路徑(左上角 >?右上角 >?右下角 >?左下角 >?左上角),在生成MOB時(shí),隨機(jī)指定其下的PathFollow2D的progress值為randi(),即為0 ~ 2^32 - 1的隨機(jī)整數(shù)。因?yàn)槁窂绞怯虚L(zhǎng)度的,本例中為2400,randi()值將按2400取模得到最終的隨機(jī)值0 - 2399,當(dāng)然也可以歸一化,設(shè)置其progress_ratio值為0.0 - 1.0,意思一樣。

查看源碼,set_progress的邏輯不只是取模,還有限制范圍。即PathFollow2D還有一個(gè)Loop屬性,如果Loop為真,才會(huì)取模,為false時(shí),會(huì)直接限制在路徑長(zhǎng)度范圍內(nèi)?progress = CLAMP(progress, 0, path_length);?之后統(tǒng)一更新_update_transform

void PathFollow2D::set_progress(real_t p_progress) {
	ERR_FAIL_COND(!isfinite(p_progress));
	progress = p_progress;
	if (path) {
		if (path->get_curve().is_valid()) {
			real_t path_length = path->get_curve()->get_baked_length();

			if (loop && path_length) {
				progress = Math::fposmod(progress, path_length);
				if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) {
					progress = path_length;
				}
			} else {
				progress = CLAMP(progress, 0, path_length);
			}
		}

		_update_transform();
	}
}

void PathFollow2D::_update_transform() {
	if (!path) {
		return;
	}

	Ref<Curve2D> c = path->get_curve();
	if (!c.is_valid()) {
		return;
	}

	real_t path_length = c->get_baked_length();
	if (path_length == 0) {
		return;
	}

	if (rotates) {
		Transform2D xform = c->sample_baked_with_rotation(progress, cubic);
		xform.translate_local(v_offset, h_offset);
		set_rotation(xform[1].angle());
		set_position(xform[2]);
	} else {
		Vector2 pos = c->sample_baked(progress, cubic);
		pos.x += h_offset;
		pos.y += v_offset;
		set_position(pos);
	}
}

從PathFollow2D代碼來(lái)看,它派生于Node2D,所以具備transform屬性:Position、Rotation、Scale、Skew,對(duì)于路徑上的點(diǎn)使用而言,這些信息就足夠了,能夠確定這些點(diǎn)的位置、方向,其實(shí)就是一個(gè)矢量?

Godot 4 源碼分析 - Path2D與PathFollow2D,godot,游戲引擎

Loop屬性值的含義前面已明確,Rotates、Cubic、H Offsets、V Offsets都是在_update_transform中起作用,具體算法可以不深究。但lookahead沒(méi)找到具體用處,感覺(jué)影響不大。

class PathFollow2D : public Node2D {
	GDCLASS(PathFollow2D, Node2D);

public:
private:
	Path2D *path = nullptr;
	real_t progress = 0.0;
	Timer *update_timer = nullptr;
	real_t h_offset = 0.0;
	real_t v_offset = 0.0;
	real_t lookahead = 4.0;
	bool cubic = true;
	bool loop = true;
	bool rotates = true;

	void _update_transform();

protected:
	void _validate_property(PropertyInfo &p_property) const;

	void _notification(int p_what);
	static void _bind_methods();

public:
	void path_changed();

	void set_progress(real_t p_progress);
	real_t get_progress() const;

	void set_h_offset(real_t p_h_offset);
	real_t get_h_offset() const;

	void set_v_offset(real_t p_v_offset);
	real_t get_v_offset() const;

	void set_progress_ratio(real_t p_ratio);
	real_t get_progress_ratio() const;

	void set_lookahead(real_t p_lookahead);
	real_t get_lookahead() const;

	void set_loop(bool p_loop);
	bool has_loop() const;

	void set_rotates(bool p_rotates);
	bool is_rotating() const;

	void set_cubic_interpolation(bool p_enable);
	bool get_cubic_interpolation() const;

	PackedStringArray get_configuration_warnings() const override;

	PathFollow2D() {}
};


void PathFollow2D::path_changed() {
	if (update_timer && !update_timer->is_stopped()) {
		update_timer->start();
	} else {
		_update_transform();
	}
}

void PathFollow2D::_update_transform() {
	if (!path) {
		return;
	}

	Ref<Curve2D> c = path->get_curve();
	if (!c.is_valid()) {
		return;
	}

	real_t path_length = c->get_baked_length();
	if (path_length == 0) {
		return;
	}

	if (rotates) {
		Transform2D xform = c->sample_baked_with_rotation(progress, cubic);
		xform.translate_local(v_offset, h_offset);
		set_rotation(xform[1].angle());
		set_position(xform[2]);
	} else {
		Vector2 pos = c->sample_baked(progress, cubic);
		pos.x += h_offset;
		pos.y += v_offset;
		set_position(pos);
	}
}

void PathFollow2D::_notification(int p_what) {
	switch (p_what) {
		case NOTIFICATION_READY: {
			if (Engine::get_singleton()->is_editor_hint()) {
				update_timer = memnew(Timer);
				update_timer->set_wait_time(0.2);
				update_timer->set_one_shot(true);
				update_timer->connect("timeout", callable_mp(this, &PathFollow2D::_update_transform));
				add_child(update_timer, false, Node::INTERNAL_MODE_BACK);
			}
		} break;

		case NOTIFICATION_ENTER_TREE: {
			path = Object::cast_to<Path2D>(get_parent());
			if (path) {
				_update_transform();
			}
		} break;

		case NOTIFICATION_EXIT_TREE: {
			path = nullptr;
		} break;
	}
}

void PathFollow2D::set_cubic_interpolation(bool p_enable) {
	cubic = p_enable;
}

bool PathFollow2D::get_cubic_interpolation() const {
	return cubic;
}

void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
	if (p_property.name == "offset") {
		real_t max = 10000.0;
		if (path && path->get_curve().is_valid()) {
			max = path->get_curve()->get_baked_length();
		}

		p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,or_greater";
	}
}

PackedStringArray PathFollow2D::get_configuration_warnings() const {
	PackedStringArray warnings = Node::get_configuration_warnings();

	if (is_visible_in_tree() && is_inside_tree()) {
		if (!Object::cast_to<Path2D>(get_parent())) {
			warnings.push_back(RTR("PathFollow2D only works when set as a child of a Path2D node."));
		}
	}

	return warnings;
}

void PathFollow2D::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_progress", "progress"), &PathFollow2D::set_progress);
	ClassDB::bind_method(D_METHOD("get_progress"), &PathFollow2D::get_progress);

	ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow2D::set_h_offset);
	ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow2D::get_h_offset);

	ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow2D::set_v_offset);
	ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow2D::get_v_offset);

	ClassDB::bind_method(D_METHOD("set_progress_ratio", "ratio"), &PathFollow2D::set_progress_ratio);
	ClassDB::bind_method(D_METHOD("get_progress_ratio"), &PathFollow2D::get_progress_ratio);

	ClassDB::bind_method(D_METHOD("set_rotates", "enable"), &PathFollow2D::set_rotates);
	ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotating);

	ClassDB::bind_method(D_METHOD("set_cubic_interpolation", "enable"), &PathFollow2D::set_cubic_interpolation);
	ClassDB::bind_method(D_METHOD("get_cubic_interpolation"), &PathFollow2D::get_cubic_interpolation);

	ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow2D::set_loop);
	ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow2D::has_loop);

	ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
	ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);

	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:px"), "set_progress", "get_progress");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
}

void PathFollow2D::set_progress(real_t p_progress) {
	ERR_FAIL_COND(!isfinite(p_progress));
	progress = p_progress;
	if (path) {
		if (path->get_curve().is_valid()) {
			real_t path_length = path->get_curve()->get_baked_length();

			if (loop && path_length) {
				progress = Math::fposmod(progress, path_length);
				if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) {
					progress = path_length;
				}
			} else {
				progress = CLAMP(progress, 0, path_length);
			}
		}

		_update_transform();
	}
}

void PathFollow2D::set_h_offset(real_t p_h_offset) {
	h_offset = p_h_offset;
	if (path) {
		_update_transform();
	}
}

real_t PathFollow2D::get_h_offset() const {
	return h_offset;
}

void PathFollow2D::set_v_offset(real_t p_v_offset) {
	v_offset = p_v_offset;
	if (path) {
		_update_transform();
	}
}

real_t PathFollow2D::get_v_offset() const {
	return v_offset;
}

real_t PathFollow2D::get_progress() const {
	return progress;
}

void PathFollow2D::set_progress_ratio(real_t p_ratio) {
	if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
		set_progress(p_ratio * path->get_curve()->get_baked_length());
	}
}

real_t PathFollow2D::get_progress_ratio() const {
	if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
		return get_progress() / path->get_curve()->get_baked_length();
	} else {
		return 0;
	}
}

void PathFollow2D::set_lookahead(real_t p_lookahead) {
	lookahead = p_lookahead;
}

real_t PathFollow2D::get_lookahead() const {
	return lookahead;
}

void PathFollow2D::set_rotates(bool p_rotates) {
	rotates = p_rotates;
	_update_transform();
}

bool PathFollow2D::is_rotating() const {
	return rotates;
}

void PathFollow2D::set_loop(bool p_loop) {
	loop = p_loop;
}

bool PathFollow2D::has_loop() const {
	return loop;
}

從代碼與用途來(lái)看,Path2D就沒(méi)啥看頭了,就負(fù)責(zé)提供一條曲線路徑

class Path2D : public Node2D {
	GDCLASS(Path2D, Node2D);

	Ref<Curve2D> curve;

	void _curve_changed();

protected:
	void _notification(int p_what);
	static void _bind_methods();

public:
#ifdef TOOLS_ENABLED
	virtual Rect2 _edit_get_rect() const override;
	virtual bool _edit_use_rect() const override;
	virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override;
#endif

	void set_curve(const Ref<Curve2D> &p_curve);
	Ref<Curve2D> get_curve() const;

	Path2D() {}
};

#ifdef TOOLS_ENABLED
Rect2 Path2D::_edit_get_rect() const {
	if (!curve.is_valid() || curve->get_point_count() == 0) {
		return Rect2(0, 0, 0, 0);
	}

	Rect2 aabb = Rect2(curve->get_point_position(0), Vector2(0, 0));

	for (int i = 0; i < curve->get_point_count(); i++) {
		for (int j = 0; j <= 8; j++) {
			real_t frac = j / 8.0;
			Vector2 p = curve->sample(i, frac);
			aabb.expand_to(p);
		}
	}

	return aabb;
}

bool Path2D::_edit_use_rect() const {
	return curve.is_valid() && curve->get_point_count() != 0;
}

bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
	if (curve.is_null()) {
		return false;
	}

	for (int i = 0; i < curve->get_point_count(); i++) {
		Vector2 s[2];
		s[0] = curve->get_point_position(i);

		for (int j = 1; j <= 8; j++) {
			real_t frac = j / 8.0;
			s[1] = curve->sample(i, frac);

			Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, s);
			if (p.distance_to(p_point) <= p_tolerance) {
				return true;
			}

			s[0] = s[1];
		}
	}

	return false;
}
#endif

void Path2D::_notification(int p_what) {
	switch (p_what) {
		// Draw the curve if path debugging is enabled.
		case NOTIFICATION_DRAW: {
			if (!curve.is_valid()) {
				break;
			}

			if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) {
				return;
			}

			if (curve->get_point_count() < 2) {
				return;
			}

#ifdef TOOLS_ENABLED
			const real_t line_width = get_tree()->get_debug_paths_width() * EDSCALE;
#else
			const real_t line_width = get_tree()->get_debug_paths_width();
#endif
			real_t interval = 10;
			const real_t length = curve->get_baked_length();

			if (length > CMP_EPSILON) {
				const int sample_count = int(length / interval) + 2;
				interval = length / (sample_count - 1); // Recalculate real interval length.

				Vector<Transform2D> frames;
				frames.resize(sample_count);

				{
					Transform2D *w = frames.ptrw();

					for (int i = 0; i < sample_count; i++) {
						w[i] = curve->sample_baked_with_rotation(i * interval, false);
					}
				}

				const Transform2D *r = frames.ptr();
				// Draw curve segments
				{
					PackedVector2Array v2p;
					v2p.resize(sample_count);
					Vector2 *w = v2p.ptrw();

					for (int i = 0; i < sample_count; i++) {
						w[i] = r[i].get_origin();
					}
					draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width, false);
				}

				// Draw fish bones
				{
					PackedVector2Array v2p;
					v2p.resize(3);
					Vector2 *w = v2p.ptrw();

					for (int i = 0; i < sample_count; i++) {
						const Vector2 p = r[i].get_origin();
						const Vector2 side = r[i].columns[0];
						const Vector2 forward = r[i].columns[1];

						// Fish Bone.
						w[0] = p + (side - forward) * 5;
						w[1] = p;
						w[2] = p + (-side - forward) * 5;

						draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width * 0.5, false);
					}
				}
			}
		} break;
	}
}

void Path2D::_curve_changed() {
	if (!is_inside_tree()) {
		return;
	}

	if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) {
		return;
	}

	queue_redraw();
	for (int i = 0; i < get_child_count(); i++) {
		PathFollow2D *follow = Object::cast_to<PathFollow2D>(get_child(i));
		if (follow) {
			follow->path_changed();
		}
	}
}

void Path2D::set_curve(const Ref<Curve2D> &p_curve) {
	if (curve.is_valid()) {
		curve->disconnect("changed", callable_mp(this, &Path2D::_curve_changed));
	}

	curve = p_curve;

	if (curve.is_valid()) {
		curve->connect("changed", callable_mp(this, &Path2D::_curve_changed));
	}

	_curve_changed();
}

Ref<Curve2D> Path2D::get_curve() const {
	return curve;
}

void Path2D::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Path2D::set_curve);
	ClassDB::bind_method(D_METHOD("get_curve"), &Path2D::get_curve);

	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_curve", "get_curve");
}

當(dāng)然,也不是啥用處沒(méi)有,比如動(dòng)態(tài)指定路徑的時(shí)候,就可以設(shè)置一條Curve2D,然后賦給Path2D,后面就照此行事。

比如,該演示項(xiàng)目中,

var curve = Curve2D.new()
curve.add_point(Vector2i(100, 100))
curve.add_point(Vector2i(400, 600))
$MobPath.curve = curve

然后,玩家呆在右上角,這就是那些MOB的死角,玩家可以活到把用戶送走

Godot 4 源碼分析 - Path2D與PathFollow2D,godot,游戲引擎

?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-627627.html

到了這里,關(guān)于Godot 4 源碼分析 - Path2D與PathFollow2D的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Godot 4 源碼分析 - 增加格式化字符串功能

    Godot 4 源碼分析 - 增加格式化字符串功能

    Godot 4的主要字符串類型為String,已經(jīng)設(shè)計(jì)得比較完善了,但有一個(gè)問(wèn)題,格式化這塊沒(méi)怎么考慮。 String中有一個(gè)format函數(shù),但這個(gè)函數(shù)只有兩個(gè)參數(shù),這咋用? 查找使用例子,都是這種效果 一看就懵。哪里有之前用的帶%s %d...之類的格式化用得舒服。 動(dòng)手實(shí)現(xiàn)一個(gè) 提供s

    2024年02月14日
    瀏覽(28)
  • Godot 官方2D C#重構(gòu)(4):TileMap進(jìn)階使用

    Godot 官方2D C#重構(gòu)(4):TileMap進(jìn)階使用

    Godot 官方 教程 Godot 2d 官方案例C#重構(gòu) 專欄 Godot 2d 重構(gòu) github地址 我們有時(shí)候需要翻轉(zhuǎn)圖片,比如這個(gè)門,我們想要左右對(duì)稱的一組 如何繪制自行摸索 Y Sort Enable是干什么的? 因?yàn)檫@兩個(gè)物體有前后關(guān)系,所以不能通過(guò)簡(jiǎn)單的判斷Z軸來(lái)設(shè)置遮擋關(guān)系(因?yàn)閆軸上下關(guān)系唯一,

    2024年02月08日
    瀏覽(26)
  • Godot 4.0 遮罩一個(gè)2D物體,使其部分顯示

    Godot 4.0 遮罩一個(gè)2D物體,使其部分顯示

    本文針對(duì)Godot 4.0。 我也查到了Godot 3.5如何實(shí)現(xiàn)遮罩,見(jiàn)這個(gè)鏈接 https://ask.godotengine.org/3031/how-do-i-mask-a-sprite 由于查到的大部分教程均針對(duì)3.5版本,特此提供4.0版本的教程。 Godot4.0的遮罩不是一個(gè)單獨(dú)的節(jié)點(diǎn),這個(gè)功能被包含在了一個(gè)常見(jiàn)的基類 CanvasItem 內(nèi)。 若要遮罩一個(gè)物體,可

    2024年02月08日
    瀏覽(161)
  • 標(biāo)題:在Godot中使用Node2D創(chuàng)建自定義的Label

    標(biāo)題:在Godot中使用Node2D創(chuàng)建自定義的Label

    在Godot游戲引擎中,我們經(jīng)常需要在游戲中顯示文本信息。通常,我們可以使用Label節(jié)點(diǎn)來(lái)實(shí)現(xiàn)這一點(diǎn)。但是,在某些情況下,你可能希望更靈活地控制文本的顯示和樣式。在本篇博客中,我們將學(xué)習(xí)如何通過(guò)使用Node2D節(jié)點(diǎn)來(lái)創(chuàng)建一個(gè)自定義的Label,從而能夠更好地控制文本的

    2024年02月11日
    瀏覽(15)
  • (02)Cartographer源碼無(wú)死角解析-(73) 2D后端優(yōu)化→OptimizationProblem2D-landmark殘差細(xì)節(jié)分析

    講解關(guān)于slam一系列文章匯總鏈接:史上最全slam從零開(kāi)始,針對(duì)于本欄目講解(02)Cartographer源碼無(wú)死角解析-鏈接如下: (02)Cartographer源碼無(wú)死角解析- (00)目錄_最新無(wú)死角講解:https://blog.csdn.net/weixin_43013761/article/details/127350885 ? 文末正下方中心提供了本人 聯(lián)系方式, 點(diǎn)擊本人照片

    2024年02月12日
    瀏覽(22)
  • OpenCV中關(guān)于二維仿射變換函數(shù)estimateAffinePartial2D的源碼分析

    關(guān)于二維仿射變化的介紹:https://www.cnblogs.com/yinheyi/p/6148886.html OpenCV3.4.1 中提供的接口為:estimateAffinePartial2D(),用于計(jì)算兩個(gè)2D點(diǎn)集之間具有4個(gè)自由度的最優(yōu)有限仿射變換。 其函數(shù)具體實(shí)現(xiàn)位于: ./opencv/sources/modules/calib3d/src/ptsetreg.cpp 函數(shù)原型: 函數(shù)具體實(shí)現(xiàn): 數(shù)據(jù)準(zhǔn)備工

    2024年02月08日
    瀏覽(13)
  • godot引擎c++源碼深度解析系列二

    記錄每次研究源碼的突破,今天已經(jīng)將打字練習(xí)的功能完成了一個(gè)基本模型,先來(lái)看下運(yùn)行效果。 godot源碼增加打字練習(xí)的demo 這個(gè)里面需要研究以下c++的控件頁(yè)面的開(kāi)發(fā)和熟悉,畢竟好久沒(méi)有使用c++了,先來(lái)看以下代碼吧。 就這樣就實(shí)現(xiàn)了文本框,輸入框和按鈕的實(shí)現(xiàn),以

    2024年02月15日
    瀏覽(24)
  • (02)Cartographer源碼無(wú)死角解析-(41) 2D柵格地圖→ActiveSubmaps2D

    (02)Cartographer源碼無(wú)死角解析-(41) 2D柵格地圖→ActiveSubmaps2D

    講解關(guān)于slam一系列文章匯總鏈接:史上最全slam從零開(kāi)始,針對(duì)于本欄目講解(02)Cartographer源碼無(wú)死角解析-鏈接如下: (02)Cartographer源碼無(wú)死角解析- (00)目錄_最新無(wú)死角講解:https://blog.csdn.net/weixin_43013761/article/details/127350885 ? 文末正下方中心提供了本人 聯(lián)系方式, 點(diǎn)擊本人照片

    2024年02月12日
    瀏覽(42)
  • (02)Cartographer源碼無(wú)死角解析-(42) 2D柵格地圖→Submap、Submap2D、MapLimits

    (02)Cartographer源碼無(wú)死角解析-(42) 2D柵格地圖→Submap、Submap2D、MapLimits

    講解關(guān)于slam一系列文章匯總鏈接:史上最全slam從零開(kāi)始,針對(duì)于本欄目講解(02)Cartographer源碼無(wú)死角解析-鏈接如下: (02)Cartographer源碼無(wú)死角解析- (00)目錄_最新無(wú)死角講解:https://blog.csdn.net/weixin_43013761/article/details/127350885 ? 文末正下方中心提供了本人 聯(lián)系方式, 點(diǎn)擊本人照片

    2024年02月16日
    瀏覽(23)
  • (02)Cartographer源碼無(wú)死角解析-(72) 2D后端優(yōu)化→OptimizationProblem2D-約束殘差、landmark殘差

    講解關(guān)于slam一系列文章匯總鏈接:史上最全slam從零開(kāi)始,針對(duì)于本欄目講解(02)Cartographer源碼無(wú)死角解析-鏈接如下: (02)Cartographer源碼無(wú)死角解析- (00)目錄_最新無(wú)死角講解:https://blog.csdn.net/weixin_43013761/article/details/127350885 ? 文末正下方中心提供了本人 聯(lián)系方式, 點(diǎn)擊本人照片

    2024年02月12日
    瀏覽(19)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包