作为在该领域小白的我,在准备该主题分享之前,我信心满满的去知乎查了下,如何学习 WebGL?
如何入手webGl以及three.js呢? - 知乎[1]
前端开发者应该如何学习计算机图形学相关的知识? - 知乎[2]
大三计算机,想接触图形学方面的知识,直接学WebGL还是OpenGL ? - 知乎[3] 等 .......
摘取自知乎回复:图形 + 数学 + 体系结构 + 操作系统 + 软件工程 + 设计模式 + 编译原理 + (C++功力) ≈ 更好的3D 软件工程师。(然而我不想成为更好的3D 软件工程师)
同时也看了很多大佬分享学习路径,基本上都是:
1 . 图形学 和 数学 打好基础。
网友说:推荐看3d数学基础这本书,学好线性代数,接口本质就是数学和物理,涉及大量矩阵变换...
2 . 选择一个领域,Web (WebGL、Threejs)、3D引擎、游戏 (Unity) .....
网友说:语言是以硬件为基础的,如果你了解CPU,学习C语言很随意,同样着色器语言GLSL是类似C语言的高级语言在GPU上执行的语言,学习 WebGL API和着色器语言最好去了解GPU的渲染管线、可编程着色器。语言和硬件又是隔离的,没有必要深入了解硬件,知道一个大概印象就行。
3 . 干:不断学习、不断实践、直到可以造轮子,再循环 ......
看了比较多的知乎回复后,我发现这玩意学习路径和门槛都比较高的,都是和底层、数学强相关的。而且 WebGL 技术和 Web 前端技术还是有比较大区别,感觉除了只是叫Web
外没别的相同啦。速成是不可能的,有尤其在该领域我是个小白,所以本次分享 (到此结束)。
本次分享,大致分为两个部分:
参考:WebGL,OpenGL和OpenGL ES三者的关系[4] 图
OpenGL (Open Graphics Library)
OpenGL[5] is a cross-language, cross-platform application programming interface (API) for rendering 2D and 3D vector graphics. The API is typically used to interact with a graphics processing unit (GPU), to achieve hardware-accelerated rendering.
OpenGL 是API 、是规范。GPU 硬件厂商需要满足统一OpenGL规范。而 OpenGL ES (Open Graphics Library for Embedded Systems) 是 OpenGL 子集,专门针对手机等嵌入式设备而设计的。
人话版本是:发动机(GPU) 驱动是方向盘、离合器等等,OpenGL 定义操纵 发动机(GPU) 发动规范,OpenGL 不关心方向盘是圆的还是方的,驱动 发动机(GPU) 干活啦。
用方向盘 (驱动器) -> 依照调用标准使用 ( OpenGL ) -> 指挥发动机 ( GPU ) 干活
WebGL (Web Graphics Library)
WebGL[6] is a cross-platform, royalty-free open web standard for a low-level 3D graphics API based on OpenGL ES, exposed to ECMAScript via the HTML5 Canvas element.
WebGL 是在 OpenGL ES 基础上建立的在 浏览器 跑起来的图形学标准,同理是浏览器厂商规范 ≈ 让JS 操作接口。光有规范是不够的,还要程序告诉 GPU 如何进行渲染。
GLSL (OpenGL Shading Language)
后面讲到图形渲染管线会说到,这里浅浅先通过例子感受下 立方体 demo[7]。
代码[8] 阉割版:有类C语言的着色器语言、有我们熟悉JS语言、有矩阵相乘 ...
<canvas id="canvas"></canvas>
<script type="shader-source" id="vertexShader">
precision mediump float; // 接收 JavaScript 传递过来的点的坐标(X, Y, Z)
attribute vec3 a_Position;
attribute vec4 a_Color; // 接收顶点颜色
varying vec4 v_Color;
uniform mat4 u_Matrix;
void main(){
gl_Position = u_Matrix * vec4(a_Position, 1);
v_Color = a_Color; // 将顶点颜色插值处理传递给片元着色器
gl_PointSize = 5.0;
}
</script>
<script type="shader-source" id="fragmentShader">
precision mediump float;
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color; // 点的最终颜色。
}
</script>
<script> //获取canvaslet
canvas = getCanvas('#canvas');
//使用该着色器程序
let program = createSimpleProgramFromScript(gl, 'vertexShader', 'fragmentShader');
gl.useProgram(program);
let positions = [
-0.5, -0.5, 0.5, 1, 0, 0, 1,
0.5, -0.5, 0.5, 1, 0, 0, 1,
0.5, 0.5, 0.5, 1, 0, 0, 1,
-0.5, 0.5, 0.5, 1, 0, 0, 1, .....
]
// ----- 省略一些代码 -----
function render() {
//先绕 Y 轴旋转矩阵。
matrix.rotationY(deg2radians(yAngle), dstMatrix);
//再绕 X 轴旋转
matrix.multiply(dstMatrix, matrix.rotationX(deg2radians(xAngle), tmpMatrix), dstMatrix);
//模型投影矩阵。
matrix.multiply(projectionMatrix, dstMatrix, dstMatrix)
// ----- 省略一些代码 -----
requestAnimationFrame(render);
}
</script>
Three.js
WebGL学习有门槛,Three.js[9] 作为方向入门,就像 jQuery 一样的存在,可以快速的创建出三维场景。
阶段总结
我们需要一个规范/接口告诉驱动如何 和 GPU 通信,这个规范/接口是 OpenGL,发展至今嵌入式设备崛起,OpenGL ES 也应运而生,WebGL 是基于 OpenGL ES 可以让其在浏览器上通过Javascript 调用的规范/接口,但WebGL门槛不低,要和GPU通信,就需要了解计算机图形学知识,那肯定也需要用到着色器,所以 Three.js 封装好成为三维引擎,也不用知道那么多底层知识,就可以创建 Web 3D。
这个过程就好比 深度学习领域:Tensorflow (xxx.js / Python) 都可以调调现有成熟模型,看起来是调参数十分的简单,但是模型背后是 线性代数、高数、统计学 ...
什么是渲染呢?简单的说就是从计算机程序最后到图像的过程。
大家面试都会被问到一个问题 从输入url到页面渲染完成,都经历了些什么呢?
大部分同学都止步于 ....... 生成Render Tree。那后续是如何将各种信息转换为屏幕上的像素呢?
在说明渲染过程之前,先来大致看下为什么需要 GPU?
下面绘制图片,引用来自该文档 The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe[10]
要对每个像素的计算,如此设计模式对CPU压力会比较大,故有 GPU 结构去处理该场景。
上述这么设计的原因是:对每个像素进行计算,而且是相同的运算,这样并行计算的效率会更高。
以上可以理解:GPU 计算能力不如 CPU,但是 GPU 人多力量大 (管子多,且管子只处理已知简单任务),类比于 建筑工程师 (CPU) 设计出来建筑图纸和每项任务,工人们 (GPU) 搬砖干活。
这些破管子都干了些啥?着色器又是什么?必须浅浅了解下 图形渲染管线 Render Pipeline。
回顾你的学习生涯,初中数学计算立方体面积,老师在 2D 黑板上画了XYZ 轴,并骗你这是个 3D立方体(视觉上)。
任何用3D空间中表示的事物,在 中都是2D像素数组,而WebGL/OpenGL 大部分工作也是把3D坐标转换为2D像素。这个过程叫做 图形渲染管线 Render Pipeline。
结合上面那些个GPU 模型里的破管子,有一堆原始图形数据 经过 一个 破管子后,最终输出至屏幕中的过程就是 图形渲染管线。
图形渲染管线 Render Pipeline 被划分为几个阶段,跟咱们的ByteCycle 流水线一样,每个阶段会把上个阶段的输出作为输入,也可以理解是函数式编程 pipeline 模式。也就是说,每个阶段都有专门的函数 / 小程序去处理,函数 / 小程序 ≈ 着色器 (Shader) 。
CPU 和 GPU 是通力合作的关系来渲染图像
渲染管线抽象流程
顶点着色器 | 3D坐标 转为 另一种3D坐标(后面会解释 从局部到世界坐标系),并对顶点属性进行处理。 |
---|---|
图元的装配 | 将 顶点着色器 输出的点作为输入,并绘制成图元形状。 |
几何着色器 | 将 图元形状 构造成新的图元 或 其他形状。 |
光栅化过程 | 把 图元 映射为 最终屏幕上相应的 像素。 |
片段着色器 | 计算一个像素的最终颜色。例如一个立方体在灯光照射下会有阴影,这里也会将其处理。 |
测试与混合 | 例如 有3D遮挡场景 或 物体是透明,在这个过程中就需要判断是否在该帧被丢弃。 |
简单了解下GLSL 语言,类似C语言,以下是顶点着色器的例子:
#version 300 es #声明了着色器版本号 300 代表是 3.0 之后版本
in vec4 aPos ;
# in = 输入变量 浮点型向量vec4 变量名称 aPos
# eg: aPos = {1.0, 1.0, 1.0, 1.0}
void main()
{
gl_Position = aPos ;
# 顶点着色器的内置输出变量
}
阶段总结
基于浏览器,通过Javascript 来实现编程技术,能在 2D屏幕 上看到 3D效果。
看到这里,你可能会有这样的疑问,如何让 3D空间点坐标 转为 屏幕 2D二维点坐标?
一个复杂场景中,物体如 、周边 等,都需要软件建模,建模好后再将其放置到该场景中。
当对每个物体 建模的时候,物体本身是有自己的独立坐标系 [1] 局部坐标系 Local Space,但 放到场景中就有不同放置位置,所有物体共享同一个坐标系,叫 [2] 世界坐标系 World Space
在世界坐标系场景下,我们是从正面某个位置去观察 ,如果视角变化至沿着Z轴负方向看呢?又是另外一个画面,叫做 [3] 视觉坐标系 View Space。
剩下两个坐标系说明:
[4] 裁剪坐标系 Clip Space / DNC: 归一化处理,和 需要判断哪个片段需要展示在屏幕内。(这里不做展开跟机器学习归一化目标一致,统计学中数据收敛作用)
[5] 屏幕坐标系 Screen Space:根据裁剪坐标系计算,再转换为屏幕坐标。最后将数据传到光栅器。
以上理解版
理解有些概念后,咱们再看看这些过程间转换,是如何离不开 线性代数基础知识的。
[1] 局部空间-> [2] 世界空间,涉及 矩阵的平移、缩放、旋转
缩放:代表多少倍,缩放S1、S2、S3 倍数
平移:
旋转:由 P(x, y, z) 变为 P' (x', y', z'),旋转 θ 角度,略过 ... 变换 - LearnOpenGL CN[11][2] 世界空间 -> [3] 视觉空间,构建 线性变换矩阵
任何方位观察到的物体都是不同的,从A 位置 变换至 B 位置,只要知道 变换前后的基向量
,就能知道 运动至哪里,方法通过 矩阵相乘
(对几何空间的线性变化) ....
矩阵向量乘积: 变换后的基向量
* 未变化前的位置 (x, y) = 基向量变换后新(x', y')
[3] 视觉空间 -> [4] 裁剪空间 -> [5] 屏幕空间
投影
-> 点积
(实际上会更复杂些) ....总之,学好线性代数很重要。
《线性代数》(同济版)——教科书中的耻辱柱[12] 该文章 引起了我相当强烈的共鸣 (没学好真不怨我)
我们先用低成本学习Three.js,快速入门 .....
如果你是个大导演,有一天你想请 安琪拉大宝贝儿 来北京 献歌一曲,
Scene 场景
,选择 人民大会堂作为 舞台吧;Light 灯光
, 才能让观众看到 安琪拉大宝贝儿 唱歌;模型
,来之前要保养一下,皮肤看起来吹弹可破 材质 Material
;贴图与纹理 Texture
;Camera 相机
360 度无死角的拍摄,她唱 XXX歌曲。你刚在脑海里构建出来的画面 ≈ 渲染器 Render
Three.js demo[13] 自己去对照着想象这个,就是 安琪拉大宝贝儿 吧
以上几个关键词是:Scene 场景
、Light 灯光
、模型
、材质 Material
、Texture
、Camera 相机
、渲染器 Render
。
理解了以上的几个概念后,对我们实践上手应用 Three.js 非常的关键。
STEP1: 创建舞台 和 相机,并渲染至页面上
import * as THREE from 'three'
class ThreeDemo {
constructor () {
this.width = window.innerWidth
this.height = window.innerHeight
this.aspectRatio = this.width / this.height
// 创建场景
this.scene = null
// 创建相机
this.camera = null
// 创建灯光
this.light = null
// 创建模型
this.model = null
// 创建材质
this.material = null
// 创建纹理
this.texture = null
// 创建渲染
this.renderer = null
}
init () {
this.createScene() // 创建舞台 和 相机
this.createRenderer() // 创建渲染
document.body.appendChild(this.renderer.domElement) // 渲染至页面上
const render = () => {
this.renderer.render(this.scene, this.camera) // 渲染场景
requestAnimationFrame(render)
}
render()
this.axesHelper()
}
createScene () {
// ====== 搭建个舞台 ======
this.scene = new THREE.Scene()
this.scene.fog = new THREE.Fog(0x090918, 1, 600)
// ====== 搭建相机 (模拟人视角去看景象) PerspectiveCamera = 透视相机 ======
this.camera = new THREE.PerspectiveCamera(
75, // 视角
this.aspectRatio, // 纵横比
0.1, // nearPlane 近平面
2000 // farPlane 远平面
)
// 设置相机位置
this.camera.position.set(10, 10, 10) // x, y, z
// 更新摄像头宽高比例
this.camera.aspect = this.aspectRatio
// 更新摄像头的矩阵
this.camera.updateProjectionMatrix()
// 将相机放到舞台上
this.scene.add(this.camera)
}
createRenderer () {
this.renderer = new THREE.WebGLRenderer({ antialias: true })
this.renderer.outputEncoding = THREE.sRGBEncoding
// 设置渲染器宽高
this.renderer.setSize(this.width, this.height)
this.renderer.setClearColor(this.scene.fog.color)
// 屏幕变化 更新渲染 (相机视角变化 和 渲染器变化)
window.addEventListener('resize', () => {
this.camera.aspect = window.innerWidth / window.innerHeight
this.camera.updateProjectionMatrix()
this.renderer.setSize(window.innerWidth, window.innerHeight)
})
}
// 辅助坐标系
axesHelper () {
const axesHelper = new THREE.AxesHelper(5)
this.scene.add(axesHelper)
}
}
const instance = new ThreeDemo()
instance.init()
this.camera.position.set(10, 10, 10)
在这个位置上看
如果我们在this.camera.position.set(0, 0, 5)
这个位置上看
STEP2: 加模型 和 灯光
// 加入环境光
// 环境光会均匀的照亮场景中的所有物体
this.light = new THREE.AmbientLight(0x404040) // soft white light
this.scene.add(this.light)
// 场景中添加球
const geometry = new THREE.BoxGeometry(2, 2, 2)
const geometry_material = new THREE.MeshStandardMaterial({ color: 0xaafabb })
instance.scene.add(new THREE.Mesh(geometry, geometry_material))
有光照
无光照 (无环境光加入)
这里不仅加入环境光,还加入了平行光,即平行光是沿着特定方向发射的光
createLight () {
// 环境光会均匀的照亮场景中的所有物体
this.light = new THREE.AmbientLight(0x404040) // soft white light
this.scene.add(this.light)
// 平行光是沿着特定方向发射的光
this.directionalLight = new THREE.DirectionalLight( 0xffffff, 0.6 )
this.directionalLight.position.set(0, 5, 5)
this.scene.add(this.directionalLight)
}
STEP3: 贴膜 (材质和纹理)
https://www.poliigon.com/ 在这个网站上去找一些贴图
// 场景中添加立方体
const geometry = new THREE.BoxGeometry(2, 2, 2)
const geometry_material = new THREE.MeshStandardMaterial({
map: textureLoader.load('../public/textures/RoofTilesTerracotta004/RoofTilesTerracotta004_COL_1K.jpg'),
aoMap: textureLoader.load('../public/textures/RoofTilesTerracotta004/RoofTilesTerracotta004_AO_1K.jpg'),
alphaMap: textureLoader.load('../public/textures/RoofTilesTerracotta004/RoofTilesTerracotta004_AO_1K.jpg'),
normalMap: textureLoader.load('../public/textures/RoofTilesTerracotta004/RoofTilesTerracotta004_NRM_1K.png'),
transparent: true,
roughness: 0,
})
const model = new THREE.Mesh(geometry, geometry_material)
instance.scene.add(model)
Step X:以上小结
1 . 先将 Scene 场景
、Light 灯光
、Camera 相机
设置好,并将其通过渲染器 Render
渲染至页面上
2 . 确定好 模型
穿上 材质 Material
和 贴图 Texture
后,并设定好该模型位置,再添加至场景Scene 场景
中,即可得到3D物体啦。
如果你没有系统的接触过该方向,那可以先从Three.js 入手,兴趣是最好的老师,通过理解场景、灯光、相机 ... 等大概知道一些概念。
图形学虽然水很深,但再深也有底,深入 WebGL + 着色器 (GLSL语言) -> 硬件上运作机制 等等等 ...
[1]如何入手webGl以及three.js呢? - 知乎: https://www.zhihu.com/question/383398859/answer/1121471144
[2]前端开发者应该如何学习计算机图形学相关的知识? - 知乎: https://www.zhihu.com/question/24351718
[3]大三计算机,想接触图形学方面的知识,直接学WebGL还是OpenGL ? - 知乎: https://www.zhihu.com/question/422713076
[4]WebGL,OpenGL和OpenGL ES三者的关系: https://blog.csdn.net/qq_23034515/article/details/108283747
[5]OpenGL: https://en.wikipedia.org/wiki/OpenGL
[6]WebGL: https://www.khronos.org/webgl/
[7]立方体 demo: http://ifanqi.top/webgl/pages/lesson12.html
[8]代码: https://github.com/lucefer/webgl/blob/master/pages/lesson12.html
[9]Three.js: https://threejs.org/
[10]The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe: https://thebookofshaders.com/01/?lan=ch
[11]变换 - LearnOpenGL CN: https://learnopengl-cn.github.io/01%20Getting%20started/07%20Transformations/#_18
[12]《线性代数》(同济版)——教科书中的耻辱柱: https://zhuanlan.zhihu.com/p/199665495
[13]Three.js demo: https://threejs.org/examples/#webgl_animation_skinning_additive_blending
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/TI6phB5E4_TZUzac7vZHEQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。