Compare commits
24 Commits
bfd5776c46
...
master
@@ -401,7 +401,7 @@ darkmode:
|
||||
end:
|
||||
|
||||
# Show scroll percent in scroll-to-top button
|
||||
rightside_scroll_percent: false
|
||||
rightside_scroll_percent: true
|
||||
|
||||
# Don't modify the following settings unless you know how they work
|
||||
# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment
|
||||
@@ -447,9 +447,9 @@ wordcount:
|
||||
|
||||
# Busuanzi count for PV / UV in site
|
||||
busuanzi:
|
||||
site_uv: true
|
||||
site_pv: true
|
||||
page_pv: true
|
||||
site_uv: false
|
||||
site_pv: false
|
||||
page_pv: false
|
||||
|
||||
# --------------------------------------
|
||||
# Math
|
||||
@@ -544,9 +544,9 @@ comments:
|
||||
# If you set it to true, the comment count will be invalid
|
||||
lazyload: false
|
||||
# Display comment count in post's top_img
|
||||
count: false
|
||||
count: true
|
||||
# Display comment count in Home Page
|
||||
card_post_count: false
|
||||
card_post_count: true
|
||||
|
||||
# Disqus
|
||||
# https://disqus.com/
|
||||
@@ -1069,19 +1069,16 @@ inject:
|
||||
|
||||
bottom:
|
||||
# - <script src="xxxx"></script>
|
||||
- <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
|
||||
- <script src="/js/random.js"></script>
|
||||
- <script src="/js/shuoshuoshouye.js"></script>
|
||||
- <script src="/js/ai-summary.js"></script>
|
||||
- <script src="/js/typesense-search.js"></script>
|
||||
- <script src="/js/statistic.js"></script>
|
||||
- <script src="/js/search/typesense-search.js"></script>
|
||||
- <script src="/js/footer.js"
|
||||
- <script src="https://code.jquery.com/jquery-4.0.0.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/npm/echarts@4.9.0/dist/echarts.min.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/npm/aplayer/dist/APlayer.min.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/npm/meting/dist/Meting.min.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/welcomemessage/txmap.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/rightmenu@1.2/rightmenu.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar/calendar.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/gh/bishshi/sidecalendar@latest/calendar.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/npm/chinese-lunar@0.1.4/lib/chinese-lunar.js"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/npm/instantsearch.js@4.56.0"></script>
|
||||
- <script src="https://cdn.jsdmirror.com/npm/typesense-instantsearch-adapter@2.7.0/dist/typesense-instantsearch-adapter.min.js"></script>
|
||||
|
||||
1161
package-lock.json
generated
1161
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,11 +12,11 @@
|
||||
"version": "8.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.13.5",
|
||||
"axios": "^1.15.0",
|
||||
"cheerio": "^1.2.0",
|
||||
"hexo": "^8.1.1",
|
||||
"hexo-abbrlink": "^2.2.1",
|
||||
"hexo-ai-summary-liushen": "^1.3.1",
|
||||
"hexo-ai-summary-liushen": "^2.0.0",
|
||||
"hexo-butterfly-swiper-lyx": "^1.0.2",
|
||||
"hexo-deployer-git": "^4.0.0",
|
||||
"hexo-douban": "^2.3.6",
|
||||
@@ -34,14 +34,14 @@
|
||||
"hexo-renderer-marked": "^7.0.1",
|
||||
"hexo-renderer-pug": "^3.0.0",
|
||||
"hexo-renderer-stylus": "^3.0.1",
|
||||
"hexo-safego": "^2.2.2",
|
||||
"hexo-safego": "^2.3.0",
|
||||
"hexo-server": "^3.0.0",
|
||||
"hexo-spoiler": "^1.7.4",
|
||||
"hexo-wordcount": "^6.0.1",
|
||||
"moment": "^2.30.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
"p-limit": "^7.3.0",
|
||||
"typesense": "^3.0.1",
|
||||
"typesense": "^3.0.5",
|
||||
"vite-plugin-require-transform": "^1.0.21",
|
||||
"xml2js": "^0.6.2"
|
||||
}
|
||||
|
||||
@@ -10,5 +10,9 @@
|
||||
"ignorePaths": [
|
||||
"themes/**",
|
||||
".gitea/**"
|
||||
]
|
||||
],
|
||||
"rangeStrategy": "bump",
|
||||
"prHourlyLimit": 0,
|
||||
"prConcurrentLimit": 0,
|
||||
"dependencyDashboard": false
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
---
|
||||
filename: add-cms-system
|
||||
title: 为博客添加CMS系统
|
||||
cover: 'https://pic.biss.click/image/883c5377-2b3d-4f7f-ba4f-1600e9c91b90.webp'
|
||||
cover: https://pic.biss.click/image/883c5377-2b3d-4f7f-ba4f-1600e9c91b90.webp
|
||||
tags: 网站
|
||||
categories: 建站手札
|
||||
abbrlink: 3a26a97a
|
||||
summary: '为博客添加CMS系统'
|
||||
toc: true
|
||||
comments: true
|
||||
summary: >-
|
||||
这篇文章介绍了如何为Hexo博客添加一个基于Sveltia CMS的CMS系统。首先,作者通过npm安装了Sveltia
|
||||
CMS,并在博客源码目录下创建了必要的文件和目录结构。接着,作者详细说明了如何在config.yml文件中配置CMS,包括字段定义、页面和集合的设置。由于作者使用的是自己的服务器,无法使用官方的认证系统,因此他还讲解了如何配置GitHub
|
||||
OAuth应用,并在Cloudflare上设置环境变量以支持CI/CD流程。最后,作者指出完成这些步骤后,可以通过访问博客的admin后台来管理内容。
|
||||
date: 2025-08-25 22:03:00
|
||||
updated: 2025-08-26 08:01:00
|
||||
---
|
||||
|
||||
# 序言
|
||||
|
||||
因为喜欢wordpress之类动态博客的在线编辑功能,但是又不想抛弃hexo,特别是这个花里胡哨的模板,所以想着给博客添加一个cms系统,在搜索一番后发现这种CMS系统叫无头CMS,然后找到一个很好的系统:sveltia-cms
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
---
|
||||
title: 为1Panel添加自己想要的应用
|
||||
categories: 技术
|
||||
tags: 1panel
|
||||
categories:
|
||||
- 技术
|
||||
tags:
|
||||
- 1panel
|
||||
cover: https://pic.biss.click/image/fa0178dd-b1f6-48eb-8690-42faf26c9f52.webp
|
||||
abbrlink: bb18d851
|
||||
summary: 为1Panel添加自己想要的应用
|
||||
summary: >-
|
||||
这篇文章详细介绍了如何为1Panel添加自定义应用的过程,包括预准备工作、创建文件和配置应用声明文件等步骤。首先,作者强调了Fork仓库和创建新分支的重要性。接着,文章逐步讲解了如何在应用目录下创建所需的文件和子目录,如halo、logo.png、data.yml、README.md等。特别详细地说明了应用声明文件data.yml的构成,包括基本信息、应用标签、类型等关键配置。此外,还解释了关于端口字段和type字段的具体使用方法,提供了实际安装时填写form表单的示例。整个过程不仅清晰易懂,而且为开发者提供了一套完整的操作指南,有助于他们更好地理解和实施应用添加到1Panel的过程。
|
||||
date: 2025-08-19 10:43:16
|
||||
---
|
||||
|
||||
记录一下自己为1Panel贡献自己应用的经历
|
||||
|
||||
# 预准备
|
||||
|
||||
@@ -5,9 +5,13 @@ categories: 建站手札
|
||||
tags: 网站
|
||||
cover: https://pic.biss.click/image/c0211558-17e4-46d2-9a35-e12f16f3f900.webp
|
||||
series: webcustom
|
||||
summary: >-
|
||||
这篇文章介绍了如何在侧边栏中添加欢迎信息,包括申请腾讯地图API
|
||||
key、添加js脚本以及根据用户的地理位置显示个性化欢迎语。首先,文章指导读者如何申请腾讯地图API
|
||||
key,并提醒注意填写信任域名时不要包含'https://'。接着,文章说明了在主题的js目录下添加txmap.js脚本的过程,并提到了一个更完善的js脚本。最后,文章详细描述了如何使用获取到的地理位置信息,通过switch语句根据不同的国家、省份和城市显示相应的欢迎语。
|
||||
date: 2025-08-10 19:30:40
|
||||
summary: 添加侧边栏的欢迎信息
|
||||
---
|
||||
|
||||
# 效果展示
|
||||
|
||||
<center><img src="https://pic.biss.click/image/e37d7241-ed48-4595-ba18-c4de11289adf.webp" alt="效果展示"></center>
|
||||
|
||||
181
source/_posts/2026/2026.3/opencv-1.md
Normal file
181
source/_posts/2026/2026.3/opencv-1.md
Normal file
@@ -0,0 +1,181 @@
|
||||
---
|
||||
title: opencv应用-基础操作
|
||||
categories:
|
||||
- 技术
|
||||
series: opencv
|
||||
tags:
|
||||
- opencv
|
||||
abbrlink: e8f95ead
|
||||
summary: >-
|
||||
这篇文章介绍了使用C++和OpenCV库进行图像处理的基础操作,包括图片的读取与展示、像素的读取与修改、图像的基本变换(缩放、旋转、平移、翻转)、以及图像通道的分离与合并。文章详细讲解了每个操作的代码实现,并展示了如何通过OpenCV库提供的函数来完成这些任务。这对于初学者来说是非常有用的,因为它帮助他们理解如何使用OpenCV进行图像处理。
|
||||
date: 2026-03-15 09:56:51
|
||||
---
|
||||
|
||||
这里用C++进行编程,发现菜鸟教程只有python的版本,那就记录一下。
|
||||
|
||||
# 图片读取与展示
|
||||
|
||||
```cpp
|
||||
// 读取图像
|
||||
#include<opencv2/opencv.hpp>
|
||||
#include<iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main(){
|
||||
Mat src = imread("../img/1.png");
|
||||
imshow("input",src);
|
||||
waitKey(0);
|
||||
destroyAllWindows();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
# 图像基本操作
|
||||
## 读取像素
|
||||
需要用到三维向量数组Vect3b,这里需要注意的是,Opencv是BGR而不是我们常用的RGB。
|
||||
```cpp
|
||||
// 读取像素
|
||||
#include<opencv2/opencv.hpp>
|
||||
#include<iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main()
|
||||
{
|
||||
string image_path = "../img/1.png";
|
||||
Mat image = imread(image_path);
|
||||
|
||||
if (image.empty()) {
|
||||
cout << "错误:无法加载图像,请检查路径是否正确。" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Vec3b pixel_value = image.at<Vec3b>(100, 150);
|
||||
|
||||
cout << "B: " << (int)pixel_value[0] << " "
|
||||
<< "G: " << (int)pixel_value[1] << " "
|
||||
<< "R: " << (int)pixel_value[2] << endl;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 修改像素
|
||||
|
||||
```cpp
|
||||
// 修改像素
|
||||
#include<opencv2/opencv.hpp>
|
||||
#include<iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main()
|
||||
{
|
||||
string image_path = "../img/1.png";
|
||||
Mat image = imread(image_path);
|
||||
Mat result = image.clone();
|
||||
|
||||
if (image.empty()) {
|
||||
cout << "错误:无法加载图像,请检查路径是否正确。" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
Rect roi_rect(0, 0, 100, 100);
|
||||
Mat roi = result(roi_rect);
|
||||
roi.setTo(Scalar(0, 255, 0));
|
||||
imshow("Original (Unchanged)", image);
|
||||
imshow("Modified Copy", result);
|
||||
waitKey(0);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
// 读取图像
|
||||
cv::Mat img = cv::imread("../img/1.png");
|
||||
if (img.empty()) {
|
||||
std::cout << "无法读取图像" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 1. 缩放
|
||||
cv::Mat resized_img;
|
||||
cv::resize(img, resized_img, cv::Size(200, 200));
|
||||
cv::imshow("resized_img", resized_img);
|
||||
|
||||
// 2. 旋转
|
||||
cv::Mat rotated_img, M_rot;
|
||||
cv::Point2f center(img.cols / 2.0, img.rows / 2.0);
|
||||
M_rot = cv::getRotationMatrix2D(center, 45, 1.0);
|
||||
cv::warpAffine(img, rotated_img, M_rot, img.size());
|
||||
cv::imshow("rotated_img", rotated_img);
|
||||
|
||||
// 3. 平移
|
||||
cv::Mat translated_img;
|
||||
cv::Mat M_trans = (cv::Mat_<float>(2, 3) << 1, 0, 100, 0, 1, 50);
|
||||
cv::warpAffine(img, translated_img, M_trans, img.size());
|
||||
cv::imshow("translated_img", translated_img);
|
||||
|
||||
// 4. 翻转
|
||||
cv::Mat flipped_img;
|
||||
cv::flip(img, flipped_img, 1);
|
||||
cv::imshow("flipped", flipped_img);
|
||||
|
||||
// 显示结果
|
||||
cv::imshow("Original", img);
|
||||
cv::waitKey(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
```cpp
|
||||
// 图像通道分离与合并
|
||||
#include<opencv2/opencv.hpp>
|
||||
#include<iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main()
|
||||
{
|
||||
string image_path = "../img/1.png";
|
||||
Mat image = imread(image_path);
|
||||
Mat result = image.clone();
|
||||
// 定义向量数组接收通道
|
||||
vector<Mat> channels;
|
||||
// 拆分
|
||||
split(result,channels);
|
||||
|
||||
Mat b = channels[0];
|
||||
Mat g = channels[1];
|
||||
Mat r = channels[2];
|
||||
|
||||
imshow("Blue Channel (Grayscale)", channels[0]);
|
||||
imshow("Green Channel (Grayscale)", channels[1]);
|
||||
imshow("Red Channel (Grayscale)", channels[2]);
|
||||
|
||||
// merge
|
||||
Mat merged_img;
|
||||
vector<cv::Mat> channels_to_merge;
|
||||
channels_to_merge.push_back(b);
|
||||
channels_to_merge.push_back(g);
|
||||
channels_to_merge.push_back(r);
|
||||
|
||||
merge(channels_to_merge, merged_img);
|
||||
imshow("merged",merged_img);
|
||||
|
||||
waitKey(0);
|
||||
|
||||
return(0);
|
||||
}
|
||||
```
|
||||
70
source/_posts/2026/2026.3/opencv-2.md
Normal file
70
source/_posts/2026/2026.3/opencv-2.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: opencv应用-算术运算
|
||||
categories:
|
||||
- 技术
|
||||
series: opencv
|
||||
tags:
|
||||
- opencv
|
||||
abbrlink: b559997d
|
||||
summary: >-
|
||||
这篇文章介绍了如何使用OpenCV进行图像的加法运算。首先,通过包含OpenCV和iostream头文件,并使用std命名空间,开始编写代码。主函数中,读取两张图片,检查是否成功加载,并确保它们的尺寸相同。如果尺寸不同,将第二张图片调整为与第一张相同的大小。然后,调用add函数对两幅图片进行加法运算,并将结果存储在result矩阵中。最后,显示原始图片和加法运算的结果,并等待按键关闭窗口。代码已上传至自建的git仓库。
|
||||
date: 2026-03-17 13:13:08
|
||||
---
|
||||
|
||||
opencv对图像的算数运算,感觉都大同小异,分为以下几种:加减乘除和位运算。
|
||||
|
||||
| 函数 | 功能 | 应用场景 |
|
||||
|-------------------|--------|------------|
|
||||
| cv2.bitwise_and() | 按位与操作 | 掩码操作、图像分割 |
|
||||
| cv2.bitwise_or() | 按位或操作 | 图像叠加 |
|
||||
| cv2.bitwise_not() | 按位取反操作 | 图像反色 |
|
||||
| cv2.bitwise_xor() | 按位异或操作 | 图像差异检测 |
|
||||
|
||||
因为感觉都差不多,所以只把加法运算代码搬过来
|
||||
|
||||
```cpp
|
||||
// 加法
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
int main()
|
||||
{
|
||||
string path1 = "../img/2.jpg";
|
||||
string path2 = "../img/3.jpg";
|
||||
|
||||
Mat img1 = imread(path1);
|
||||
Mat img2 = imread(path2);
|
||||
|
||||
if (img1.empty() || img2.empty())
|
||||
{
|
||||
cout << "无法读取图片,请检查路径!" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (img1.size() != img2.size())
|
||||
{
|
||||
cout << "尺寸不一致,正在自动调整 img2 的尺寸..." << endl;
|
||||
// 将 img2 缩放到与 img1 相同的尺寸
|
||||
resize(img2, img2, img1.size());
|
||||
}
|
||||
|
||||
Mat result;
|
||||
add(img1, img2, result);
|
||||
|
||||
imshow("Original Image 1", img1);
|
||||
imshow("Original Image 2", img2);
|
||||
imshow("Add Result", result);
|
||||
|
||||
// 等待按键后关闭窗口
|
||||
waitKey(0);
|
||||
destroyAllWindows();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
另外,把代码上传到了自建的git中
|
||||
{% link opencv-learning,opencv-learning,https://git.biss.click/biss/opencv-learning/src/branch/master/Arithmetic%20operations %}
|
||||
50
source/_posts/2026/2026.3/opencv-install.md
Normal file
50
source/_posts/2026/2026.3/opencv-install.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: 配置opencv
|
||||
cover: https://pic.biss.click/image/c177a2e2-63af-4582-98b6-e95726f6cdc5.webp
|
||||
categories:
|
||||
- 技术
|
||||
series: opencv
|
||||
tags: opencv
|
||||
abbrlink: 6e3332b
|
||||
summary: >-
|
||||
这篇文章介绍了在Ubuntu和Windows系统上配置OpenCV的过程。在Ubuntu系统中,通过包管理器安装了Visual
|
||||
Studio、GCC、G++、OpenCV以及Python的OpenCV绑定。而在Windows系统中,则通过安装Visual
|
||||
Studio并下载OpenCV的Windows安装包进行配置,包括将安装路径添加到系统环境变量中。
|
||||
date: 2026-03-14 11:48:36
|
||||
---
|
||||
|
||||
# 引言
|
||||
不知道为什么我们专业看起来与计算机八竿子打不着,竟然要学`opencv`,那就来记录一下吧!
|
||||
# Ubuntu 篇
|
||||
|
||||
`Ubuntu`因为有完善的包管理体系,所以配环境相对简单。
|
||||
|
||||
先安装`vscode`,当然也可以不安装,只是个编辑器;
|
||||
{% link vscode,Microsoft,https://code.visualstudio.com/ %}
|
||||
到这里下载`deb`格式的软件包,然后`dpkg`安装即可。可以安装这些扩展:
|
||||
|
||||
<center><img src=https://pic.biss.click/image/3369ff6a-3286-4ccd-b261-a38802f7d9f2.webp)></center>
|
||||
|
||||
接下来安装编译器
|
||||
|
||||
```bash
|
||||
# 先更新软件包
|
||||
apt update
|
||||
apt upgrade -y
|
||||
# 安装C/C++编译器
|
||||
apt install gcc g++
|
||||
# 安装opencv
|
||||
apt install -y mesa-utils
|
||||
apt install -y libopencv-dev
|
||||
apt install -y opencv
|
||||
apt install -y python3-opencv #Python opencv
|
||||
```
|
||||
然后就可以了。
|
||||
|
||||
# Windows 篇
|
||||
`Windows` 下需要安装`Visual Studio`,比较简单,官网下载安装就行。选择使用C++桌面开发就行。
|
||||
下载`opencv`,在下边网站下载`Windows`安装包,
|
||||
{% link opencv,opencv,https://opencv.org/releases/ %}
|
||||
下载后是一个自解压包,解压路径设置成自己想要的路径,
|
||||
把安装路径添加到系统环境变量中,例如`D:\Opencv\opencv\build\x64\vc16\bin`
|
||||
然后应该就没问题了。
|
||||
130
source/_posts/2026/2026.4/install-opengl.md
Normal file
130
source/_posts/2026/2026.4/install-opengl.md
Normal file
@@ -0,0 +1,130 @@
|
||||
---
|
||||
title: 配置OpenGL环境
|
||||
cover: https://pic.biss.click/image/d19b9e03-9442-4b85-94a0-a3780b9f4440.webp
|
||||
categories:
|
||||
- 技术
|
||||
- 学习
|
||||
series: OpenGL
|
||||
tags: OpenGL
|
||||
abbrlink: c4477b0c
|
||||
summary: >-
|
||||
这篇文章详细介绍了配置OpenGL环境所需步骤,包括安装Visual
|
||||
Studio、CMake和GLFW等关键组件,并提供了具体的配置方法和测试代码,旨在帮助读者顺利开始计算机图形学的学习之旅。
|
||||
date: 2026-04-02 04:52:16
|
||||
---
|
||||
|
||||
最近要学计算机图形学,所以会用到`OpenGL`,配置环境有点繁琐,记录了下来。
|
||||
|
||||
# 安装Visual Studio
|
||||
现在我们先来安装`Visual Studio`:[visual studio](https://visualstudio.microsoft.com/zh-hans/vs/),下载后安装即可|在安装时选择“使用C++的桌面开发”,这样安装时就会安装C++的编译器了。
|
||||

|
||||
|
||||
# 安装 Cmake
|
||||
这个可选,因为我们可以使用`Visual Studio`的编译器`MSVC`来编译项目。
|
||||
`Cmake`是一个开源的跨平台软件构建工具,它可以生成不同系统的构建文件,比如`Makefile`,`Ninja`,`VS`项目文件等等。
|
||||
我们可以下载`Cmake`:[cmake](https://cmake.org/download/),下载后安装即可。
|
||||
|
||||
# 安装GLFW
|
||||
OpenGL有许多工具,比如GLFW,GLEW等等,这里我们安装GLFW。
|
||||
|工具|类别|主要职责|特点|
|
||||
|----|----|----|----|
|
||||
|GLUT|窗口管理 + 工具库|创建窗口、处理鼠标键盘、提供内置渲染循环。|古老、简单。使用“固定管线”(老旧技术),适合教学。|
|
||||
|GLFW|窗口管理库|创建窗口、处理输入、管理多个上下文。|现代、轻量。只管窗口和输入,不负责渲染逻辑,是目前的主流。|
|
||||
|GLAD|配置/加载库|加载 OpenGL 函数指针(连接驱动)。|底层必备。因为 OpenGL 函数在显卡驱动里,需要它来“找”函数地址。|
|
||||
|
||||
## 下载GLFW 和 glad
|
||||
`GLFW`是一个开源的跨平台`C/C++`窗口管理库,它可以创建窗口、处理输入、管理多个上下文。
|
||||
下载`GLFW`:[glfw](https://www.glfw.org/download.html),下载后解压即可。
|
||||
|
||||
|
||||
|
||||
## 创建项目与配置
|
||||
用`Visual Studio`创建一个空的`C++`项目,然后添加GLFW的目录到项目中。
|
||||
在项目属性中添加GLFW的目录到“C/C++->General->Additional Include Directories”中。
|
||||
如图所示:
|
||||

|
||||
|
||||
## 测试
|
||||
|
||||
创建一个`main.cpp`文件,内容如下:
|
||||
```cpp
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <iostream>
|
||||
|
||||
// 顶点着色器源码
|
||||
const char* vertexShaderSource = "#version 330 core\n"
|
||||
"layout (location = 0) in vec3 aPos;\n"
|
||||
"void main() {\n"
|
||||
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
|
||||
"}\0";
|
||||
|
||||
// 片段着色器源码
|
||||
const char* fragmentShaderSource = "#version 330 core\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"void main() {\n"
|
||||
" FragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);\n" // 白色
|
||||
"}\n\0";
|
||||
|
||||
int main() {
|
||||
// 1. 初始化 GLFW
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
// 2. 创建窗口
|
||||
GLFWwindow* window = glfwCreateWindow(800, 600, "Simple OpenGL", NULL, NULL);
|
||||
glfwMakeContextCurrent(window);
|
||||
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
|
||||
|
||||
// 3. 编译着色器
|
||||
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
|
||||
glCompileShader(vertexShader);
|
||||
|
||||
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
|
||||
glCompileShader(fragmentShader);
|
||||
|
||||
unsigned int shaderProgram = glCreateProgram();
|
||||
glAttachShader(shaderProgram, vertexShader);
|
||||
glAttachShader(shaderProgram, fragmentShader);
|
||||
glLinkProgram(shaderProgram);
|
||||
|
||||
// 4. 定义三角形顶点数据
|
||||
float vertices[] = {
|
||||
-0.5f, -0.5f, 0.0f, // 左下
|
||||
0.5f, -0.5f, 0.0f, // 右下
|
||||
0.0f, 0.5f, 0.0f // 顶部
|
||||
};
|
||||
|
||||
unsigned int VBO, VAO;
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// 5. 渲染循环
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // 深青色背景
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glUseProgram(shaderProgram);
|
||||
glBindVertexArray(VAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
如果能运行成功应该就没问题了。
|
||||
131
source/_posts/2026/2026.4/opengl-1.md
Normal file
131
source/_posts/2026/2026.4/opengl-1.md
Normal file
@@ -0,0 +1,131 @@
|
||||
---
|
||||
title: OpenGL-基础程序
|
||||
cover: https://pic.biss.click/image/2fcb9566-f7f6-4132-81cb-4cd646967519.webp
|
||||
categories:
|
||||
- 技术
|
||||
- 学习
|
||||
series: OpenGL
|
||||
tags: OpenGL
|
||||
abbrlink: 437a5198
|
||||
summary: >-
|
||||
这篇文章详细介绍了OpenGL的基础程序,包括代码展示和代码解释两部分。代码展示部分呈现了一个简单的OpenGL程序,涵盖了初始化与窗口管理、状态设置与缓冲区操作、矩阵与坐标变换以及几何图形绘制等关键步骤。代码解释则将这些步骤按照功能类别进行了归纳,帮助读者更好地理解OpenGL的渲染流程。通过这个示例,读者可以初步掌握OpenGL的基本操作和概念。
|
||||
date: 2026-04-11 18:20:34
|
||||
---
|
||||
|
||||
# 代码展示
|
||||
|
||||
我们先从基本的OpenGL程序开始吧,这是一个简单的OpenGL程序:
|
||||
|
||||
```cpp
|
||||
#include<GL/glut.h>
|
||||
using namespace std;
|
||||
|
||||
// 回调函数
|
||||
void myDisplay()
|
||||
{
|
||||
// 清除缓冲区
|
||||
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// 正交模式
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
|
||||
glColor4f(0.0, 1.0, 0.0, 0.0);
|
||||
glRectf(50.0, 50.0, 400.0, 400.0);
|
||||
|
||||
// 划线
|
||||
glColor3f(1.0, 1.0, 0.0);
|
||||
glBegin(GL_LINES);
|
||||
glVertex2f(50.0, 50.0);
|
||||
glVertex2f(400.0, 400.0);
|
||||
glVertex2f(400.0, 50.0);
|
||||
glVertex2f(50.0, 400.0);
|
||||
glEnd();
|
||||
|
||||
// 画点
|
||||
glColor3f(1.0, 0.0, 0.0);
|
||||
glPointSize(20.0);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex2f(15.0, 15.0);
|
||||
glEnd();
|
||||
|
||||
// 画三角形
|
||||
glBegin(GL_TRIANGLES);
|
||||
glColor3f(0.0, 0.0, 1.0);
|
||||
glVertex2i(200, 300);
|
||||
glVertex2i(100, 100);
|
||||
glVertex2i(300, 100);
|
||||
glEnd();
|
||||
|
||||
|
||||
glFlush();
|
||||
|
||||
}
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
|
||||
glutInitWindowPosition(100, 100);
|
||||
glutInitWindowSize(500, 500);
|
||||
glutCreateWindow("");
|
||||
glutDisplayFunc(&myDisplay);
|
||||
glutMainLoop();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
这是运行结果图:
|
||||

|
||||
|
||||
# 代码解释
|
||||
这段代码展示了经典的 OpenGL (GLUT) 固定渲染管线基本操作。为了方便理解,我将这些函数按照 **初始化与窗口管理**、**状态设置**、**坐标变换** 以及 **图形绘制** 四个类别进行了整理。
|
||||
|
||||
## 1. 窗口管理与初始化 (GLUT 库)
|
||||
这类函数主要用于配置窗口系统和处理程序的运行流程。
|
||||
|
||||
| 函数名称 | 功能描述 | 核心参数说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| `glutInit` | 初始化 GLUT 库 | 接收 `main` 函数的命令行参数 |
|
||||
| `glutInitDisplayMode` | 设置显示模式 | `GLUT_RGB` (使用颜色模式), `GLUT_SINGLE` (单缓冲区) |
|
||||
| `glutInitWindowPosition` | 设置窗口在屏幕上的初始位置 | 窗口左上角坐标 $(x, y)$ |
|
||||
| `glutInitWindowSize` | 设置窗口的宽度和高度 | 像素值 (Width, Height) |
|
||||
| `glutCreateWindow` | 创建窗口 | 字符串参数作为窗口标题 |
|
||||
| `glutDisplayFunc` | 注册显示回调函数 | 传入负责绘图的函数指针 |
|
||||
| `glutMainLoop` | 进入 GLUT 事件处理循环 | 让程序持续运行,等待重绘或交互 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 状态设置与缓冲区操作
|
||||
这些函数用于配置 OpenGL 的全局状态(如颜色、点大小)或清理画布。
|
||||
|
||||
| 函数名称 | 功能描述 | 核心参数说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| `glClearColor` | 设置清除颜色(背景色) | RGBA 值 (0.0~1.0),此处设为黑色 |
|
||||
| `glClear` | 清除指定的缓冲区 | `GL_COLOR_BUFFER_BIT` 表示清除颜色缓存 |
|
||||
| `glColor4f` | 设置当前的绘制颜色 (带透明度) | RGBA 分量 |
|
||||
| `glColor3f` | 设置当前的绘制颜色 (不带透明度) | RGB 分量 |
|
||||
| `glPointSize` | 设置点的像素大小 | 浮点数,数值越大点越粗 |
|
||||
| `glFlush` | 强制刷新缓冲区 | 确保绘图命令立即执行并输出到显示设备 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 矩阵与坐标变换
|
||||
用于定义物体是如何投影到屏幕上的。
|
||||
|
||||
| 函数名称 | 功能描述 | 核心参数说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| `glMatrixMode` | 设置当前矩阵模式 | `GL_PROJECTION` 切换到投影矩阵堆栈 |
|
||||
| `gluOrtho2D` | 定义二维正交投影裁剪区域 | 定义视野的左、右、下、上边界范围 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 几何图形绘制
|
||||
OpenGL 的核心绘图逻辑,通过指定顶点来构建形状。
|
||||
|
||||
| 函数名称 | 功能描述 | 核心参数说明 |
|
||||
| :--- | :--- | :--- |
|
||||
| `glRectf` | 绘制一个实心矩形 | 传入左下角坐标和右上角坐标 $(x1, y1, x2, y2)$ |
|
||||
| `glBegin` | 标记图元绘制的开始 | `GL_LINES` (线), `GL_POINTS` (点), `GL_TRIANGLES` (三角形) |
|
||||
| `glVertex2f` | 指定一个二维顶点 (浮点型) | 坐标 $(x, y)$ |
|
||||
| `glVertex2i` | 指定一个二维顶点 (整型) | 坐标 $(x, y)$ |
|
||||
| `glEnd` | 标记图元绘制的结束 | 必须与 `glBegin` 成对出现 |
|
||||
|
||||
---
|
||||
279
source/_posts/2026/2026.4/opengl-2.md
Normal file
279
source/_posts/2026/2026.4/opengl-2.md
Normal file
@@ -0,0 +1,279 @@
|
||||
---
|
||||
title: OpenGL-直线的扫描转换
|
||||
cover: https://pic.biss.click/image/c5457adc-214c-4a18-9aa6-43fbc0bfc2f4.webp
|
||||
categories:
|
||||
- 技术
|
||||
- 学习
|
||||
series: OpenGL
|
||||
tags: OpenGL
|
||||
abbrlink: 7207243b
|
||||
summary: >-
|
||||
这篇文章介绍了三种直线扫描转换算法:DDA算法、中点画线算法和Bresenham算法。
|
||||
DDA算法通过计算直线起点和终点的坐标差值来确定步数和增量,依次绘制直线上的点。算法实现简单,适用于任意直线,但精度较低。
|
||||
中点画线算法仅适用于斜率为0或1的直线,通过计算中点和斜率来确定直线上的像素点,效率较高。
|
||||
Bresenham算法根据直线的斜率和误差项来确定像素点的位置,适用于任意直线,且精度高,但实现稍复杂。
|
||||
date: 2026-04-11 19:01:02
|
||||
---
|
||||
|
||||
这篇文章来介绍直线扫描转换算法
|
||||
# DDA数值微分线段算法
|
||||
## 算法简介
|
||||
数值微分法即DDA法(Digital Differential Analyzer),是一种基于微分方程来生成直线的方法。在计算机图形学中,并没有线段的概念,而是一个个像素点组成了线段。
|
||||
|
||||
DDA法生成线段的步骤一般如下:
|
||||
|
||||
1. 有了起始点($x_1,y_1$)和终点($x_n,y_n$);
|
||||
2. $$\Delta x =|x_n-x_1|, \Delta y=|y_n-y_1|$$
|
||||
3. 比较$\Delta x$和$\Delta y$的大小;
|
||||
steps=$\Delta x$和$\Delta y$中较大者;
|
||||
4. $$step_x=\frac{\Delta x}{steps},step_y=\frac{\Delta y}{steps}$$
|
||||
## 算法实现
|
||||
DDA算法实现如下:
|
||||
```cpp
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <GL/glut.h>
|
||||
|
||||
// 窗口宽度和高度
|
||||
const int WIDTH = 640;
|
||||
const int HEIGHT = 480;
|
||||
|
||||
void drawDDALine(int x1, int y1, int x2, int y2) {
|
||||
float x = x1;
|
||||
float y = y1;
|
||||
|
||||
// 计算差值
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
|
||||
// 确定步数,取 dx 和 dy 中绝对值较大的那个
|
||||
int steps = std::abs(dx) > std::abs(dy) ? std::abs(dx) : std::abs(dy); //三元表达式
|
||||
|
||||
// 计算每一步的增量
|
||||
float xIncrement = (float)dx / steps;
|
||||
float yIncrement = (float)dy / steps;
|
||||
|
||||
// 开始绘制点
|
||||
glBegin(GL_POINTS);
|
||||
glVertex2i((int)round(x), (int)round(y)); // 绘制起点
|
||||
|
||||
for (int k = 0; k < steps; k++) {
|
||||
x += xIncrement;
|
||||
y += yIncrement;
|
||||
// 将浮点坐标四舍五入取整转换为整数像素坐标
|
||||
std::cout << (int)round(x) << ", " << (int)round(y)<<"\n";
|
||||
glVertex2i((int)round(x), (int)round(y));
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// 显示回调函数
|
||||
void display() {
|
||||
drawDDALine(0, 0, 50, 20);
|
||||
glFlush();
|
||||
}
|
||||
|
||||
// 初始化 OpenGL 设置
|
||||
void init() {
|
||||
// 设置背景颜色为白色
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
// 设置投影矩阵为 2D 正交投影
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
// 定义可视区域,左下角(0,0),右上角(WIDTH, HEIGHT)
|
||||
gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
// 初始化 GLUT
|
||||
glutInit(&argc, argv);
|
||||
|
||||
// 设置显示模式:单缓冲、RGB 颜色模式
|
||||
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
|
||||
|
||||
// 设置窗口大小和位置
|
||||
glutInitWindowSize(WIDTH, HEIGHT);
|
||||
glutInitWindowPosition(100, 100);
|
||||
|
||||
// 创建窗口
|
||||
glutCreateWindow("DDA算法");
|
||||
|
||||
// 注册回调函数
|
||||
glutDisplayFunc(display);
|
||||
|
||||
// 初始化设置
|
||||
init();
|
||||
|
||||
// 进入主循环
|
||||
glutMainLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
# 中点画线算法
|
||||
## 算法简介
|
||||
只考虑当直线的斜率$|k|< 1$时的情况,假设现在有一条直线$(x_1,y_1,x_2,y_2)$,那么第一个点一定是$(x_1,y_1)$无疑,下一个点的$x$坐标为$x_1+1$,$y$坐标要么为$y1$要么为$y1+1$。关键在于每次取下一个点时,是取前一个的$y1$呢,还是$y1+1$,这时一定是取直线上点最靠近的那个了,而判断取哪个点就用到了中点,我们将中点代入直线中 $d=F(x_1+1,y_1+0.5)=a \cdot (x_1+1)+b \cdot (y_1+0.5)+c$。
|
||||
|
||||
1. 如果直线$d>=0$,则取下边的点也就是$(x_1+1,y_1)$。
|
||||
2. 如果直线$d<0$,则取上边的点也就是$(x_1+1,y_1+1)$。
|
||||
|
||||
它的实际过程就是这样每次根据前边的点判断下一个点在哪,然后进行打亮,但这样每次判断的时候都得代入直线方程计算太麻烦了,我们将这俩种情况分别代入直线方程中可以找出规律:
|
||||
|
||||
1. 当直线$d>=0$时,经过化解得$d_1=d+a$;
|
||||
2. 当直线$d<0$时,经过化解得$d_2=d+a+b$;
|
||||
3. 初始值$d_0=a+0.5b$。
|
||||
|
||||
也就是说每次的增量要么为$a$,要么为$a+b$,那么这样判断的时候就简单多了,因为我们每次只是判断它的正负。所以给等式同时乘2,将其中浮点数0.5化为整数,这样硬件操作时无疑更快了。
|
||||
|
||||
## 算法实现
|
||||
```cpp
|
||||
#include <GL/freeglut.h>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
// 中点画线算法函数 (仅针对斜率 0 <= k <= 1 的情况进行演示,其它象限需类比处理)
|
||||
void drawLineMidpoint(int x0, int y0, int x1, int y1) {
|
||||
int a = y0 - y1;
|
||||
int b = x1 - x0;
|
||||
int d = 2 * a + b;
|
||||
int d1 = 2 * a;
|
||||
int d2 = 2 * (a + b);
|
||||
|
||||
int x = x0, y = y0;
|
||||
|
||||
glBegin(GL_POINTS);
|
||||
glVertex2i(x, y); // 画起点
|
||||
|
||||
while (x < x1) {
|
||||
if (d < 0) {
|
||||
x++;
|
||||
y++;
|
||||
d += d2;
|
||||
} else {
|
||||
x++;
|
||||
d += d1;
|
||||
}
|
||||
glVertex2i(x, y);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// 渲染回调函数
|
||||
void display() {
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glColor3f(1.0, 1.0, 1.0); // 设置画笔颜色为白色
|
||||
|
||||
// 调用算法画一条直线 (x0, y0) 到 (x1, y1)
|
||||
// 注意:此处的坐标对应屏幕像素坐标
|
||||
drawLineMidpoint(50, 50, 450, 300);
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
// 初始化设置
|
||||
void init() {
|
||||
glClearColor(0.0, 0.0, 0.0, 1.0); // 背景设为黑色
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
// 设置正交投影矩阵,使坐标系与窗口像素对应
|
||||
gluOrtho2D(0, 500, 0, 500);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
|
||||
glutInitWindowSize(500, 500);
|
||||
glutInitWindowPosition(100, 100);
|
||||
glutCreateWindow("Midpoint Line Algorithm - FreeGLUT");
|
||||
|
||||
init();
|
||||
glutDisplayFunc(display);
|
||||
glutMainLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
# Bresenham算法
|
||||
## 算法简介
|
||||
假设我们需要由$(x_0, y_0)$这一点,绘画一直线至右下角的另一点$(x_1, y_1)$,x,y分别代表其水平及垂直坐标,并且$x_1 - x_0 > y_1 - y_0$。在此我们使用电脑系统常用的坐标系,即$x$坐标值沿$x$轴向右增长,$y$坐标值沿$y$轴向下增长。
|
||||
|
||||
因此x及y之值分别向右及向下增加,而两点之水平距离为$x_{1}-x_{0}$且垂直距离为$y_{1}-y_{0}$。由此得之,该线的斜率必定介乎于$0$至$1$之间。而此算法之目的,就是找出在$x_{0}$与$x_{1}$之间,第$x$行相对应的第$y$列,从而得出一像素点,使得该像素点的位置最接近原本的线。
|
||||
|
||||
对于由$(x_0, y_0)$及$(x_1, y_1)$两点所组成之直线,公式如下:
|
||||
$$y-y_{0}={\frac {y_{1}-y_{0}}{x_{1}-x_{0}}}(x-x_{0})$$
|
||||
因此,对于每一点的x,其y的值是
|
||||
$${\frac {y_{1}-y_{0}}{x_{1}-x_{0}}}(x-x_{0})+y_{0}$$
|
||||
因为$x$及$y$皆为整数,但并非每一点$x$所对应的$y$皆为整数,故此没有必要去计算每一点x所对应之$y$值。反之由于此线之斜率介乎于$1$至$0$之间,故此我们只需要找出当$x$到达那一个数值时,会使$y$上升$1$,若$x$尚未到此值,则$y$不变。至于如何找出相关的$x$值,则需依靠斜率。斜率之计算方法为$m=(y_{1}-y_{0})/(x_{1}-x_{0})$。由于此值不变,故可于运算前预先计算,减少运算次数。
|
||||
|
||||
要实行此算法,我们需计算每一像素点与该线之间的误差。于上述例子中,误差应为每一点$x$中,其相对的像素点之$y$值与该线实际之$y$值的差距。每当$y$的值增加$1$,误差的值就会增加$m$。每当误差的值超出$0.5$,线就会比较靠近下一个映像点,因此$y$的值便会加$1$,且误差减$1$。
|
||||
|
||||
## 算法实现
|
||||
```cpp
|
||||
#include <GL/freeglut.h>
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
|
||||
// 通用 Bresenham 画线算法
|
||||
void drawLineBresenham(int x0, int y0, int x1, int y1) {
|
||||
int dx = abs(x1 - x0);
|
||||
int dy = abs(y1 - y0);
|
||||
int sx = (x0 < x1) ? 1 : -1; // X 方向步进
|
||||
int sy = (y0 < y1) ? 1 : -1; // Y 方向步进
|
||||
int err = dx - dy; // 初始误差项
|
||||
|
||||
glBegin(GL_POINTS);
|
||||
while (true) {
|
||||
glVertex2i(x0, y0); // 绘制当前点
|
||||
|
||||
if (x0 == x1 && y0 == y1) break; // 到达终点
|
||||
|
||||
int e2 = 2 * err;
|
||||
// 判断是否在 X 方向步进
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x0 += sx;
|
||||
}
|
||||
// 判断是否在 Y 方向步进
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y0 += sy;
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
// 渲染回调
|
||||
void display() {
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glColor3f(0.0f, 0.8f, 0.4f); // 设置一个好看的绿色(类似你图中的图标颜色)
|
||||
|
||||
// 绘制几条不同方向的线来测试算法的健壮性
|
||||
drawLineBresenham(50, 50, 450, 400); // 第一象限
|
||||
drawLineBresenham(50, 400, 450, 50); // 第四象限
|
||||
drawLineBresenham(250, 50, 250, 450); // 垂直线
|
||||
drawLineBresenham(50, 250, 450, 250); // 水平线
|
||||
|
||||
glFlush();
|
||||
}
|
||||
|
||||
void init() {
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // 深色背景
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluOrtho2D(0, 500, 0, 500); // 建立 500x500 的直角坐标系
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
|
||||
glutInitWindowSize(600, 600);
|
||||
glutCreateWindow("Bresenham Line Algorithm");
|
||||
init();
|
||||
glutDisplayFunc(display);
|
||||
glutMainLoop();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
@@ -9,21 +9,20 @@ nav#nav
|
||||
.ls-grid
|
||||
a(href="/") #[i.fas.fa-rss] 个人博客
|
||||
a(href="https://github.com/bishshi") #[i.fab.fa-github] Github
|
||||
a(href="https://space.bilibili.com/20665809") #[i.fab.fa-bilibili] 哔哩哔哩
|
||||
.ls-section
|
||||
.ls-title 😎 常用服务
|
||||
.ls-grid
|
||||
a(href="https://git.biss.click/biss") #[i.fas.fa-code] 代码仓库
|
||||
a(href="https://mm.biss.click") #[i.fas.fa-pen-nib] 日常yy
|
||||
a(href="https://statstic.biss.click") #[i.fas.fa-users] 访客统计
|
||||
a(href="https://mm.biss.click") #[i.fas.fa-pen-nib] 日常说说
|
||||
a(href="https://pic.biss.click") #[i.fas.fa-image] 图床
|
||||
a(href="https://chat.biss.click") #[i.fas.fa-robot] AI网站
|
||||
a(href="https://git.biss.click") #[i.fas.fa-code-branch] 代码仓库
|
||||
.ls-section
|
||||
.ls-title 🛸 实用工具
|
||||
.ls-grid
|
||||
a(href="https://cover.biss.click") #[i.fas.fa-palette] 封面设计
|
||||
a(href="https://doc.biss.click") #[i.fas.fa-file] 文档服务
|
||||
a(href="https://doc.biss.click") #[i.fas.fa-server]服务监测
|
||||
a(href="https://status.biss.click") #[i.fas.fa-server] 服务监测
|
||||
a(href="https://typesense.biss.click") #[i.fas.fa-magnifying-glass] 搜索后端
|
||||
|
||||
a.nav-site-title(href=url_for('/'))
|
||||
|
||||
@@ -95,7 +95,7 @@ fontawesome:
|
||||
name: '@fortawesome/fontawesome-free'
|
||||
file: css/all.min.css
|
||||
other_name: font-awesome
|
||||
version: 7.1.0
|
||||
version: 7.2.0
|
||||
gitalk:
|
||||
name: gitalk
|
||||
file: dist/gitalk.min.js
|
||||
@@ -112,12 +112,12 @@ katex:
|
||||
name: katex
|
||||
file: dist/katex.min.css
|
||||
other_name: KaTeX
|
||||
version: 0.16.28
|
||||
version: 0.16.45
|
||||
katex_copytex:
|
||||
name: katex
|
||||
file: dist/contrib/copy-tex.min.js
|
||||
other_name: KaTeX
|
||||
version: 0.16.28
|
||||
version: 0.16.45
|
||||
lazyload:
|
||||
name: vanilla-lazyload
|
||||
file: dist/lazyload.iife.min.js
|
||||
@@ -137,7 +137,7 @@ mermaid:
|
||||
meting_js:
|
||||
name: butterfly-extsrc
|
||||
file: metingjs/dist/Meting.min.js
|
||||
version: 1.1.6
|
||||
version: 2.0.2
|
||||
pace_default_css:
|
||||
name: pace-js
|
||||
other_name: pace
|
||||
@@ -185,8 +185,8 @@ snackbar_css:
|
||||
version: 0.1.16
|
||||
twikoo:
|
||||
name: twikoo
|
||||
file: dist/twikoo.all.min.js
|
||||
version: 1.6.44
|
||||
file: dist/twikoo.min.js
|
||||
version: 1.7.7
|
||||
typed:
|
||||
name: typed.js
|
||||
file: dist/typed.umd.js
|
||||
|
||||
@@ -697,3 +697,90 @@
|
||||
[data-theme='dark'] .my-footer-social-amoeba-path {
|
||||
fill: #2b3f49;
|
||||
}
|
||||
|
||||
/* 仿照 Liushen & Butterfly 逻辑的高级表格美化 */
|
||||
|
||||
/* 1. 表格容器处理 - 关键响应式滚动层 */
|
||||
#article-container .table-wrap,
|
||||
#article-container > table {
|
||||
background: var(--liushen-card-bg);
|
||||
border: var(--liushen-card-border);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--card-box-shadow);
|
||||
margin: 20px 0;
|
||||
backdrop-filter: blur(10px);
|
||||
|
||||
/* 开启横向滚动逻辑 */
|
||||
width: 100%;
|
||||
overflow-x: auto; /* 小屏幕自动开启滚动 */
|
||||
display: block; /* 必须设为 block 滚动才生效 */
|
||||
}
|
||||
|
||||
/* 2. 针对数据表格的结构重置(排除代码块 .highlight) */
|
||||
#article-container :not(.highlight) > table {
|
||||
display: table; /* 容器内部恢复为 table 模式 */
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
border: none !important;
|
||||
width: 100%;
|
||||
min-width: 500px; /* 强制表格在窄屏下不收缩过猛,从而触发容器滚动 */
|
||||
}
|
||||
|
||||
/* 3. 表头美化 - 渐变风格 */
|
||||
#article-container :not(.highlight) > table thead {
|
||||
background: linear-gradient(-45deg, #3eb8be, #6ecad0);
|
||||
}
|
||||
|
||||
#article-container :not(.highlight) > table th {
|
||||
color: #fff !important;
|
||||
font-weight: 700;
|
||||
padding: 12px 16px;
|
||||
border: none !important;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 4. 单元格美化 */
|
||||
#article-container :not(.highlight) > table td {
|
||||
padding: 10px 16px;
|
||||
color: var(--liushen-text);
|
||||
/* 仅保留底部细线,模仿 Liushen 的极简风格 */
|
||||
border-bottom: 1px solid rgba(128, 128, 128, 0.1) !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-left: none !important;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
/* 5. 隔行变色 */
|
||||
#article-container :not(.highlight) > table tbody tr:nth-child(even) {
|
||||
background: rgba(153, 169, 191, 0.05);
|
||||
}
|
||||
|
||||
/* 6. 悬停高亮 */
|
||||
#article-container :not(.highlight) > table tbody tr:hover td {
|
||||
background: rgba(62, 184, 190, 0.1);
|
||||
}
|
||||
|
||||
/* 7. 滚动条美化 (仿照你代码中的蓝色滚动条) */
|
||||
#article-container .table-wrap::-webkit-scrollbar {
|
||||
height: 4px; /* 横向滚动条高度 */
|
||||
}
|
||||
#article-container .table-wrap::-webkit-scrollbar-thumb {
|
||||
background: var(--scrollbar-color, #2679cc);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* 8. 黑夜模式适配 */
|
||||
[data-theme='dark'] #article-container .table-wrap,
|
||||
[data-theme='dark'] #article-container > table {
|
||||
background: var(--liushen-card-secondbg);
|
||||
}
|
||||
|
||||
[data-theme='dark'] #article-container :not(.highlight) > table thead {
|
||||
background: linear-gradient(-45deg, #1f4a4d, #3eb8be);
|
||||
}
|
||||
|
||||
[data-theme='dark'] #article-container :not(.highlight) > table td {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
// 配置区域 - 请根据实际情况修改
|
||||
// ============================================================================
|
||||
const CONFIG = {
|
||||
apiKey: "VramSTWKUAggeZ5viQw8SlCwXQqmGCmA", // ⚠️ 建议使用 Search-Only API Key
|
||||
apiKey: "2uxQzk7eD2GBCljdSmIiuU3ause7UK9n", // ⚠️ 建议使用 Search-Only API Key
|
||||
server: {
|
||||
host: "typesense.biss.click",
|
||||
port: "443",
|
||||
@@ -1,11 +0,0 @@
|
||||
var _paq = window._paq = window._paq || [];
|
||||
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function() {
|
||||
var u="https://statistic.biss.click/";
|
||||
_paq.push(['setTrackerUrl', u+'matomo.php']);
|
||||
_paq.push(['setSiteId', '1']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
Reference in New Issue
Block a user