1 初步尝试
import { Scene, WebGLRenderer, OrthographicCamera, PlaneGeometry, ShaderMateria } from 'three.js'
const scene = new Scene()
const camera = new OrthographicCamera(-1,1,1,-1,0.1, 10)
const renderer = new WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
// 创建一个大小为2 的平面几何容器
const geometry = new PlaneGeometry(2,2)
// 设置着色器材质
const material = new ShaderMaterial()
// 创建网格对象 绘制平面
const plane = new mesh(geometry, material)
scene.add(plane)
//设置相机z轴以便能看到平面,注意范围为0.1 - 10,即远近裁截面
camera.position.z = 1
renderer.render(scene, camera)
2 颜色随时间改变
const fragmentShader = {
uniform float u_time;
void main() {
vec3 color = vec3((sin(u_time) + 1.0) /2.0, 0.0, (cos(u_time) + 1.0) /2.0);
gl_FragColor = vec4(color, 1.0);
}
}
const uniforms = {
u_time: { value: 0.0 }
}
const clock = new THREE.Clock()
function animate(){
requestAnimation(animate)
uniforms.u_time.value += clock.getDelta()
renderer.render(scene, camera)
}
3 混合
用法:mix(a,b,c)
公式:a*(1-c)+b*c, 0<=c<=1
4 颜色随位置改变
注意:位置坐标大小可能大于1,小于0,因此要将其转化为0-1之间
clamp(num, min, max):将num值约束在(min, max)之间,小于min,值为min,大于max,值为max,在min-max之间,值为num
//注意带分号
//顶点
const vshader = `
varying vec3 v_position;
void main() {
v_position = position;
// 左乘modelMatrix 将坐标转换到世界坐标系下 左乘viewMatrix 将坐标转换到相机坐标系下 左乘projectMatrix 将三维坐标映射到二维屏幕上
gl_Position = projectMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const fshader = `
varying vec3 v_position;
void main(){
vec3 color = vec3(0.0);
color.r = clamp(position.x, 0.0, 1.0);
color.g = clamp(position.y, 0.0, 1.0);
gl_FragColor = vec4(color, 1.0);
}
`
5 位置颜色分块
step(n, x):当x<n, 返回0;否则返回1
const fshader = `
varying vec3 v_position;
void main(){
vec3 color = vec3(0.0);
color.r = step(0.0, position.x);
color.g = step(0.0, position.y);
gl_FragColor = vec4(color, 1.0);
}
`
6 画一个圆
const fshader = `
varying vec3 v_position;
void main(){
// 半径为0.5范围内的显示颜色
float inCircle = 1.0 - step(0.5, length(v_position.xy))
vec3 color = vec3(1.0, 1.0, 0.0) * inCircle;
gl_FlagColor = veec4(color, 1.0);
}
`
7 画一个矩形
const fshader = `
varying vec3 v_position;
//位置是否处于矩形边界内,三个参数分别为检测点坐标,矩形宽高和矩形中心的坐标
flat rect(vec2 pt, vec2 size, vec2 center) {
vec2 p = pt - center;
vec2 halfSize = size * 0.5;
//float horz = (v_position.x>-halfSize.x && v_position.x<halfSize.x) ? 1.0 : 0.0;
// 大于左边界返回1 小于右边界返回0
float horz = step(-halfSize.x, p.x) - step(halfSize.x, p.x);
float vert = step(-halfSize.y, p.y) - step(halfSize.y, p.y);
return horz * vert;
}
void main(){
float inRect = rect(v_position.xy, vec2(1.0), vec2(0.0));
vec3 color = vec3(1.0, 1.0, 0.0) * inRect;
gl_FlagColor = veec4(color, 1.0);
}
`
8 绕中心旋转
设长度为r,则可列出如下公式
const uniforms = {
u_time: { value: 0.0 }
}
const fshader = `
uniform float u_time;
flat rect(vec2 pt, vec2 size, vec2 center) {
vec2 p = pt - center;
vec2 halfSize = size * 0.5;
//float horz = (v_position.x>-halfSize.x && v_position.x<halfSize.x) ? 1.0 : 0.0;
// 大于左边界返回1 小于右边界返回0
float horz = step(-halfSize.x, p.x) - step(halfSize.x, p.x);
float vert = step(-halfSize.y, p.y) - step(halfSize.y, p.y);
return horz * vert;
}
mat getRotationMatrix(float theta) {
float s = sin(theta);
float c = cos(theta);
return mat2(c, -s, s, c)
}
void main() {
vec2 center = vec2(0.0);
mat2 mat = getRotationMatrix(u_time);
vac2 pt = mat * position.xy;
float inRect = rect(pt, vec2(0.5),vec2(0.0))
fl_FragColor = vec4(color, 1.0)
}
`
const clock = new THREE.Clock()
function animate(){
requestAnimation(animate);
uniforms.u_time.value += clock.getDelta();
renderer.render(scene, camera);
}
animate();
9 实战——辉光效果
由于光照的运算需要放在视图空间下,所以需要将法线向量变换到视图矩阵中
//法线和法线矩阵相乘将会被变换到视图空间,归一化向量可以保证使用点乘得到余弦值
vec3 viewNormal = normalize(normalMatrix * normal);
首先画出最外层的辉光
这里是将intensity大于0.55的全部改成0
// 顶点着色器
// 计算顶点法向量 顶点的世界坐标
const vertexShader = `
varying vec3 vVertexWorldPosition;
varying vec3 vVertexNormal;
varying vec4 FragColor;
void main(){
vVertexNormal = normalize(normalMatrix * normal);
vVertexWorldPosition = (modelMMatrix * vec4(position, 1.0)).xyz;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
//计算世界坐标下 顶点位置到相机位置的距离 计算距离向量在视图坐标系下的坐标
//计算不透明度 从中心向外角度越来越大,点乘得到的cos值越来越小,因此intensity不断减小
//所以可以得到一个从中心向两边透明度逐渐减小的圆
const fragmentShader = `
uniform vec3 glowColor;
uniform float coeficient;
varying vec3 vVertexWorldPosition;
varying vec3 vVertexNormal;
varying vec4 FragColor;
void main() {
vec3 worldCameraToVertex = cameraPosition - vVertexWorldPosition;
vec3 viewCameraToVertex = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;
viewCameraToVertex = normalize(viewCameraToVertex);
float intensity = coeficient+ dot(vVertexNormal, viewCameraToVertex);
if(intensity > 0.55){ intensity = 0.0;}
gl_FragColor = vec4(FragColor, intensity)
}
`
之后在画大气层
从中心向外面角度越来越小(从钝角到锐角)从cos函数也可以知道这个值由负变正
图和文字完全不能理解,这里放弃了文章来源:https://www.toymoban.com/news/detail-810254.html
文章来源地址https://www.toymoban.com/news/detail-810254.html
//计算世界坐标下 相机位置到顶点位置的距离 计算距离向量在视图坐标系下的坐标
//计算不透明度
const fragmentShader = `
uniform vec3 glowColor;
uniform float coeficient;
uniform float power;
varying vec3 vVertexWorldPosition;
varying vec3 vVertexNormal;
varying vec4 FragColor;
void main() {
vec3 worldCameraToVertex = vVertexWorldPosition- cameraPosition;
vec3 viewCameraToVertex = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;
viewCameraToVertex = normalize(viewCameraToVertex);
float intensity = pow(coeficient+ dot(vVertexNormal, viewCameraToVertex), power);
gl_FragColor = vec4(FragColor, intensity)
}
`
const container = document.createElement( 'div' );
const camera = new THREE.PerspectiveCamera( 45, window.innerWidth/window.innerHeight, 1, 1000 );
const scene = new THREE.Scene()
const render = new THREE.webGLRenderer()
render.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement);
const sphere = new THREE.SphereBufferGeometry(6. 32, 32)
const material = new THREE.ShaderMaterial({
uniforms: {
coeficient : {
type: "f",
value : 1.0
},
power: {
type : "f",
value : 2
},
glowColor: {
type : "c",
value : new THREE.Color('blue')
}
},
vertexShader: vertexShader,
fragmentShader,
blending: THREE.NormalBlending,
transparent: true,
})
const mesh = new THREE.Mesh(sphere, material)
scene.add(mesh)
10 实战-小球上的粒子
const r = 60
// r小球半径 num 生成粒子数量
// 在球面上生成随机均匀分布的粒子
// 随机产生随机数u,v∈[-1,1]
// 满足 u^2+v^2 <=1
// radiu = u^2+v^2
// x = 2*u*sqrt(1-r^2)
// y = 2*v*sqrt(1-r^2)
// z = 1-2*r^2
const getPointsxyz = (r, num) => {
const position = []
for (let i = 0;i<num;i++) {
const u = Math.random() * 2 - 1
const v = Math.random() * 2 - 1
const radius = u **2 + v ** 2
if (radius <= 1) {
const x = 2 * u * Math.sqrt(1- radius**2)
const x = 2 * v * Math.sqrt(1- radius**2)
const z = 1 - 2*radius**2
position.push({x, y, z})
}
}
return position
}
const pointUniforms = {
pointSize: {value: 1.0},
color: { value: new Color('#ffffff') },
center: { value: new Vector2(width / 2, height / 2) },
}
// 随机生成粒子坐标
const posxyz = getPointsxyz(r, 10000)
const geometry = new THREE.Geometry()
//将点放入几何体中
for (let i = 0;i<posxyz.length;i++) {
const {x,y,z} = posxyz[i]
const vertex = new Vector3(x,y,z)
geometry.vertices.push(vertex)
}
//顶点着色器
const vertexShader = `
uniform float pointSize;
void main() {
gl_PointSize = pointSize;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
const fragmentShader = `
uniform vec3 color;
uniform vec2 center;
float random2(float x, float x1) {
return smoothstep(-40.0, x, x1)
}
void main (){
gl_FragColor = vec4(color, random2(center.x, length(gl_FragCoord.xy - center))) ;
}
`
const pointMaterial = new ShaderMaterial({
uniforms: pointUniforms,
vertexShader,
fragmentShader,
transparent: true, //启用透明效果
blending: THREE.AdditiveBlending, //颜色直接相加, 不受透明度影响
depthWrite: false //禁用depthWrite可防止渲染材质影响深度缓冲区
})
const spherePoint = new Points(geometry, pointMaterial)
group.add(spherePoint)
到了这里,关于着色器语言GLSL学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!