three.js的着色器(巨详细 初学者 大白话)

news2024/11/24 0:57:37

three.js就不过多介绍了 可以看另一篇文章 总结就是场景  相机  和 渲染器

学起来 也比较轻松

后来看到了着色器 给我整懵乐了  一会一个API  一会一个API 都没见过 然后就一点点去学习 真的是费了好大劲了 需要知道很多新东西 才能初步知道和使用着色器

当然如果只是简单的使用着色器  比如就画一个点  加个颜色还是很容易的

我想做的是一个几个顶点确定一个平面 并且颜色是渐变色的

(之前还好奇渐变色是怎么做的 就是 顶点间的颜色不同 两个顶点间就会有过渡色了)

上最后效果图

 

要想知道着色器的使用 确实需要了解一下webgl 因为是用它的底层实现的 不然很多基本的概念很模糊

webgl 其实就和canvas差不多 都是用来绘画的  

他的用法 例子  推荐一篇文章 初学者很适合

【WebGL】简单入门教程_小沈曰的博客-CSDN博客

建议看一遍 然后 我再用大白话解释一遍 以及总结一下 不然初学者可能会问 为什么使用这个API

1首先要想使用webgl 就要有canvs画布

 2 获取到画布元素的基于webgl上下文环境对象  可以把这个当做webgl(可能概念不是那么准确不较真的话是可以这么认为的)

3  一个webgl 最少两个着色器 当然我也只是试了两个着色器  一个是顶点着色器 一个是片段着色器

 顶点着色器 是描述顶点的  片段着色器是用来描述颜色的 (当前我是这么用的)

如果涉及到了变量 需要注意的是 都是将变量传递到顶点着色器  再在着色器内 赋值给两个共用的变量

里面的变量声明 有三个标识  我反正没纠结他 就当做 public  private这种表明一下是什么变量吧

attribute,varying 这种

 var vertShader = gl.createShader(gl.VERTEX_SHADER)

    var fragShader = gl.createShader(gl.FRAGMENT_SHADER)

4 声明好两个着色器以后 就要把代码段传进去

 gl.shaderSource(fragShader, FSHADER_SOURCE)

   gl.shaderSource(vertShader, VSHADER_SOURCE)

5 传进去后 就要编译代码段 类似执行里面的预言main函数

    gl.compileShader(fragShader)

    gl.compileShader(vertShader)

6任何的着色器都需要一个启动程序

 创建启动程序  然后 将两个着色器加进去   然后 将两个着色器连接起来

  var shaderProgram = gl.createProgram()

    //分别附加两个已编译好的着色器对象

    gl.attachShader(shaderProgram, vertShader)

    gl.attachShader(shaderProgram, fragShader)

    //链接两个附件加好的着色器程序

    gl.linkProgram(shaderProgram)

  gl.useProgram(shaderProgram)

7 然后就可以绘画了 无语的是绘画这里还有个坑 第一个参数代表了绘画的类型  图形 线和点都是不一样的

  gl.drawArrays(gl.TRIANGLES, 0, 3)

8不使用变量的话 这里就结束了

使用变量的话  

需要一个中间第三方 缓存区 将变量的值赋值给第三方 然后 再从第三方去取 

可以理解为不可以直接将我们的js 的变量传给webgl使用

 流程就是 

  创建一个缓存区 

  然后绑定缓存区  其实就是定义他的类型

得到webgl执行程序的变量 这个是我们js理解的那种变量 不是具体的值 只是声明得一个变量

然后将变量值赋值  ( 使用这个API 会直接将缓存区的值赋值到变量中 第一个参数是数字是说第几个变量 webgl自己算出来的 )

开启变量的使用就可以了

var vertexBuffer = gl.createBuffer()

    //说明缓存对象保存的类型

    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)

    //写入坐标数据

    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

    //获取到数组中单个元素的字节数

    var FSIZE = vertices.BYTES_PER_ELEMENT

    //获取到顶点着色器中变量

    var a_Position = gl.getAttribLocation(shaderProgram, 'a_Position')

    //将坐标值赋值给变量

    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0)

    //开启变量值的使用

    gl.enableVertexAttribArray(a_Position)

代码

<body>
  <canvas id="cvs" width="200" height="200" style="border: dashed 1px red">
    你的浏览器不支持画布元素
  </canvas>
  <script type="text/javascript">
    //获取画布元素
    var cvs = document.getElementById('cvs')
    //获取到元素的上下文环境对象
    var gl = cvs.getContext('webgl')

    //顶点着色器变量
    var VSHADER_SOURCE =
      //使用存储限定符定义一个接受顶点坐标的变量
      'attribute vec4 a_Position;' +
      'attribute vec4 a_Color;' +
      'varying vec4 v_Color;' +
      'void main() {' +
      //定义点的坐标并转换成变量保存
      'gl_Position = a_Position; ' +
      'v_Color = a_Color; ' +
      '} '

    //片段着色器变量
    var FSHADER_SOURCE =
      'precision mediump float;' +
      'varying vec4 v_Color;' +
      'void main() {' +
      //设置图形像素的颜色并保存
      'gl_FragColor = v_Color ;' +
      '}'

    //新建一个用于装顶点字符串的着色器对象
    var vertShader = gl.createShader(gl.VERTEX_SHADER)
    //加载保存好的顶点代码字符串变量
    gl.shaderSource(vertShader, VSHADER_SOURCE)
    //编译顶点着色器
    gl.compileShader(vertShader)

    //新建一个用于装片段字符串的着色器对象
    var fragShader = gl.createShader(gl.FRAGMENT_SHADER)
    //加载保存好的片段代码字符串变量
    gl.shaderSource(fragShader, FSHADER_SOURCE)
    //编译片段着色器
    gl.compileShader(fragShader)

    //新建一个程序
    var shaderProgram = gl.createProgram()

    //分别附加两个已编译好的着色器对象
    gl.attachShader(shaderProgram, vertShader)
    gl.attachShader(shaderProgram, fragShader)

    //链接两个附件加好的着色器程序
    gl.linkProgram(shaderProgram)
    //开启程序的使用
    gl.useProgram(shaderProgram)
    //定义一个类型数组保存顶点坐标值
    var vertices = new Float32Array([
      //  x,   y,   red, green, blue
      0.0, 0.5, 1.0, 0.0, 0.0, -0.5, -0.5, 0.0, 1.0, 0.0, 0.5, -0.5, 0.0, 0.0,
      1.0,
    ])
    //先创建一个缓存对象
    var vertexBuffer = gl.createBuffer()
    //说明缓存对象保存的类型
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
    //写入坐标数据
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
    //获取到数组中单个元素的字节数
    var FSIZE = vertices.BYTES_PER_ELEMENT

    //获取到顶点着色器中变量
    var a_Position = gl.getAttribLocation(shaderProgram, 'a_Position')
    //将坐标值赋值给变量
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 5, 0)
    //开启变量值的使用
    gl.enableVertexAttribArray(a_Position)

    //获取到顶点着色器中变量
    var a_Color = gl.getAttribLocation(shaderProgram, 'a_Color')
    //将坐标值赋值给变量
    gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2)
    //开启变量值的使用
    gl.enableVertexAttribArray(a_Color)

    //绘制指定位置的图形
    gl.drawArrays(gl.TRIANGLES, 0, 3)
  </script>
</body>

这是webgl 的简单使用 

three.js的 着色器 底层是他  但是使用却不完全一样的

首先声明好three的要素对象  场景 相机 渲染器

最简单的 是可以只传坐标 着色器都不写的 因为three已经写好了

可是我想传颜色 就需要 我们自己写一下了

说一下流程 

首先定义颜色和坐标

然后给几何体设置这两个属性 (然后在main函数里面这两个就是默认的变量了)

然后定义着色器 因为颜色是变量需要传进去  所以没办法  只能定义着色器了

这里用到了gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0)

   gl_FragColor = vec4(vColor, 1.0); 

1 注意 两个共用的变量使用    varying  来声明

2 projectionMatrix * modelViewMatrix * vec4(position, 1.0) 这个算出来的就是世界坐标

  在这个场景中有各种各样的坐标系  这是几个坐标系的转化  可以这么简单的记 这就是转化公式 到了世界坐标系

3 vertexColors: true, 要想颜色生效需要这个属性

4 必须加; 

最后的代码

<template>
  <div id="my-three"></div>
</template>
<script lang="ts" setup>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { onMounted } from "vue";

//创建一个三维场景
const scene = new THREE.Scene();
//创建一个物体(形状)
const geometry = new THREE.BufferGeometry();
const points = [0, 0, 5, 5, 0, 5, -5, 5, 0];
// const points=[]
// points.push(2.5,2.5,0)
// points.push(-2.5,2.5,0)
// points.push(0,0,2.5)
geometry.setAttribute("position", new THREE.Float32BufferAttribute(points, 3));
const colors = [1, 0, 0, 6.6613381, 1, 0, 0, 6.661, 1];

geometry.setAttribute("color", new THREE.Float32BufferAttribute(colors, 3));
//创建材质(外观)
const material = new THREE.ShaderMaterial({
  vertexShader: `
        varying vec3 vColor;
        void main() {
          vColor = color;
          gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }`,
  fragmentShader: `
        varying vec3 vColor;
        void main() {
          gl_FragColor = vec4(vColor, 1.0);
        }`,
  side: THREE.FrontSide,
  blending: THREE.AdditiveBlending,
  depthTest: false,
  transparent: true,
  vertexColors: true,
});
//创建一个网格模型对象
const mesh = new THREE.Mesh(geometry, material); //网络模型对象Mesh
//把网格模型添加到三维场景
scene.add(mesh); //网络模型添加到场景中
mesh.position.set(0, 0, 0);

//添加光源 //会照亮场景里的全部物体(氛围灯),前提是物体是可以接受灯光的,这种灯是无方向的,即不会有阴影。
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
const light = new THREE.PointLight("yellow", 1); //点光源,color:灯光颜色,intensity:光照强度

scene.add(ambient);
light.position.set(200, 300, 400);

scene.add(light);

//创建一个透视相机,窗口宽度,窗口高度
const width = window.innerWidth,
  height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000);

//设置相机位置  相机的位置
camera.position.set(300, 300, 300);
//设置相机方向  相机的摄像头对准的位置
camera.lookAt(0, 0, 0);

//创建辅助坐标轴
const axesHelper = new THREE.AxesHelper(200); //参数200标示坐标系大小,可以根据场景大小去设置
scene.add(axesHelper);

//创建一个WebGL渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区尺寸
renderer.render(scene, camera); //执行渲染操作、指定场景、相机作为参数

const controls = new OrbitControls(camera, renderer.domElement); //创建控件对象
controls.addEventListener("change", () => {
  renderer.render(scene, camera); //监听鼠标,键盘事件
});
onMounted(() => {
  document.getElementById("my-three")?.appendChild(renderer.domElement);
});
</script>
<style scoped></style>

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

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

相关文章

docker-harbor私有仓库的部署与管理

目录 Harbor Harbor介绍 Harbor的特性 Harbor的构成 部署Harbor 搭建本地私有仓库 Docker容器的重启策略 部署Docker-compose服务 部署Harbor服务 关于Harbor.cfg配置文件中两类参数 启动Harbor 查看 Harbor 启动镜像 创建一个新项目 在其他客户端上传镜像 维护管…

如何创建 2023 年营销日历(内含免费模板和示例)

沟通、文案撰写、社媒营销、点击付费广告、事件营销和搜索引擎排名优化有什么共同点&#xff1f; 它们都属于营销部门的工作范畴&#xff0c;而且很可能是围绕着同一个日程表进行工作排期。 你的营销团队比你想象的要大&#xff0c;当你考虑跨职能项目和团队成员在你整体战略…

ImageJ 用户手册——第四部分(ImageJ用户界面)

ImageJ 用户手册——第四部分&#xff08;ImageJ用户界面&#xff09; ImageJ用户界面工具栏&#xff08;Toolbar&#xff09;状态栏进度条19. 工具19.1 区域选择工具19.1.1 矩形选择工具19.1.2 圆角矩形选择工具19.1.3 圆形选择工具19.1.4 椭圆选择工具19.1.5 笔刷选择工具19.…

内网渗透基础-域环境搭建

一、环境准备 1.1虚拟机安装 Mac环境&#xff1a; vmware fusion&#xff1b;parallels desktop。 windows环境&#xff1a; vmware&#xff1b;virtualbox; 有习惯用其他软件的也都一样的&#xff0c;下载安装可以找百度教程。 1.2虚拟机三种网络配置模式 桥接模式&am…

塔望3W消费战略全案丨阳澄湖牌大闸蟹:承诺就是价值,打响官方第一枪

阳澄湖牌 大闸蟹 客户&#xff1a;苏州市阳澄湖大闸蟹营销有限公司 品牌&#xff1a;阳澄湖/阳澄湖牌 服务&#xff1a;3W消费战略 品牌全案 项目背景 苏州市阳澄湖大闸蟹营销有限公司是由苏州市相城区阳澄湖大闸蟹集团公司、苏州市阳澄湖现代农业产业园特种水产养殖有限公…

Springboot整合elasticsearch

​ 前言 elasticsearch基本介绍&#xff0c;这篇文章介绍了elasticsearch安装和使用。下面根据网上查来的各种资料&#xff0c;总结如何在springboot中使用elasticsearch。 文章中用es代替elasticsearch。 依赖 springboot版本是2.0&#xff0c;es版本用的是7.6.2。不同的…

专业做护眼灯的有哪些品牌?盘点专业护眼灯品牌排行

护眼灯是家庭照明必备的工具&#xff0c;专业做护眼灯的却不多&#xff0c;许多家长找不到合适的护眼灯&#xff0c;我就根据标准GB/T 9473-2017《读写作业台灯性能要求》&#xff0c;筛选出五款合适国人使用的护眼灯。 TOP1、南卡护眼台灯Pro 光源舒适度&#xff1a;❤❤❤❤…

电子工程有哪些SCI期刊推荐? - 易智编译EaseEditing

以下是电子工程领域的SCI期刊推荐&#xff1a; IEEE Transactions on Electron Devices&#xff1a; 该期刊是IEEE出版社的顶级期刊&#xff0c;涵盖电子学、固态电子学、电子器件、材料科学等多个领域。 IEEE Transactions on Industrial Electronics&#xff1a; 该期刊是I…

ChatGPT写21个程序,16个有漏洞:离取代程序员还远着呢!

一、ChatGPT 生成的代码有多安全&#xff1f; 近年来&#xff0c;大型语言模型推动人工智能领域取得了巨大的进步。其中&#xff0c;OpenAI 打造的 ChatGPT 甫一亮相&#xff0c;就凭借出色的性能震惊全球。ChatGPT 不仅能够处理普通文本&#xff0c;还能将自然语言翻译成代码…

Linux嵌入式uboot使用tftp网络启动加载zImage、设备树

文章目录 一、前言二、Linux U-boot 相关命令&#xff08;1&#xff09;help 命令&#xff08;2&#xff09;printenv 命令&#xff08;3&#xff09;setenv 函数&#xff08;4&#xff09;saveenv 函数 三、tftp启动linux内核步骤&#xff08;1&#xff09;进入u-boot模式&…

使用chatgpt探索SQL注入

今天尝试使用chatgpt尝试探讨咨询一下SQL注入的问题以及如何解决。 首先问的是“作为一个安全工作人员&#xff0c;写一篇关于Java SQL注入以及如何预防的文章&#xff0c;包含所有使用SQL可能存在注入的情况” 结果&#xff0c;结果就是没有等到结果&#xff0c;直接出错了。…

数百家数科公司齐聚用友BIP技术大会,共享企业数智化领先实践

4月19日&#xff5e;4月21日&#xff0c;由用友公司主办的“2023用友BIP技术大会“在用友产业园&#xff08;北京&#xff09;盛大召开&#xff0c;用友介绍了更懂企业业务的用友BIP-iuap平台&#xff0c;并发布了全面数智化能力体系&#xff0c;助力企业升级数智化底座&#x…

15、Context

目录 一、常规gorutine控制二、context控制groutine1 - 使用context控制单个gorutine2 - context创建3 - context函数4 - Context接口5 - 使用context控制多个gorutine停止 一、常规gorutine控制 控制并发的两种方式&#xff1a; 使用WaitGroup&#xff1a;多个Goroutine执行同…

SQL经典50题总结

SQL经典50题总结 SQL经典50题总结1.数据准备50题1.查询"01" 课程比 "02" 课程成绩高的学生的信息及课程分数2.查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩3.查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩4.查询姓“…

推荐一个开源的区块链开发者工具网站

开源区块链开发者工具箱 https://ChainTool.tech 今天可以正式上线了。ChainTool 使用完全开源的方式编写一些开发者日常经常使用的工具。 关于 ChainToolDAO 大约在两个月前&#xff0c; ChainToolDAO 成立了&#xff0c;成立 ChainToolDAO 的来由是这样的&#xff1a;我是一…

Python模块练习题-测试你的Python技能。

练习题&#xff1a; 1.logging模块有几个日志级别&#xff1f;2.请配置logging模块&#xff0c;使其在屏幕和文件里同时打印以下格式的日志3.json、pickle、shelve三个区别是什么&#xff1f;4.json的作用是什么&#xff1f;5.subprocess执行命令方法有几种&#xff1f;6.为什么…

idea 2023版本创建maven管理的Scala项目教程

目录 1、创建项目1.1、创建项目名及简单配置1、2 刚开始创建好后的项目是这样的1、3 进行相关设置1&#xff09;增加maven管理2&#xff09;增加scala目录&#xff0c;并设置成resource目录 注意&#xff1a; 本项目写得教程是基于您得Java jdk、Scala jdk、maven这些都是安装配…

汽车充电桩检测设备TK4860C交流充电桩检定装置

TK4860C是一款在交流充电桩充电过程中实时检测充电电量的标准仪器&#xff0c;仪器以新能源车为负载&#xff0c;结合宽动态范围测量技术、电能ms级高速刷新等技术&#xff0c;TK4860C实现充电全过程的累积电能精准计量&#xff0c;相比于传统的预设检定点的稳态计量&#xff0…

PyQt5、Pyside2学习---02

1.界面布局 我们最常用的 Layout布局 有4种&#xff0c;分别是 QHBoxLayout 水平布局QVBoxLayout 垂直布局QGridLayout 表格布局QFormLayout 表单布局 2.调整控件位置和大小 调整layout中控件的大小比例: 可以通过设定控件的sizePolicy来调整&#xff0c; 调整控件间距: …

kafka多用户访问权限配置指导

一、场景描述 现场业务由于多厂商集成,共享数据需要,需对接当前kafka集群,为做到类似租户隔离的功能,需要开启kafka的权限控制和动态用户管理功能,实现不同厂商访问被授权的合法资源,消费者账号只能消费数据,生产者账号只能生产数据。 二、控制方式 Kafka 有三种认证模…