纯shader实现动态警告可视化组件(three.js实战16)
Posted 点燃火柴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了纯shader实现动态警告可视化组件(three.js实战16)相关的知识,希望对你有一定的参考价值。
纯shader实现动态警告可视化组件
1. demo效果
waring-circle
2. 实现要点
2.1 绘制外层
外层由两部分组成,一个是组成圆环的小圆点,一个是动态变换的弧段,具体实现如下
vec4 drawOutCirclePoint(vec2 st){
vec4 outColor = vec4(0.0);
vec2 outerVertexs[60];
float outerRadius = 0.5;
float angle = 0.0;
float one_point_angle = PI * 2.0 / 60.0;
for(int i = 0; i < 60; i++){
angle += one_point_angle;
outerVertexs[i] = vec2(cos(angle)*outerRadius,sin(angle)*outerRadius);
}
float pct = 0.0;
//绘制外层圆点
for(int i = 0; i < 60;i++){
vec3 pointColor = vec3(0.17,0.97,1.0);
pct = circle(st,outerVertexs[i],0.01,0.002);
vec4 layer = vec4(pointColor.rgb, pct);
//混合图层
outColor = mix(outColor, layer, layer.a);
}
return outColor;
}
//绘制外层旋转圆环
vec4 drawOuterFlowingRing(vec2 st){
vec2 p = st;
float time = u_time * 1.5;
vec3 outRingColor = vec3(0.17,0.97,1.0);
float angle = -(time - sin(time + PI) * cos(time )) - time *.95;
mat2 rot = mat2(cos(angle),sin(angle),-sin(angle),cos(angle));
p = rot * p;
float L = length(p);
float f = 0.;
f = smoothstep(L-.005, L, .51);
f -= smoothstep(L,L + 0.005, .49);
//f = step(sin(L * 200. + u_time * p.x)*.5+.5,.25);
float t = mod(time,2.0*PI) - PI;
float t1 = sin(t) * (PI - .25);
float a = atan(p.y,p.x) ;
f = f * step(a,t1);
vec4 outColor = vec4(outRingColor.rgb, f);
return outColor;
}
2.2绘制中间环状圆
绘制圆环比较简单,只需要用两个圆相减即可
float circle(vec2 uv,vec2 p, float r,float blur){
float dist = length(uv-p);//计算屏幕上任意点到指定点p点的距离
float c = smoothstep(r,r-blur,dist);
return c;
}
//绘制中层圆环
vec4 drawInnerRing(vec2 st){
vec3 ringColor = vec3(202.0/255.0,73.0/255.0,205.0/255.0);
float pct = circle(st,vec2(0.0),0.4,0.02)-circle(st,vec2(0.0),0.3,0.02);
vec4 outColor = vec4(ringColor.rgb, pct);
return outColor;
}
2.3 绘制中心感叹号
//绘制梯形
float trapezoid( in vec2 p, in float topWidth, float bottomWidth, float height,float blur )
{
if(topWidth > bottomWidth){
p *= rotate2d(PI);
}
float width = max(topWidth,bottomWidth);
float k1 = height/((bottomWidth-topWidth)/2.0);
float fun = p.y-k1*p.x-width;
float k2 = -height/((bottomWidth-topWidth)/2.0);
float fun2 = p.y-k2*p.x-width;
if(p.y > -height/2.0 && p.y < height/2.0){
//return smoothstep(k1*p.x+width,k1*p.x,fun);
return smoothstep(k1*p.x+blur*width,k1*p.x,fun)-smoothstep(k2*p.x,k2*p.x + blur*width,fun2);
}else{
return 0.0;
}
}
//绘制中心感叹号
vec4 drawExclamatoryMark(vec2 st) {
vec3 color = vec3(0.17,0.97,1.0);
vec4 outColor = vec4(0.0);
float pct = 0.0;
st.y -= 0.05;
pct = trapezoid( st, 0.28, 0.24, 0.2, 2.);
vec4 layer = vec4(color.rgb, pct);
outColor = mix(outColor, layer, layer.a);
st.y += 0.2;
pct = circle(st,vec2(0.0),0.04,0.02);
vec4 layer1 = vec4(color.rgb, pct);
outColor = mix(outColor, layer1, layer1.a);
return outColor;
}
3. demo代码
<body>
<div id="container"></div>
<script type="text/javascript" src="../three/build/three.js"></script>
<script>
var container;
var camera, scene, planeMesh, renderer;
var clock = new THREE.Clock(); // 创建THREE.Clock对象
var uniforms = {
u_resolution: {
type: "v2",
value: new THREE.Vector2()
},
radius: {
type: "f",
value: 0.5
},
u_time: {
type: "f",
value: 0.5
}
};
var vertexShader = `
attribute vec3 position;
void main() {
gl_Position = vec4( position, 1.0 );
}
`
var fragmentShader = `
#define PI 3.1415926535897932384626433832795
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform float u_time;
//二维旋转矩阵
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),sin(_angle),cos(_angle));
}
float dot2(in vec2 v ) { return dot(v,v); }
//绘制梯形
float trapezoid( in vec2 p, in float topWidth, float bottomWidth, float height,float blur )
{
if(topWidth > bottomWidth){
p *= rotate2d(PI);
}
float width = max(topWidth,bottomWidth);
float k1 = height/((bottomWidth-topWidth)/2.0);
float fun = p.y-k1*p.x-width;
float k2 = -height/((bottomWidth-topWidth)/2.0);
float fun2 = p.y-k2*p.x-width;
if(p.y > -height/2.0 && p.y < height/2.0){
//return smoothstep(k1*p.x+width,k1*p.x,fun);
return smoothstep(k1*p.x+blur*width,k1*p.x,fun)-smoothstep(k2*p.x,k2*p.x + blur*width,fun2);
}else{
return 0.0;
}
}
float circle(vec2 uv,vec2 p, float r,float blur){
float dist = length(uv-p);//计算屏幕上任意点到指定点p点的距离
float c = smoothstep(r,r-blur,dist);
return c;
}
vec4 drawOutCirclePoint(vec2 st){
vec4 outColor = vec4(0.0);
vec2 outerVertexs[60];
float outerRadius = 0.5;
float angle = 0.0;
float one_point_angle = PI * 2.0 / 60.0;
for(int i = 0; i < 60; i++){
angle += one_point_angle;
outerVertexs[i] = vec2(cos(angle)*outerRadius,sin(angle)*outerRadius);
}
float pct = 0.0;
//绘制外层圆点
for(int i = 0; i < 60;i++){
vec3 pointColor = vec3(0.17,0.97,1.0);
pct = circle(st,outerVertexs[i],0.01,0.002);
vec4 layer = vec4(pointColor.rgb, pct);
//混合图层
outColor = mix(outColor, layer, layer.a);
}
return outColor;
}
//绘制外层旋转圆环
vec4 drawOuterFlowingRing(vec2 st){
vec2 p = st;
float time = u_time * 1.5;
vec3 outRingColor = vec3(0.17,0.97,1.0);
float angle = -(time - sin(time + PI) * cos(time )) - time *.95;
mat2 rot = mat2(cos(angle),sin(angle),-sin(angle),cos(angle));
p = rot * p;
float L = length(p);
float f = 0.;
f = smoothstep(L-.005, L, .51);
f -= smoothstep(L,L + 0.005, .49);
//f = step(sin(L * 200. + u_time * p.x)*.5+.5,.25);
float t = mod(time,2.0*PI) - PI;
float t1 = sin(t) * (PI - .25);
float a = atan(p.y,p.x) ;
f = f * step(a,t1);
vec4 outColor = vec4(outRingColor.rgb, f);
return outColor;
}
//绘制中层圆环
vec4 drawInnerRing(vec2 st){
vec3 ringColor = vec3(202.0/255.0,73.0/255.0,205.0/255.0);
float pct = circle(st,vec2(0.0),0.4,0.02)-circle(st,vec2(0.0),0.3,0.02);
vec4 outColor = vec4(ringColor.rgb, pct);
return outColor;
}
//绘制中心感叹号
vec4 drawExclamatoryMark(vec2 st) {
vec3 color = vec3(0.17,0.97,1.0);
vec4 outColor = vec4(0.0);
float pct = 0.0;
st.y -= 0.05;
pct = trapezoid( st, 0.28, 0.24, 0.2, 2.);
vec4 layer = vec4(color.rgb, pct);
outColor = mix(outColor, layer, layer.a);
st.y += 0.2;
pct = circle(st,vec2(0.0),0.04,0.02);
vec4 layer1 = vec4(color.rgb, pct);
outColor = mix(outColor, layer1, layer1.a);
return outColor;
}
void main( void ) {
//转换为窗口坐标[0,1],坐标原点在屏幕左下角
//vec2 st = gl_FragCoord.xy/u_resolution.y;
//窗口坐标调整为[-1,1],坐标原点在屏幕中心
vec2 st = (gl_FragCoord.xy * 2. - u_resolution) / u_resolution.y;
vec4 lastColor = vec4(0.0);
//绘制外层环绕圆点
vec4 layer1 = drawOutCirclePoint(st);
lastColor = mix(lastColor, layer1, layer1.a);
//绘制外层旋转圆环
vec4 layer2 = drawOuterFlowingRing(st);
lastColor = mix(lastColor, layer2, layer2.a);
//绘制中层紫色圆环
vec4 layer3 = drawInnerRing(st);
lastColor = mix(lastColor, layer3, layer3.a);
//绘制中心感叹号
vec4 layer4 = drawExclamatoryMark(st);
lastColor = mix(lastColor, layer4, layer4.a);
gl_FragColor = lastColor;
}
`
init();
animate();
function init() {
container = document.getElementById('container');
camera = new THREE.Camera();
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry(2, 2);
var material = new THREE.RawShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
planeMesh = new THREE.Mesh(geometry, material);
scene.add(planeMesh);
renderer = new THREE.WebGLRenderer();
renderer.setSize(1000, 800); //设置窗口大小800px*800px
container.appendChild(renderer.domElement);
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame(animate);
const elapsed = clock.getElapsedTime();
planeMesh.material.uniforms.u_time.value = clock.getElapsedTime();
renderer.render(scene, camera);
}
</script>
</body>
以上是关于纯shader实现动态警告可视化组件(three.js实战16)的主要内容,如果未能解决你的问题,请参考以下文章
ShaderJoy —— 纯 shader 实现立方体的渲染(含线框效果,虚线线框效果),带你了解渲染管线内部细节和原理GLSL