没看过的朋友,记得先去看下入门一。
基础代码同样不变
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
}
canvas {
width: 100%;
height: 100%
}
</style>
</head>
<body>
</body>
<script src="./three.js">
</script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.PlaneGeometry(2, 2);
const uniforms = {
}
const material = new THREE.ShaderMaterial({
});
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
camera.position.z = 1;
onWindowResize();
window.addEventListener("resize", onWindowResize, false);
animate();
function onWindowResize(event) {
const aspectRatio = window.innerWidth / window.innerHeight;
let width, height;
if (aspectRatio >= 1) {
width = 1;
height = (window.innerHeight / window.innerWidth) * width;
} else {
width = aspectRatio;
height = 1;
}
camera.left = -width;
camera.right = width;
camera.top = height;
camera.bottom = -height;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
</script>
</html>
加入shader:
const vshader = `
void main(){
gl_Position=projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`;
const fshader = `
uniform vec2 u_resolution;
uniform vec2 u_mouse;
void main(){
vec2 color= gl_FragCoord.xy/u_resolution;
gl_FragColor=vec4(color,0.0,1.0);
}
`;
...
//u_mouse还没用到,等会会使用
const uniforms = {
u_mouse: { value: { x: 0, y: 0 } },
u_resolution: { value: { x: 0, y: 0 } }
}
...
const material = new THREE.ShaderMaterial({
vertexShader: vshader,
fragmentShader: fshader,
uniforms,
});
...
function onWindowResize(event) {
const aspectRatio = window.innerWidth / window.innerHeight;
uniforms.u_resolution.value.x=window.innerWidth;
uniforms.u_resolution.value.y=window.innerHeight;
let width, height;
if (aspectRatio >= 1) {
width = 1;
height = (window.innerHeight / window.innerWidth) * width;
} else {
width = aspectRatio;
height = 1;
}
camera.left = -width;
camera.right = width;
camera.top = height;
camera.bottom = -height;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
...
// gl_FragCoord:表示当前片元着色器处理的候选片元窗口相对坐标信息,是一个 vec4 类型的变量 (x, y, z, 1/w),其中 x, y 是当前片元的窗口坐标。例如gl_FragCoord.xy左下角为(0,0) 右上角 如果屏幕是1000,1000 则为(1000,1000)
接下来我们让画一个矩形,让矩形跟随鼠标运动。
const fshader = `
uniform vec2 u_resolution;
uniform vec2 u_mouse;
float rect(vec2 pt,vec2 wh,vec2 center){
vec2 rangeMax=center + wh/2.0;
vec2 rangeMin=center - wh/2.0;
return step(rangeMin.x,pt.x)*step(pt.x,rangeMax.x)*step(rangeMin.y,pt.y)*step(pt.y,rangeMax.y);
}
void main(){
vec3 color=vec3(1.0,0.0,0.0)*rect(gl_FragCoord.xy,vec2(30),u_mouse);
gl_FragColor=vec4(color,1.0);
}
`;
...
window.addEventListener('mousemove', move)
function move(e) {
uniforms.u_mouse.value.x = e.clientX
uniforms.u_mouse.value.y = window.innerHeight-e.clientY
}
接下来画一个圆
const fshader = `
float circle(vec2 xy,float r,vec2 center){
return step(length(xy-center),r);
}
void main(){
vec3 color=vec3(1.0,0.0,0.0)*circle(gl_FragCoord.xy,30.0,vec2(500,500));
gl_FragColor=vec4(color,1.0);
}
`;
// length(a); 返回向量a的长度;比如 vec2 a=vec2(2,2); length(a)= 根号下(22 +22)
接下来在画一个模糊圆。
const fshader = `
float circle(vec2 xy,float r,vec2 center){
return step(length(xy-center),r);
}
float smoothCircle(vec2 xy,float r,vec2 center){
return smoothstep(r,r*0.75,length(xy-center));
}
void main(){
vec3 color=vec3(1.0,0.0,0.0)*(
circle(gl_FragCoord.xy,30.0,vec2(100))
+smoothCircle(gl_FragCoord.xy,30.0,vec2(100,200))
);
gl_FragColor=vec4(color,1.0);
}
`;
smoothstep(edg0, edg1, x); edg0<edg1时,edg0左边缘,edg1右边缘,使x在edg0和edg1区间内进行平滑处理。返回值在[0, 1]区间内,当x > edg1时,返回1,当x < edg0时,返回0,当x在edg0和edg1之间时,返回x; edg0>edg1时情况相反.
说人话就是 smoothstep(0,1,x)x为-1,返回0,x为2返回1.
smoothstep(1,0,x为-1,返回1,x为2返回0.
接下来画一个空心圆
const fshader = `
float circle(vec2 xy,float r,vec2 center){
return step(length(xy-center),r);
}
float smoothCircle(vec2 xy,float r,vec2 center){
return smoothstep(r,r*0.75,length(xy-center));
}
float hollowCircle(vec2 xy,float r,float strokeWidth,vec2 center){
return step(r,length(xy-center))*step(length(xy-center),r+strokeWidth);
}
void main(){
vec3 color=vec3(1.0,0.0,0.0)*(
circle(gl_FragCoord.xy,30.0,vec2(100))
+smoothCircle(gl_FragCoord.xy,30.0,vec2(100,200))
+hollowCircle(gl_FragCoord.xy,60.0,60.0,vec2(500,500))
);
gl_FragColor=vec4(color,1.0);
}
`;
第二节课就到此结束了。记住gl_FragCoord, smoothstep, length的用法即可。