Source Code:
https://github.com/mattdesl/three-line-2d/tree/master/test/shader-dash.js
Reference article:
https://mattdesl.svbtle.com/drawing-lines-is-hard
Drawing a broken line 031 - to achieve a custom shader
Final results:
1, using the built-in methods Three.js
App.js
addLine() {
var lineGeometry = new THREE.Geometry();//生成几何体
lineGeometry.vertices.push(new THREE.Vector3(0, 0, 25));//线段的两个顶点
lineGeometry.vertices.push(new THREE.Vector3(0, 1, 25));
let material = new THREE.LineDashedMaterial({
color: 0xffffff,//线段的颜色
dashSize: 1,//短划线的大小
gapSize: 3//短划线之间的距离
})
var line = new THREE.Line(lineGeometry, material);
// 不可或缺的,若无,则线段不能显示为虚线
line.computeLineDistances();
this.stage.scene.add(line);
}
2, custom shader achieve
shader-dash.js
export default class ShaderDash{
static getShaderData(opt){
opt=opt||{};
var ret=Object.assign({
transparent:true,
uniforms:{
dashSteps:{type:'f',value:10},
dashDistance:{type:'f',value:.5},
},
vertexShader:`
attribute float lineDistance;
varying float lineU;
void main(){
lineU=lineDistance;
gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.);
}`,
fragmentShader:`
// 当前点距离起点的距离
varying float lineU;
uniform float dashSteps;
uniform float dashDistance;
void main(){
float lineUMod=mod(lineU,1./dashSteps)*dashSteps;
float dash=step(dashDistance,lineUMod);
gl_FragColor=vec4(vec3(dash),1.);
}`
},opt);
return ret;
}
}
App.js
class App {
...
addDashLine() {
var lineGeometry = new THREE.Geometry();//生成几何体
lineGeometry.vertices.push(new THREE.Vector3(0, 0, 25));//线段的两个顶点
lineGeometry.vertices.push(new THREE.Vector3(0, 1, 25));
let material = new THREE.ShaderMaterial(ShaderDash.getShaderData({
side: THREE.DoubleSide
}))
var line = new THREE.Line(lineGeometry, material);
// 不可或缺的,若无,则线段不能显示为虚线
line.computeLineDistances();
this.stage.scene.add(line);
}
...
}
3, the principle of the code
For the fragment shader:
// lineU 当前像素点距离起点的距离
varying float lineU;
// 单位直线虚线的段数 10
uniform float dashSteps;
// 虚线的间距 0.5
uniform float dashDistance;
void main(){
float lineUMod=mod(lineU,1./dashSteps)*dashSteps;
float dash=step(dashDistance,lineUMod);
gl_FragColor=vec4(vec3(dash),1.);
}
- A total of 10 segments.
- Number pitch per segment = 1 / * segment pitch * 1/10 = 0.5.
- Each pixel is the distance regarded pixel mapped to each segment 0 ~ pitch.
float lineUMod=mod(lineU,1./dashSteps);
- The current pixel comparison distance and the line segment, return is less than 0, returns greater than 1, as the color of the pixel.
float dash=1-step(dashDistance,lineUMod); gl_FragColor=vec4(vec3(dash),1.);
<Full end>