分享webgl魔幻星球

2024-04-07 16:28
文章标签 分享 webgl 星球 魔幻

本文主要是介绍分享webgl魔幻星球,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

webgl 是在网页上绘制和渲染三维图形的技术,可以让用户与其进行交互。div+css、canvas 2d 专注于二维图形。对公司而言,webgl 可以解决他们在三维模型的显示和交互上的问题;对开发者而言,webgl 可以让我们是实现更多、更炫酷的效果,让我们即使工作,也可以乐在其中,并且还会有一份不错的薪资。

色相偏移动画

!(function animation() {color.offsetHSL(0.005, 0, 0);gl.clearColor(color.r, color.g, color.b, 1);gl.clear(gl.COLOR_BUFFER_BIT);requestAnimationFrame(animation);})();

webgl画布和着色器

webgl画布的建立和获取,和canvas 2d是一样的。一旦我们使用canvas.getContext()方法获取了webgl 类型的上下文对象,那这张画布就不再是以前的canvas 2d 画布。

canvas 2d 画布和webgl 画布使用的坐标系都是二维直角坐标系,只不过它们坐标原点、y 轴的坐标方向,坐标基底都不一样了。

canvas 2d 坐标系的原点在左上角。

canvas 2d 坐标系的y 轴方向是朝下的。

canvas 2d 坐标系的坐标基底有两个分量,分别是一个像素的宽和一个像素的高,即1个单位的宽便是1个像素的宽,1个单位的高便是一个像素的高。

webgl坐标系的坐标原点在画布中心。

webgl坐标系的y 轴方向是朝上的。

webgl坐标基底中的两个分量分别是半个canvas的宽和canvas的高,即1个单位的宽便是半个个canvas的宽,1个单位的高便是半个canvas的高。

绘图逻辑

webgl 的绘图逻辑和canvas 2d 的绘图逻辑有一个本质的差别。

浏览器有三大线程: js 引擎线程、GUI 渲染线程、浏览器事件触发线程。

其中GUI 渲染线程就是用于渲图的,在这个渲染线程里,有负责不同渲染工作的工人。比如有负责渲染HTML+css的工人,有负责渲染二维图形的工人,有负责渲染三维图形的工人。

渲染二维图形的工人和渲染三维图形的工人不是一个国家的,他们说的语言不一样。

渲染二维图形的工人说的是js语言。

渲染三维图形的工人说的是GLSL ES 语言。

而我们在做web项目时,业务逻辑、交互操作都是用js 写的。

我们在用js 绘制canvas 2d 图形的时候,渲染二维图形的工人认识js 语言,所以它可以正常渲图。

但我们在用js 绘制webgl图形时,渲染三维图形的工人就不认识这个js 语言了,因为它只认识GLSL ES 语言。

手绘板 - 程序对象

就像手绘板,在webgl 里叫“程序对象”。手绘板 - 程序对象,承载GLSL ES语言,翻译GLSL ES语言和js语言,使两者可以相互通信。

着色器shader

webgl 的着色器语言是GLSL ES语言,webgl 绘图需要两种着色器:

顶点着色器(Vertex shader):描述顶点的特征,如位置、颜色等。

片元着色器(Fragment shader):进行逐片元处理,如光照。

//顶点着色器
<script id="vertexShader" type="x-shader/x-vertex">void main() {gl_Position = vec4(0.0, 0.0, 0.0, 1.0);gl_PointSize = 100.0;}
</script>
//片元着色器
<script id="fragmentShader" type="x-shader/x-fragment">void main() {gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);}
</script>

在js中获取顶点着色器和片元着色器的文本

const vsSource = document.getElementById('vertexShader').innerText;
const fsSource = document.getElementById('fragmentShader').innerText;

初始化着色器

initShaders(gl, vsSource, fsSource);

指定将要用来清空绘图区的颜色

gl.clearColor(0,0,0,1);

使用之前指定的颜色,清空绘图区

gl.clear(gl.COLOR_BUFFER_BIT);

绘制顶点

gl.drawArrays(gl.POINTS, 0, 1);

完整代码

const canvas = document.createElement("canvas")
const gl = canvas.getContext("webgl2")document.title = "??"
document.body.innerHTML = ""
document.body.appendChild(canvas)
document.body.style = "margin:0;touch-action:none;overflow:hidden;"
canvas.style.width = "100%"
canvas.style.height = "auto"
canvas.style.userSelect = "none"const dpr = Math.max(1, .5*window.devicePixelRatio)function resize() {const {innerWidth: width,innerHeight: height} = windowcanvas.width = width * dprcanvas.height = height * dprgl.viewport(0, 0, width * dpr, height * dpr)
}
window.onresize = resizeconst vertexSource = `#version 300 es#ifdef GL_FRAGMENT_PRECISION_HIGHprecision highp float;#elseprecision mediump float;#endifin vec4 position;void main(void) {gl_Position = position;}`const fragmentSource = `#version 300 es/********** made by Matthias Hurrle (@atzedent) * * Adaptation of "Quasar" by @kishimisu * Source: https://www.shadertoy.com/view/msGyzc*/#ifdef GL_FRAGMENT_PRECISION_HIGHprecision highp float;#elseprecision mediump float;#endifout vec4 fragColor;uniform vec2 resolution;uniform float time;uniform vec2 touch;uniform int pointerCount;#define mouse (touch/resolution)#define P pointerCount#define T (10.+time*.5)#define S smoothstep#define hue(a) (.6+.6*cos(6.3*(a)+vec3(0,23,21)))mat2 rot(float a) {float c = cos(a), s = sin(a);return mat2(c, -s, s, c);}float orbit(vec2 p, float s) {return floor(atan(p.x, p.y)*s+.5)/s;}void cam(inout vec3 p) {if (P > 0) {p.yz *= rot(mouse.y*acos(-1.)+acos(.0));p.xz *= rot(-mouse.x*acos(-1.)*2.);}}void main(void) {vec2 uv = (gl_FragCoord.xy-.5*resolution)/min(resolution.x, resolution.y);vec3 col = vec3(0), p = vec3(0),rd = normalize(vec3(uv, 1));cam(p);cam(rd);const float steps = 30.;float dd = .0;for (float i=.0; i<steps; i++) {p.z  -= 4.;p.xz *= rot(T*.2);p.yz *= rot(sin(T*.2)*.5); p.zx *= rot(orbit(p.zx, 12.));float a = p.x;p.yx *= rot(orbit(p.yx, 2.));float b = p.x-T;p.x = fract(b-.5)-.5;float d = length(p)-(a-S(b+.05,b,T)*30.)*(cos(T)*5e-2+1e-1)*1e-1;dd += d;col += (hue(dd)*.04)/(1.+abs(d)*40.);p = rd * dd;}fragColor = vec4(col, 1);}`function compile(shader, source) {gl.shaderSource(shader, source)gl.compileShader(shader);if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {console.error(gl.getShaderInfoLog(shader))}
}let programfunction setup() {const vs = gl.createShader(gl.VERTEX_SHADER)const fs = gl.createShader(gl.FRAGMENT_SHADER)compile(vs, vertexSource)compile(fs, fragmentSource)program = gl.createProgram()gl.attachShader(program, vs)gl.attachShader(program, fs)gl.linkProgram(program)if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {console.error(gl.getProgramInfoLog(program))}
}let vertices, bufferfunction init() {vertices = [-1., -1., 1.,-1., -1., 1.,-1., 1., 1.,-1., 1., 1.,]buffer = gl.createBuffer()gl.bindBuffer(gl.ARRAY_BUFFER, buffer)gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)const position = gl.getAttribLocation(program, "position")gl.enableVertexAttribArray(position)gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0)program.resolution = gl.getUniformLocation(program, "resolution")program.time = gl.getUniformLocation(program, "time")program.touch = gl.getUniformLocation(program, "touch")program.pointerCount = gl.getUniformLocation(program, "pointerCount")
}const mouse = {x: 0,y: 0,touches: new Set(),update: function(x, y, pointerId) {this.x = x * dpr;this.y = (innerHeight - y) * dpr;this.touches.add(pointerId)},remove: function(pointerId) { this.touches.delete(pointerId) }
}function loop(now) {gl.clearColor(0, 0, 0, 1)gl.clear(gl.COLOR_BUFFER_BIT)gl.useProgram(program)gl.bindBuffer(gl.ARRAY_BUFFER, buffer)gl.uniform2f(program.resolution, canvas.width, canvas.height)gl.uniform1f(program.time, now * 1e-3)gl.uniform2f(program.touch, mouse.x, mouse.y)gl.uniform1i(program.pointerCount, mouse.touches.size)gl.drawArrays(gl.TRIANGLES, 0, vertices.length * .5)requestAnimationFrame(loop)
}setup()
init()
resize()
loop(0)window.addEventListener("pointerdown", e => mouse.update(e.clientX, e.clientY, e.pointerId))
window.addEventListener("pointerup", e => mouse.remove(e.pointerId))
window.addEventListener("pointermove", e => {if (mouse.touches.has(e.pointerId))mouse.update(e.clientX, e.clientY, e.pointerId)
})

 渲染效果截图

d87235398463404eac2b25e28face0f5.png

参见:

jQuery插件库-收集最全最新最好的jQuery插件

这篇关于分享webgl魔幻星球的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/883086

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

java常用面试题-基础知识分享

什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法相对简单,易于学习和使用。面向对象:Java是一种完全面向对象的语言,支持封装、继承和多态。跨平台性:Java的程序可以在不同的操作系统上运行,称为"Write once,

分享5款免费录屏的工具,搞定网课不怕错过!

虽然现在学生们不怎么上网课, 但是对于上班族或者是没有办法到学校参加课程的人来说,网课还是很重要的,今天,我就来跟大家分享一下我用过的几款录屏软件=,看看它们在录制网课时的表现如何。 福昕录屏大师 网址:https://www.foxitsoftware.cn/REC/ 这款软件给我的第一印象就是界面简洁,操作起来很直观。它支持全屏录制,也支持区域录制,这对于我这种需要同时录制PPT和老师讲

【干货分享】基于SSM的体育场管理系统的开题报告(附源码下载地址)

中秋送好礼 中秋佳节将至,祝福大家中秋快乐,阖家幸福。本期免费分享毕业设计作品:《基于SSM的体育场管理系统》。 基于SSM的体育场管理系统的开题报告 一、课题背景与意义 随着全民健身理念的深入人心,体育场已成为广大师生和社区居民进行体育锻炼的重要场所。然而,传统的体育场管理方式存在诸多问题,如资源分配不均、预约流程繁琐、数据统计不准确等,严重影响了体育场的使用效率和用户体验。

图书管理系统系统分享

分享一个图书管理系统,Java、SpringBoot、Vue和MySQL开发的图书馆管理系统 gitee项目地址:https://gitee.com/yuanmomoya/open-source-project/tree/master/books-management-system GitHub项目地址:https://github.com/yuanmomoya/open-source-pro

站长常用Shell脚本整理分享(全)

站长常用Shell脚本整理分享 站长常用Shell脚本整理分享1-10 站长常用Shell脚本整理分享11-20 站长常用Shell脚本整理分享21-30 站长常用Shell脚本整理分享31-40 站长常用Shell脚本整理分享41-50 站长常用Shell脚本整理分享51-59 长期更新

分享MSSQL、MySql、Oracle的大数据批量导入方法及编程手法细节

1:MSSQL SQL语法篇: BULK INSERT      [ database_name . [ schema_name ] . | schema_name . ] [ table_name | view_name ]         FROM 'data_file'        [ WITH       (      [ [ , ] BATCHSIZE = batch_siz

分享一个基于uniapp科技馆服务微信小程序 博物馆管理小程序(源码、调试、LW、开题、PPT)

💕💕作者:计算机源码社 💕💕个人简介:本人 八年开发经验,擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等,大家有这一块的问题可以一起交流! 💕💕学习资料、程序开发、技术解答、文档报告 💕💕如需要源码,可以扫取文章下方二维码联系咨询 💕💕Java项目 💕💕微信小程序项目 💕💕Android项目 �

2024年 Biomedical Signal Processing and Control 期刊投稿经验最新分享

期刊介绍 《Biomedical Signal Processing and Control 》期刊旨在为临床医学和生物科学中信号和图像的测量和分析研究提供一个跨学科的国际论坛。重点放在处理在临床诊断,患者监测和管理中使用的方法和设备的实际,应用为主导的研究的贡献。 生物医学信号处理和控制反映了这些方法在工程和临床科学的界面上被使用和发展的主要领域。期刊的范围包括相关的评论论文(review p