【three.js】22. Imported Models导入模型

news2024/11/25 4:24:27

22. Imported Models导入模型

介绍

Three.js 可以让你创建很多原始几何体,但是当涉及到更复杂的形状时,我们最好使用专用的 3D 软件建模。
在本课中,我们将使用已经制作好的模型,但我们将在以后的课程中学习如何完全在 3D 软件中创建模型。

格式

随着时间的推移,已经出现了许多 3D 模型格式。每个3D格式都在给予大家解决方案,比如模型中嵌入了什么数据、权重、压缩、兼容性、版权等。
这就是为什么今天我们可以访问数百种模型格式:https://en.wikipedia.org/wiki/List_of_file_formats#3D_graphics。
有些3D格式专用于一种软件。一些已知非常轻,但有时缺乏具体数据。众所周知,有些存储库几乎包含您可能需要的所有数据,但它们很重。有些格式是开源的,有些格式不是,有些是二进制的,有些是 ASCII,等等。
如果您需要精确的数据并且找不到您的软件支持的适当格式,您甚至可以很容易地创建自己的格式。
以下是您可能会遇到的流行格式列表:

  • OBJ
  • FBX
  • STL
  • PLY
  • COLLADA
  • 3DS
  • GLTF

我们不会涵盖所有这些格式。这会很无聊,我们不需要这样做,因为已经有一种格式正在成为一种标准,应该可以满足您的大部分需求。

GLTF

GLTF 代表 GL 传输格式。它由 Khronos Group(OpenGL、WebGL、Vulkan、Collada 背后的人以及许多成员,如 AMD / ATI、Nvidia、Apple、id Software、Google、Nintendo 等)制作。
GLTF 在过去几年变得非常流行。
它支持不同的数据集。它可以包括几何体和材质等数据,也可以包括相机、灯光、场景图、动画、骨架、变形甚至多场景等数据。
它还支持各种文件格式,如 json、binary、embed textures。
GLTF 已成为实时标准。由于它正在成为一种标准,大多数 3D 软件、游戏引擎和库都要支持它。这意味着您可以在不同的环境中轻松获得相似的结果。
这并不意味着您必须在所有情况下都使用 GLTF。如果您只需要一个几何图形,您最好使用其他格式,如 OBJ、FBX、STL 或 PLY。你应该在每个项目上测试不同的格式,看看你是否拥有你需要的所有数据,文件是否太大,如果信息被压缩需要多长时间才能解压等等。

查找模型

首先,我们需要一个模型。正如我们之前所说,稍后我们将学习如何在 3D 软件中创建我们自己的模型,但现在,让我们使用预制模型。
GLTF 团队还提供各种模型,从简单的三角形到逼真的模型以及动画、变形、透明涂层材料等。
您可以在此存储库中找到它们:https://github.com/KhronosGroup/glTF-Sample-Models
如果你想测试这些模型,你必须下载或克隆整个存储库并获取你需要的文件。但我们将从一只简单的鸭子开始,您可以在/static/models/启动器的文件夹中找到它。

GLTF格式

虽然 GLTF 本身是一种格式,但它也可以有不同的文件格式。这有点复杂,但有充分的理由。
如果您打开该/static/models/Duck/文件夹,您将看到 4 个不同的文件夹。每个都包含鸭子,但 GLTF 格式不同:

  • glTF
  • glTF-Binary
  • glTF-Draco
  • glTF-Embedded

你甚至可以找到其他格式,但这 4 种是最重要的,涵盖了我们需要学习的内容。
当心; 您的操作系统可能会隐藏其中一些文件的扩展名。请参考代码编辑器中应显示扩展名的文件名。

glTF

这种格式是一种默认格式。该Duck.gltf文件是一个 JSON格式,您可以在编辑器中打开它。它包含各种信息,如相机、灯光、场景、材质、对象转换,但既不包含几何体也不包含纹理。该Duck0.bin文件是二进制文件,您无法打开阅读。它通常包含几何数据和与顶点相关的所有信息,如 UV 坐标、法线、顶点颜色等。DuckCM.png文件只是鸭子的纹理。
当我们加载这种格式时,我们只要加载Duck.gltf包含对其他文件的引用的文件,这些文件将被自动加载。

glTF-Binary

这种格式仅由一个文件组成。它包含我们在 glTF 默认格式中讨论的所有数据。那是一个二进制文件,您不能只在代码编辑器中打开它来查看里面的内容。
由于只有一个文件,因此这种格式可以更轻便且加载起来更舒适,但您将无法轻松更改其数据。例如,如果你想调整纹理大小或压缩纹理,你不能因为它在那个二进制文件中而与其他文件合并。

glTF-Draco

这种格式类似于glTF 默认格式,但缓冲区数据(通常是几何图形)是使用Draco 算法压缩的。如果比较.bin文件大小,您会发现它要轻得多。
虽然此格式有一个单独的文件夹,但您可以将 Draco 压缩应用于其他格式。
这个先放一边,以后再说。

glTF-Embedded

这种格式类似于glTF-Binary格式,因为它只有一个文件,但这个文件实际上是一个 JSON,您可以在编辑器中打开它。
这种格式的唯一好处是只有一个易于编辑的文件。

选择

选择正确的格式取决于您希望如何处理资源。
如果你想在导出后能够改变纹理或灯光的坐标,你最好选择glTF-default。它还具有分别加载不同文件的优势,从而提高了加载速度。
如果每个模型只需要一个文件并且不关心要不要修改资源,则最好选择glTF-Binary
在这两种情况下,您都必须决定是否要使用Draco压缩,但我们稍后会介绍这一部分。

设置

启动器由一个空平面组成。
因为 GLTF 是一个标准,它显然支持灯光。通常,当您将 GLTF 导入 Three.js 项目时,您最终会得到具有MeshStandardMaterial的网格,您可能还记得,如果您的场景中没有灯光,您将看不到太多这些材料。
启动器中已经有一个AmbientLight和一个DirectionalLight 。

在 Three.js 中加载模型

要在 Three.js 中加载 GLTF 文件,我们必须使用GLTFLoader。此类在THREE变量中默认不可用。我们需要从three位于examples/依赖项中的文件夹中导入它:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'

然后我们可以像为 TextureLoader 一样实例化它:

/**
 * Models
 */
const gltfLoader = new GLTFLoader()

如果需要,我们也可以像在纹理课程中那样使用LoadingManager。
要加载模型,好消息,它几乎和加载纹理一样简单。我们调用该load(...)方法并使用正确的参数:

  • 文件的路径
  • 成功回调函数
  • 进度回调函数
  • 错误回调函数
gltfLoader.load(
    '/models/Duck/glTF/Duck.gltf',
    (gltf) =>
    {
        console.log('success')
        console.log(gltf)
    },
    (progress) =>
    {
        console.log('progress')
        console.log(progress)
    },
    (error) =>
    {
        console.log('error')
        console.log(error)
    }
)

您应该看到进度和正在调用的成功函数。如果无法加载文件,可能会调用错误函数。检查路径,不要忘记我们不能添加路径是/static的部分。

gltfLoader.load(
    '/models/Duck/glTF/Duck.gltf',
    (gltf) =>
    {
        console.log(gltf)
    }
)

将加载的模型添加到我们的场景中

如果查看控制台中记录的对象,您会发现很多元素。最重要的部分是scene属性,因为我们在导出的模型中只有一个场景。
scene包含了我们需要的一切。但它还包括更多。始终从研究其中可用的内容开始,并观察不同Groups、Object3D和Mesh的scale缩放属性。
我们得到这样的东西:

THREE.Group: scene
└───Array: children
    └───THREE.Object3D
        └───Array: children
            ├───THREE.PerspectiveCamera
            └───THREE.Mesh

mesh网格应该是我们的鸭子。我们并不真正关心PerspectiveCamera。相机和鸭子似乎都在场景的子数组中的第一个也是唯一一个Object3D中。更糟糕的是,Object3D已将scale设置为最小值。
正如您所看到的,即使是获取我们的鸭子也有点复杂,这是大多数初学者迷路的地方。
我们想要的只是让我们的鸭子出现在场景中。我们有多种方法可以做到这一点:

  • 将整体添加到我们的scene场景中。我们可以这样做,因为即使它的名字是scene,它实际上是一个Group。
  • scene的子项添加到我们的场景中并忽略未使用的PerspectiveCamera。
  • 在添加到场景之前过滤子项以删除不需要的对象,如PerspectiveCamera。
  • 仅添加网格,但最终得到的鸭子可能会被错误地缩放、定位或旋转。
  • 在 3D 软件中打开文件并删除PerspectiveCamera,然后再次导出GITF文件。

因为我们的模型结构简单,我们将Object3D添加到我们的场景中,而忽略里面未使用的PerspectiveCamera。在以后的课程中,我们会将整个场景添加为一个对象:

gltfLoader.load(
    '/models/Duck/glTF/Duck.gltf',
    (gltf) =>
    {
        scene.add(gltf.scene.children[0])
    }
)


你应该看到渲染了一只鸭子。
您可以尝试其他格式,但不能尝试尚不能使用的 Draco

gltfLoader.load(
    '/models/Duck/glTF/Duck.gltf', // Default glTF

// Or
gltfLoader.load(
    '/models/Duck/glTF-Binary/Duck.glb', // glTF-Binary

// Or
gltfLoader.load(
    '/models/Duck/glTF-Embedded/Duck.gltf', // glTF-Embedded

文件夹中提供了另一个名为FlightHelmet(也取自glTF 模型示例/static/models/)的模型。该模型只有一种格式,即默认的 glTF。
尝试加载此模型:

gltfLoader.load(
    '/models/FlightHelmet/glTF/FlightHelmet.gltf',
    (gltf) =>
    {
        scene.add(gltf.scene.children[0])
    }
)


我们没有得到漂亮的头盔,只渲染了几个零件。
问题是我们只将 loaded 的第一个child添加到我们的scene场景中。
我们可以尝试的是循环孩子并将他们添加到场景中:

for(const child of gltf.scene.children)
{
    scene.add(child)
}


这将产生更多元素,但不是全部。更糟糕的是,刷新时,您可能会得到不同的部分。
问题是当我们将一个child从一个场景添加到另一个场景时,它会自动从第一个场景中删除。这意味着现在第一个场景中的child更少了。
当我们添加第一个对象时,它会从第一个场景中移除,而第二个元素只是移动到第一个位置。但是您的循环现在采用数组的第二个元素。您将始终在children数组中保留元素。
这个问题有多种解决方案。第一个解决方案是获取已加载场景的第一个子节点并将其添加到我们的场景中,直到没有剩余为止:

while(gltf.scene.children.length)
{
    scene.add(gltf.scene.children[0])
}


我们现在得到了整个头盔。
另一种解决方案是复制children数组以获得一个未更改的独立数组。为此,我们可以使用扩展运算符...并将结果放入一个全新的数组中[]:

const children = [...gltf.scene.children]
for(const child of children)
{
    scene.add(child)
}

这是一种原生 JavaScript 技术,可以在不触及原始数组的情况下复制数组。
最后,我们之前提到的一个简单好用的解决方案是添加属性scene

scene.add(gltf.scene)

我们的头盔太小了,我们只能增加比例,但我们会回到我们的 Duck 并尝试使用 Draco 压缩版本。

Draco compression 压缩

让我们回到我们的鸭子,但这一次,我们将使用 Draco 版本:

gltfLoader.load(
    '/models/Duck/glTF-Draco/Duck.gltf',


可悲的是,我们没有得到任何鸭子。如果您查看日志,您应该会看到如下所示的警告No DRACOLoader instance provided。我们需要为我们的GLTFLoader提供一个DRACOLoader实例,以便它可以加载压缩文件。
image.png
正如我们在浏览文件时看到的,Draco 版本比默认版本要轻得多。压缩应用于缓冲区数据(通常是几何图形)。使用默认的 glTF、二进制 glTF或嵌入式 glTF并不重要。
它甚至不是 glTF 独有的,您可以将它与其他格式一起使用。但是 glTF 和 Draco 同时流行起来,所以 glTF 导出器的实现速度更快。
谷歌在开源 Apache 许可下开发算法:

  • 网站: https: //google.github.io/draco/
  • Git 存储库: https: //github.com/google/draco

添加 DRACOLoader

Three.js 已经支持 Draco。我们必须从DRACOLoader导入开始:

import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'

然后我们可以实例化加载器(在 gltfLoader 之前):

const dracoLoader = new DRACOLoader()

解码器在原生 JavaScript 和 Web Assembly (wasm) 中可用,并且它可以在 worker 中运行(我们在物理课结束时看到的另一个线程)。这两个功能显著提高了性能,但它们意味着具有完全独立的代码。
Three.js 已经提供了这个分离的代码。要找到它,我们必须浏览到 Three.js 依赖项并将 Draco 解码器文件夹复制到我们的/static/文件夹中。
这个 Draco 文件夹位于/node_modules/three/examples/js/libs/. 获取整个/draco/文件夹并将其复制到您的/static/文件夹中。我们现在可以将此文件夹的路径提供给我们的dracoLoader

dracoLoader.setDecoderPath('/draco/')

最后,我们可以使用setDRACOLoader(...)方法将DRACOLoader实例提供给GLTFLoader实例:

gltfLoader.setDRACOLoader(dracoLoader)


你的鸭子应该回来了,但这次是 Draco 压缩版本。
您仍然可以使用GLTFLoader加载未压缩的 glTF 文件,并且仅在需要时加载 Draco 解码器。

何时使用 Draco 压缩

虽然您可能认为 Draco 压缩是一个双赢的局面,但事实并非如此。是的,几何体更轻,但首先,您必须加载DRACOLoader类和解码器。其次,您的计算机需要花费时间和资源来解码压缩文件,这可能会导致体验开始时出现短暂的卡顿,即使我们使用的是 worker 和 Web Assembly 代码也是如此。
你必须适应并决定什么是最好的解决方案。如果你只有一个 100kB 几何模型,你可能不需要 Draco。但是,如果您有很大 MB 的模型要加载并且不关心用户体验开始时要进行一些等待,您可能需要 Draco 压缩。

动画

正如我们之前所说,glTF 也支持动画。Three.js 可以处理这些动画。

加载动画模型

首先,我们需要一个动画模型。我们可以使用位于文件夹中的狐狸/static/models/Fox/(也取自glTF 模型示例)。
更改加载该狐狸的路径:

gltfLoader.load(
    '/models/Fox/glTF/Fox.gltf',

tutieshi_640x400_5s.gif
我们渲染出现了问题; 狐狸太大了。如果您看不到它,请查看上方或缩小。
在处理动画之前,让我们修复比例。如果您查看导入场景的组成,狐狸由一个Object3D组成,它本身由一个Bone和一个SkinnedMesh组成。我不会解释它们是什么,但是我们不应该简单地缩放Object3D就解决问题了。即使现在可以用缩放解决,但是它可能不适用于更复杂的模型。
我们在这里可以做的是缩放加载的场景并将其直接添加到我们的场景中:

gltfLoader.load(
    '/models/Fox/glTF/Fox.gltf',
    (gltf) =>
    {
        gltf.scene.scale.set(0.025, 0.025, 0.025)
        scene.add(gltf.scene)
    }
)

处理动画

如果查看加载的对象,您会看到一个名为gltf包含多个AnimationClip 的animations属性。
image.png
这些AnimationClip不能轻易使用。我们首先需要创建一个AnimationMixer。AnimationMixer就像一个可以包含一个或多个AnimationClips 的对象相关联的播放器。这个想法是为每个需要动画的对象创建一个。
在 success 函数中,创建一个AnimationMixer混音器并发送gltf.sceneas 参数:

const mixer = new THREE.AnimationMixer(gltf.scene)

我们现在可以使用clipAction(...)该方法将AnimationClip添加到混合器中。让我们从第一个动画开始:

const action = mixer.clipAction(gltf.animations[0])

这个方法返回一个AnimationAction,我们终于可以调用play()它的方法了:

action.play()

遗憾的是,还是没有动画。
要播放动画,我们必须告诉混音器在每一帧更新自己。问题是我们的mixer变量已经在加载回调函数中声明了,我们在函数中无权访问它tick。为了解决这个问题,我们可以在加载回调函数之外声明一个mixer = null值的变量,并在加载模型时更新它:

let mixer = null

gltfLoader.load(
    '/models/Fox/glTF/Fox.gltf',
    (gltf) =>
    {
        gltf.scene.scale.set(0.03, 0.03, 0.03)
        scene.add(gltf.scene)

        mixer = new THREE.AnimationMixer(gltf.scene)
        const action = mixer.clipAction(gltf.animations[0])
        action.play()
    }
)

最后,我们可以用已经计算好的deltaTime 更新tick函数中的混音器。
但在更新它之前,我们必须测试mixer变量是否与null不同。这样,如果模型已加载,我们不会更新混音器,这意味着动画尚未准备好:

const tick = () =>
{
    // ...

    if(mixer)
    {
        mixer.update(deltaTime)
    }

    // ...
}

tutieshi_640x400_6s.gif
动画应该正在运行。您可以通过更改clipAction(...)方法中的值来测试其他动画。

const action = mixer.clipAction(gltf.animations[2])

tutieshi_640x400_4s.gif

Three.js在线编辑器

Three.js 拥有自己的在线编辑器。你可以在这里找到它: https: //threejs.org/editor/

它就像一个 3D 软件,但在线且功能较少。您可以创建图元、灯光、材质等。
因为您可以导入模型,所以这是测试您的模型是否正常工作的好方法。虽然要小心; 您只能测试由一个文件组成的模型。您可以尝试使用 glTF-Binary 或 glTF-Embedded 的文件格式。
将模型拖放到编辑器中。

你应该看到一只黑鸭子,因为没有光。从菜单中添加一个AmbientLight和一个DirectionalLight以更清楚地查看它。

最后,您可以以各种格式导出您的场景,您可以在您的代码中重复使用这些格式,但不在我们讨论范围内。
目前就是这样,但我们将在接下来的课程中多次使用加载的模型进行开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1494487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人人都写过的6个bug

大家好&#xff0c;我是知微。 程序员写bug几乎是家常便饭&#xff0c;也是我们每个人成长过程中难以避免的一部分。 为了缓解这份“尴尬”&#xff0c;今天想和大家分享一些曾经都会遇到过的bug&#xff0c;让我们一起来看看这些“经典之作”。 1、数组越界 #include <…

如何给Vue项目配置好一个nginx.conf文件?

如何给Vue项目配置好一个nginx.conf文件&#xff1f; 一般前端项目中&#xff0c;会有一个docker/nginx/nginx.conf文件&#xff0c;用于配置DockerFile配置等。 那么&#xff0c;如何给项目写好一个nginx.conf文件&#xff0c;以DockerFile为例&#xff1a; # 使用 Node.js …

SpringBoot+Mybatis-plus+shardingsphere实现分库分表

SpringBootMybatis-plusshardingsphere实现分库分表 文章目录 SpringBootMybatis-plusshardingsphere实现分库分表介绍引入依赖yaml配置DDL准备数据库ds0数据库ds1 entitycotrollerserviceMapper启动类测试添加修改查询删除 总结 介绍 实现亿级数据量分库分表的项目是一个挑战…

第三百八十五回

文章目录 1.概念介绍2.使用方法3.示例代码 我们在上一章回中介绍了Snackbar Widget相关的内容,本章回中将介绍TimePickerDialog Widget.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1.概念介绍 我们在这里说的TimePickerDialog是一种弹出窗口&#xff0c;只不过窗口的内容…

Windows10 安装Neo4j流程

1、下载并安装ava运行环境 官网链接&#xff08;需要注册Oracle账号&#xff09;&#xff1a;https://www.oracle.com/java/technologies/downloads/ 根据自己Neo4j版本确认需要的JDK版本 百度网盘链接&#xff1a; 链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/…

Unity 整体界面淡入淡出效果

在Unity中&#xff0c;如果我们要实现控制多个组件同时淡出&#xff0c;同时淡入的效果&#xff0c;可以使用DOTween插件实现。 如图&#xff0c;一个页面中带有背景&#xff0c;一张图片&#xff0c;一个文本&#xff0c;一个滑动条。 要实现以上界面的整体淡入淡出&#xff…

企业内部培训考试系统在线考试都用到了哪些防作弊技术?

企业内部培训考试系统在线考试功能采用了多种技术手段来防止作弊行为&#xff0c;确保考试的公平性和有效性&#xff0c;具体如下&#xff1a; 1. 人脸识别验证&#xff1a;在考试开始前&#xff0c;考生需要进行人脸识别核验。系统会根据考生的姓名和身份证号实时采集人脸与公…

Python 弱引用全解析:深入探讨对象引用机制!

目录 前言 弱引用的概述 弱引用的原理 使用 WeakRef 类创建弱引用 使用 WeakValueDictionary 类创建弱引用字典 实际应用场景 1. 解决循环引用问题 2. 对象缓存 总结 前言 在Python编程中&#xff0c;弱引用&#xff08;Weak Reference&#xff09;是一种特殊的引用方式…

Android开发技巧,最详细的解释小白也能听懂

今天&#xff0c;跟大家聊聊&#xff0c;Framework开发的那些事。 系统应用开发&#xff0c;现在来说&#xff0c;已经开始脱离系统&#xff0c;单独拿出来开发&#xff0c;系统定制接口&#xff0c;已提供给应用调用&#xff0c;用来增强功能。 原生的桌面&#xff0c;拨号&…

【Java面试/24春招】技术面试题的准备

Spring MVC的原理 Mybatis的多级缓存机制 线程池的大小和工作原理 上述问题&#xff0c;我们称为静态的问题&#xff0c;具有标准的答案&#xff0c;而且这个答案不会变化&#xff01; 如果没有Spring&#xff0c;会怎么样&#xff1f;IOC这个思想是解决什么问题&#xff1f…

2024年腾讯云发红包了,可用于抵扣订单金额,你们领了吗?

在2024年腾讯云新春采购节优惠活动上&#xff0c;可以领取新年惊喜红包&#xff0c;打开活动链接 https://curl.qcloud.com/oRMoSucP 会自动弹出红包领取窗口&#xff0c;如下图&#xff1a; 腾讯云2024新春采购节红包领取 如上图所示&#xff0c;点击“领”红包&#xff0c;每…

Android学习笔记在互联网上火了,Android资深架构师分享学习经验及总结

本篇将由 环境搭建、实现原理、编程开发、插件开发、编译运行、性能稳定、发展未来 等七个方面&#xff0c;对当前的 React Native 和 Flutter 进行全面的分析对比&#xff0c;希望能给你更有价值的参考。 前言 移动端跨平台在经历数年沉浮之后&#xff0c;如今还能在舞台聚光…

Android开发真等于废人,历经30天

前言 回顾一下自己这段时间的经历&#xff0c;三月份的时候&#xff0c;疫情原因公司通知了裁员&#xff0c;我匆匆忙忙地出去面了几家&#xff0c;但最终都没有拿到offer&#xff0c;我感觉今年的寒冬有点冷。到五月份&#xff0c;公司开始第二波裁员&#xff0c;我决定主动拿…

【《高性能 MySQL》摘录】第 9 章 操作系统和硬件优化

文章目录 9.1 什么限制了MySQL的性能9.2 如何为 MySQL 选择 CPU9.2.1 哪个更好&#xff1a;更快的 CPU 还是更多的 CPU9.2.2 CPU架构9.2.3 扩展到多个CPU和核心 9.3 平衡内存和磁盘资源9.3.1 随机 I/O 和顺序 I/O9.3.2 缓存&#xff0c;读和写9.3.3 工作集是什么9.3.4 找到有效…

QT 5.14.2版本 MAC环境安装部署流程

下载地址 &#xff1a;https://download.qt.io/archive/qt/5.14/5.14.2/ 下载完成后如下 双击打开安装&#xff0c;会弹出验证&#xff0c;等待验证完成 点击next 下一步&#xff0c;开始安装 如果你还没有qt账号&#xff0c;则先注册账号 &#xff0c;注册完后输入账号&#…

【报错】PyCharm安装插件时出现Error loading package list:Unexpected end of file from server

Q PyCharm安装插件时出现 Error loading package list:Unexpected end of file from server提示窗口。 A 将Python Interpreter——>——>Manage Repositories中无法用的源删掉 刷新

Xilinx 7系列 FPGA硬件知识系列(三)—— Bank划分及引脚定义

目录 用户Bank BANK 0&#xff08;配置BANK&#xff09; BANK 14&#xff08;HR BANK&#xff09; BANK 116/117/118&#xff08;GTX BANK&#xff09; 7系列的FPGA开始才有HP BANK和HR BANK&#xff0c;UltraScale FPGA有HP BANK、HR BANK和HD BANK&#xff0c;但并不是一…

HashMap 源码解读

文章目录 一、什么是HashMap HashMap 是一种快速的查找并且插入、删除性能都良好的一种 K/V键值对的数据结构&#xff0c;key唯一&#xff0c;value允许重复它基于哈希表的 Map 接口实现&#xff0c;是常用的 Java 集合之一&#xff0c;是非线程安全的。 二、HashMap的数据结…

android开发板调试,Android程序员的春天

前言 大家好&#xff01;给大家介绍一下&#xff0c;这是我们持续更新整理的2021年最新的阿里&#xff1b;百度&#xff1b;腾讯&#xff1b;字节跳动等大厂的Android面试真题解析&#xff01; 早在2018年我们就建了第一个BAT等大厂的面试群给大家讨论面试的东西。期间累计有…

java工程师面试技巧,最新Java开发面试解答

一、前言 聊的是八股的文&#xff0c;干的是搬砖的活&#xff01; 面我的题开发都用不到&#xff0c;你为什么要问&#xff1f;可能这是大部分程序员求职时的经历&#xff0c;甚至也是大家讨厌和烦躁的点。明明给的是拧螺丝的钱、明明做的是写CRUD的事、明明担的是成工具的人…