当前位置: 首页 > article >正文

Unity利用噪声生成动态地形

引言

在游戏开发中,地形是构建游戏世界的基础元素之一。传统的地形创建方法通常依赖于手动建模或预设资源,这种方式虽然精确但缺乏灵活性,且工作量巨大。而使用噪声算法生成地形则提供了一种程序化、动态且高效的解决方案。本文将详细介绍如何在Unity中利用噪声函数生成动态地形,从基本概念到实际实现,帮助开发者掌握这一强大技术。

噪声函数基础

什么是噪声函数?

噪声函数是一种数学函数,能够生成看似随机但实际上是确定性的值。在地形生成中,最常用的噪声函数包括:

  1. Perlin噪声:由Ken Perlin在1980年代开发,能生成自然流畅的随机模式
  2. Simplex噪声:Perlin噪声的改进版,计算效率更高,尤其在高维度空间
  3. 分形布朗运动(FBM):通过叠加不同频率和振幅的噪声来创造更复杂的模式
  4. Worley噪声:也称为Cellular噪声,可以创建类似细胞或蜂窝状的模式

噪声参数解析

理解以下关键参数对掌握噪声地形生成至关重要:

  • 频率(Frequency):控制噪声变化的密集程度,高频率产生更多细节
  • 振幅(Amplitude):控制噪声值的范围大小,影响地形的高度变化
  • 八度(Octaves):叠加的噪声层数,增加八度数可以增加地形细节
  • 持续度(Persistence):控制每个八度的振幅如何变化
  • 粗糙度(Lacunarity):控制每个八度的频率如何变化
  • 种子(Seed):初始化噪声生成的随机数,相同种子产生相同地形

Unity中实现噪声地形生成

基本方法

在Unity中生成噪声地形主要有两种方式:

  1. Mesh生成法:直接创建和修改网格顶点
  2. Unity地形系统:利用Unity内置的Terrain系统

我们将重点介绍Mesh生成法,因为它提供了更多的灵活性和控制力。

实现步骤

1. 创建基础项目结构

首先,创建一个新的Unity项目并设置基本场景:

using UnityEngine;public class TerrainGenerator : MonoBehaviour
{[Header("地形设置")]public int width = 256;public int height = 256;public float scale = 20f;[Header("噪声设置")]public int octaves = 4;public float persistence = 0.5f;public float lacunarity = 2f;public int seed = 42;public Vector2 offset = Vector2.zero;[Header("地形网格")]public float heightMultiplier = 10f;public AnimationCurve heightCurve;private MeshFilter meshFilter;private MeshRenderer meshRenderer;void Start(){// 初始化组件meshFilter = GetComponent<MeshFilter>();meshRenderer = GetComponent<MeshRenderer>();// 生成地形GenerateTerrain();}// 更新地形(可在运行时调用以动态更新)public void GenerateTerrain(){// 实现地形生成逻辑}
}
2. 实现噪声函数

接下来,我们需要实现噪声计算函数:

// 生成噪声高度图
float[,] GenerateNoiseMap()
{float[,] noiseMap = new float[width, height];// 使用种子初始化随机数生成器System.Random prng = new System.Random(seed);Vector2[] octaveOffsets = new Vector2[octaves];for (int i = 0; i < octaves; i++){float offsetX = prng.Next(-100000, 100000) + offset.x;float offsetY = prng.Next(-100000, 100000) + offset.y;octaveOffsets[i] = new Vector2(offsetX, offsetY);}float maxNoiseHeight = float.MinValue;float minNoiseHeight = float.MaxValue;// 计算噪声中心点,使缩放效果以地图中心为基准float halfWidth = width / 2f;float halfHeight = height / 2f;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){float amplitude = 1;float frequency = 1;float noiseHeight = 0;// 计算多个八度的噪声叠加for (int i = 0; i < octaves; i++){float sampleX = (x - halfWidth) / scale * frequency + octaveOffsets[i].x;float sampleY = (y - halfHeight) / scale * frequency + octaveOffsets[i].y;// 使用Unity内置的Perlin噪声函数float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;noiseHeight += perlinValue * amplitude;// 应用持续度和粗糙度amplitude *= persistence;frequency *= lacunarity;}// 记录最大和最小噪声高度,用于后续归一化if (noiseHeight > maxNoiseHeight)maxNoiseHeight = noiseHeight;if (noiseHeight < minNoiseHeight)minNoiseHeight = noiseHeight;noiseMap[x, y] = noiseHeight;}}// 归一化噪声值到0-1范围for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){noiseMap[x, y] = Mathf.InverseLerp(minNoiseHeight, maxNoiseHeight, noiseMap[x, y]);}}return noiseMap;
}
3. 生成网格

使用噪声高度图生成实际的地形网格:

void GenerateTerrain()
{// 生成噪声高度图float[,] noiseMap = GenerateNoiseMap();// 创建网格数据Mesh mesh = new Mesh();Vector3[] vertices = new Vector3[(width + 1) * (height + 1)];int[] triangles = new int[width * height * 6];Vector2[] uvs = new Vector2[(width + 1) * (height + 1)];// 设置顶点和UV坐标for (int i = 0, y = 0; y <= height; y++){for (int x = 0; x <= width; x++, i++){// 计算顶点高度float heightValue = 0;if (x < width && y < height){heightValue = noiseMap[x, y];// 应用高度曲线和乘数heightValue = heightCurve.Evaluate(heightValue) * heightMultiplier;}vertices[i] = new Vector3(x, heightValue, y);uvs[i] = new Vector2((float)x / width, (float)y / height);}}// 设置三角形索引int vert = 0;int tris = 0;for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){triangles[tris + 0] = vert + 0;triangles[tris + 1] = vert + width + 1;triangles[tris + 2] = vert + 1;triangles[tris + 3] = vert + 1;triangles[tris + 4] = vert + width + 1;triangles[tris + 5] = vert + width + 2;vert++;tris += 6;}vert++;}// 设置网格数据mesh.Clear();mesh.vertices = vertices;mesh.triangles = triangles;mesh.uv = uvs;// 重新计算法线和边界mesh.RecalculateNormals();mesh.RecalculateBounds();// 应用到网格过滤器meshFilter.sharedMesh = mesh;
}
4. 添加材质和纹理

为了使地形更加真实,我们可以添加基于高度的纹理:

[Header("纹理设置")]
public Texture2D[] terrainTextures;  // 不同高度的纹理
public float[] textureHeights;       // 纹理对应的高度阈值// 在GenerateTerrain方法中添加
void ApplyTerrainTexture(float[,] noiseMap)
{int textureWidth = width + 1;int textureHeight = height + 1;// 创建颜色图Texture2D texture = new Texture2D(textureWidth, textureHeight);Color[] colorMap = new Color[textureWidth * textureHeight];for (int y = 0; y < textureHeight; y++){for (int x = 0; x < textureWidth; x++){if (x < width && y < height){float currentHeight = noiseMap[x, y];// 根据高度选择纹理for (int i = 0; i < textureHeights.Length; i++){if (currentHeight <= textureHeights[i]){// 从纹理中采样颜色float u = (float)x / width * terrainTextures[i].width;float v = (float)y / height * terrainTextures[i].height;colorMap[y * textureWidth + x] = terrainTextures[i].GetPixelBilinear(u, v);break;}}}else{// 边缘处理colorMap[y * textureWidth + x] = Color.black;}}}texture.SetPixels(colorMap);texture.Apply();// 应用到渲染器meshRenderer.material.mainTexture = texture;
}

5. 实现动态更新

为了实现动态地形,我们可以添加实时更新功能:

[Header("动态更新")]
public bool autoUpdate = true;
public float updateInterval = 1f;
private float updateTimer = 0f;void Update()
{if (autoUpdate){updateTimer += Time.deltaTime;if (updateTimer >= updateInterval){// 更新偏移以创建移动效果offset += new Vector2(0.01f, 0.01f);GenerateTerrain();updateTimer = 0f;}}
}

高级技术与优化

LOD系统实现

对于大型地形,实现级别细节(LOD)系统至关重要:

[Header("LOD设置")]
public int maxLOD = 3;
public float[] lodDistances = new float[] { 50f, 100f, 200f };void UpdateLOD()
{// 获取到相机的距离float distanceToCamera = Vector3.Distance(Camera.main.transform.position, transform.position);// 根据距离确定LOD级别int currentLOD = maxLOD;for (int i = 0; i < lodDistances.Length; i++){if (distanceToCamera < lodDistances[i]){currentLOD = i;break;}}// 根据LOD级别调整网格细节int lodWidth = width >> currentLOD;  // 位移操作,相当于除以2的currentLOD次方int lodHeight = height >> currentLOD;// 使用调整后的分辨率生成地形GenerateTerrainWithResolution(lodWidth, lodHeight);
}void GenerateTerrainWithResolution(int resWidth, int resHeight)
{// 类似GenerateTerrain,但使用指定分辨率// ...
}

多线程优化

噪声计算是CPU密集型操作,可以使用多线程优化:

using System.Threading;
using System.Collections.Generic;[Header("多线程设置")]
public bool useMultithreading = true;
public int threadCount = 4;// 多线程生成噪声图
float[,] GenerateNoiseMapMultithreaded()
{float[,] noiseMap = new float[width, height];if (!useMultithreading){return GenerateNoiseMap();}// 准备线程参数int rowsPerThread = height / threadCount;Thread[] threads = new Thread[threadCount];NoiseMapThreadInfo[] threadInfos = new NoiseMapThreadInfo[threadCount];// 启动线程for (int i = 0; i < threadCount; i++){int threadIndex = i;threadInfos[i] = new NoiseMapThreadInfo(threadIndex * rowsPerThread,(threadIndex == threadCount - 1) ? height : (threadIndex + 1) * rowsPerThread);threads[i] = new Thread(() => GenerateNoiseMapPart(noiseMap, threadInfos[threadIndex]));threads[i].Start();}// 等待所有线程完成foreach (Thread thread in threads){thread.Join();}// 归一化处理NormalizeNoiseMap(noiseMap);return noiseMap;
}// 线程信息类
class NoiseMapThreadInfo
{public int startY;public int endY;public float maxNoiseHeight;public float minNoiseHeight;public NoiseMapThreadInfo(int startY, int endY){this.startY = startY;this.endY = endY;this.maxNoiseHeight = float.MinValue;this.minNoiseHeight = float.MaxValue;}
}// 生成部分噪声图
void GenerateNoiseMapPart(float[,] noiseMap, NoiseMapThreadInfo threadInfo)
{// 类似GenerateNoiseMap中的循环,但只处理指定范围的行// ...
}

GPU加速

对于更高性能需求,可以使用计算着色器在GPU上生成噪声:

[Header("GPU加速")]
public bool useGPU = true;
public ComputeShader noiseComputeShader;// 使用GPU生成噪声图
float[,] GenerateNoiseMapGPU()
{if (!useGPU || noiseComputeShader == null){return GenerateNoiseMap();}// 创建结果缓冲区float[] noiseData = new float[width * height];ComputeBuffer noiseBuffer = new ComputeBuffer(width * height, sizeof(float));noiseBuffer.SetData(noiseData);// 设置计算着色器参数int kernelHandle = noiseComputeShader.FindKernel("CSMain");noiseComputeShader.SetBuffer(kernelHandle, "NoiseBuffer", noiseBuffer);noiseComputeShader.SetInt("Width", width);noiseComputeShader.SetInt("Height", height);noiseComputeShader.SetFloat("Scale", scale);noiseComputeShader.SetInt("Octaves", octaves);noiseComputeShader.SetFloat("Persistence", persistence);noiseComputeShader.SetFloat("Lacunarity", lacunarity);noiseComputeShader.SetInt("Seed", seed);noiseComputeShader.SetVector("Offset", new Vector4(offset.x, offset.y, 0, 0));// 执行计算着色器int threadGroupsX = Mathf.CeilToInt(width / 8.0f);int threadGroupsY = Mathf.CeilToInt(height / 8.0f);noiseComputeShader.Dispatch(kernelHandle, threadGroupsX, threadGroupsY, 1);// 获取结果noiseBuffer.GetData(noiseData);noiseBuffer.Release();// 转换为二维数组float[,] noiseMap = new float[width, height];for (int y = 0; y < height; y++){for (int x = 0; x < width; x++){noiseMap[x, y] = noiseData[y * width + x];}}return noiseMap;
}

实际应用案例

无限地形生成

通过分块加载和卸载,可以实现"无限"地形:

[Header("无限地形设置")]
public Transform viewer;           // 通常是玩家或相机
public float viewDistance = 300f;  // 可见距离
public int chunkSize = 256;        // 每个地形块的大小
public int chunksVisibleInViewDst = 5;Dictionary<Vector2, TerrainChunk> terrainChunks = new Dictionary<Vector2, TerrainChunk>();
List<TerrainChunk> visibleTerrainChunks = new List<TerrainChunk>();void Update()
{// 获取玩家当前所在的地形块坐标Vector2 viewerPosition = new Vector2(viewer.position.x, viewer.position.z);Vector2 viewerChunkCoord = new Vector2(Mathf.RoundToInt(viewerPosition.x / chunkSize),Mathf.RoundToInt(viewerPosition.y / chunkSize));// 更新可见地形块for (int yOffset = -chunksVisibleInViewDst; yOffset <= chunksVisibleInViewDst; yOffset++){for (int xOffset = -chunksVisibleInViewDst; xOffset <= chunksVisibleInViewDst; xOffset++){Vector2 chunkCoord = new Vector2(viewerChunkCoord.x + xOffset, viewerChunkCoord.y + yOffset);// 检查该块是否已加载if (terrainChunks.ContainsKey(chunkCoord)){terrainChunks[chunkCoord].UpdateChunk();}else{// 创建新的地形块terrainChunks.Add(chunkCoord, new TerrainChunk(chunkCoord, chunkSize, transform, material));}}}
}// 地形块类
public class TerrainChunk
{GameObject meshObject;Vector2 position;Bounds bounds;public TerrainChunk(Vector2 coord, int size, Transform parent, Material material){position = coord * size;bounds = new Bounds(position, Vector2.one * size);// 创建地形块游戏对象meshObject = new GameObject("Terrain Chunk");meshObject.transform.position = new Vector3(position.x, 0, position.y);meshObject.transform.parent = parent;// 添加组件MeshRenderer meshRenderer = meshObject.AddComponent<MeshRenderer>();meshRenderer.material = material;MeshFilter meshFilter = meshObject.AddComponent<MeshFilter>();// 生成地形// ...}public void UpdateChunk(){// 检查是否在视距内float viewerDistanceFromNearestEdge = bounds.SqrDistance(viewerPosition);bool visible = viewerDistanceFromNearestEdge <= viewDistance * viewDistance;meshObject.SetActive(visible);}
}

地形编辑器

创建一个自定义编辑器工具,方便调整地形参数:

#if UNITY_EDITOR
using UnityEditor;[CustomEditor(typeof(TerrainGenerator))]
public class TerrainGeneratorEditor : Editor
{public override void OnInspectorGUI(){TerrainGenerator terrainGen = (TerrainGenerator)target;// 绘制默认检查器DrawDefaultInspector();// 添加生成按钮if (GUILayout.Button("生成地形")){terrainGen.GenerateTerrain();}// 添加随机种子按钮if (GUILayout.Button("随机种子")){terrainGen.seed = Random.Range(0, 100000);terrainGen.GenerateTerrain();}// 添加保存地形按钮if (GUILayout.Button("保存地形")){SaveTerrainMesh(terrainGen);}}void SaveTerrainMesh(TerrainGenerator terrainGen){// 获取当前网格Mesh mesh = terrainGen.GetComponent<MeshFilter>().sharedMesh;// 保存为资源if (mesh != null){string path = EditorUtility.SaveFilePanelInProject("保存地形网格","TerrainMesh","asset","请选择保存位置");if (path.Length > 0){AssetDatabase.CreateAsset(mesh, path);AssetDatabase.SaveAssets();}}}
}
#endif

总结与展望

通过本文的介绍,我们详细探讨了如何在Unity中利用噪声函数生成动态地形。从基本的Perlin噪声应用到高级的多线程和GPU优化,从简单的网格生成到无限地形系统,这些技术为游戏开发者提供了强大的工具,可以创建丰富多样的游戏环境。

随着技术的不断发展,基于噪声的程序化地形生成还将继续演进。未来的发展方向包括:

  1. 机器学习辅助地形生成:利用GAN等技术学习真实地形特征
  2. 混合噪声算法:结合多种噪声函数创造更自然的地形
  3. 实时全球尺度地形:支持行星级别的无缝地形生成和探索
  4. 地形与生态系统集成:基于地形特征自动生成匹配的植被和生态系统

无论是独立游戏开发者还是大型游戏工作室,掌握噪声地形生成技术都能显著提升游戏开发效率和游戏世界的丰富度。希望本文能为您的Unity开发之旅提供有价值的参考。

参考资源

  • Unity官方文档 - 程序化地形生成
  • Sebastian Lague - 程序化地形生成教程
  • The Nature of Code - 噪声算法
  • GPU Gems 3 - 实时程序化地形技术

相关文章:

Unity利用噪声生成动态地形

引言 在游戏开发中&#xff0c;地形是构建游戏世界的基础元素之一。传统的地形创建方法通常依赖于手动建模或预设资源&#xff0c;这种方式虽然精确但缺乏灵活性&#xff0c;且工作量巨大。而使用噪声算法生成地形则提供了一种程序化、动态且高效的解决方案。本文将详细介绍如…...

浅谈StarRocks SQL性能检查与调优

StarRocks性能受数据建模、查询设计及资源配置核心影响。分桶键选择直接决定数据分布与Shuffle效率&#xff0c;物化视图可预计算复杂逻辑。执行计划需关注分区裁剪、谓词下推及Join策略&#xff0c;避免全表扫描或数据倾斜。资源层面&#xff0c;需平衡并行度、内存限制与网络…...

java 中散列表(Hash Table)和散列集(Hash Set)是基于哈希算法实现的两种不同的数据结构

在 Java 中&#xff0c;散列表&#xff08;Hash Table&#xff09;和散列集&#xff08;Hash Set&#xff09;是两种不同的数据结构&#xff0c;但它们都基于哈希表的原理来实现。下面是它们的联系与区别、实现类以及各自的优缺点&#xff0c;并用表格进行对比整理。 联系与区…...

python编写的一个打砖块小游戏

游戏介绍 打砖块是一款经典的街机游戏&#xff0c;玩家控制底部的挡板&#xff0c;使球反弹以击碎上方的砖块。当球击中砖块时&#xff0c;砖块消失&#xff0c;球反弹&#xff1b;若球碰到挡板&#xff0c;则改变方向继续运动&#xff1b;若球掉出屏幕底部&#xff0c;玩家失…...

【菜鸟飞】通过vsCode用python访问公网deepseek-r1等模型(Tocken模式)

目标 通过vsCode用python访问deepseek。 环境准备 没有环境的&#xff0c;vscode环境准备请参考之前的文章&#xff0c;另外需安装ollama&#xff1a; 【菜鸟飞】用vsCode搭建python运行环境-CSDN博客 AI入门1&#xff1a;AI模型管家婆ollama的安装和使用-CSDN博客 选读文章…...

Figma介绍(基于云的协作式界面设计工具,主要用于UI/UX设计、原型制作和团队协作)

文章目录 注册和登录简单操作说明Figma介绍**核心特点**1. **云端协作与实时同步**2. **跨平台兼容**3. **高效设计工具**4. **原型交互与动效**5. **开发对接友好**6. **插件生态**7. **版本控制与历史记录** **适用场景**- **团队协作**&#xff1a;远程团队共同设计、评审、…...

Text-to-SQL将自然语言转换为数据库查询语句

有关Text-To-SQL方法&#xff0c;可以查阅我的另一篇文章&#xff0c;Text-to-SQL方法研究 直接与数据库对话-text2sql Text2sql就是把文本转换为sql语言&#xff0c;这段时间公司有这方面的需求&#xff0c;调研了一下市面上text2sql的方法&#xff0c;比如阿里的Chat2DB,麻…...

什么是 Fisher 信息矩阵

什么是 Fisher 信息矩阵 Fisher 信息矩阵是统计学和机器学习中一个重要的概念,它用于衡量样本数据所包含的关于模型参数的信息量。 伯努利分布示例 问题描述 假设我们有一个服从伯努利分布的随机变量 X X X,其概率质量函数为 P ( X ...

XSS漏洞靶场---(复现)

XSS漏洞靶场—&#xff08;复现&#xff09; 反射型 XSS 的特点是攻击者诱导用户点击包含恶意脚本的 URL&#xff0c;服务器接收到请求后将恶意脚本反射回响应页面&#xff0c;浏览器执行该脚本从而造成攻击&#xff0c;恶意脚本不会在服务器端存储。 Level 1(反射型XSS) 此漏…...

基于ssm的电子病历系统(全套)

一、系统架构 前端&#xff1a;jsp | bootstrap | jquery 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven | tomcat | idea 二、代码及数据库 三、功能介绍 01. 登录 02. 主页 03. 管理员-个人中心-修改密码…...

Linux-数据结构-线性表-单链表

一.链表的概念 【1】线性表的链式存储 解决顺序存储的缺点&#xff0c;插入和删除&#xff0c;动态存储问题。 【2】特点&#xff1a; 线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素&#xff0c;存储单元可以是连续的&#xff0c;也可以不连续。可以被存…...

基于SpringBoot的Mybatis和纯MyBatis项目搭建的区别

【由于之前学习MyBatis的时候是跟着视频敲的纯MyBatis项目&#xff0c;以至于在突然看到别人在SpringBoot项目里搭建MyBatis方式的时候很懵比…特此文字形式记录一下区别&#xff08;应该还有好多种其他方式是我不知道的&#xff0c;主要应该就是要知道关键的流程步骤&#xff…...

通过 Python 爬虫提高股票选股胜率

此贴为Python爬虫技术学习贴 在股票中&#xff0c;即便有了选股规则&#xff0c;从5000多只股票中筛选出符合规则的股票也是十分困难的&#xff0c;于是想通过爬虫来实现自动化的快速选股。全文用GP代替股票 实现方案 1、指定两套规则&#xff0c;第一套弱约束&#xff0c;第…...

OpenEuler20.3 安装 Elasticsearch7.17

1、下载elasticsearch wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.17-linux-x86_64.tar.gz wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.17-linux-x86_64.tar.gz.sha512 shasum -a 512 -c elasticsea…...

大数据学习(68)- Flink和Spark Streaming

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…...

Fastdata极数:中国民宿行业发展趋势报告2025

2024年&#xff0c;中国游客出行次数大幅上涨&#xff0c;旅游相关支出也复苏强劲。2025年中国旅游业还将持续稳健的复苏及增长。同时&#xff0c;中国旅游业将见证一场深刻的变革&#xff0c;这场变革的推动力是消费者对旅游期望的转变&#xff0c;经济因素和年轻人全新价值观…...

图论——广度优先搜索实现

99. 岛屿数量 题目描述 给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成,并且四周都是水域。你可以假设矩阵外均被水包围。 输入描述 第一行包含两个整数 N, M,表示矩阵的行数和列数。 后续 N 行,每行…...

【FAQ】HarmonyOS SDK 闭源开放能力 —Map Kit(6)

1.问题描述&#xff1a; 使用华为内置的MapComponent&#xff0c; 发现显示不出来。查看日志&#xff0c; MapRender底层有报错。 解决方案&#xff1a; 麻烦按以下步骤检查下地图服务&#xff0c;特别是签名证书指纹那部分。 1.一般没有展示地图&#xff0c;可能和没有配置…...

【MySQL】B树和B+树的区别?MySQL为什么选用B+树作为索引数据结构?

B树和B树的区别&#xff1a; 结构方面&#xff1a; 1.节点存储内容&#xff1a; B树&#xff1a; 节点同时存储索引和数据。B树&#xff1a;只有叶子节点存储数据记录或指向数据记录的指针&#xff0c;非叶子节点只存键值&#xff0c;用于索引。 B 树的非叶子节点可以存储更…...

鸿蒙路由 HMrouter 配置及使用一

1、学习链接 HMRouter地址 https://gitee.com/hadss/hmrouter/blob/dev/HMRouterLibrary/README.md 2、工程配置 下载安装 ohpm install hadss/hmrouter 添加编译插件配置 在工程目录下的build-profile.json5中&#xff0c;配置useNormalizedOHMUrl属性为true (我这项目创…...

ERC-6909 最小多代币标准

ERC-6909 Token标准是 ERC-1155 Token标准的一种简化替代方案。 ERC-1155 标准引入了一种多Token接口&#xff0c;使得单个智能合约能够结合可替代的和不可替代的Token&#xff08;即&#xff0c;​ERC20 和 ERC721&#xff09;。 ERC-1155 解决了多个挑战&#xff0c;例如降…...

各省水资源平台 水资源遥测终端机都用什么协议

各个省水资源平台 水资源遥测终端机 的建设大部分从2012年开始启动&#xff0c;经过多年建设&#xff0c;基本都已经形成了稳定的通讯要求&#xff1b;河北瑾航科技 遥测终端机&#xff0c;兼容了大部分省市的通讯协议&#xff0c;如果需要&#xff0c;可以咨询和互相学习&…...

需求分析、定义、验证、变更、跟踪(高软47)

系列文章目录 需求分析、定义、验证、变更、跟踪 文章目录 系列文章目录前言一、需求分析二、需求定义三、需求验证四、需求变更五、需求跟踪六、真题总结 前言 本节讲明需求分析、定义、验证、变更、跟踪相关知识。 一、需求分析 二、需求定义 三、需求验证 四、需求变更 五、…...

从零开始 | C语言基础刷题DAY3

❤个人主页&#xff1a;折枝寄北的博客 目录 1.打印3的倍数的数2.从大到小输出3. 打印素数4.打印闰年5.最大公约数 1.打印3的倍数的数 题目&#xff1a; 写一个代码打印1-100之间所有3的倍数的数字 代码&#xff1a; int main(){int i 0;for (i 1; i < 100; i){if (i % …...

PostreSQL指南-内幕探索-学习笔记-01-数据库集簇的逻辑与物理结构

目录 一、环境信息 二、参考内容 三、逻辑结构概念 四、物理结构概念 五、逻辑映射关系 1、数据库与oid映射关系 2、堆表对象与oid映射关系 五、物理映射关系 1、数据库与oid映射关系 2、堆表对象与oid映射关系 六、数据库文件布局 1、表格 2、postmaster.pid文件解…...

docker入门篇

使用docker可以很快部署相同的环境,这也是最快的环境构建,接下来就主要对docker中的基础内容进行讲解.Docker 是一个用于开发、交付和运行应用程序的开源平台&#xff0c;它可以让开发者将应用程序及其依赖打包到一个容器中&#xff0c;然后在任何环境中运行这个容器&#xff0…...

Unity Shader - UI Sprite Shader之简单抠图效果

Sprite抠图效果&#xff1a; 前言 在PhotoShop中我们经常会用到抠图操作&#xff0c;现在就用Shader实现一个简单的抠图效果。 实现原理&#xff1a; 使用当前像素颜色与需要抠掉的颜色相减作比较&#xff0c;然后与一个指定的阈值比较以决定是否将其显示出来&#xff1b; U…...

本地仓库设置

将代码仓库初始化为远程仓库&#xff0c;主要涉及在服务器上搭建 Git 服务&#xff0c;并将本地代码推送到服务器上。以下是详细的步骤&#xff1a; 1. 选择服务器 首先&#xff0c;你需要一台服务器作为代码托管的远程仓库。服务器可以是本地服务器、云服务器&#xff0c;甚…...

30、Vuex 为啥可以进行缓存处理

Vuex 状态管理基础与缓存的关联 Vuex 的核心概念&#xff1a; Vuex 主要由五个部分组成&#xff1a;state、mutations、actions、getters和modules。其中&#xff0c;state是存储数据的地方&#xff0c;类似于一个全局的数据仓库。在这个菜谱 APP 的例子中&#xff0c;缓存的数…...

ngx_http_conf_ctx_t

定义在 src/http/ngx_http_config.h typedef struct {void **main_conf;void **srv_conf;void **loc_conf; } ngx_http_conf_ctx_t; ngx_http_conf_ctx_t 是 Nginx 中用于管理 HTTP 配置上下文的核心结构体&#xff0c;其设计体现了 Nginx 多级配置&…...