-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
1447 lines (1010 loc) · 157 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 lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/images/logo.svg" color="#222">
<link rel="stylesheet" href="/css/main.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css" integrity="sha256-2H3fkXt6FEmrReK448mDVGKb3WW2ZZw35gI7vqHOE4Y=" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">
<script class="next-config" data-name="main" type="application/json">{"hostname":"mingxingren.github.io","root":"/","images":"/images","scheme":"Pisces","version":"8.5.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":false,"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"},"path":"/search.xml","localsearch":{"enable":true,"trigger":"auto","top_n_per_article":-1,"unescape":false,"preload":false}}</script><script src="/js/config.js"></script>
<meta name="description" content="挖一口自己的井">
<meta property="og:type" content="website">
<meta property="og:title" content="mingxingren的博客">
<meta property="og:url" content="https://mingxingren.github.io/index.html">
<meta property="og:site_name" content="mingxingren的博客">
<meta property="og:description" content="挖一口自己的井">
<meta property="og:locale">
<meta property="article:author" content="mingxingren">
<meta property="article:tag" content="多少句都形容不了我">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="https://mingxingren.github.io/">
<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-Hans","comments":"","permalink":"","path":"index.html","title":""}</script>
<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>mingxingren的博客</title>
<noscript>
<link rel="stylesheet" href="/css/noscript.css">
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
<div class="headband"></div>
<main class="main">
<header class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="切换导航栏" role="button">
</div>
</div>
<div class="site-meta">
<a href="/" class="brand" rel="start">
<i class="logo-line"></i>
<h1 class="site-title">mingxingren的博客</h1>
<i class="logo-line"></i>
</a>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
<i class="fa fa-search fa-fw fa-lg"></i>
</div>
</div>
</div>
<nav class="site-nav">
<ul class="main-menu menu">
<li class="menu-item menu-item-search">
<a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
</a>
</li>
</ul>
</nav>
<div class="search-pop-overlay">
<div class="popup search-popup"><div class="search-header">
<span class="search-icon">
<i class="fa fa-search"></i>
</span>
<div class="search-input-container">
<input autocomplete="off" autocapitalize="off" maxlength="80"
placeholder="搜索..." spellcheck="false"
type="search" class="search-input">
</div>
<span class="popup-btn-close" role="button">
<i class="fa fa-times-circle"></i>
</span>
</div>
<div class="search-result-container no-result">
<div class="search-result-icon">
<i class="fa fa-spinner fa-pulse fa-5x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="toggle sidebar-toggle" role="button">
<span class="toggle-line"></span>
<span class="toggle-line"></span>
<span class="toggle-line"></span>
</div>
<aside class="sidebar">
<div class="sidebar-inner sidebar-overview-active">
<ul class="sidebar-nav">
<li class="sidebar-nav-toc">
文章目录
</li>
<li class="sidebar-nav-overview">
站点概览
</li>
</ul>
<div class="sidebar-panel-container">
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
<img class="site-author-image" itemprop="image" alt="mingxingren"
src="/images/avatar01.png">
<p class="site-author-name" itemprop="name">mingxingren</p>
<div class="site-description" itemprop="description">挖一口自己的井</div>
</div>
<div class="site-state-wrap site-overview-item animated">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/archives">
<span class="site-state-item-count">18</span>
<span class="site-state-item-name">日志</span>
</a>
</div>
<div class="site-state-item site-state-tags">
<span class="site-state-item-count">19</span>
<span class="site-state-item-name">标签</span>
</div>
</nav>
</div>
</div>
</div>
</div>
</aside>
<div class="sidebar-dimmer"></div>
</header>
<div class="back-to-top" role="button" aria-label="返回顶部">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<noscript>
<div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>
<div class="main-inner index posts-expand">
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2022/09/14/%E7%A7%91%E7%9B%AE%E4%B8%89%E8%80%83%E8%AF%95%E7%AC%94%E8%AE%B0/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2022/09/14/%E7%A7%91%E7%9B%AE%E4%B8%89%E8%80%83%E8%AF%95%E7%AC%94%E8%AE%B0/" class="post-title-link" itemprop="url">科目三考试笔记</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2022-09-14 18:47:00" itemprop="dateCreated datePublished" datetime="2022-09-14T18:47:00+08:00">2022-09-14</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2023-08-14 23:33:29" itemprop="dateModified" datetime="2023-08-14T23:33:29+08:00">2023-08-14</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="远近交替"><a href="#远近交替" class="headerlink" title="远近交替"></a>远近交替</h2><p>① 应用场景: 急弯、坡路、拱桥</p>
<p>② 通过人行横道 没有交通信号的路口</p>
<p>③ 超车</p>
<h2 id="远光灯"><a href="#远光灯" class="headerlink" title="远光灯"></a>远光灯</h2><p>① 夜间无照明,照明不良的道路行驶</p>
<h2 id="近光灯"><a href="#近光灯" class="headerlink" title="近光灯"></a>近光灯</h2><p>① 近距离跟车行驶</p>
<p>② 照明良好的道路</p>
<p>③ 有交通信号灯的路口</p>
<p>④ 夜间会车</p>
<h2 id="示廓灯-危险警报灯"><a href="#示廓灯-危险警报灯" class="headerlink" title="示廓灯+危险警报灯"></a>示廓灯+危险警报灯</h2><p>① 路边临时停车,提示他人注意</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2022/07/28/C#%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2022/07/28/C#%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/" class="post-title-link" itemprop="url">C#知识整理</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2022-07-28 10:23:00" itemprop="dateCreated datePublished" datetime="2022-07-28T10:23:00+08:00">2022-07-28</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2022-08-03 11:47:06" itemprop="dateModified" datetime="2022-08-03T11:47:06+08:00">2022-08-03</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<ol>
<li><p>C# 函数传递地址的方式有</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">static void AddSum(ref int i, int j)</span><br><span class="line">{</span><br><span class="line"> i += j;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 调用</span><br><span class="line">AddSum(ref a, b);</span><br></pre></td></tr></table></figure></li>
<li><p>C# 中的数据类型分 <code>值类型</code> 和 <code>引用类型</code>.</p>
<p>① 值类型: 直接存储数据的值, 保存在内存中. 一些预定义简单类型, 例如: <code>int</code>, <code>float</code>, <code>bool</code>, <code>char</code> 都是值类型, 另外 <code>enum</code>, <code>struct</code> 也是值类型</p>
<p>② 引用类型: 存储对值的引用, 实际上存储的就是一个内存的地址. <code>string</code>, <code>数组</code>,<code>class</code>, <code>interface</code>, <code>委托</code>和 <code>封装</code> 都是引用类型,其中 string 是比较特殊的引用类型</p>
</li>
<li><p>C# 泛型编程使用 <code>where</code> 约束</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"> 约束 说明</span><br><span class="line"> T: struct 类型参数必须是值类型. 可以指定除 Nullable 以外的任何值类型</span><br><span class="line"> </span><br><span class="line"> T: class 类型参数必须是引用类型,包括任何类、接口、委托或者数组类型</span><br><span class="line"> </span><br><span class="line"> T:new() 类型参数必须具有无参数的公共构造函数. 当与其他约束一起使用时, new()</span><br><span class="line"> 约束必须最后指定</span><br><span class="line"> </span><br><span class="line"> T:<基类名> 类型参数必须是指定的基类或派生自指定的基类</span><br><span class="line"> </span><br><span class="line"> T:<接口名称> 类型参数必须是指定的接口或者实现指定的接口. 可以指定多个接口约束. 约束</span><br><span class="line"> 接口也可以是泛型的</span><br><span class="line"> </span><br><span class="line"> T: U 为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数.</span><br><span class="line"> 这称为裸类型约束</span><br></pre></td></tr></table></figure></li>
<li><p>C# params 关键字</p>
<p>在 C# 中, 使用 <code>params</code> 关键字可以给一个方法 (method) 传递数量可变的参数 ( paramter ), 类似于<code>python</code> 中的 <code>*arg</code></p>
<p>注:</p>
<p>① <code>params</code>后面的参数类型必须是一个数组</p>
<p>② <code>params</code>后面不允许再有其他参数</p>
<p>③ 一个方法的申明中只能又一个 <code>params</code> 关键字</p>
<p>传递方式:</p>
<p>① 用逗号分隔的一串参数</p>
<p>② 一个一维数组</p>
<p>③ 空参数, <code>length</code> 为 0</p>
</li>
</ol>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2022/07/13/%E7%9C%9F%E5%BF%83%E4%B8%BA%E4%BD%A0/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2022/07/13/%E7%9C%9F%E5%BF%83%E4%B8%BA%E4%BD%A0/" class="post-title-link" itemprop="url">真心为你</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2022-07-13 22:17:00 / 修改时间:22:19:44" itemprop="dateCreated datePublished" datetime="2022-07-13T22:17:00+08:00">2022-07-13</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id=""><a href="#" class="headerlink" title=""></a></h1><h1 id="真心为你"><a href="#真心为你" class="headerlink" title="真心为你"></a>真心为你</h1>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2022/06/21/%E5%85%89%E7%85%A7/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2022/06/21/%E5%85%89%E7%85%A7/" class="post-title-link" itemprop="url">光照</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2022-06-21 16:04:00 / 修改时间:16:05:12" itemprop="dateCreated datePublished" datetime="2022-06-21T16:04:00+08:00">2022-06-21</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="光照"><a href="#光照" class="headerlink" title="光照"></a>光照</h1><h2 id="简单的颜色叠加"><a href="#简单的颜色叠加" class="headerlink" title="简单的颜色叠加"></a>简单的颜色叠加</h2><p>两个颜色向量相乘等于最终的反射颜色</p>
<h2 id="基础光照"><a href="#基础光照" class="headerlink" title="基础光照"></a>基础光照</h2><p>① 环境光照(Ambient Lighting): 即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的. 为了模拟这个,我们会使用一个环境光照常量,它永远给物体一些颜色.</p>
<p>实现: 用光的颜色乘以一个很小常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色.</p>
<figure class="highlight glsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> main() {</span><br><span class="line"> <span class="type">float</span> ambientStrength = <span class="number">0.1</span>;</span><br><span class="line"> <span class="type">vec3</span> ambient = ambientStrength * lightColor;</span><br><span class="line"> </span><br><span class="line"> <span class="type">vec3</span> result = ambient * objectColor;</span><br><span class="line"> FragColor = <span class="type">vec4</span>(result, <span class="number">1.0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>② 漫反射光照(Diffuse Lighting): 模拟光源对物体的方向性影响(Directional Impact). 它是冯氏光照模型中视觉上最显著的分量. 物体的某一个部分越是正对着光源,它就会越亮.</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">1. 算出 光源点指向着色点 的单位向量</span><br><span class="line">2. 单位向量与平面法线向量点乘 算出光线向量是否在法线方向有大于0的分量</span><br><span class="line">3. 与 光的颜色 相乘算出 光通过反射损失后的系数 a</span><br><span class="line">4. a 与 环境光系数相加得出 b</span><br><span class="line">5. b 与 物体表面颜色相乘得出最终颜色</span><br></pre></td></tr></table></figure>
<p>注: 每当我们应用一个不等比缩放时(等比缩放不会破坏法线,因为法线的方向没被改变,仅仅改变法线的长度,很容易通过标准化来修复), 法向量就不会再垂直于对应表面了,这样光照就会破坏. 可以使用 <code>法线矩阵</code> 来移除对法向量错误缩放的影响</p>
<figure class="highlight glsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Normal = <span class="type">mat3</span>(<span class="built_in">transpose</span>(<span class="built_in">inverse</span>(model))) * aNormal;</span><br></pre></td></tr></table></figure>
<p><code>矩阵求逆是一项对于着色器开销很大的运算,因为它必须再场景中的每一个顶点上进行,所以应该尽可能地避免在着色器中进行求逆运算. 所以我们需要在 CPU 上计算出法线矩阵,然后再通过 uniform 把它传递给着色器在GPU资源中做计算</code></p>
<p>③ 镜面光照(Specular Lighting): 模拟有光泽物体上面出现的亮点. 镜面光照的颜色相比于物体的颜色会更倾向于光的颜色.</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">1. 获取观察者坐标</span><br><span class="line">2. 获取着色点指向观察点的向量 a </span><br><span class="line">3. 通过入射光和法线算出反射光线 b</span><br><span class="line">4. a 和 b 点乘</span><br><span class="line">5. 根据 反光度(Shininess) 算出高光系数</span><br><span class="line">glsl code eg:</span><br><span class="line"> vec3 result = (ambient + diffuse + specular) * objectColor;</span><br><span class="line"> FragColor = vec4(result, 1.0);</span><br></pre></td></tr></table></figure>
<h2 id="材质"><a href="#材质" class="headerlink" title="材质"></a>材质</h2><p>现实世界里,每个物体会对光产生不同的反应. 比如,钢制物体看起来通常会比陶土花瓶更闪闪发光,一个木头箱子也不会与一个钢制箱子反射同样程度的光. 有些物体反射光的时候不会有太多的散射(Scatter), 因而产生较小的高光点,而有些物体会散射很多,产生一个有着更大半径的高光点. 如果我们想要在 <code>OpenGL</code> 中模拟多种类型的物体,需要对每种表面定义不同的<code>材质</code>属性</p>
<figure class="highlight glsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line">struct Meterial {</span><br><span class="line"> <span class="type">vec3</span> ambient; <span class="comment">// 环境光</span></span><br><span class="line"> <span class="type">vec3</span> diffuse; <span class="comment">// 漫反射</span></span><br><span class="line"> <span class="type">vec3</span> specular; <span class="comment">// 镜面光照</span></span><br><span class="line"> <span class="type">float</span> shininess; <span class="comment">// 高光系数</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">uniform</span> Material meterial;</span><br></pre></td></tr></table></figure>
<p>在片段着色器中,我们创建一个结构体(Struct)来存储物体的材质属性,我们也可以把它们存储为独立的 <code>uniform</code> 值,但是作为</p>
<p>一个结构体来存储会更有条理一点. 我们首先定义结构体的布局(Layout), 然后简单地以刚创建的结构体作为类型声明一个 <code>uniform</code> 变量.</p>
<p>如你所见,我们为冯氏光照模型的每个分量都定义一个颜色向量. <code>ambient</code> 材质向量定义了在环境光照下这个表面反射的是什么颜色,</p>
<p>通常与表面的颜色相同. <code>diffuse</code> 材质向量定义了在漫反射光照下表面的颜色. 漫反射颜色(和环境光照一样) 也被设置为我们期望的物体颜色. <code>specular</code>材质向量设置的是表面上镜面高光的颜色(或者甚至可能反应一个特定表面的颜色). 最后,<code>shininess</code> 影响镜面高光的散射/半径.</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2022/03/27/%E5%9F%BA%E4%BA%8EFFmpeg%E5%92%8CDX11%E7%9A%84%E6%B5%81%E5%AA%92%E4%BD%93%E8%A7%86%E9%A2%91%E2%80%94%E2%80%94%E7%BF%BB%E8%AF%91/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2022/03/27/%E5%9F%BA%E4%BA%8EFFmpeg%E5%92%8CDX11%E7%9A%84%E6%B5%81%E5%AA%92%E4%BD%93%E8%A7%86%E9%A2%91%E2%80%94%E2%80%94%E7%BF%BB%E8%AF%91/" class="post-title-link" itemprop="url">基于FFmpeg和DX11的流媒体视频——翻译</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2022-03-27 20:21:36 / 修改时间:20:28:27" itemprop="dateCreated datePublished" datetime="2022-03-27T20:21:36+08:00">2022-03-27</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h1 id="基于FFMPEG-和-DirectX11的流媒体视频"><a href="#基于FFMPEG-和-DirectX11的流媒体视频" class="headerlink" title="基于FFMPEG 和 DirectX11的流媒体视频"></a>基于FFMPEG 和 DirectX11的流媒体视频</h1><p>事情起因:因为工作需求,我需要使用ffmpeg进行硬解实时视频并显示到屏幕, 但是性能一直不太理想。偶然发现一篇英文博客与我的需求类似,所以我决定翻译这边英文博客,这是原文地址:<a target="_blank" rel="noopener" href="https://medium.com/swlh/streaming-video-with-ffmpeg-and-directx-11-7395fcb372c4">https://medium.com/swlh/streaming-video-with-ffmpeg-and-directx-11-7395fcb372c4</a></p>
<p>在几个月之前,我被分配开发一个低延迟的视频播放器。在之前,我只接触过FFmpeg没接触过DirectX11。但是我认为它应该不难。FFmpeg是非常受欢迎的,DirectX11也出现了很长一段时间了,并且我应该不会用到3D图形或者更复杂的东西。</p>
<p>所以,应该会有一些能借鉴的解码和渲染视频例子,是吧?</p>
<p>但很不幸,没有…, 因此才写这篇文章。</p>
<p>所以下一个对FFmpeg和DirectX11不熟悉的人不必为了显示视频而伤脑筋。</p>
<p>首先,我们需要搞清楚一些重要的事情</p>
<p>① 样例代码需要足够简单。我省略返回码检测的,错误处理等,我的观点是代码例子就只是例子(我会提供更全面得例子,但是你知道,知识产权等等)</p>
<p>② 我不会介绍硬件加速视频解码/渲染原理,因为它有点超出了本文的范围。此外,还有很多其他资源比我能更好地解释它</p>
<p>③ ffmpeg 支持相当多地协议和编码格式。RTSP 和 UDP 的例子都有用它,h264和h265编码同样用到ffmpeg,我相信很多人参考它。</p>
<p>④ 我使用CMake创建此工程,使它不依赖Visual Studio’s 编译平台(因为我们同样需要支持不需要DirectX的渲染)。这让事情变得更加有难度,这就是我为什么提到它</p>
<h2 id="第一步:设置源流和视频解码器"><a href="#第一步:设置源流和视频解码器" class="headerlink" title="第一步:设置源流和视频解码器"></a>第一步:设置源流和视频解码器</h2><p>这是ffmpeg这块的,只是设置格式上下文,解码上下文,和所有ffmpeg需要的结构体。对于此处,我参考了<a target="_blank" rel="noopener" href="https://ffmpeg.org/doxygen/3.4/hw__decode_8c_source.html">这个例子</a>和<a target="_blank" rel="noopener" href="https://github.com/moonlight-stream/moonlight-qt/blob/master/app/streaming/video/ffmpeg.cpp">MoonLight</a>的源码。</p>
<p>注意你需要以某种方式向 AVCodecContext 提供硬件设备类型。我选择与ffmpeg相同的方式执行此操作。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// initialize stream</span></span><br><span class="line"><span class="keyword">const</span> std::string hw_device_name = <span class="string">"d3d11va"</span>;</span><br><span class="line">AVHWDeviceType device_type = <span class="built_in">av_hwdevice_find_type_by_name</span>(hw_device_name.<span class="built_in">c_str</span>());</span><br><span class="line"><span class="comment">// set up codec context</span></span><br><span class="line">AVBufferRef* hw_device_ctx;</span><br><span class="line"><span class="built_in">av_hwdevice_ctx_create</span>(&hw_device_ctx, device_type, <span class="literal">nullptr</span>, <span class="literal">nullptr</span>, <span class="number">0</span>);</span><br><span class="line">codec_ctx->hw_device_ctx = <span class="built_in">av_buffer_ref</span>(hw_device_ctx);</span><br><span class="line"><span class="comment">// open stream</span></span><br></pre></td></tr></table></figure>
<p>一旦设置完成,解码是相当简单的;它仅仅是从源流种获取AVPacket并且将它们解码成AVFrames这些事情。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">AVPacket* packet = <span class="built_in">av_packet_alloc</span>();</span><br><span class="line"><span class="built_in">av_read_frame</span>(format_ctx, packet);</span><br><span class="line"><span class="built_in">avcodec_send_packet</span>(codec_ctx, packet);</span><br><span class="line">AVFrame* frame = <span class="built_in">av_frame_alloc</span>();</span><br><span class="line"><span class="built_in">avcodec_receive_frame</span>(codec_ctx, frame);</span><br></pre></td></tr></table></figure>
<p>这些都是简化的,但组在一起也不需要太麻烦。虽然我还不能将它显示到屏幕上,我想验证是否生成有效的帧,所以我认为我只需将它们写入bitmap来验证。</p>
<p>这里有个小问题</p>
<h2 id="第二步:转换-NV12-为-RGBA"><a href="#第二步:转换-NV12-为-RGBA" class="headerlink" title="第二步:转换 NV12 为 RGBA"></a>第二步:转换 NV12 为 RGBA</h2><p>创建一个 bitmap(并且当它转换成功后,使用DX11 swapchain呈现),我需要RGBA格式的帧。然后这个解码器解出来的是 NV12格式,所以我使用 FFmpeg的<a target="_blank" rel="noopener" href="https://ffmpeg.org/doxygen/0.5/swscale-example_8c-source.html">swscale</a>将 AV_PIX_FMT_NV12 转换成 AV_PIX_FMT_RGBA。</p>
<p>设置 SwsContext就像调用单个函数一样简单</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">SwsContext* conversion_ctx = <span class="built_in">sws_getContext</span>(</span><br><span class="line"> SRC_WIDTH, SRC_HEIGHT, AV_PIX_FMT_NV12,</span><br><span class="line"> DST_WIDTH, DST_HEIGHT, AV_PIX_FMT_RGBA,</span><br><span class="line"> SWS_BICUBLIN | SWS_BITEXACT, <span class="literal">nullptr</span>, <span class="literal">nullptr</span>, <span class="literal">nullptr</span>);</span><br></pre></td></tr></table></figure>
<p>当然,为了使用sws_scale(), 我们需要将帧数据从GPU转换到CPU. 利用ffmpeg的av_hwframe_transfer_data() 。有很多这样的<a target="_blank" rel="noopener" href="https://ffmpeg.org/doxygen/3.4/hw__decode_8c_source.html">例子</a></p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// decode frame</span></span><br><span class="line">AVFrame* sw_frame = <span class="built_in">av_frame_alloc</span>();</span><br><span class="line"><span class="built_in">av_hwframe_transfer_data</span>(sw_frame, frame, <span class="number">0</span>);</span><br><span class="line"><span class="built_in">sws_scale</span>(conversion_ctx, sw_frame->data, sw_frame->linesize, </span><br><span class="line"> <span class="number">0</span>, sw_frame->height, dst_data, dst_linesize);</span><br><span class="line">sw_frame->data = dst_data</span><br><span class="line">sw_frame->linesize = dst_linesize</span><br><span class="line">sw_frame->pix_fmt = AV_PIX_FMT_RGBA</span><br><span class="line">sw_frame->width = DST_WIDTH</span><br><span class="line">sw_frame->height = DST_HEIGHT</span><br></pre></td></tr></table></figure>
<p>这样能正常工作,但作为一个长期解决方案有两个问题.</p>
<ol>
<li>我想从 AVFrame 得到是一个简单字节数组;使用”d3d11va” 给我们帧数据并不是简单字节数组。因此我将硬件名称改成 “dxva”. 通过这种方式,frame->data 就是 uint8_t* 形式的位图。目前它是有效的,但是作为一个长期解决方案,不使用 “d3d11va” 基本没抓住重点</li>
<li>当调用 sws_scale() 将帧转换成RGBA,我们需要将帧从GPU移动到CPU。确实,现在是有效的,但是很明显我们将这步移除</li>
</ol>
<p>所以无论如何都不是完美,但至少我们解出了帧,并以bitmap形式呈现到我们眼前。</p>
<h2 id="第三步:设置-DirectX11-渲染"><a href="#第三步:设置-DirectX11-渲染" class="headerlink" title="第三步:设置 DirectX11 渲染"></a>第三步:设置 DirectX11 渲染</h2><p>如果你还不知道,这是对你的忠告:DirectX11 是完全不同于 DirectX9,完全不同!</p>
<p>经过很多失败的尝试,我复制并粘贴了这个<a href="directxtutorial.com/Lesson.aspx?lessonid=11-4-5">示例</a>,这样我可以开始写代码了。之后将三角形编程了正方形的异常复杂的任务。</p>
<p>此外,我没有在运行时编译着色器,而是选择在编译时编译它们。有那么一瞬间,我想我必须包含一个第三方库才能做到这点。但是它只需要在CMakeList.txt文件中的几行代码。找到 fxc.exe 可执行文件,并使用适当的选项执行命令来编译着色器。(我使用 /Fh 将它们编译成自动生成的头文件)</p>
<h2 id="第四步:交换纹理颜色"><a href="#第四步:交换纹理颜色" class="headerlink" title="第四步:交换纹理颜色"></a>第四步:交换纹理颜色</h2><p>当我得到一个彩虹方块,只需在定义的输入布局中为 TEXCOORD 切换成 COLOR即可。显然,这意味着要改变一些事情:</p>
<ol>
<li>顶点结构现在有 <code>XMFLOAT2</code> (<em>x, y</em>) 对应纹理坐标映射值为 <code>XMFLOAT4</code> (<em>r</em>, <em>g</em>, <em>b</em>, <em>a</em>)</li>
<li>片段着色器需要从纹理中采样而不是我们直接提供颜色,这意味着我们需要一个 sampler</li>
<li>另外,<a target="_blank" rel="noopener" href="http://www.rastertek.com/dx11s2tut05.html">纹理坐标系和位置坐标系是不同的</a></li>
</ol>
<p>当我能渲染一张基础的静态图时,我知道我接近了,剩下的就是将实际位图从帧传输到共享纹理。</p>
<h2 id="第五步:渲染实际的帧"><a href="#第五步:渲染实际的帧" class="headerlink" title="第五步:渲染实际的帧"></a>第五步:渲染实际的帧</h2><p>因为我们的帧仍然是简单的RGBA字节数组,并且我们的 ID3D11Texture2D 是 DXGI_FORMAT_R8G8B8A8_UNORM 的格式。使用 memcpy 就可以了,我们需要根据计算得出来的数组长度:<code>width_in_pixels * height_in_pixels * bytes_per_pixel</code>.</p>
<p>注意我们同样需要调用device context’s <code>Map()</code> 获取能访问纹理底层数据的权限</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// decode and convert frame</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">constexpr</span> <span class="keyword">int</span> BYTES_IN_RGBA_PIXEL = <span class="number">4</span>;</span><br><span class="line">D3D11_MAPPED_SUBRESOURCE ms;</span><br><span class="line">device_context-><span class="built_in">Map</span>(m_texture.<span class="built_in">Get</span>(), <span class="number">0</span>, D3D11_MAP_WRITE_DISCARD, <span class="number">0</span>, &ms);</span><br><span class="line"><span class="built_in">memcpy</span>(ms.pData, frame->data[<span class="number">0</span>], frame->width * frame->height * BYTES_IN_RGBA_PIXEL);</span><br><span class="line">device_context-><span class="built_in">Unmap</span>(m_texture.<span class="built_in">Get</span>(), <span class="number">0</span>);</span><br><span class="line"><span class="comment">// clear the render target view, draw the indices, present the swapchain</span></span><br></pre></td></tr></table></figure>
<h2 id="第六步:渲染实际帧…-可能是正确的"><a href="#第六步:渲染实际帧…-可能是正确的" class="headerlink" title="第六步:渲染实际帧… 可能是正确的"></a>第六步:渲染实际帧… 可能是正确的</h2><p>从我的研究开始,我就知道使用 “d3d11va” 硬件加速解出来 AVFrame 可以使用 DirectX11 进行渲染。哪要怎么做呢?</p>
<p>我需要初始化 <strong>d3d11va hardware device context.</strong> 基本上,FFmpeg解码器需要了解它正在使用D3D11设备。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">AVBufferRef* hw_device_ctx = <span class="built_in">av_hwdevice_ctx_alloc</span>(AV_HWDEVICE_TYPE_D3D11VA);</span><br><span class="line">AVHWDeviceContext* device_ctx = <span class="keyword">reinterpret_cast</span><AVHWDeviceContext*>(hw_device_ctx->data);</span><br><span class="line">AVD3D11VADeviceContext* d3d11va_device_ctx = <span class="keyword">reinterpret_cast</span><AVD3D11VADeviceContext*>(device_ctx->hwctx);</span><br><span class="line"><span class="comment">// m_device is our ComPtr<ID3D11Device></span></span><br><span class="line">d3d11va_device_ctx->device = m_device.<span class="built_in">Get</span>();</span><br><span class="line"><span class="comment">// codec_ctx is a pointer to our FFmpeg AVCodecContext</span></span><br><span class="line">codec_ctx->hw_device_ctx = <span class="built_in">av_buffer_ref</span>(hw_device_ctx);</span><br><span class="line"><span class="built_in">av_hwdevice_ctx_init</span>(codec_ctx->hw_device_ctx);</span><br></pre></td></tr></table></figure>
<p>所以现在,当我把解出来的帧传到渲染器时,不需要将他们传输到CPU上,并且也不要将它们转成RGBA。我们可以简单地这样做:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ComPtr<ID3D11Texture2D> texture = (ID3D11Texture2D*)frame->data[<span class="number">0</span>];</span><br></pre></td></tr></table></figure>
<p>但是我们完成了么,并没有,还差很多。</p>
<p>我们需要将像素格式转成GPU。我们的交换链并没有神奇地开始渲染NV12帧,这意味着从NV12到RGBA转换需要在某个地方进行。现在,它将在GPU中进行,具体来说是在着色器中进行。这是合乎逻辑的;我们不仅是对纹理进行采样,因为纹理格式不是RGBA。为了让我们的着色器为每个像素返回正确的RGBA值,它需要根据纹理的YUV值来计算。</p>
<p>加入另一个着色器资源视图。当这个RGBA片段着色器将单个着色器资源视图作为输入,但是NV12片段着色器实际上需要两个:色度和亮度。因此,我们因此将一个纹理拆分成两个着色器资源视图。(在此之前,我不明白为什么DirectX需要区分纹理和着色器资源视图。天哪,我很高兴他们这样做了)</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// DXGI_FORMAT_R8_UNORM for NV12 luminance channel</span></span><br><span class="line">D3D11_SHADER_RESOURCE_VIEW_DESC luminance_desc = <span class="built_in">CD3D11_SHADER_RESOURCE_VIEW_DESC</span>(m_texture, D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8_UNORM);</span><br><span class="line">m_device-><span class="built_in">CreateShaderResourceView</span>(m_texture, &luminance_desc, &m_luminance_shader_resource_view); </span><br><span class="line"><span class="comment">// DXGI_FORMAT_R8G8_UNORM for NV12 chrominance channel</span></span><br><span class="line">D3D11_SHADER_RESOURCE_VIEW_DESC chrominance_desc = <span class="built_in">CD3D11_SHADER_RESOURCE_VIEW_DESC</span>(texture, D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8_UNORM);</span><br><span class="line">m_device-><span class="built_in">CreateShaderResourceView</span>(m_texture, &chrominance_desc, &m_chrominance_shader_resource_view);</span><br></pre></td></tr></table></figure>
<p>当然,我们还需要确保允许我们的片段着色器访问这些色度和亮度通道。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">m_device_context-><span class="built_in">PSSetShaderResources</span>(<span class="number">0</span>, <span class="number">1</span>, m_luminance_shader_resource_view.<span class="built_in">GetAddressOf</span>());</span><br><span class="line">m_device_context-><span class="built_in">PSSetShaderResources</span>(<span class="number">1</span>, <span class="number">1</span>, m_chrominance_shader_resource_view.<span class="built_in">GetAddressOf</span>());</span><br></pre></td></tr></table></figure>
<p>我们需要将纹理作为共享资源打开,这个ID3D11Texture2D 对象作为渲染器资源视图和FFmpeg 解出来帧的桥梁。我们将新解出来的帧复制到 ID3D11Texture2D 并且从中提取着色器资源视图。它是一种共享资源。</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ComPtr<IDXGIResource> dxgi_resource;</span><br><span class="line">m_texture-><span class="built_in">QueryInterface</span>(__uuidof(IDXGIResource), <span class="keyword">reinterpret_cast</span><<span class="keyword">void</span>**>(dxgi_resource.<span class="built_in">GetAddressOf</span>()));</span><br><span class="line">dxgi_resource-><span class="built_in">GetSharedHandle</span>(&m_shared_handle);</span><br><span class="line">m_device-><span class="built_in">OpenSharedResource</span>(m_shared_handle, __uuidof(ID3D11Texture2D), <span class="keyword">reinterpret_cast</span><<span class="keyword">void</span>**>(m_texture.<span class="built_in">GetAddressOf</span>()));</span><br></pre></td></tr></table></figure>
<p>我们需要改变我们接收复制纹理的方式。很显然每次渲染一帧时创建新的着色器资源视图代价是高昂。而且 <code>memcpy</code> 不再是一个选择因为我们无法简单访问纹理数据。我认为通过调用像 <code>CopySubresourceRegion</code> DirectX 函数来复制解出来的帧到纹理资源</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">ComPtr<ID3D11Texture2D> new_texture = (ID3D11Texture2D*)frame->data[<span class="number">0</span>];</span><br><span class="line"><span class="keyword">const</span> <span class="keyword">int</span> texture_index = frame->data[<span class="number">1</span>];</span><br><span class="line">m_device_context-><span class="built_in">CopySubresourceRegion</span>(</span><br><span class="line"> m_texture.<span class="built_in">Get</span>(), <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, </span><br><span class="line"> new_texture.<span class="built_in">Get</span>(), texture_index, <span class="literal">nullptr</span>);</span><br></pre></td></tr></table></figure>
<p>通过这些更改,我可以放心的告别那些 <code>av_hwframe_transfer_data()</code>和 <code>sws_scale()</code>这些函数,并且终于,向完全集成的FFmpeg-DirectX11视频播放器问好。</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2022/03/16/DirectX11Tutorial/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2022/03/16/DirectX11Tutorial/" class="post-title-link" itemprop="url">DirectX11 Tutorial</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2022-03-16 23:06:23 / 修改时间:23:31:57" itemprop="dateCreated datePublished" datetime="2022-03-16T23:06:23+08:00">2022-03-16</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="DirectX11-Tutorial"><a href="#DirectX11-Tutorial" class="headerlink" title="DirectX11 Tutorial"></a>DirectX11 Tutorial</h2><h3 id="渲染Yuv纹理流程"><a href="#渲染Yuv纹理流程" class="headerlink" title="渲染Yuv纹理流程"></a>渲染Yuv纹理流程</h3><div id="flowchart-0" class="flow-chart"></div>
<h3 id="1-Direct3D初始化-创建ID3D11Device、ID3D11DeviceContext、IDXGISwapChain"><a href="#1-Direct3D初始化-创建ID3D11Device、ID3D11DeviceContext、IDXGISwapChain" class="headerlink" title="1. Direct3D初始化: 创建ID3D11Device、ID3D11DeviceContext、IDXGISwapChain"></a>1. Direct3D初始化: 创建ID3D11Device、ID3D11DeviceContext、IDXGISwapChain</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">ID3D11Device: 显示适配器, 用于创建资源, 常用资源有: 资源类(ID3D11Resource 包括纹理和缓冲区), 视图类以及着色器. 还可以检测系统环境对功能支持</span><br><span class="line"></span><br><span class="line">ID3D11DeviceContext: D3D设备上下文, 可以看做是一个渲染管线. 渲染管线主要负责渲染和计算工作, 它需要绑定来自与它关联的ID3D11Device所创建的各种资源、视图和着色器才能正常运转, 初次之外,它还能够负责对资源的直接读写操作</span><br><span class="line"></span><br><span class="line">IDXGISwapChain: DXGI交换链, 缓存一个或多个表面(2D纹理), 它们都可以称为后备缓冲(backbuffer)的离屏纹理. 前台缓冲区(front buffer)为当前显示在屏幕上的帧.后备缓冲区是我们主要进行渲染的场所. 这些后备缓冲区通过合适的手段成为渲染管线的输出对象. 呈现(Present)有两种方法:</span><br><span class="line">① BitBlt Model(位块传输模型): 将后备缓冲区的数据进行BitBlt(位块传输, 即内容上的拷贝), 传入到DWM(桌面窗口管理器)与DX共享的后备缓冲, 然后进行翻转以显示其内容. 使用这种模型至少需要一个后备缓冲区。这时Win32应用程序最常用使用的方式, 在进行呈现后, 渲染管线仍然是对同一个后备缓冲区进行输出(支持Windows7 及 更高版本)</span><br><span class="line">② Flip Model(翻转模型): 该模型可以避免上一种方式多余复制, 后备缓冲区表面可以直接与DWM内的前台缓冲区进行翻转. 但是需要创建至少两个后备缓冲区, 并且每次完成呈现后通过代码切换到另一个后备缓冲区进行渲染. 该模型可以用于Win32应用程序已经UWP应用程序(需要DX1.2, 支持Window8 及 更高版本)</span><br></pre></td></tr></table></figure>
<figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建显示适配器和用于渲染的IDXGISwapChain</span></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * param pAdapter 视频适配器指针, 传递NULL以使用默认适配器(为IDXGIFactory1::EnumAdapters枚举的第一个适配器)</span></span><br><span class="line"><span class="comment"> * param DriverType 需要什么类型的驱动设备, 一般指 D3D_DRIVER_TYPE_HARDWARE </span></span><br><span class="line"><span class="comment"> * param Software 用于支持软件光栅化设备, 参数总是设定为NULL, 因为我们使用 D3D_DRIVER_TYPE_HARDWARE 类型即硬件渲染, 若使用此功能需要安装一个软件光栅化设备</span></span><br><span class="line"><span class="comment"> * param Flags 设备创建标志, 当以release模式生成程序时,该参数通常设为0(无附加标志值);当以debug模式生成程序时,该参数应设为:D3D11_CREATE_DEVICE_DEBUG用以激活调试层</span></span><br><span class="line"><span class="comment"> * param pFeatureLevels 指向 D3D_FEATURE_LEVEL 数组的指针, 默认为NULL</span></span><br><span class="line"><span class="comment"> * param FeatureLevels pFeatureLevels数组长度</span></span><br><span class="line"><span class="comment"> * param SDKVersion SDK版本, 为 D3D11_SDK_VERSION</span></span><br><span class="line"><span class="comment"> * param pSwapChainDesc 初始化交换链参数</span></span><br><span class="line"><span class="comment"> * param ppSwapChain out</span></span><br><span class="line"><span class="comment"> * param ppDevice out</span></span><br><span class="line"><span class="comment"> * param pFeatureLevel 返回设备功能支持数组中第一个元素</span></span><br><span class="line"><span class="comment"> * param ppImmediateContext out</span></span><br><span class="line"><span class="comment"> **/</span></span><br><span class="line"><span class="function">HRESULT <span class="title">D3D11CreateDeviceAndSwapChain</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"> [in, optional] IDXGIAdapter *pAdapter,</span></span></span><br><span class="line"><span class="params"><span class="function"> D3D_DRIVER_TYPE DriverType,</span></span></span><br><span class="line"><span class="params"><span class="function"> HMODULE Software,</span></span></span><br><span class="line"><span class="params"><span class="function"> UINT Flags,</span></span></span><br><span class="line"><span class="params"><span class="function"> [in, optional] <span class="keyword">const</span> D3D_FEATURE_LEVEL *pFeatureLevels,</span></span></span><br><span class="line"><span class="params"><span class="function"> UINT FeatureLevels,</span></span></span><br><span class="line"><span class="params"><span class="function"> UINT SDKVersion,</span></span></span><br><span class="line"><span class="params"><span class="function"> [in, optional] <span class="keyword">const</span> DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,</span></span></span><br><span class="line"><span class="params"><span class="function"> [out, optional] IDXGISwapChain **ppSwapChain,</span></span></span><br><span class="line"><span class="params"><span class="function"> [out, optional] ID3D11Device **ppDevice,</span></span></span><br><span class="line"><span class="params"><span class="function"> [out, optional] D3D_FEATURE_LEVEL *pFeatureLevel,</span></span></span><br><span class="line"><span class="params"><span class="function"> [out, optional] ID3D11DeviceContext **ppImmediateContext</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure>
<h4 id="DXGI交换链与Direct3D设备的交互"><a href="#DXGI交换链与Direct3D设备的交互" class="headerlink" title="DXGI交换链与Direct3D设备的交互"></a>DXGI交换链与Direct3D设备的交互</h4><p>① 获取交换链后备缓冲区 <strong>ID3D11Texture2D</strong> 接口对象</p>
<p>② 为后备缓冲区创建一个<strong>ID3D11RenderTargetView</strong></p>
<p>③ 通过<strong>ID3D11Device</strong>创建一个<strong>ID3D11Texture2D</strong>用作深度/模板缓冲区, 要求与后备缓冲区等宽高</p>
<p>④ 创建深度/模板视图 <strong>ID3D11DepthStrenilView</strong>, 绑定上步创建的2D纹理</p>
<p>⑤ 通过<strong>ID3D11DeviceContext</strong>, 在渲染管线的输出合并阶段设置渲染目标</p>
<p>⑥ 在渲染管线的光栅化阶段设置好渲染的视图区域</p>
<p><img src="https://github.com/mingxingren/Notes/raw/master/resource/photo/image-2022031601.png" alt="image-01"></p>
<h3 id="2-IDXGISwapChain-创建-ID3D11Texture2D"><a href="#2-IDXGISwapChain-创建-ID3D11Texture2D" class="headerlink" title="2. IDXGISwapChain 创建 ID3D11Texture2D"></a>2. IDXGISwapChain 创建 ID3D11Texture2D</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 返回交换链得后台缓冲</span></span><br><span class="line"><span class="comment"> * param Buffer 从零开始缓冲区, 缓冲区数量由 DXGI_SWAP_CHAIN_DESC.BufferCount 指定</span></span><br><span class="line"><span class="comment"> * param riid in</span></span><br><span class="line"><span class="comment"> * param ppSurface out</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function">HRESULT <span class="title">GetBuffer</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"> UINT Buffer,</span></span></span><br><span class="line"><span class="params"><span class="function"> [in] REFIID riid,</span></span></span><br><span class="line"><span class="params"><span class="function"> [out] <span class="keyword">void</span> **ppSurface</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure>
<h3 id="3-ID3D11Device-CreateRenderTargetView-创建渲染目标视图"><a href="#3-ID3D11Device-CreateRenderTargetView-创建渲染目标视图" class="headerlink" title="3.ID3D11Device::CreateRenderTargetView 创建渲染目标视图"></a>3.ID3D11Device::CreateRenderTargetView 创建渲染目标视图</h3><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 创建用于访问资源数据的渲染目标视图</span></span><br><span class="line"><span class="comment"> * param ID3D12Resource 指定了将要作为渲染目标的资源</span></span><br><span class="line"><span class="comment"> * param pDesc </span></span><br><span class="line"><span class="comment"> * param ppRTView out</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="function">HRESULT <span class="title">CreateRenderTargetView</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function"> [in] ID3D11Resource *pResource,</span></span></span><br><span class="line"><span class="params"><span class="function"> [in, optional] <span class="keyword">const</span> D3D11_RENDER_TARGET_VIEW_DESC *pDesc,</span></span></span><br><span class="line"><span class="params"><span class="function"> [out, optional] ID3D11RenderTargetView **ppRTView</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span>;</span><br></pre></td></tr></table></figure>
<h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><p><a target="_blank" rel="noopener" href="https://www.cnblogs.com/X-Jun/p/9069608.html">DirectX11 With Windows SDK – 01 DirectX初始化</a></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.2.7/raphael.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.6.5/flowchart.min.js"></script><textarea id="flowchart-0-code" style="display: none">start=>start: 开始
end=>end: 结束
op1=>operation: 创建 D3D11Device
op2=>operation: 创建 D3D11Swapchain
op3=>operation: 创建纹理 D3D11Texture
op4=>operation: 创建 ID3D11ShaderResourceView
op5=>operation: 创建渲染目标视图 CreateRenderTargetView
op6=>operation: 将渲染目标视图绑定到渲染管线 OMSetRenderTargets
op7=>operation: 创建 shader 字节码
op8=>operation: 创建 Vertex shader 对象 CreateVertexShader
op9=>operation: 创建 输入布局 CreateInputLayout
op10=>operation: 创建 Pixel shader 对象 CreatePixelShader
start->op1->op2->op3->op4->op5->op6->op7->op9->op10->end</textarea><textarea id="flowchart-0-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("flowchart-0-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-0-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-0", options);</script>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2021/12/22/opengl%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2021/12/22/opengl%E7%9F%A5%E8%AF%86%E6%95%B4%E7%90%86/" class="post-title-link" itemprop="url">OpenGL知识整理</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2021-12-22 00:40:00" itemprop="dateCreated datePublished" datetime="2021-12-22T00:40:00+08:00">2021-12-22</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2022-06-21 16:05:19" itemprop="dateModified" datetime="2022-06-21T16:05:19+08:00">2022-06-21</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="OpenGL-Sharders(着色器)"><a href="#OpenGL-Sharders(着色器)" class="headerlink" title="OpenGL Sharders(着色器)"></a>OpenGL Sharders(着色器)</h2><h3 id="GPU显示数据流程"><a href="#GPU显示数据流程" class="headerlink" title="GPU显示数据流程"></a>GPU显示数据流程</h3><p><img src="https://raw.githubusercontent.com/mingxingren/Notes/master/resource/photo/image-2021123001.png" alt="image-01"></p>
<h3 id="顶点着色器的坐标系统"><a href="#顶点着色器的坐标系统" class="headerlink" title="顶点着色器的坐标系统"></a>顶点着色器的坐标系统</h3><p>顶点着色器的坐标很有意思, 它使用 -1 和 1表示坐标系轴方向上的负边界和正边界. 仔细想想确实应该如此,假使我们想渲染的一块区域的大小是 10x10大小的矩形,那么边界就是 -5 ~ 5,当区域是20x20时,边界便改为 -10~10. 我猜如果以确定边界绘制左边代码便不具有普适性,这个矩形尺寸调整一下,那个矩形尺寸调整一下. 所以统一用 -1 和 1表示边界值, 中间值乘以系数表示其他坐标点,这样就不用受到渲染矩形区域大小的影响.</p>
<p><img src="https://github.com/mingxingren/Notes/raw/master/resource/photo/image-2021120501.png" alt="image-01"></p>
<p>着色器(<strong>Shader</strong>)是运行在GPU上的小程序,这些小程序为图形渲染管线的某个特定部分而运行。使用一种叫 <strong>GLSL</strong> 的类C语言写成,一个典型的着色器有下面的结构</p>
<figure class="highlight glsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version version_number</span></span><br><span class="line"><span class="keyword">in</span> type in_variable_name;</span><br><span class="line"><span class="keyword">in</span> type in_variable_name;</span><br><span class="line"></span><br><span class="line"><span class="keyword">out</span> type out_variable_name;</span><br><span class="line"></span><br><span class="line"><span class="keyword">uniform</span> type uniform_name;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> main()</span><br><span class="line">{</span><br><span class="line"> <span class="comment">// 处理输入并进行一些图形操作</span></span><br><span class="line"> ...</span><br><span class="line"> <span class="comment">// 输出处理过的结果到输出变量</span></span><br><span class="line"> out_variable_name = weird_stuff_we_processed;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="着色器数据输入"><a href="#着色器数据输入" class="headerlink" title="着色器数据输入"></a>着色器数据输入</h3><p>CPU数据通过OpenGL缓冲区发送到GPU</p>
<p><img src="https://github.com/mingxingren/Notes/raw/master/resource/photo/image-2021123002.png" alt="image-02"></p>
<h4 id="glsl支持的数据类型"><a href="#glsl支持的数据类型" class="headerlink" title="glsl支持的数据类型"></a><a target="_blank" rel="noopener" href="https://github.com/qyvlik/GLSL.qml/blob/master/glsl/GLSL%E5%8F%98%E9%87%8F%E5%92%8C%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B.md">glsl支持的数据类型</a></h4><h2 id="双缓冲"><a href="#双缓冲" class="headerlink" title="双缓冲"></a>双缓冲</h2><p>应用程序使用单缓冲绘图时可能会存在图像闪烁的问题。 这是因为生成的图像不是一下子被绘制出来的,而是按照从左到右,由上而下逐像素地绘制而成的。最终图像不是在瞬间显示给用户,而是通过一步一步生成的,这会导致渲染的结果很不真实。为了规避这些问题,我们应用双缓冲渲染窗口应用程序。<strong>前</strong>缓冲保存着最终输出的图像,它会在屏幕上显示;而所有的的渲染指令都会在<strong>后</strong>缓冲上绘制。当所有的渲染指令执行完毕后,我们<strong>交换</strong>(Swap)前缓冲和后缓冲,这样图像就立即呈显出来,之前提到的不真实感就消除了。</p>
<h2 id="OpenGL-调用流程"><a href="#OpenGL-调用流程" class="headerlink" title="OpenGL 调用流程"></a>OpenGL 调用流程</h2><ol>
<li>着色器创建流程</li>
</ol>
<div id="flowchart-0" class="flow-chart"></div>
<ol start="2">
<li>创建 OpenGL 工程对象</li>
</ol>
<div id="flowchart-1" class="flow-chart"></div>
<ol start="3">
<li><p>申请顶点队列对象(VAO)、顶点缓冲对象(VBO)、索引缓冲对象(EBO), 细节参考: (<a target="_blank" rel="noopener" href="https://blog.csdn.net/xiji333/article/details/114934590">https://blog.csdn.net/xiji333/article/details/114934590</a>)</p>
<div id="flowchart-2" class="flow-chart"></div>
<p> 注:顶点缓冲区使用步骤:</p>
<p> </p>
<div id="flowchart-3" class="flow-chart"></div></li>
<li><p>使用 texture(纹理) 流程</p>
<div id="flowchart-4" class="flow-chart"></div></li>
</ol>
<p>片段着色器中的变量和我们程序申请的texture资源是通过纹理单元进行传值的. 其关系大致为:</p>
<div id="sequence-0"></div>
<p>注: OpenGL CPU像素数据向GPU纹理传输细节 —— <a target="_blank" rel="noopener" href="https://www.cnblogs.com/dongguolei/p/11982230.html">glPixelStorei</a></p>
<p>注: glActiveTexture 激活纹理单元后,调用 glBindTexture 会将 纹理绑定到纹理单元,此时如果再调用 glBindTexture 去操作其他纹理,那当前活跃的纹理单元就绑定为其他的纹理。故在要使用纹理的时候,一定要先 glActiveTexture 然后再 glBindTexture 。</p>
<h2 id="opengl-参考资料"><a href="#opengl-参考资料" class="headerlink" title="opengl 参考资料"></a>opengl 参考资料</h2><p><a target="_blank" rel="noopener" href="https://antongerdelan.net/opengl/index.html#onlinetuts">https://antongerdelan.net/opengl/index.html#onlinetuts</a></p>
<h2 id="片段着色器变量"><a href="#片段着色器变量" class="headerlink" title="片段着色器变量"></a>片段着色器变量</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">gl_FragCoord: 记录顶点在窗体的实际坐标, x和y分量是片段的窗口空间(Window-space)坐标, 原点为窗口左下角</span><br><span class="line"></span><br><span class="line">gl_FrontFacing: 当不启用面剔除 (GL_FACE_CULL), gl_FrontFacing 将会告诉我们当前片段是属于正向面的一部分还是背向面的一部分</span><br><span class="line"></span><br><span class="line">gl_FragDepth: 可以设置的当前片段的深度值, 如果着色器没有写入值到gl_FragDepth,它会自动取用gl_FragCoord.z的值</span><br></pre></td></tr></table></figure>
<h2 id="接口块"><a href="#接口块" class="headerlink" title="接口块"></a>接口块</h2><p>接口块的声明和 <code>struct</code> 的声明有点想象,不同的是,现在 根据它是一个输入还是输出块(Block), 使用 <code>in</code> 和 <code>out</code> 关键字来定义</p>
<figure class="highlight glsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// vertex shader</span></span><br><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line"><span class="keyword">layout</span> (<span class="keyword">location</span> = <span class="number">0</span>) <span class="keyword">in</span> <span class="type">vec3</span> aPos;</span><br><span class="line"><span class="keyword">layout</span> (<span class="keyword">location</span> = <span class="number">1</span>) <span class="keyword">in</span> <span class="type">vec2</span> aTexCoords;</span><br><span class="line"></span><br><span class="line"><span class="keyword">uniform</span> <span class="type">mat4</span> model;</span><br><span class="line"><span class="keyword">uniform</span> <span class="type">mat4</span> view;</span><br><span class="line"><span class="keyword">uniform</span> <span class="type">mat4</span> projection;</span><br><span class="line"></span><br><span class="line"><span class="keyword">out</span> VS_OUT</span><br><span class="line">{</span><br><span class="line"> <span class="type">vec2</span> TexCoords;</span><br><span class="line">} vs_out;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> main()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">gl_Position</span> = projection * view * model * <span class="type">vec4</span>(aPos, <span class="number">1.0</span>); </span><br><span class="line"> vs_out.TexCoords = aTexCoords;</span><br><span class="line">} </span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Pixel shader</span></span><br><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line"><span class="keyword">out</span> <span class="type">vec4</span> FragColor;</span><br><span class="line"></span><br><span class="line"><span class="keyword">in</span> VS_OUT</span><br><span class="line">{</span><br><span class="line"> <span class="type">vec2</span> TexCoords;</span><br><span class="line">} fs_in;</span><br><span class="line"></span><br><span class="line"><span class="keyword">uniform</span> <span class="type">sampler2D</span> <span class="built_in">texture</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> main()</span><br><span class="line">{ </span><br><span class="line"> FragColor = <span class="built_in">texture</span>(<span class="built_in">texture</span>, fs_in.TexCoords); </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="uniform-缓冲对象"><a href="#uniform-缓冲对象" class="headerlink" title="uniform 缓冲对象"></a>uniform 缓冲对象</h2><figure class="highlight glsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#version 330 core</span></span><br><span class="line"><span class="keyword">layout</span> (<span class="keyword">location</span> = <span class="number">0</span>) <span class="keyword">in</span> <span class="type">vec3</span> aPos;</span><br><span class="line"></span><br><span class="line"><span class="keyword">layout</span> (<span class="keyword">std140</span>) <span class="keyword">uniform</span> Matrices</span><br><span class="line">{</span><br><span class="line"> <span class="type">mat4</span> projection;</span><br><span class="line"> <span class="type">mat4</span> view;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">uniform</span> <span class="type">mat4</span> model;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> main()</span><br><span class="line">{</span><br><span class="line"> <span class="built_in">gl_Position</span> = projection * view * model * <span class="type">vec4</span>(aPos, <span class="number">1.0</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>uniform buffer object 比 独立的uniform的好处:</p>
<p>① 一次设置很多 uniform会比一个一个设置要快很多</p>
<p>② 可以同时修改多个 shader程序中的 uniform 变量</p>
<p>③ 如果使用Uniform缓冲对象的话,你可以在着色器中使用更多的uniform。OpenGL限制了它能够处理的uniform数量,这可以通过GL_MAX_VERTEX_UNIFORM_COMPONENTS来查询</p>
<h2 id="几何着色器"><a href="#几何着色器" class="headerlink" title="几何着色器"></a>几何着色器</h2><p>几何着色器的输入是一个的图元(如点或者三角形)的一组顶点, 可以在顶点发送到下一个着色器阶段之前对他们随意变换.</p>
<h2 id="实例化"><a href="#实例化" class="headerlink" title="实例化"></a>实例化</h2><p>在需要渲染大量物体时, 非常消耗性能. 与绘制顶点本身相比,使用 <code>glDrawArrays</code>和 <code>glDrawElements</code> 函数告诉GPU去绘制你的顶点数据会消耗更多的性能, 因为 OpenGL 绘制顶点数据前需要做很多工作(比如告诉GPU该从哪个缓冲读取数据, 从哪寻找顶点数据属性, 而且这些都是在相对缓慢的CPU到GPU总线上进行的).</p>
<p>而实例化能够降数据一次性发给GPU, 然后使用一个绘制函数让OpenGL利用这些数据绘制多个物体.</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* glDrawArraysInstanced 绘画多个一组顶点的实例</span></span><br><span class="line"><span class="comment">* @param mode 指出要画的基本形状</span></span><br><span class="line"><span class="comment">* @param first 顶点数据起点</span></span><br><span class="line"><span class="comment">* @param count 基本形状需要使用的顶点数据</span></span><br><span class="line"><span class="comment">* @param instancecount 要绘画的实例数量</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">glDrawArraysInstanced</span><span class="params">(GLenum mode, GLint first, GLsizei count, GLsizei instancecount)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* glDrawElementsInstanced 绘画多个元素集合形式的实例</span></span><br><span class="line"><span class="comment">* @param mode 指出要画的基本形状</span></span><br><span class="line"><span class="comment">* @param count 表示一个实例需要的元素数量</span></span><br><span class="line"><span class="comment">* @param type 元素类型</span></span><br><span class="line"><span class="comment">* @param indices 元素起始位置</span></span><br><span class="line"><span class="comment">* @param instancecount 实例数量</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">glDrawElementsInstanced</span><span class="params">(GLenum mode, GLsizei count, GLenum type, <span class="keyword">const</span> <span class="keyword">void</span> * indices, GLsizei instancecount)</span></span>;</span><br></pre></td></tr></table></figure>
<h2 id="实例化数组"><a href="#实例化数组" class="headerlink" title="实例化数组"></a>实例化数组</h2><p>定义为一个顶点属性(能够让我们存储更多的数据), 仅在顶点着色器渲染一个新的实例时才会更新</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">* glVertexAttribDivisor 修改实例化渲染时通用顶点数据更新速度</span></span><br><span class="line"><span class="comment">* @param index 输入顶点的index</span></span><br><span class="line"><span class="comment">* @param divisor 除数, 描述每渲染几个实例顶点数据更新成下一个, 为 0 时表示每一个顶点都会更新数据而不是每个实例</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">glVertexAttribDivisor</span><span class="params">(GLuint index,GLuint divisor)</span></span>;</span><br></pre></td></tr></table></figure>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.2.7/raphael.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.6.5/flowchart.min.js"></script><textarea id="flowchart-0-code" style="display: none">start=>start: Start
op_1=>operation: glCreateShader 创建着器句柄
op_2=>operation: glShaderSource 加载着色器脚本
op_3=>operation: glCompileShader 编译着色器脚本
op_4=>operation: glGetShaderiv 判断着色器编译结果是否成功
op_5=>operation: glGetShaderInfoLog 获取着色器信息日志
cond=>condition: 是否成功
end=>end
start->op_1->op_2->op_3->op_4->cond
cond(yes)->end
cond(no)->op_5->end</textarea><textarea id="flowchart-0-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("flowchart-0-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-0-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-0", options);</script><textarea id="flowchart-1-code" style="display: none">st=>start: Start
op_1=>operation: glCreateProgram 创建工程对象
op_2=>operation: glAttachShader 加载顶点着色器,片段着色器
op_3=>operation: glLinkProgram 构建工程
op_4=>operation: glGetProgramiv 获取工程构建状态
op_5=>operation: glDeleteShader 删除着色器
op_6=>operation: glGetProgramInfoLog 获取工程日志
cond=>condition: 是否成功
e=>end
st->op_1->op_2->op_3->op_4->cond
cond(yes)->op_5->e
cond(no)->op_6->e</textarea><textarea id="flowchart-1-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("flowchart-1-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-1-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-1", options);</script><textarea id="flowchart-2-code" style="display: none"> st=>start: Start
op_1=>operation: glGenVertexArrays 申请顶点队列对象(VAO)
op_2=>operation: glGetBuffer 创建VBO(顶点缓冲对象) EBO(索引缓冲对象)等缓冲对象
op_3=>operation: glBindVertexArray 将当前执行对象绑定到VAO
op_4=>operation: glBindData 将VBO绑定到VAO上,并将当前操作对象指向VBO
op_5=>operation: glBufferData 对VBO EBO填入数据
op_6=>operation: glVertexAttribPointer 将location id 绑定到当前的 VBO 缓存
op_7=>operation: glDrawElements 根据 EBO 画出图形
e=>end: End
st->op_1->op_2->op_3->op_4->op_5->op_6->op_7->e</textarea><textarea id="flowchart-2-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("flowchart-2-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-2-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-2", options);</script><textarea id="flowchart-3-code" style="display: none"> st=>start: Start
op_1=>operation: 获取缓冲区标识: glGenBuffers(GLsizei n, GLuint* buffers);
op_2=>operation: 绑定缓冲区对象: glBindBuffer(GLenum target, GLuint buffer);
op_3=>operation: 用数据填充缓冲区: glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage)
op_4=>operation: 更新缓冲数据: glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
op_5=>operation: 清楚缓冲区对象 glDeleteBuffers(GLsizei n, const GLuint* buffers);
e=>end: End
st->op_1->op_2->op_3->op_4->op_5->e</textarea><textarea id="flowchart-3-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("flowchart-3-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-3-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-3", options);</script><textarea id="flowchart-4-code" style="display: none"> st=>start: Start
op_1=>operation: glGenTextures 申请 texture 对象
op_2=>operation: glBindTexture 绑定当前需要操作的 texture
op_3=>operation: glTexParameteri 设置 texture 属性?
op_4=>operation: glTexImage2D 对 texture 填入数据
op_5=>operation: glGenerateMipmap 生成 mipmap https://zh.wikipedia.org/wiki/Mipmap
op_6=>operation: glUniform1i 特殊用法: 将 片段着色器中 texture变量 指定为对应的纹理单元
op_7=>operation: glActiveTexture 激活纹理单元例如:GL_TEXTURE0, 并设置成当前操作的纹理单元
op_8=>operation: glBindTexture 将我们申请的texture对象绑定到当前的纹理单元中
e=>end: End
st->op_1->op_2->op_3->op_4->op_5->op_6->op_7->op_8->e</textarea><textarea id="flowchart-4-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("flowchart-4-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("flowchart-4-options").value)); var diagram = flowchart.parse(code); diagram.drawSVG("flowchart-4", options);</script><script src="https://cdnjs.cloudflare.com/ajax/libs/webfont/1.6.27/webfontloader.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.4.1/snap.svg-min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/js-sequence-diagrams/1.0.6/sequence-diagram-min.js"></script><textarea id="sequence-0-code" style="display: none">fs texture变量->texture unit: 绑定对应的纹理单元
程序 texture对象资源->texture unit: 程序申请的texture资源输入到纹理单元
texture unit->fs texture变量: 映射</textarea><textarea id="sequence-0-options" style="display: none">{"theme":"simple","scale":1,"line-width":2,"line-length":50,"text-margin":10,"font-size":12}</textarea><script> var code = document.getElementById("sequence-0-code").value; var options = JSON.parse(decodeURIComponent(document.getElementById("sequence-0-options").value)); var diagram = Diagram.parse(code); diagram.drawSVG("sequence-0", options);</script>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<div class="post-block">
<article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
<link itemprop="mainEntityOfPage" href="https://mingxingren.github.io/2021/11/25/imgui%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/images/avatar01.png">
<meta itemprop="name" content="mingxingren">
<meta itemprop="description" content="挖一口自己的井">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="mingxingren的博客">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/2021/11/25/imgui%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3/" class="post-title-link" itemprop="url">imgui接口说明文档</a>
</h2>
<div class="post-meta-container">
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time title="创建时间:2021-11-25 23:22:00" itemprop="dateCreated datePublished" datetime="2021-11-25T23:22:00+08:00">2021-11-25</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar-check"></i>
</span>
<span class="post-meta-item-text">更新于</span>
<time title="修改时间:2022-03-27 20:27:46" itemprop="dateModified" datetime="2022-03-27T20:27:46+08:00">2022-03-27</time>
</span>
</div>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="Dear-Imgui-Ui部分的API说明"><a href="#Dear-Imgui-Ui部分的API说明" class="headerlink" title="Dear Imgui Ui部分的API说明"></a>Dear Imgui Ui部分的API说明</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 开始新的一帧,可以提交任何指令直到调用 Render()/EndFrame()</span></span><br><span class="line"><span class="function">IMGUI_API <span class="keyword">void</span> <span class="title">NewFrame</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 将 window 入栈并且开始调用命令修饰它,直到调用 End 让 window 出栈</span></span><br><span class="line"><span class="comment">// 当 bool *p_open!= NULL, 窗体右上角会有关闭选项, 点击这个选项会设置p_open为false</span></span><br><span class="line"><span class="comment">// 可以在同一帧调用多次 Begin()/End() 来对同一个窗体进行多次操作,前提是 name 相同</span></span><br><span class="line"><span class="comment">// 像 flags 或者 p_open 只在第一次调用 Begin() 起作用</span></span><br><span class="line"><span class="comment">// Begin() 返回 false 表示窗口已折叠或完全裁剪,因此可以提前退出并省略提交</span></span><br><span class="line"><span class="comment">// [重要提示: 由于遗留问题,这与大多数其他函数如 BeginMenu/EndMenu、BeginPopup/EndPopup 等不一致</span></span><br><span class="line"><span class="comment">// , 只有在相应的 BeginXXX函数返回 true 时才应调用 EndXXX 调用. Begin 和 BeginChild 是唯一奇数. </span></span><br><span class="line"><span class="comment">// 将在未来的更新中修复]</span></span><br><span class="line"><span class="comment">// 请注意,窗口堆栈的底部始终包含一个名为"调试"的窗口</span></span><br><span class="line"><span class="function">IMGUI_API <span class="keyword">bool</span> <span class="title">Begin</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* name, <span class="keyword">bool</span>* p_open = <span class="literal">NULL</span>, ImGuiWindowFlags flags = <span class="number">0</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// ImGuiWindowFlags 说明</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">ImGuiWindowFlags_</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> ImGuiWindowFlags_None = <span class="number">0</span>,</span><br><span class="line"> ImGuiWindowFlags_NoTitleBar = <span class="number">1</span> << <span class="number">0</span>, <span class="comment">// 禁用标题栏</span></span><br><span class="line"> ImGuiWindowFlags_NoResize = <span class="number">1</span> << <span class="number">1</span>, <span class="comment">// 禁止用户调整通过右下角调整大小</span></span><br><span class="line"> ImGuiWindowFlags_NoMove = <span class="number">1</span> << <span class="number">2</span>, <span class="comment">// 禁止用户移动窗体</span></span><br><span class="line"> ImGuiWindowFlags_NoScrollbar = <span class="number">1</span> << <span class="number">3</span>, <span class="comment">// 禁止滚动条 (window can still scroll with mouse or programmatically)</span></span><br><span class="line"> ImGuiWindowFlags_NoScrollWithMouse = <span class="number">1</span> << <span class="number">4</span>, <span class="comment">// 禁止用户使用鼠标滚轮垂直滚动. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set.</span></span><br><span class="line"> ImGuiWindowFlags_NoCollapse = <span class="number">1</span> << <span class="number">5</span>, <span class="comment">// 禁止用户通过双击折叠窗口</span></span><br><span class="line"> ImGuiWindowFlags_AlwaysAutoResize = <span class="number">1</span> << <span class="number">6</span>, <span class="comment">// 窗体大小自适应每帧内容</span></span><br><span class="line"> ImGuiWindowFlags_NoBackground = <span class="number">1</span> << <span class="number">7</span>, <span class="comment">// 禁止画背景和边框. Similar as using SetNextWindowBgAlpha(0.0f).</span></span><br><span class="line"> ImGuiWindowFlags_NoSavedSettings = <span class="number">1</span> << <span class="number">8</span>, <span class="comment">// Never load/save settings in .ini file</span></span><br><span class="line"> ImGuiWindowFlags_NoMouseInputs = <span class="number">1</span> << <span class="number">9</span>, <span class="comment">// 禁止捕捉鼠标, hovering test with pass through.</span></span><br><span class="line"> ImGuiWindowFlags_MenuBar = <span class="number">1</span> << <span class="number">10</span>, <span class="comment">// 有一个菜单栏</span></span><br><span class="line"> ImGuiWindowFlags_HorizontalScrollbar = <span class="number">1</span> << <span class="number">11</span>, <span class="comment">// 允许有一个水平滚动条 (默认关闭). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section.</span></span><br><span class="line"> ImGuiWindowFlags_NoFocusOnAppearing = <span class="number">1</span> << <span class="number">12</span>, <span class="comment">// 从隐藏状态转换为可见状态时禁用获取焦点</span></span><br><span class="line"> ImGuiWindowFlags_NoBringToFrontOnFocus = <span class="number">1</span> << <span class="number">13</span>, <span class="comment">// Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus)</span></span><br><span class="line"> ImGuiWindowFlags_AlwaysVerticalScrollbar= <span class="number">1</span> << <span class="number">14</span>, <span class="comment">// 总是显示垂直滚动条(even if ContentSize.y < Size.y)</span></span><br><span class="line"> ImGuiWindowFlags_AlwaysHorizontalScrollbar=<span class="number">1</span><< <span class="number">15</span>, <span class="comment">// 总是显示水平滚动条 (even if ContentSize.x < Size.x)</span></span><br><span class="line"> ImGuiWindowFlags_AlwaysUseWindowPadding = <span class="number">1</span> << <span class="number">16</span>, <span class="comment">// 使用style.Window Padding 确保子窗体没有边框 (ignored by default for non-bordered child windows, because more convenient)</span></span><br><span class="line"> ImGuiWindowFlags_NoNavInputs = <span class="number">1</span> << <span class="number">18</span>, <span class="comment">// 窗口内没有游戏手柄/键盘导航</span></span><br><span class="line"> ImGuiWindowFlags_NoNavFocus = <span class="number">1</span> << <span class="number">19</span>, <span class="comment">// No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)</span></span><br><span class="line"> ImGuiWindowFlags_UnsavedDocument = <span class="number">1</span> << <span class="number">20</span>, <span class="comment">// Display a dot next to the title. When used in a tab/docking context, tab is selected when clicking the X + closure is not assumed (will wait for user to stop submitting the tab). Otherwise closure is assumed when pressing the X, so if you keep submitting the tab may reappear at end of tab bar.</span></span><br><span class="line"> ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,</span><br><span class="line"> ImGuiWindowFlags_NoDecoration = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,</span><br><span class="line"> ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,</span><br><span class="line"></span><br><span class="line"> <span class="comment">// [Internal]</span></span><br><span class="line"> ImGuiWindowFlags_NavFlattened = <span class="number">1</span> << <span class="number">23</span>, <span class="comment">// [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)</span></span><br><span class="line"> ImGuiWindowFlags_ChildWindow = <span class="number">1</span> << <span class="number">24</span>, <span class="comment">// Don't use! For internal use by BeginChild()</span></span><br><span class="line"> ImGuiWindowFlags_Tooltip = <span class="number">1</span> << <span class="number">25</span>, <span class="comment">// Don't use! For internal use by BeginTooltip()</span></span><br><span class="line"> ImGuiWindowFlags_Popup = <span class="number">1</span> << <span class="number">26</span>, <span class="comment">// Don't use! For internal use by BeginPopup()</span></span><br><span class="line"> ImGuiWindowFlags_Modal = <span class="number">1</span> << <span class="number">27</span>, <span class="comment">// Don't use! For internal use by BeginPopupModal()</span></span><br><span class="line"> ImGuiWindowFlags_ChildMenu = <span class="number">1</span> << <span class="number">28</span> <span class="comment">// Don't use! For internal use by BeginMenu()</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// [Obsolete]</span></span><br><span class="line"> <span class="comment">//ImGuiWindowFlags_ResizeFromAnySide = 1 << 17, // --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by backend (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 弹出框: 打开 / 关闭 功能</span></span><br><span class="line"><span class="comment">// - OpenPopup(): 设置弹出框为打开, ImGuiPopupFlags 可用于打开选项</span></span><br><span class="line"><span class="comment">// - If not modal: 通过点击其他地方关闭弹出框 或者 点击 ESCAPE</span></span><br><span class="line"><span class="comment">// - CloseCurrentPopup(): 在 BeginPopup 到 EndPopup 命令执行中,调用 CloseCurrentPopup 可以手动关闭, 当 Selectable()/MenuItem() 激活时, CloseCurrentPopup()默认被调用 </span></span><br><span class="line"><span class="comment">// - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup().</span></span><br><span class="line"><span class="comment">// - 在BeginPopup() 之后使用 IsWindowAppearing() 判断窗口是否刚刚打开</span></span><br><span class="line"><span class="function">IMGUI_API <span class="keyword">void</span> <span class="title">OpenPopup</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* str_id, ImGuiPopupFlags popup_flags = <span class="number">0</span>)</span></span>; <span class="comment">// call to mark popup as open (don't call every frame!).</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 弹出层, 模态</span></span><br><span class="line"><span class="comment">// - 会阻塞 调用 后面的鼠标悬停检测(以及大多数鼠标交互)</span></span><br><span class="line"><span class="comment">// - if not modal: 通过点击其他地方关闭弹出框 或者 点击 ESCAPE</span></span><br><span class="line"><span class="comment">// - 可见性状态 (~bool) 是在内部保存的, 并不是被调用者保存</span></span><br><span class="line"><span class="comment">// - 上面的三个属性是相关的: 我们需要在库中保留弹出窗口可见性状态,因为弹出窗口可能随时关闭</span></span><br><span class="line"><span class="comment">// - 可以调用 IsItemHovered() or IsWindowHovered() 时使用 ImGuiHoveredFlags_AllowWhenBlockedByPopup 来绕过悬停限制</span></span><br><span class="line"><span class="comment">// - 重要提示: Popup 标识符时相对于当前 ID 堆栈的, 因此 OpenPopup 和 BeginPopup 一般需要在堆栈的同一级别</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Popups: begin/end functions</span></span><br><span class="line"><span class="comment">// -BeginPopup(): 查询弹出状态, 如果打开就附加到 window. 之后调用 EndPopup(). ImGuiWindowFlags 被转发到window</span></span><br><span class="line"><span class="comment">// -BeginPopupModal(): block every interactions behind the window, cannot be closed by user, add a dimming background, has a title bar.</span></span><br><span class="line"><span class="function">IMGUI_API <span class="keyword">bool</span> <span class="title">BeginPopup</span><span class="params">(<span class="keyword">const</span> <span class="keyword">char</span>* str_id, ImGuiWindowFlags flags = <span class="number">0</span>)</span></span>; <span class="comment">// return true if the popup is open, and you can start outputting to it.</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>