-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1672 lines (1380 loc) · 106 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Zgh's</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Zgh的个人站">
<meta property="og:type" content="website">
<meta property="og:title" content="Zgh's">
<meta property="og:url" content="http://zgh20060114.github.io/index.html">
<meta property="og:site_name" content="Zgh's">
<meta property="og:description" content="Zgh的个人站">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
<link rel="alternate" href="/atom.xml" title="Zgh's" type="application/atom+xml">
<link rel="shortcut icon" href="/favicon.png">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/fancybox/jquery.fancybox.min.css">
<meta name="generator" content="Hexo 6.3.0"></head>
<body>
<div id="container">
<div id="wrap">
<header id="header">
<div id="banner"></div>
<div id="header-outer" class="outer">
<div id="header-title" class="inner">
<h1 id="logo-wrap">
<a href="/" id="logo">Zgh's</a>
</h1>
</div>
<div id="header-inner" class="inner">
<nav id="main-nav">
<a id="main-nav-toggle" class="nav-icon"><span class="fa fa-bars"></span></a>
<a class="main-nav-link" href="/">Home</a>
<a class="main-nav-link" href="/archives">Archives</a>
</nav>
<nav id="sub-nav">
<a class="nav-icon" href="/atom.xml" title="RSS Feed"><span class="fa fa-rss"></span></a>
<a class="nav-icon nav-search-btn" title="Search"><span class="fa fa-search"></span></a>
</nav>
<div id="search-form-wrap">
<form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit"></button><input type="hidden" name="sitesearch" value="http://Zgh20060114.github.io"></form>
</div>
</div>
</div>
</header>
<div class="outer">
<section id="main">
<article id="post-四足" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/%E5%9B%9B%E8%B6%B3.html" class="article-date">
<time class="dt-published" datetime="2024-11-13T00:30:10.000Z" itemprop="datePublished">2024-11-13</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/%E5%9B%9B%E8%B6%B3.html">四足</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/%E5%9B%9B%E8%B6%B3.html" data-id="cm3f5a1ib0000czcx489zdgnv" data-title="四足" class="article-share-link"><span class="fa fa-share">Share</span></a>
</footer>
</div>
</article>
<article id="post-图形学" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/%E5%9B%BE%E5%BD%A2%E5%AD%A6.html" class="article-date">
<time class="dt-published" datetime="2024-11-02T08:34:15.000Z" itemprop="datePublished">2024-11-02</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/%E5%9B%BE%E5%BD%A2%E5%AD%A6.html">图形学</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p><img src="/../images/image-20241102163615219.png" alt="image-20241102163615219"></p>
<p><img src="/../images/image-20241102170537184.png" alt="image-20241102170537184"></p>
<p><img src="/../images/image-20241102170633713.png" alt="image-20241102170633713"></p>
<p>光线与球体的相交测试:</p>
<p><img src="/../images/image-20241102170834824.png" alt="image-20241102170834824"></p>
<p>可以通过判断这个一元二次方程的delta判别式判断光线是否击中了球体</p>
<p><strong>结构体</strong>:默认的成员访问权限是 <code>public</code>。</p>
<p><strong>类</strong>:默认的成员访问权限是 <code>private</code>。</p>
<h3 id="视口裁剪(Viewport-Clipping)"><a href="#视口裁剪(Viewport-Clipping)" class="headerlink" title="视口裁剪(Viewport Clipping)"></a>视口裁剪(Viewport Clipping)</h3><p>视口裁剪是指在渲染过程中,图形系统根据当前的视口(viewport)大小和位置,裁剪出只在视口内的部分。这通常发生在将三维场景转换为二维图像时。</p>
<ul>
<li><strong>视口定义</strong>:视口是指在窗口或屏幕上的一个矩形区域,图形渲染的结果只显示在这个区域内。</li>
<li><strong>用途</strong>:视口裁剪确保只绘制视口范围内的图形,避免无效的计算和渲染,提高效率。</li>
</ul>
<h3 id="透视裁剪(Perspective-Clipping)"><a href="#透视裁剪(Perspective-Clipping)" class="headerlink" title="透视裁剪(Perspective Clipping)"></a>透视裁剪(Perspective Clipping)</h3><p>透视裁剪是指在透视投影过程中,决定哪些对象在视锥体内并且可见,从而只渲染可见部分。透视投影会产生一个视锥体,位于观察者与场景之间。</p>
<ul>
<li><strong>视锥体</strong>:在透视投影中,视锥体是一个从观察点(摄像机位置)向外扩展的锥形区域。只有位于这个区域内的对象才会被渲染。</li>
<li><strong>裁剪</strong>:透视裁剪会去除视锥体外的对象,避免不必要的计算和渲染,并处理对象的深度关系。</li>
</ul>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul>
<li><strong>视口裁剪</strong>:关注的是最终图像在屏幕上的显示区域,只显示视口内的内容。</li>
<li><strong>透视裁剪</strong>:关注的是三维场景中哪些对象在视锥体内,以决定哪些对象是可见的。</li>
</ul>
<p>屏幕空间和 NDC(Normalized Device Coordinates)空间之间的关系:</p>
<h3 id="坐标变换流程"><a href="#坐标变换流程" class="headerlink" title="坐标变换流程"></a>坐标变换流程</h3><p>在图形渲染过程中,顶点坐标经历多个变换,从世界空间到最终的屏幕空间,这个过程大致包括:</p>
<ol>
<li><strong>模型变换</strong>:将顶点从局部模型坐标转换到世界坐标。</li>
<li><strong>视图变换</strong>:将世界坐标转换到相机坐标(视图空间)。</li>
<li><strong>投影变换</strong>:将相机坐标转换到裁剪空间。</li>
<li><strong>裁剪</strong>:将不在视野范围内的顶点剔除。</li>
<li><strong>透视除法</strong>:将裁剪空间的坐标转换到 NDC 空间。这个步骤涉及将每个坐标的 x、y 和 z 分别除以 w(齐次坐标),使得坐标范围归一化到 [-1, 1]。</li>
</ol>
<h3 id="NDC-到屏幕空间的转换"><a href="#NDC-到屏幕空间的转换" class="headerlink" title="NDC 到屏幕空间的转换"></a>NDC 到屏幕空间的转换</h3><p>一旦顶点处于 NDC 空间,它们需要被转换到屏幕空间:</p>
<ol>
<li><strong>视口变换</strong>:将 NDC 坐标映射到实际的屏幕像素坐标。视口变换使用屏幕的分辨率来进行坐标的线性变换。具体步骤是:<ul>
<li>将 NDC 的 x 和 y 坐标从 [-1, 1] 范围映射到屏幕像素的范围。例如,对于一个宽度为 W,高度为 H 的屏幕:<ul>
<li><code>screenX = (ndcX + 1) * 0.5 * (W - 1)</code></li>
<li><code>screenY = (1 - (ndcY + 1) * 0.5) * (H - 1)</code>(Y 轴可能需要翻转,具体取决于坐标系统的定义)</li>
</ul>
</li>
</ul>
</li>
</ol>
<ul>
<li><strong>NDC 空间</strong> 是一个归一化的坐标系统,主要用于在渲染管线中的处理,使得顶点坐标能够统一处理,不论目标显示设备的分辨率如何。</li>
<li><strong>屏幕空间</strong> 是实际显示的坐标系统,与屏幕的物理尺寸和分辨率相关。</li>
<li><strong>转换</strong>:通过视口变换,NDC 空间的坐标被转换为屏幕空间的像素坐标,从而最终呈现在用户的屏幕上。</li>
</ul>
<p>NDC 空间可以看作是从三维世界到二维屏幕的中间步骤,而屏幕空间则是最终的输出结果。</p>
<p><img src="/../images/image-20241103175728042.png" alt="image-20241103175728042"></p>
<p><img src="/../images/image-20241103181614993.png" alt="image-20241103181614993"></p>
<h3 id="虚函数(Virtual-Function)"><a href="#虚函数(Virtual-Function)" class="headerlink" title="虚函数(Virtual Function)"></a>虚函数(Virtual Function)</h3><ol>
<li><strong>定义</strong>:虚函数是在基类中声明为<code>virtual</code>的成员函数,可以在派生类中重写(override)。</li>
<li><strong>实现</strong>:虚函数可以有具体的实现。基类中的虚函数可以提供默认的实现,派生类可以选择重写它。</li>
<li><strong>对象创建</strong>:可以创建基类的对象,也可以创建派生类的对象。</li>
</ol>
<h3 id="纯虚函数(Pure-Virtual-Function)"><a href="#纯虚函数(Pure-Virtual-Function)" class="headerlink" title="纯虚函数(Pure Virtual Function)"></a>纯虚函数(Pure Virtual Function)</h3><ol>
<li><strong>定义</strong>:纯虚函数是在基类中声明为<code>virtual</code>并且等于0的函数。语法是<code>virtual void functionName() = 0;</code>。</li>
<li><strong>实现</strong>:纯虚函数没有实现,基类通常不可以实例化。</li>
<li><strong>对象创建</strong>:不能直接创建类的对象(即抽象类),只能创建派生类的对象。</li>
<li><strong>用途</strong>:用于定义接口,强制派生类实现特定的函数</li>
</ol>
<p>输入流操作符 (<code>>></code>) 在处理流时,会自动跳过空格和其他空白字符(如换行符和制表符),直到遇到下一个有意义的值为止。因此,空格在这一过程中并不会被显式处理。</p>
<h3 id="line-compare-0-2-v-的含义:"><a href="#line-compare-0-2-v-的含义:" class="headerlink" title="line.compare(0, 2, "v ") 的含义:"></a><code>line.compare(0, 2, "v ")</code> 的含义:</h3><ol>
<li>**<code>0</code>**:表示从 <code>line</code> 字符串的第一个字符开始进行比较。</li>
<li>**<code>2</code>**:表示比较的长度为 2,也就是说,只比较 <code>line</code> 字符串的前两个字符。</li>
<li>**<code>"v "</code>**:表示要将 <code>line</code> 字符串的前两个字符与字符串 <code>"v "</code> 进行比较。</li>
<li>如果 <code>line</code> 的前两个字符与 <code>"v "</code> 完全匹配,<code>compare</code> 方法返回 0。</li>
<li>如果不匹配,返回一个非 0 的值(具体的值取决于比较的结果:如果 <code>line</code> 字符串小于 <code>"v "</code>,返回一个负数;如果 <code>line</code> 字符串大于 <code>"v "</code>,返回一个正数)。</li>
</ol>
<h3 id="平面和场景"><a href="#平面和场景" class="headerlink" title="平面和场景"></a>平面和场景</h3><p>场景:管理世界空间下所有的形状(Shape)</p>
<p>平面的数学定义:</p>
<p><img src="/../images/image-20241105220133619.png" alt="image-20241105220133619"></p>
<p><img src="/../images/image-20241105220823204.png" alt="image-20241105220823204"></p>
<p>修改是为了改进多线程环境中的 <strong>线程安全性</strong> 和 <strong>竞态条件</strong> 的问题。我们来详细分析一下原始代码和修改后的代码之间的差异,以及为什么要这样修改。</p>
<h3 id="原始代码:"><a href="#原始代码:" class="headerlink" title="原始代码:"></a>原始代码:</h3><pre><code class="cpp">count++;
if (count % film.getWidth() == 0) {
std::cout << static_cast<float>(count) / (film.getWidth() * film.getHeight()) << std::endl;
}
</code></pre>
<h3 id="修改后的代码:"><a href="#修改后的代码:" class="headerlink" title="修改后的代码:"></a>修改后的代码:</h3><pre><code class="cpp">int n = ++count;
if (n % film.getWidth() == 0) {
std::cout << static_cast<float>(n) / (film.getWidth() * film.getHeight()) << std::endl;
}
</code></pre>
<h3 id="问题分析:"><a href="#问题分析:" class="headerlink" title="问题分析:"></a>问题分析:</h3><h4 id="1-count-是非原子操作"><a href="#1-count-是非原子操作" class="headerlink" title="1. count++ 是非原子操作"></a>1. <strong><code>count++</code> 是非原子操作</strong></h4><ul>
<li><code>count++</code> 实际上是由 <strong>两个操作</strong> 组成的:<strong>读取 <code>count</code> 的值</strong>,然后 **增加 <code>count</code>**。在多线程环境中,如果多个线程同时执行 <code>count++</code>,就会发生 <strong>竞态条件</strong>(race condition),可能导致 <code>count</code> 的值增加不正确或者丢失。</li>
<li>例如,如果线程 A 和线程 B 同时读取到相同的 <code>count</code> 值,然后都加 1 写回,这样就会丢失一个递增的结果,导致 <code>count</code> 的值不准确。</li>
</ul>
<h4 id="2-count-是原子操作"><a href="#2-count-是原子操作" class="headerlink" title="2. ++count 是原子操作"></a>2. <strong><code>++count</code> 是原子操作</strong></h4><ul>
<li><code>++count</code> 是 <strong>自增并返回自增后的值</strong>,它在执行过程中是原子的,不会有并发冲突(前提是 <code>count</code> 本身是原子变量或操作)。这是因为它在自增的时候直接对 <code>count</code> 的值进行更新并返回,而不需要先读取再写入,避免了多个线程同时读取和写入的情况。</li>
</ul>
<h4 id="3-存储递增结果到-n"><a href="#3-存储递增结果到-n" class="headerlink" title="3. 存储递增结果到 n"></a>3. <strong>存储递增结果到 <code>n</code></strong></h4><ul>
<li>修改后的代码 <code>int n = ++count;</code> 将自增后的结果保存在 <code>n</code> 中。这样做的好处是:<ol>
<li><strong>保证了 <code>count</code> 更新后的值在后续代码中是确定的</strong>。如果我们直接在 <code>if (count % film.getWidth() == 0)</code> 中访问 <code>count</code>,其他线程可能会在我们检查 <code>count</code> 时修改它,导致判断条件不稳定。而 <code>n</code> 是在更新后的值保存时就固定了,因此后续的判断和输出使用 <code>n</code> 可以确保一致性。</li>
<li><strong>避免了 <code>count</code> 被其他线程修改时的影响</strong>。虽然 <code>count</code> 本身是全局共享的,但通过把递增结果保存在 <code>n</code> 中,我们保证了 <code>n</code> 的值不会在后续代码执行时被其他线程改动,确保了输出的正确性。</li>
</ol>
</li>
</ul>
<h3 id="线程安全与性能考虑:"><a href="#线程安全与性能考虑:" class="headerlink" title="线程安全与性能考虑:"></a>线程安全与性能考虑:</h3><ul>
<li>使用 <code>int n = ++count;</code> 的修改,确保了 <strong>每个线程对 <code>count</code> 的更新是安全的</strong>。同时,虽然 <code>++count</code> 在某些情况下可能是原子操作,但若 <code>count</code> 是一个普通变量,并且没有显式的线程同步机制,那么可能仍然存在隐性的问题。将更新后的 <code>count</code> 值保存到 <code>n</code> 可以减少这种不确定性。</li>
<li>在多线程环境下,避免直接在条件判断中使用共享变量(如 <code>count</code>)是一个常见的做法,尤其是当这个变量在多个线程中共享且没有其他同步机制时。通过中间变量 <code>n</code> 来持有更新后的值,避免了在 <code>count</code> 被其他线程修改时产生的竞态条件。</li>
</ul>
<pre><code class="cpp"> glm::translate(glm::mat4(1.f), pos) *
glm::rotate(glm::mat4(1.f), glm::radians(rotate.z), { 0, 0, 1 }) *
glm::rotate(glm::mat4(1.f), glm::radians(rotate.y), { 0, 1, 0 }) *
glm::rotate(glm::mat4(1.f), glm::radians(rotate.x), { 1, 0, 0 }) *
glm::scale(glm::mat4(1.f), scale)
</code></pre>
<ul>
<li><code>glm::mat4(1.f)</code>:创建一个单位矩阵,表示没有任何变换。</li>
<li><code>glm::translate(..., pos)</code>:将矩阵平移到 <code>pos</code> 指定的位置,<code>pos</code> 是一个 <code>glm::vec3</code> 向量,表示物体在3D空间中的平移偏移量(<code>x</code>, <code>y</code>, <code>z</code>)。</li>
<li><code>glm::radians(rotate.z)</code>:将角度 <code>rotate.z</code> 转换为弧度,因为GLM的 <code>rotate</code> 函数期望的旋转角度单位是弧度。</li>
<li><code>{ 0, 0, 1 }</code>:指定旋转轴为Z轴。</li>
<li><code>glm::scale(glm::mat4(1.f), scale)</code>:执行一个缩放变换,其中 <code>scale</code> 是一个 <code>glm::vec3</code> 向量,表示沿着X、Y和Z轴的缩放比例。例如,<code>scale = { 2.f, 3.f, 1.f }</code> 表示在X轴上放大2倍,在Y轴上放大3倍,而Z轴保持不变。</li>
</ul>
<p>在GLM中,矩阵的乘法是从 <strong>右到左</strong> 进行的</p>
<p><img src="/../images/image-20241109162036809.png" alt="image-20241109162036809"></p>
<p><img src="/../images/image-20241109213953208.png" alt="image-20241109213953208"></p>
<p><img src="/../images/image-20241110094231486.png" alt="image-20241110094231486"></p>
<p><img src="/../images/image-20241110095142061.png" alt="image-20241110095142061"></p>
<p><img src="/../images/image-20241110095414276.png" alt="image-20241110095414276"></p>
<p><img src="/../images/image-20241110095522416.png" alt="image-20241110095522416"></p>
<p><img src="/../images/image-20241110144226840.png" alt="image-20241110144226840"></p>
<p>frame坐标系不用储存坐标系的原点,只用存储坐标轴的方向</p>
<p><img src="/../images/image-20241112092245780.png" alt="image-20241112092245780"></p>
<p>镜面反射:x,z取反</p>
<p>漫反射:采样</p>
<p><img src="/../images/image-20241112092430966.png" alt="image-20241112092430966"></p>
<pre><code class="cpp">for (size_t i = 0; i < shapeInstances.size(); i++) {
auto shapeInstance = shapeInstances[i];
auto ray_object = ray.rayObjectFromWorld(shapeInstance.object_from_world);
hitInfo = shapeInstance.shape.intersect(ray_object, t_min, t_max); // 需要把世界空间下的光线转换成对象空间里相交测试
if (hitInfo.has_value()) {
t_max = hitInfo->distance;
closest_hitInfo = hitInfo;
closest_instance = &shapeInstance;
}
}
</code></pre>
<p>与:</p>
<pre><code class="cpp"> for (size_t i = 0; i < shapeInstances.size(); i++) {
auto ray_object = ray.rayObjectFromWorld(shapeInstances[i].object_from_world);
hitInfo = shapeInstances[i].shape.intersect(ray_object, t_min, t_max); //需要把世界空间下的光线转换成对象空间里相交测试
if (hitInfo.has_value()) {
t_max = hitInfo->distance;
closest_hitInfo = hitInfo;
closest_instance = &shapeInstances[i];
}
}
</code></pre>
<p>看似一样,实则不一样</p>
<p>第一个是拷贝,</p>
<p><code>shapeInstance</code> 就是一个独立的对象,它与原始 <code>shapeInstances[i]</code> 没有直接关系</p>
<p>减小光追的噪点:</p>
<p><img src="/../images/image-20241112200209893.png" alt="image-20241112200209893"></p>
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/%E5%9B%BE%E5%BD%A2%E5%AD%A6.html" data-id="cm2zwq9rd0000h9cxga7gdlb6" data-title="图形学" class="article-share-link"><span class="fa fa-share">Share</span></a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9B%BE%E5%BD%A2%E5%AD%A6/" rel="tag">计算机图形学</a></li></ul>
</footer>
</div>
</article>
<article id="post-motion-planning" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/motion-planning.html" class="article-date">
<time class="dt-published" datetime="2024-10-27T11:56:49.000Z" itemprop="datePublished">2024-10-27</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/motion-planning.html">motion_planning</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p><img src="/../images/image-20241027200509747.png" alt="image-20241027200509747"></p>
<p><img src="/../images/image-20241027200356742.png" alt="image-20241027200356742"></p>
<p><img src="/../images/image-20241027200333906.png" alt="image-20241027200333906"></p>
<p><img src="/../images/image-20241027200800232.png" alt="image-20241027200800232"></p>
<p><img src="/../images/image-20241027205352801.png" alt="image-20241027205352801"></p>
<p><img src="/../images/image-20241028081500141.png" alt="image-20241028081500141"></p>
<p><img src="/../images/image-20241028082324091.png" alt="image-20241028082324091"></p>
<p>地图处理:</p>
<p><img src="/../images/image-20241027205539229.png" alt="image-20241027205539229"></p>
<p>Octree Map存储效率高,占用内存小,适合三维空间</p>
<p>缺点:构建和查询比较复杂,需要递归操作</p>
<p><img src="/../images/image-20241027210518464.png" alt="image-20241027210518464"></p>
<p>对于平面,可以使用四叉树地图</p>
<p>拓扑地图</p>
<p><img src="/../images/image-20241027210407252.png" alt="image-20241027210407252"></p>
<p>不能生成具体的路径</p>
<p>欧式距离场地图</p>
<p><img src="/../images/image-20241027210719429.png" alt="image-20241027210719429"></p>
<p>每一个像素点的值是到目标点的距离</p>
<p>高精地图+激光雷达:</p>
<p><img src="/../images/image-20241027211413340.png" alt="image-20241027211413340"></p>
<p><img src="/../images/image-20241027211825655.png" alt="image-20241027211825655"></p>
<p><img src="/../images/image-20241027212906123.png" alt="image-20241027212906123"></p>
<p><img src="/../images/image-20241028075246319.png" alt="image-20241028075246319"></p>
<p><img src="/../images/image-20241028075418437.png" alt="image-20241028075418437"></p>
<p><img src="/../images/image-20241028080419520.png" alt="image-20241028080419520"></p>
<p><img src="/../images/image-20241028080601730.png" alt="image-20241028080601730"></p>
<p>基于结构化地图(已经使用数据结构/储存方式存储好了环境信息)的搜索:</p>
<p><img src="/../images/image-20241028083144863.png" alt="image-20241028083144863"></p>
<p>基于采样的路径搜索算法(不太适用于移动机器人)</p>
<p>没有地图的算法:概率路图</p>
<p><img src="/../images/image-20241028083334678.png" alt="image-20241028083334678"></p>
<p><img src="/../images/image-20241028084401881.png" alt="image-20241028084401881"></p>
<p>没有地图,先构造地图:<br><img src="/../images/image-20241028085903682.png" alt="image-20241028085903682"></p>
<p>建完图后路径规划:</p>
<p><img src="/../images/image-20241028090435029.png" alt="image-20241028090435029"></p>
<p><img src="/../images/image-20241028090508977.png" alt="image-20241028090508977"></p>
<p><img src="/../images/image-20241028090709696.png" alt="image-20241028090709696"><img src="/../images/image-20241028090740717.png" alt="image-20241028090740717"></p>
<p><img src="/../images/image-20241028091720342.png" alt="image-20241028091720342"></p>
<p><img src="/../images/image-20241028093035763.png" alt="image-20241028093035763"></p>
<p>PRM的升级:RRT(快速搜索随机数)</p>
<p>(一边构建地图,一边搜索路径)</p>
<p><img src="/../images/image-20241028204215612.png" alt="image-20241028204215612"></p>
<p><img src="/../images/image-20241028204322405.png" alt="image-20241028204322405"></p>
<p><img src="/../images/image-20241028204556756.png" alt="image-20241028204556756"></p>
<p><img src="/../images/image-20241028205030612.png" alt="image-20241028205030612"></p>
<p><img src="/../images/image-20241028205207024.png" alt="image-20241028205207024"></p>
<p><img src="/../images/image-20241028205744700.png" alt="image-20241028205744700"></p>
<p><img src="/../images/image-20241028210026292.png" alt="image-20241028210026292"></p>
<p><img src="/../images/image-20241028210759396.png" alt="image-20241028210759396"></p>
<p><img src="/../images/image-20241028211121913.png" alt="image-20241028211121913"></p>
<p>基于图搜索的路径搜索算法</p>
<p>1.朴素的搜索思想——BFS,DFS</p>
<p><img src="/../images/image-20241028212530583.png" alt="image-20241028212530583"></p>
<p>栅格地图可以很容易的转换成graph,欧式距离场可以很容易的转换成栅格地图,拓扑地图本身就是graph</p>
<p><img src="/../images/image-20241028213223056.png" alt="image-20241028213223056"></p>
<p>图搜索的核心问题:</p>
<p><img src="/../images/image-20241028213700790.png" alt="image-20241028213700790"></p>
<p><img src="/../images/image-20241028213931204.png" alt="image-20241028213931204"></p>
<p><img src="/../images/image-20241029075416595.png" alt="image-20241029075416595"></p>
<p><img src="/../images/image-20241029145851838.png" alt="image-20241029145851838"></p>
<p><code>std::reverse</code> 是 C++ 标准库中的一个算法,用于反转给定范围内的元素顺序。它定义在 <code><algorithm></code> 头文件中。</p>
<p><code>std::reverse</code> 接受两个迭代器作为参数,表示要反转的范围。其基本语法如下:</p>
<pre><code class="cpp">#include <algorithm> // 需要包含这个头文件
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 反转 vec 中的元素
std::reverse(vec.begin(), vec.end());
// 输出反转后的结果
for (int v : vec) {
std::cout << v << " "; // 输出: 5 4 3 2 1
}
return 0;
}
</code></pre>
<p>2.(DFS,BFS)搜索算法的进化————Dijkstra,A*</p>
<p><img src="/../images/image-20241029160810942.png" alt="image-20241029160810942"></p>
<p>Dijkstra(使用八联通图,可以走斜线)</p>
<p><img src="/../images/image-20241029165736780.png" alt="image-20241029165736780"></p>
<p>为什么: 如果distance._current大于distance[current]: 继续下一次循环</p>
<ol>
<li><ul>
<li><p>优先队列会按照节点的最小距离进行排序。可能在多个阶段,一个节点被加入队列,但这些加入可能是基于旧的距离值。</p>
</li>
<li><p>当我们从队列中弹出一个节点时,这个节点的距离可能并不是它的最短距离(因为它可能已经被更短的路径更新过)。</p>
</li>
<li><p>如果当前弹出的节点的距离大于我们在 <code>distance</code> 数组中记录的最短距离,这意味着我们已经找到了一条更短的路径到达这个节点,因此可以跳过对这个节点的处理。</p>
</li>
</ul>
</li>
</ol>
<p>A*(优化搜索速度)</p>
<p>A*的核心思想:不但考虑七点到当前节点的代价值,还要考虑当前节点到目标点的代价值</p>
<p><img src="/../images/image-20241029212450000.png" alt="image-20241029212450000"><img src="/../images/image-20241029212535602.png" alt="image-20241029212535602"></p>
<p>这里的估算函数叫启发式函数</p>
<p>常用的启发式函数</p>
<p><img src="/../images/image-20241029213145988.png" alt="image-20241029213145988"></p>
<p>注意:曼哈顿距离>真实距离(有可能无法保证路径最优),但就因为它比较大,所以有时候它的效果最好</p>
<p><img src="/../images/image-20241029213403921.png" alt="image-20241029213403921"></p>
<p><img src="/../images/image-20241029215149569.png" alt="image-20241029215149569"></p>
<p>A*算法的最优性保证:</p>
<p>只有满足条件,A*所得的路径才是最短路径</p>
<p><img src="/../images/image-20241029220508538.png" alt="image-20241029220508538"></p>
<p><img src="/../images/image-20241029220721469.png" alt="image-20241029220721469"></p>
<p><img src="/../images/image-20241030000750748.png" alt="image-20241030000750748"></p>
<p><img src="/../images/image-20241029234519659.png" alt="image-20241029234519659"></p>
<p>启发函数的选择:</p>
<p><img src="/../images/image-20241029234454890.png" alt="image-20241029234454890"></p>
<p>A*的平衡性问题:</p>
<p>虽然A* 算法的结果和理想结果的路径都是最短的,但是理想结果的转折更少,更适合使用,而且A* 算法搜索的节点还是有点多</p>
<p><img src="/../images/image-20241030000139507.png" alt="image-20241030000139507"></p>
<p>怎么解决呢?</p>
<p>从Dijkstra到A *增加了一个指标,效果大大提升,那再加一个指标</p>
<p><img src="/../images/image-20241030000250579.png" alt="image-20241030000250579"></p>
<p>在实际工程上,DFS会用递归方法实现</p>
<p><img src="/../images/image-20241030001223316.png" alt="image-20241030001223316"></p>
<h4 id="一种有趣的搜索思路:JPS"><a href="#一种有趣的搜索思路:JPS" class="headerlink" title="一种有趣的搜索思路:JPS"></a>一种有趣的搜索思路:JPS</h4><p><img src="/../images/image-20241030081738023.png" alt="image-20241030081738023"></p>
<p>JPS是一种跳跃式搜索算法:关注障碍物边缘的关键性节点(最短路径是起点+障碍物边缘节点+终点)</p>
<p>解决A *算法的平衡性问题</p>
<p>强迫邻居是必须要探索的点(强迫邻居有可能就是绕过障碍物的关键节点)</p>
<p>跳点和强迫邻居都需要继续拓展,所以都要加到openlist里面</p>
<p>这就是向前看规则:</p>
<p><img src="/../images/image-20241030090946938.png" alt="image-20241030090946938"></p>
<p>跳跃规则: </p>
<p>起点的八个邻居都需要加入到openlist里,都需要拓展</p>
<p><img src="/../images/image-20241030091816758.png" alt="image-20241030091816758"></p>
<p>八邻域探索方向可分为正向和对角线方向</p>
<p><img src="/../images/image-20241030092325008.png" alt="image-20241030092325008"></p>
<p>A*会八个方向一圈一圈的探索,JPS是只沿一个方向探索:</p>
<p><img src="/../images/image-20241030092925681.png" alt="image-20241030092925681"></p>
<p><img src="/../images/image-20241030102440054.png" alt="image-20241030102440054"></p>
<p><img src="/../images/image-20241030102733661.png" alt="image-20241030102733661"></p>
<p><img src="/../images/image-20241030103012358.png" alt="image-20241030103012358"></p>
<p><img src="/../images/image-20241030111828675.png" alt="image-20241030111828675"></p>
<p>对比:</p>
<p><img src="/../images/image-20241030113042835.png" alt="image-20241030113042835"></p>
<p>蓝色是被拓展过并添加到openlist里的,绿色是没有拓展过但是添加到openlist里的,右图里灰色是访问过的点</p>
<p>A*的openlist里的节点更多</p>
<p><img src="/../images/image-20241030124811683.png" alt="image-20241030124811683"></p>
<h4 id="从容应对动态障碍物–D-(动态A星算法)"><a href="#从容应对动态障碍物–D-(动态A星算法)" class="headerlink" title="从容应对动态障碍物–D*(动态A星算法)"></a>从容应对动态障碍物–D*(动态A星算法)</h4><p>D* 又称Dynamic A* </p>
<p>初始生成一条最优路径,在跟踪过程中,根据障碍物的变化,实时调整受影响的局部局部路径</p>
<p>算法流程:</p>
<p><img src="/../images/image-20241030130705029.png" alt="image-20241030130705029"></p>
<p>1.方向构建:</p>
<p><img src="/../images/image-20241030135745527.png" alt="image-20241030135745527"></p>
<p>h(X):用来存储路径代价,指从X到达终点G的路径({X,……G},简记为{X})代价,不一定是全局最优,第一次搜索到起点时时,所有点的h会被更新,计算方式同Dijkstra算法,是用相邻两点的代价+上一个点的代价累加得到</p>
<p>k(X):用来记录自X节点被加入到OPEN_LIST中后的最小h(X)值(具体计算方式由Insert函数决定),也是优先队列OPEN_LIST的排序依据,k将会保持到最小,它表示了本点在全图环境中到G点的最小代价(k(x)没有受到障碍物增加的影响)</p>
<p>3,代价修改:</p>
<p><img src="/../images/image-20241030140245818.png" alt="image-20241030140245818"></p>
<p>4,状态处理</p>
<p><img src="/../images/image-20241030141730446.png" alt="image-20241030141730446"></p>
<p><img src="/../images/image-20241030142134552.png" alt="image-20241030142134552"></p>
<p><strong><img src="/../images/image-20241031163648792.png" alt="image-20241031163648792"></strong> </p>
<p>考虑动力学和运动学的路径搜索</p>
<p><img src="/../images/image-20241031164340672.png" alt="image-20241031164340672"></p>
<p>优化了节点的扩展方式,节点不一定是栅格的中心(弧形路径)</p>
<p><img src="/../images/image-20241031164749998.png" alt="image-20241031164749998"></p>
<p>优化了启发式函数</p>
<p><img src="/../images/image-20241031170710478.png" alt="image-20241031170710478"></p>
<p><img src="/../images/image-20241031171111390.png" alt="image-20241031171111390"></p>
<p>搜索到的路径还要进行轨迹优化</p>
<p><img src="/../images/image-20241031171824387.png" alt="image-20241031171824387"></p>
<p>轨迹优化——Min-Jerk(jerk是加加速度)</p>
<p><img src="/../images/image-20241031173115830.png" alt="image-20241031173115830"></p>
<ol>
<li></li>
</ol>
<p><img src="/../images/image-20241031173311282.png" alt="image-20241031173311282"></p>
<p><img src="/../images/image-20241031173953976.png" alt="image-20241031173953976"></p>
<p>贝塞尔曲线把对连续曲线的规划,转变为对控制点的规划</p>
<p>贝塞尔曲线还有一个巨大的优点:导数还是贝塞尔曲线,仍然有控制点</p>
<p>缺点:贝塞尔曲线的形状完全依赖于控制点的数量和位置</p>
<p>移动一个控制点可能会对曲线的整体形状产生意想不到的影响,这使得局部控制变得困难</p>
<p>B样条曲线解决这两个问题</p>
<p><img src="/../images/image-20241031185043102.png" alt="image-20241031185043102"></p>
<p>2.<img src="/../images/image-20241031190211093.png" alt="image-20241031190211093"></p>
<ol start="3">
<li></li>
</ol>
<p><img src="/../images/image-20241031190753360.png" alt="image-20241031190753360"></p>
<ol start="4">
<li></li>
</ol>
<p><img src="/../images/image-20241031191654657.png" alt="image-20241031191654657">Min-Jerk是舒适性,Min-Snap是节省燃料</p>
<h3 id="lattice-planner"><a href="#lattice-planner" class="headerlink" title="lattice planner"></a>lattice planner</h3><p><img src="/../images/image-20241031192442070.png" alt="image-20241031192442070"></p>
<ol>
<li></li>
</ol>
<p><img src="/../images/image-20241031192808923.png" alt="image-20241031192808923"></p>
<p><img src="/../images/image-20241031193006723.png" alt="image-20241031193006723"></p>
<ol start="2">
<li></li>
</ol>
<p><img src="/../images/image-20241031195516780.png" alt="image-20241031195516780"></p>
<h3 id="轨迹跟踪"><a href="#轨迹跟踪" class="headerlink" title="轨迹跟踪"></a>轨迹跟踪</h3><p><img src="/../images/image-20241031195747013.png" alt="image-20241031195747013"></p>
<p><img src="/../images/image-20241031201328125.png" alt="image-20241031201328125"></p>
<p><img src="/../images/image-20241031201528244.png" alt="image-20241031201528244"></p>
<p><img src="/../images/image-20241031202702436.png" alt="image-20241031202702436"></p>
<p>Navigation2组成模块</p>
<p><img src="/../images/image-20241101083306228.png" alt="image-20241101083306228"></p>
<p>运行流程:</p>
<p><img src="/../images/image-20241101090545162.png" alt="image-20241101090545162"></p>
<p>功能包:</p>
<p><img src="/../images/image-20241101102148537.png" alt="image-20241101102148537"></p>
<h3 id="Nav2中的地图"><a href="#Nav2中的地图" class="headerlink" title="Nav2中的地图"></a>Nav2中的地图</h3><p>代价地图</p>
<p><img src="/../images/image-20241101103945972.png" alt="image-20241101103945972"></p>
<p><img src="/../images/image-20241101104611414.png" alt="image-20241101104611414"></p>
<p>分层代价地图:(直更新有变化的区域)</p>
<p>论文里的分层:</p>
<p><img src="/../images/image-20241101110059183.png" alt="image-20241101110059183"></p>
<p>Nav2分层:</p>
<p><img src="/../images/image-20241101110624721.png" alt="image-20241101110624721"></p>
<p>(速度过滤器:限速区)</p>
<p>重启蓝牙服务:</p>
<pre><code class="bash">sudo systemctl restart bluetooth
</code></pre>
<p>代价地图局部更新的过程:</p>
<p><img src="/../images/image-20241101143628088.png" alt="image-20241101143628088"></p>
<p>更新边界,更新值</p>
<p>Nav2的核心特点是使用插件机制,插件机制的实现过程是每个层去继承一个基类</p>
<p><img src="/../images/image-20241101144958061.png" alt="image-20241101144958061"></p>
<p><img src="/../images/image-20241101145411730.png" alt="image-20241101145411730"> </p>
<p>膨胀层具体实现:</p>
<p><img src="/../images/image-20241101164120062.png" alt="image-20241101164120062"></p>
<p><img src="/../images/image-20241101164142361.png" alt="image-20241101164142361"></p>
<p><img src="/../images/image-20241101164200699.png" alt="image-20241101164200699"></p>
<p>限速区具体实现:</p>
<p><img src="/../images/image-20241101164645369.png" alt="image-20241101164645369"></p>
<h3 id="配置参数"><a href="#配置参数" class="headerlink" title="配置参数"></a>配置参数</h3><p>机器人坐标系:</p>
<p><img src="/../images/image-20241101175725933.png" alt="image-20241101175725933"></p>
<p>(TF树里只能有一个parent)</p>
<p>代价地图有两张:</p>
<p>全局路径搜索(静态),局部轨迹优化(动态)</p>
<p><img src="/../images/image-20241101180415555.png" alt="image-20241101180415555"></p>
<p>全局代价地图参数:</p>
<p><img src="/../images/image-20241101182125726.png" alt="image-20241101182125726"></p>
<p>局部代价地图参数:</p>
<p><img src="/../images/image-20241101183829578.png" alt="image-20241101183829578"></p>
<p><code>footprint</code> 是机器人在环境中占据的空间的几何形状。这个形状通常用一组坐标点来表示,形成一个多边形。</p>
<p><code>resolution=0.05</code> 表示地图的分辨率。指每个栅格(grid cell)的大小,以米为单位</p>
<h2 id="全局路径规划服务器"><a href="#全局路径规划服务器" class="headerlink" title="全局路径规划服务器"></a>全局路径规划服务器</h2><p>Planner_Server的功能</p>
<p><img src="/../images/image-20241101190731449.png" alt="image-20241101190731449"></p>
<p>1.对行为树接口:</p>
<p><img src="/../images/image-20241101191646808.png" alt="image-20241101191646808"></p>
<p>(navigation2里面使用了大量的action通信机制)</p>
<p><img src="/../images/image-20241101193625811.png" alt="image-20241101193625811"></p>
<p>2,开启全局代价地图</p>
<p><img src="/../images/image-20241101193934386.png" alt="image-20241101193934386"></p>
<p>3.加载规划算法</p>
<p><img src="/../images/image-20241101203600662.png" alt="image-20241101203600662"></p>
<p>插件机制:</p>
<p><img src="/../images/image-20241101203800248.png" alt="image-20241101203800248"></p>
<p><img src="/../images/image-20241101205003460.png" alt="image-20241101205003460"></p>
<p>planning_server的源码实现:</p>
<p><img src="/../images/image-20241101210227207.png" alt="image-20241101210227207"></p>
<p><img src="/../images/image-20241101211444648.png" alt="image-20241101211444648"></p>
<p><img src="/../images/image-20241101211549670.png" alt="image-20241101211549670"></p>
<p><img src="/../images/image-20241101223410617.png" alt="image-20241101223410617"></p>
<h3 id="planner-server参数配置"><a href="#planner-server参数配置" class="headerlink" title="planner_server参数配置"></a>planner_server参数配置</h3><p><img src="/../images/image-20241101224154321.png" alt="image-20241101224154321"></p>
<p> <img src="/../images/image-20241101225936142.png" alt="image-20241101225936142"></p>
<h2 id="Controller-Server"><a href="#Controller-Server" class="headerlink" title="Controller_Server"></a>Controller_Server</h2><p><img src="/../images/image-20241103224438065.png" alt="image-20241103224438065"></p>
<p>1.接口回调函数(给行为树调用)</p>
<p><img src="/../images/image-20241103225206814.png" alt="image-20241103225206814"></p>
<p><img src="/../images/image-20241103225751593.png" alt="image-20241103225751593"></p>
<p><img src="/../images/image-20241103230254653.png" alt="image-20241103230254653"></p>
<p>2.控制器插件</p>
<p><img src="/../images/image-20241103230812738.png" alt="image-20241103230812738"></p>
<p>重要插件–进度检查器</p>
<p><img src="/../images/image-20241103231323752.png" alt="image-20241103231323752"></p>
<p>重要插件–目标检查器</p>
<p><img src="/../images/image-20241103231740311.png" alt="image-20241103231740311"></p>
<p>控制流程:</p>
<p><img src="/../images/image-20241104000032308.png" alt="image-20241104000032308"></p>
<p>3.开启局部代价地图</p>
<p>和Planner_Server类似</p>
<h3 id="DWB算法详解"><a href="#DWB算法详解" class="headerlink" title="DWB算法详解"></a>DWB算法详解</h3><p><img src="/../images/image-20241104000312567.png" alt="image-20241104000312567"></p>
<p><img src="/../images/image-20241104001209166.png" alt="image-20241104001209166"></p>
<p><img src="/../images/image-20241104001344505.png" alt="image-20241104001344505"> </p>
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/motion-planning.html" data-id="cm2rjbwlo0000kycxa1c9h8rg" data-title="motion_planning" class="article-share-link"><span class="fa fa-share">Share</span></a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/PNC/" rel="tag">PNC</a></li></ul>
</footer>
</div>
</article>
<article id="post-Realsense" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/Realsense.html" class="article-date">
<time class="dt-published" datetime="2024-10-12T06:30:23.000Z" itemprop="datePublished">2024-10-12</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/Realsense.html">Realsense</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<h2 id="pyrealsense-core-module"><a href="#pyrealsense-core-module" class="headerlink" title="pyrealsense.core module"></a>pyrealsense.core module</h2><p>pyrealsense.core.Device(service, device_id=0, streams=None, depth_control_preset=None, ivcam_preset=None)</p>
<p>class pyrealsense.core.DeviceBase(dev, device_id, name, serial, version, streams)</p>
<p>class pyrealsense.core.Service</p>
<h2 id="pyrealsense-stream-module"><a href="#pyrealsense-stream-module" class="headerlink" title="pyrealsense.stream module"></a>pyrealsense.stream module</h2>
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/Realsense.html" data-id="cm25s218300030ncxbcsj7w6f" data-title="Realsense" class="article-share-link"><span class="fa fa-share">Share</span></a>
</footer>
</div>
</article>
<article id="post-C-STL" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/C-STL.html" class="article-date">
<time class="dt-published" datetime="2024-10-11T13:13:31.000Z" itemprop="datePublished">2024-10-11</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/C-STL.html">C++STL</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p>STL 即<strong>标准模板库</strong>(Standard Template Library),是 C++ 标准库的一部分,里面包含了一些模板化的通用的数据结构和算法。由于其模板化的特点,它能够兼容自定义的数据类型,避免大量的造轮子工作。NOI 和 ICPC 赛事都支持 STL 库的使用,因此合理利用 STL 可以避免编写无用算法,并且充分利用编译器对模板库优化提高效率。</p>
<p><a target="_blank" rel="noopener" href="https://www.boost.org/">Boost</a> 是除了标准库外,另一个久副盛名的开源 C++ 工具库,其代码具有可移植、高质量、高性能、高可靠性等特点。Boost 中的模块数量非常之大,功能全面,并且拥有完备的跨平台支持,因此被看作 C++ 的准标准库。C++ 标准中的不少特性也都来自于 Boost,如智能指针、元编程、日期和时间等。尽管在 OI 中无法使用 Boost,但是 Boost 中有不少轮子可以用来验证算法或者对拍,如 Boost.Geometry 有 R 树的实现,Boost.Graph 有图的相关算法,Boost.Intrusive 则提供了一套与 STL 容器用法相似的侵入式容器。</p>
<h2 id="STL-容器"><a href="#STL-容器" class="headerlink" title="STL 容器"></a>STL 容器</h2><p><img src="/../images/container1.png" alt="img"></p>
<h3 id="分类:"><a href="#分类:" class="headerlink" title="分类:"></a>分类:</h3><h4 id="1-序列式-容器"><a href="#1-序列式-容器" class="headerlink" title="1. ==序列式==容器"></a>1. ==序列式==容器</h4><ul>
<li>vector(向量)后端可高效增加元素的顺序表.</li>
<li>array(数组),定长的顺序表。</li>
<li>deque(双端队列)双端可高效增加元素的顺序表。</li>
<li>list(列表)可以沿双向遍历的链表。</li>
<li>forward_list(单向列表)只能沿一个方向遍历的链表。</li>
</ul>
<h4 id="2,-关联式-容器"><a href="#2,-关联式-容器" class="headerlink" title="2,==关联式==容器"></a>2,==关联式==容器</h4><ul>
<li>set(集合)有序储存互异元素的容器<ul>
<li>不允许重复元素。存储唯一的元素,且自动按升序排序。</li>
<li>元素的插入、删除和查找操作的时间复杂度为O(log n)。</li>
</ul>
</li>
<li>multiset(多重集合)允许存储重复的元素,且也会自动按升序排序<ul>
<li>允许重复元素。</li>
<li>与<code>set</code>类似,插入、删除和查找操作的时间复杂度同样为O(log n)。</li>
</ul>
</li>
<li>map(映射)由{建,值}对组成的集合(也是集合)<ul>
<li><strong>唯一性</strong>:每个键只能出现一次;如果插入一个已存在的键,则会更新其对应的值。</li>
<li><strong>有序性</strong>:<code>map</code>中的元素会根据键自动排序,默认情况下是升序排列。</li>
<li><strong>时间复杂度</strong>:插入、删除和查找操作的平均时间复杂度为O(log n)。</li>
</ul>
</li>
</ul>
<h4 id="3,无序-并联式-容器"><a href="#3,无序-并联式-容器" class="headerlink" title="3,无序(并联式)容器"></a>3,无序(并联式)容器</h4><ul>
<li><strong>无序(多重)集合</strong>(<code>unordered_set</code>/<code>unordered_multiset</code>)<strong>C++11</strong>,与 <code>set</code>/<code>multiset</code> 的区别在于元素无序,只关心「元素是否存在」,使用哈希实现。<ul>
<li><strong>唯一性</strong>:<code>unordered_set</code> 中的每个元素都是唯一的,不能重复。</li>
<li><strong>无序性</strong>:元素的排列是基于哈希值的,不按照任何特定顺序存储。</li>
<li><strong>性能</strong>:插入、查找和删除操作的平均时间复杂度为 O(1),但在最坏情况下可能会退化为 O(n)</li>
</ul>
</li>
<li><strong>无序(多重)映射</strong>(<code>unordered_map</code>/<code>unordered_multimap</code>)<strong>C++11</strong>,与 <code>map</code>/<code>multimap</code> 的区别在于键 (key) 无序,只关心 “键与值的对应关系”,使用哈希实现。</li>
</ul>
<h4 id="容器适配器"><a href="#容器适配器" class="headerlink" title="容器适配器"></a>容器适配器</h4><p>容器适配器其实并不是容器。它们不具有容器的某些特点(如:有迭代器、有 <code>clear()</code> 函数……)。</p>
<p> 「适配器是使一种事物的行为类似于另外一种事物行为的一种机制」,适配器对容 器进行包装,使其表现出另外一种行为。</p>
<ul>
<li><strong>栈</strong>(<code>stack</code>) 后进先出 (LIFO) 的容器,默认是对双端队列(<code>deque</code>)的包装。</li>
<li><strong>队列</strong>(<code>queue</code>) 先进先出 (FIFO) 的容器,默认是对双端队列(<code>deque</code>)的包装。</li>
<li><strong>优先队列</strong>(<code>priority_queue</code>) 元素的次序是由作用于所存储的值对上的某种谓词决定的的一种队列,默认是对向量(<code>vector</code>)的包装。</li>
</ul>
<h4 id="容器声明"><a href="#容器声明" class="headerlink" title="容器声明"></a>容器声明</h4><p>都是 <code>containerName<typeName,...> name</code> 的形式,但模板参数(<code><></code> 内的参数)的个数、形式会根据具体容器而变。</p>
<p>本质原因:STL 就是「标准模板库」,所以容器都是模板类。</p>
<h4 id="容器共有函数"><a href="#容器共有函数" class="headerlink" title="容器共有函数"></a>容器共有函数</h4><p>= :赋值运算符,赋值构造函数</p>
<p>begain() :返回指向开头元素的迭代器</p>
<p>end():返回指向末尾的下一个元素的迭代器。<code>end()</code> 不指向某个元素.end() 迭代器指向的是一个“哨兵”位置,表示容器的结束。可以用来判断迭代是否完成。</p>
<p>size():返回容器内的元素个数</p>
<p><code>max_size()</code>:返回容器 理论上 能存储的最大元素个数。依容器类型和所存储变量的类型而变。</p>
<p><code>empty()</code>:返回容器是否为空。</p>
<p><code>swap()</code>:交换两个容器。</p>
<p><code>clear()</code>:清空容器。</p>
<p><code>==</code>/<code>!=</code>/<code><</code>/<code>></code>/<code><=</code>/<code>>=</code>:按 <strong>字典序</strong> 比较两个容器的大小.无序容器不支持 <code><</code>/<code>></code>/<code><=</code>/<code>>=</code>。</p>
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/C-STL.html" data-id="cm25s217y00000ncxdg95b2ai" data-title="C++STL" class="article-share-link"><span class="fa fa-share">Share</span></a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/C-STL/" rel="tag">C++STL</a></li></ul>
</footer>
</div>
</article>
<article id="post-kinematics" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/kinematics.html" class="article-date">
<time class="dt-published" datetime="2024-10-07T14:26:21.000Z" itemprop="datePublished">2024-10-07</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/kinematics.html">kinematics</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p><img src="/../images/image-20241009151945396.png" alt="image-20241009151945396"></p>
<p><img src="/../images/image-20241011082114462.png" alt="image-20241011082114462"></p>
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/kinematics.html" data-id="cm24he2gj0000pzcx40pwa14w" data-title="kinematics" class="article-share-link"><span class="fa fa-share">Share</span></a>
<ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/robot-kinematics/" rel="tag">robot_kinematics</a></li></ul>
</footer>
</div>
</article>
<article id="post-Webots" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/Webots.html" class="article-date">
<time class="dt-published" datetime="2024-10-03T08:34:22.000Z" itemprop="datePublished">2024-10-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/Webots.html">Webots</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p>WARNING: To drag this element, first rotate the view so that the horizontal plane is clearly visible.</p>
<p>旋转到水平面上再shift+左键<img src="/../images/image-20241003163738576.png" alt="image-20241003163738576"></p>
<p>右键平移</p>
<p>保存:Ctrl shift s</p>
<p>向导:<br>1.新建项目目录向导(新建场景)</p>
<p>2.新建机器人控制器向导(新建控制器)</p>
<p><img src="/../images/image-20241004122441260.png" alt="image-20241004122441260"></p>
<p>只有机器人节点才能导出urdf文件</p>
<p>转换完后的文件放到protos目录下<br><img src="/../images/image-20241004122612323.png" alt="image-20241004122612323"></p>
<p>在 Webots 中,<code>Solid</code> 节点用于定义具有物理属性的物体,主要用于仿真中的动态交互。它包含了物理模拟所需的各种参数,如质量、摩擦力和弹性等。</p>
<p>在 Webots 中,<code>Shape</code> 节点用于定义物体的外观和几何形状。</p>
<p><code>Solid</code> 节点通常与 <code>Shape</code> 节点结合使用,以创建既有外观又具物理特性的对象</p>
<ol>
<li>**形状 (Geometry)**:指的是物体的几何结构和形式,比如它是一个立方体、球体、圆柱体等。形状决定了物体在空间中的占用区域,以及与其他物体的交互和碰撞。</li>
<li>**外观 (Appearance)**:指的是物体的视觉特征,如颜色、材质、纹理等。外观影响的是物体的视觉效果,而不是其物理结构。</li>
</ol>
<p><img src="/../images/image-20241026190357404.png" alt="image-20241026190357404"></p>
<p><img src="/../images/image-20241026210538601.png" alt="image-20241026210538601"></p>
<p><img src="/../images/image-20241026212402481.png" alt="image-20241026212402481"></p>
<p><img src="/../images/image-20241027094729155.png" alt="image-20241027094729155"></p>
</div>
<footer class="article-footer">
<a data-url="http://zgh20060114.github.io/post/Webots.html" data-id="cm1t1isj80000qycx3ovfhwj3" data-title="Webots" class="article-share-link"><span class="fa fa-share">Share</span></a>
</footer>
</div>
</article>
<article id="post-ubuntu-nvidia" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
<div class="article-meta">
<a href="/post/ubuntu-nvidia.html" class="article-date">
<time class="dt-published" datetime="2024-10-02T16:44:34.000Z" itemprop="datePublished">2024-10-03</time>
</a>
</div>
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="p-name article-title" href="/post/ubuntu-nvidia.html">ubuntu-nvidia</a>
</h1>
</header>
<div class="e-content article-entry" itemprop="articleBody">
<p>写于2024-10-3-00:46</p>
<p>记录一次把ubnutu20.04de nvidia 驱动搞坏又修复,加上对ubuntu显卡驱动和独显/混显,lightdm/gdm3桌面管理器的理解。</p>
<p>由于webots仿真卡死崩溃,就找到一篇博客说:</p>
<pre><code>glxinfo | grep OpenGL
</code></pre>
<p>确实opengl输出的是intel集显,使用</p>
<pre><code>sudo prime-select nvidia
</code></pre>
<p>再次查看输出:</p>
<pre><code>zgh@zgh-Legion-Y7000P-IAH7:~$ glxinfo | grep OpenGL
OpenGL vendor string: Mesa/X.org
OpenGL renderer string: llvmpipe (LLVM 12.0.0, 256 bits)
</code></pre>
<p>虽然不是nvidia,但好歹不是intel了,而且仿真不会卡死崩溃了</p>
<pre><code>sudo systemctl restart gdm3
/etc/X11/xorg.conf
xrandr
glxinfo | grep OpenGL
nvidia-settings
</code></pre>
<p>####sudo nvidia-xconfig 不要用这个命令,它会生成什么Xorg的配置文件,把你之前能用的显示配置覆盖掉</p>
<p><code>/etc/X11/xorg.conf</code>内容:</p>
<pre><code> # nvidia-xconfig: X configuration file generated by nvidia-xconfig
# nvidia-xconfig: version 535.154.05
Section "ServerLayout"
Identifier "Layout0"
Screen 0 "Screen0" 0 0
InputDevice "Keyboard0" "CoreKeyboard"
InputDevice "Mouse0" "CorePointer"
EndSection
Section "Files"
EndSection
Section "InputDevice"
# generated from default
Identifier "Mouse0"
Driver "mouse"
Option "Protocol" "auto"
Option "Device" "/dev/psaux"
Option "Emulate3Buttons" "no"
Option "ZAxisMapping" "4 5"
EndSection
Section "InputDevice"
# generated from default
Identifier "Keyboard0"
Driver "kbd"
EndSection
Section "Monitor"
Identifier "Monitor0"
VendorName "Unknown"
ModelName "Unknown"
Option "DPMS"
EndSection
Section "Device"
Identifier "Device0"
Driver "nvidia"
VendorName "NVIDIA Corporation"
BusID "PCI:1:0:0"
EndSection
Section "Screen"
Identifier "Screen0"
Device "Device0" #就是要用独立显卡启动
Monitor "Monitor0"
DefaultDepth 24
SubSection "Display"
Depth 24
EndSubSection
EndSection
</code></pre>
<p>如果这样写:</p>
<pre><code>Section "Device"
Identifier "Device0"
Driver "nvidia"
VendorName "NVIDIA Corporation"
BusID "PCI:1:0:0"
EndSection
Section "Screen"
Identifier "Screen0"
Device "Device1"
Monitor "Monitor0"
DefaultDepth 24
SubSection "Display"
Depth 24
EndSubSection
EndSection
Section "Device"
Identifier "Device1"
Driver "intel"
VendorName "Intel Corporation"
Option "TripleBuffer" "true"
Option "TearFree" "true"
Option "DRI" "false" #这三条都是为了防止集显显示桌面的时候画面割裂
BusID "PCI:0:2:0"
EndSection
</code></pre>
<p>是以Intel集显启动,确实有用</p>
<p>但是此时bios里设置的混合显示,只会使用集显,nvidia-settings内容错误,只能显示笔记本屏幕,无法连接外接显示器。</p>