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>