UNPKG

20.3 kBJavaScriptView Raw
1/*!
2* image3DCore - 🍊 使用webGL绘制三维图片。Drawing three-dimensional images using webGL.
3* git+https://github.com/hai2007/image3D.git
4*
5* author 你好2007
6*
7* version 3.3.0
8*
9* build Thu Apr 11 2019
10*
11* Copyright hai2007 < https://hai2007.gitee.io/sweethome/ >
12* Released under the MIT license
13*
14* Date:Sat Jan 08 2022 20:32:28 GMT+0800 (GMT+08:00)
15*/
16
17'use strict';
18
19var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
20
21(function () {
22 'use strict';
23
24 /**
25 * 着色器一些公共的方法
26 * --------------------------------------------
27 * 主要是和生成特定着色器无关的方法
28 * 着色器分为两类:顶点着色器 + 片段着色器
29 * 前者用于定义一个点的特性,比如位置,大小,颜色等
30 * 后者用于针对每个片段(可以理解为像素)进行处理
31 *
32 * 着色器采用的语言是:GLSL ES语言
33 */
34
35 // 把着色器字符串加载成着色器对象
36
37 var loadShader = function loadShader(gl, type, source) {
38 // 创建着色器对象
39 var shader = gl.createShader(type);
40 if (shader == null) throw new Error('Unable to create shader!');
41 // 绑定资源
42 gl.shaderSource(shader, source);
43 // 编译着色器
44 gl.compileShader(shader);
45 // 检测着色器编译是否成功
46 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error('Failed to compile shader:' + gl.getShaderInfoLog(shader));
47 return shader;
48 };
49
50 // 初始化着色器
51 var useShader = function useShader(gl, vshaderSource, fshaderSource) {
52 // 分别加载顶点着色器对象和片段着色器对象
53 var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshaderSource),
54 fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshaderSource);
55 // 创建一个着色器程序
56 var glProgram = gl.createProgram();
57 // 把前面创建的两个着色器对象添加到着色器程序中
58 gl.attachShader(glProgram, vertexShader);
59 gl.attachShader(glProgram, fragmentShader);
60 // 把着色器程序链接成一个完整的程序
61 gl.linkProgram(glProgram);
62 // 检测着色器程序链接是否成功
63 if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) throw new Error('Failed to link program: ' + gl.getProgramInfoLog(glProgram));
64 // 使用这个完整的程序
65 gl.useProgram(glProgram);
66 return glProgram;
67 };
68
69 /**
70 * 缓冲区核心方法
71 * --------------------------------------------
72 * 缓冲区分为两种:
73 * 1.缓冲区中保存了包含顶点的数据
74 * 2.缓冲区保存了包含顶点的索引值
75 *
76 */
77
78 // 获取一个新的缓冲区
79 // isElement默认false,创建第一种缓冲区,为true创建第二种
80 var newBuffer = function newBuffer(gl, isElement) {
81 var buffer = gl.createBuffer(),
82 TYPE = isElement ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
83 // 把缓冲区对象绑定到目标
84 gl.bindBuffer(TYPE, buffer);
85 return buffer;
86 };
87
88 // 数据写入缓冲区
89 // data是一个类型化数组,表示写入的数据
90 // usage表示程序如何使用存储在缓冲区的数据
91 var writeBuffer = function writeBuffer(gl, data, usage, isElement) {
92 var TYPE = isElement ? gl.ELEMENT_ARRAY_BUFFER : gl.ARRAY_BUFFER;
93 gl.bufferData(TYPE, data, usage);
94 };
95
96 // 使用缓冲区数据
97 // location指定待分配的attribute变量的存储位置
98 // size每个分量个数
99 // type数据类型,应该是以下的某个:
100 // gl.UNSIGNED_BYTE Uint8Array
101 // gl.SHORT Int16Array
102 // gl.UNSIGNED_SHORT Uint16Array
103 // gl.INT Int32Array
104 // gl.UNSIGNED_INT Uint32Array
105 // gl.FLOAT Float32Array
106 // stride相邻两个数据项的字节数
107 // offset数据的起点字节位置
108 // normalized是否把非浮点型的数据归一化到[0,1]或[-1,1]区间
109 var useBuffer = function useBuffer(gl, location, size, type, stride, offset, normalized) {
110 // 把缓冲区对象分配给目标变量
111 gl.vertexAttribPointer(location, size, type, normalized || false, stride || 0, offset || 0);
112 // 连接目标对象和缓冲区对象
113 gl.enableVertexAttribArray(location);
114 };
115
116 /**
117 * 纹理方法
118 * --------------------------------------------
119 * 在绘制的多边形上贴图
120 * 丰富效果
121 */
122
123 // 初始化一个纹理对象
124 // type有gl.TEXTURE_2D代表二维纹理,gl.TEXTURE_CUBE_MAP 立方体纹理等
125 var initTexture = function initTexture(gl, type, unit, _type_) {
126 // 创建纹理对象
127 var texture = gl.createTexture();
128
129 if (_type_ == '2d') {
130 unit = unit || 0;
131 // 开启纹理单元,unit表示开启的编号
132 gl.activeTexture(gl['TEXTURE' + unit]);
133 }
134
135 // 绑定纹理对象到目标上
136 gl.bindTexture(type, texture);
137 return texture;
138 };
139
140 // 链接资源图片
141 // level默认传入0即可,和金字塔纹理有关
142 // format表示图像的内部格式:
143 // gl.RGB(红绿蓝)
144 // gl.RGBA(红绿蓝透明度)
145 // gl.ALPHA(0.0,0.0,0.0,透明度)
146 // gl.LUMINANCE(L、L、L、1L:流明)
147 // gl.LUMINANCE_ALPHA(L、L、L,透明度)
148 // textureType表示纹理数据的格式:
149 // gl.UNSIGNED_BYTE: 表示无符号整形,每一个颜色分量占据1字节
150 // gl.UNSIGNED_SHORT_5_6_5: 表示RGB,每一个分量分别占据占据5, 6, 5比特
151 // gl.UNSIGNED_SHORT_4_4_4_4: 表示RGBA,每一个分量分别占据占据4, 4, 4, 4比特
152 // gl.UNSIGNED_SHORT_5_5_5_1: 表示RGBA,每一个分量分别占据占据5比特,A分量占据1比特
153 var linkImage = function linkImage(gl, type, level, format, textureType, image) {
154 format = {
155 "rgb": gl.RGB,
156 "rgba": gl.RGBA,
157 "alpha": gl.ALPHA
158 }[format] || gl.RGBA;
159
160 gl.texImage2D(type, level || 0, format, format, {
161
162 // 目前一律采用默认值,先不对外提供修改权限
163
164 }[textureType] || gl.UNSIGNED_BYTE, image);
165 };
166
167 var linkCube = function linkCube(gl, type, level, format, textureType, images, width, height, texture) {
168 format = {
169 "rgb": gl.RGB,
170 "rgba": gl.RGBA,
171 "alpha": gl.ALPHA
172 }[format] || gl.RGBA;
173
174 level = level || 0;
175
176 textureType = {
177
178 // 目前一律采用默认值,先不对外提供修改权限
179
180 }[textureType] || gl.UNSIGNED_BYTE;
181
182 var types = [gl.TEXTURE_CUBE_MAP_POSITIVE_X, //右
183 gl.TEXTURE_CUBE_MAP_NEGATIVE_X, //左
184 gl.TEXTURE_CUBE_MAP_POSITIVE_Y, //上
185 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, //下
186 gl.TEXTURE_CUBE_MAP_POSITIVE_Z, //后
187 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z //前
188 ],
189 i = void 0,
190 target = void 0;
191
192 for (i = 0; i < types.length; i++) {
193 target = types[i];
194 gl.texImage2D(target, level, format, width, height, 0, format, textureType, null);
195 gl.bindTexture(type, texture);
196 gl.texImage2D(target, level, format, format, textureType, images[i]);
197 }
198
199 gl.generateMipmap(type);
200 };
201
202 function value(gl) {
203 return {
204
205 /**
206 * attribue
207 * ----------------------------------------
208 */
209
210 // 浮点数
211 setAttribute1f: function setAttribute1f(name, v0) {
212 // 获取存储位置
213 var location = gl.getAttribLocation(gl.program, name);
214 // 传递数据给变量
215 gl.vertexAttrib1f(location, v0);
216 },
217 setAttribute2f: function setAttribute2f(name, v0, v1) {
218 var location = gl.getAttribLocation(gl.program, name);
219 gl.vertexAttrib2f(location, v0, v1);
220 },
221 setAttribute3f: function setAttribute3f(name, v0, v1, v2) {
222 var location = gl.getAttribLocation(gl.program, name);
223 gl.vertexAttrib3f(location, v0, v1, v2);
224 },
225 setAttribute4f: function setAttribute4f(name, v0, v1, v2, v3) {
226 var location = gl.getAttribLocation(gl.program, name);
227 gl.vertexAttrib4f(location, v0, v1, v2, v3);
228 },
229
230
231 // 整数
232 setAttribute1i: function setAttribute1i(name, v0) {
233 // 获取存储位置
234 var location = gl.getAttribLocation(gl.program, name);
235 // 传递数据给变量
236 gl.vertexAttrib1i(location, v0);
237 },
238 setAttribute2i: function setAttribute2i(name, v0, v1) {
239 var location = gl.getAttribLocation(gl.program, name);
240 gl.vertexAttrib2i(location, v0, v1);
241 },
242 setAttribute3i: function setAttribute3i(name, v0, v1, v2) {
243 var location = gl.getAttribLocation(gl.program, name);
244 gl.vertexAttrib3i(location, v0, v1, v2);
245 },
246 setAttribute4i: function setAttribute4i(name, v0, v1, v2, v3) {
247 var location = gl.getAttribLocation(gl.program, name);
248 gl.vertexAttrib4i(location, v0, v1, v2, v3);
249 },
250
251
252 /**
253 * uniform
254 * ----------------------------------------
255 */
256
257 // 浮点数
258 setUniform1f: function setUniform1f(name, v0) {
259 var location = gl.getUniformLocation(gl.program, name);
260 gl.uniform1f(location, v0);
261 },
262 setUniform2f: function setUniform2f(name, v0, v1) {
263 var location = gl.getUniformLocation(gl.program, name);
264 gl.uniform2f(location, v0, v1);
265 },
266 setUniform3f: function setUniform3f(name, v0, v1, v2) {
267 var location = gl.getUniformLocation(gl.program, name);
268 gl.uniform3f(location, v0, v1, v2);
269 },
270 setUniform4f: function setUniform4f(name, v0, v1, v2, v3) {
271 var location = gl.getUniformLocation(gl.program, name);
272 gl.uniform4f(location, v0, v1, v2, v3);
273 },
274
275
276 // 整数
277 setUniform1i: function setUniform1i(name, v0) {
278 var location = gl.getUniformLocation(gl.program, name);
279 gl.uniform1i(location, v0);
280 },
281 setUniform2i: function setUniform2i(name, v0, v1) {
282 var location = gl.getUniformLocation(gl.program, name);
283 gl.uniform2i(location, v0, v1);
284 },
285 setUniform3i: function setUniform3i(name, v0, v1, v2) {
286 var location = gl.getUniformLocation(gl.program, name);
287 gl.uniform3i(location, v0, v1, v2);
288 },
289 setUniform4i: function setUniform4i(name, v0, v1, v2, v3) {
290 var location = gl.getUniformLocation(gl.program, name);
291 gl.uniform4i(location, v0, v1, v2, v3);
292 },
293
294
295 // 矩阵
296 setUniformMatrix2fv: function setUniformMatrix2fv(name, value) {
297 var location = gl.getUniformLocation(gl.program, name);
298 gl.uniformMatrix2fv(location, false, value);
299 },
300 setUniformMatrix3fv: function setUniformMatrix3fv(name, value) {
301 var location = gl.getUniformLocation(gl.program, name);
302 gl.uniformMatrix3fv(location, false, value);
303 },
304 setUniformMatrix4fv: function setUniformMatrix4fv(name, value) {
305 var location = gl.getUniformLocation(gl.program, name);
306 gl.uniformMatrix4fv(location, false, value);
307 }
308 };
309 }
310
311 function _painter(gl) {
312
313 var typeMap = {
314 "byte": gl.UNSIGNED_BYTE,
315 "short": gl.UNSIGNED_SHORT
316 };
317
318 return {
319
320 // 开启深度计算
321 openDeep: function openDeep() {
322 gl.enable(gl.DEPTH_TEST);
323 return this;
324 },
325
326
327 // 绘制点
328 points: function points(first, count, type) {
329 if (type) {
330 gl.drawElements(gl.POINTS, count, typeMap[type], first);
331 } else {
332 gl.drawArrays(gl.POINTS, first, count);
333 }
334 return this;
335 },
336
337
338 // 绘制直线
339 lines: function lines(first, count, type) {
340 if (type) {
341 gl.drawElements(gl.LINES, count, typeMap[type], first);
342 } else {
343 gl.drawArrays(gl.LINES, first, count);
344 }
345 return this;
346 },
347
348
349 // 绘制连续直线
350 stripLines: function stripLines(first, count, type) {
351 if (type) {
352 gl.drawElements(gl.LINE_STRIP, count, typeMap[type], first);
353 } else {
354 gl.drawArrays(gl.LINE_STRIP, first, count);
355 }
356 return this;
357 },
358
359
360 // 绘制闭合直线
361 loopLines: function loopLines(first, count, type) {
362 if (type) {
363 gl.drawElements(gl.LINE_LOOP, count, typeMap[type], first);
364 } else {
365 gl.drawArrays(gl.LINE_LOOP, first, count);
366 }
367 return this;
368 },
369
370
371 // 绘制三角形
372 triangles: function triangles(first, count, type) {
373 if (type) {
374 gl.drawElements(gl.TRIANGLES, count, typeMap[type], first);
375 } else {
376 gl.drawArrays(gl.TRIANGLES, first, count);
377 }
378 return this;
379 },
380
381
382 // 绘制共有边三角形
383 stripTriangles: function stripTriangles(first, count, type) {
384 if (type) {
385 gl.drawElements(gl.TRIANGLE_STRIP, count, typeMap[type], first);
386 } else {
387 gl.drawArrays(gl.TRIANGLE_STRIP, first, count);
388 }
389 return this;
390 },
391
392
393 // 绘制旋转围绕三角形
394 fanTriangles: function fanTriangles(first, count, type) {
395 if (type) {
396 gl.drawElements(gl.TRIANGLE_FAN, count, typeMap[type], first);
397 } else {
398 gl.drawArrays(gl.TRIANGLE_FAN, first, count);
399 }
400 return this;
401 }
402 };
403 }
404
405 // 获取webgl上下文
406 var getCanvasWebgl = function getCanvasWebgl(node, opts) {
407 var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"],
408 context = null,
409 i = void 0;
410 for (i = 0; i < names.length; i++) {
411 try {
412 context = node.getContext(names[i], opts);
413 } catch (e) {}
414 if (context) break;
415 }
416 if (!context) throw new Error('Non canvas or browser does not support webgl.');
417 return context;
418 };
419
420 // 绘图核心对象
421 function image3DCore(node, opts) {
422 var gl = getCanvasWebgl(node, opts),
423 glObj = {
424
425 "_gl_": gl,
426
427 // 画笔
428 "painter": function painter() {
429 return _painter(gl);
430 },
431
432 // 启用着色器
433 "shader": function shader(vshaderSource, fshaderSource) {
434 gl.program = useShader(gl, vshaderSource, fshaderSource);
435 return glObj;
436 },
437
438 // 缓冲区
439 "buffer": function buffer(isElement) {
440 // 创建缓冲区
441 newBuffer(gl, isElement);
442 var bufferData = void 0,
443 bufferObj = {
444 // 写入数据
445 "write": function write(data, usage) {
446 usage = usage || gl.STATIC_DRAW;
447 writeBuffer(gl, data, usage, isElement);
448 bufferData = data;
449 return bufferObj;
450 },
451 // 分配使用
452 "use": function use(location, size, stride, offset, type, normalized) {
453 var fsize = bufferData.BYTES_PER_ELEMENT;
454 if (typeof location == 'string') location = gl.getAttribLocation(gl.program, location);
455 stride = stride || 0;
456 offset = offset || 0;
457 type = type || gl.FLOAT;
458 useBuffer(gl, location, size, type, stride * fsize, offset * fsize, normalized);
459 return bufferObj;
460 }
461 };
462 return bufferObj;
463 },
464
465 // 纹理
466 "texture": function texture(_type_, unit) {
467 var type = {
468 "2d": gl.TEXTURE_2D, /*二维纹理*/
469 "cube": gl.TEXTURE_CUBE_MAP /*立方体纹理*/
470 }[_type_];
471
472 // 创建纹理
473 var texture = initTexture(gl, type, unit, _type_);
474
475 // 配置纹理(默认配置)
476 gl.texParameteri(type, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
477 gl.texParameteri(type, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
478 gl.texParameteri(type, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
479
480 var textureObj = {
481 // 链接图片资源
482 "useImage": function useImage(image, level, format, textureType) {
483 linkImage(gl, type, level, format, textureType, image);
484 return textureObj;
485 },
486 // 链接多张图片
487 "useCube": function useCube(images, width, height, level, format, textureType) {
488 linkCube(gl, type, level, format, textureType, images, width, height, texture);
489 }
490 };
491 return textureObj;
492 }
493
494 };
495
496 // attribue和uniform数据设置
497 var valueMethods = value(gl);
498 for (var key in valueMethods) {
499 glObj[key] = valueMethods[key];
500 }
501
502 /**
503 * gl.viewport告诉WebGL如何将裁剪空间(-1 到 +1)中的点转换到像素空间
504 * 当你第一次创建WebGL上下文的时候WebGL会设置视域大小和画布大小匹配
505 * 但是在那之后就需要你自己设置(当你改变画布大小就需要告诉WebGL新的视域设置)
506 * 为了避免麻烦,我们每次都主动调用一下
507 */
508 gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
509
510 return glObj;
511 }
512
513 if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === "object" && _typeof(module.exports) === "object") {
514 module.exports = image3DCore;
515 } else {
516 var
517 // 保存之前的image3DCore,防止直接覆盖
518 _image3DCore = window.image3DCore;
519
520 image3D.noConflict = function () {
521
522 // 如果当前的$$是被最新的image3DCore覆盖的
523 // 恢复之前的
524 if (window.image3DCore === image3DCore) {
525 window.image3DCore = _image3DCore;
526 }
527
528 // 返回当前image3DCore
529 // 因为调用这个方法以后
530 // 全局window下的image3DCore和$$是什么
531 // 已经不一定了
532 return image3DCore;
533 };
534
535 // 挂载对象到根
536 window.image3DCore = image3DCore;
537 }
538})();
\No newline at end of file