一、效果

二、源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>绘制线</title>
<style>
body {
margin: 0px;
padding: 0px;
text-align: center;
}
#canvas {
margin: 0;
position: absolute;
width: 100%;
height: 100%;
left: 0px;
top: 0px;
}
</style>
<script src="/lib/webgl-utils.js"></script>
<script src="/lib/webgl-debug.js"></script>
<script src="/lib/cuon-utils.js"></script>
<script src="/lib/cuon-matrix.js"></script>
<script src="/data/city.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
<script type="module">
import { SphereGeometry } from "/geometry/SphereGeometry.js"
import { PointsGeometry } from "/geometry/PointsGeometry.js"
import { Texture2D } from './texture/Texture2D.js'
import { Program } from './core/Program.js'
import { toRadian, Cartesian3 } from './core/Math.js'
import { Material } from './material/Material.js'
import { Control } from './core/Control.js'
import { Object3D } from './core/Object3D.js'
import { Scene } from './core/Scene.js'
import { Camera } from './core/Camera.js'
import { Renderer } from './core/Renderer.js'
import { MeshLineGeometry } from './geometry/MeshLineGeometry.js'
import { earthVS, earthFS } from './material/shaders/Earth.js'
import { shanxiJSON } from './data/shanxi.js'
var VSHADER_SOURCE = `
attribute vec3 a_PrevPosition;
attribute vec3 a_NextPosition;
attribute vec3 a_Position;
attribute float a_Sides;
attribute vec2 a_Uv;
uniform mat4 u_MvpMatrix;
uniform vec2 u_Resolution;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectMatrix;
// uniform float u_Test;
varying vec2 v_Uv;
vec2 transToNDC(vec4 clipPosition,float aspect){
vec2 ndcPosition=clipPosition.xy/clipPosition.w;
ndcPosition.x*=aspect;
return ndcPosition;
}
vec2 screenToClip(vec2 screenPosition){
return vec2(screenPosition.x/u_Resolution.x,screenPosition.x/u_Resolution.x);
}
void main(){
float width=5.0;
mat4 mvp_Matrix=u_ProjectMatrix*u_ViewMatrix*u_ModelMatrix;
vec4 clip_Position=mvp_Matrix*vec4(a_Position,1.0);
vec4 clip_PrevPosition=mvp_Matrix*vec4(a_PrevPosition,1.0);
vec4 clip_NextPosition=mvp_Matrix*vec4(a_NextPosition,1.0);
float aspect=u_Resolution.x/u_Resolution.y;
// float test=u_Test;
//转换到NDC空间
vec2 ndcPosition=transToNDC(clip_Position,aspect);
vec2 ndcPrevPosition=transToNDC(clip_PrevPosition,aspect);
vec2 ndcNextPosition=transToNDC(clip_NextPosition,aspect);
vec2 dir=vec2(0.0);
float theckness=width;
//计算方向
if(ndcPosition==ndcPrevPosition){
dir=normalize(ndcNextPosition-ndcPosition);
}else if(ndcPosition==ndcNextPosition){
dir=normalize(ndcPosition-ndcPrevPosition);
}else{
vec2 dir1= normalize(ndcPosition-ndcPrevPosition);
vec2 dir2= normalize(ndcNextPosition-ndcPosition);
vec2 tanget=normalize(dir1+dir2);
vec2 dir1Normal=vec2(-dir1.y,dir1.x);
vec2 normal=vec2(-tanget.y,tanget.x);
dir=tanget;
float cosTheta=dot(dir1Normal,normal);
theckness=min(width/abs(cosTheta),width*5.0);
}
float sizeAttenuation=0.0;
vec4 normal=vec4(-dir.y,dir.x,0.0,1.0);
normal.xy*=theckness*0.5;
// normal*=u_ProjectMatrix;
normal.x/=aspect;
if( sizeAttenuation == 0. ) {
normal.xy *= clip_Position.w;
normal.x*=aspect;
normal.xy /= vec2(u_Resolution.x,u_Resolution.y);
}
clip_Position.xy+=normal.xy*a_Sides;
v_Uv=a_Uv;
gl_Position=clip_Position;
// gl_Position=clip_Position+clipOffset;
}`;
var FSHADER_SOURCE = `
#ifdef GL_ES
precision mediump float;
#endif
uniform vec3 u_Color;
varying vec2 v_Uv;
void main(){
gl_FragColor=vec4(u_Color,1.0);
}`;
var canvas = document.getElementById("canvas");
console.log(canvas.clientWidth)
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
window.gl = getWebGLContext(canvas);
const scene = new Scene()
const camera = new Camera(30, canvas.width / canvas.height, 0.1, 10)
var viewMatrix = camera.viewMatrix
const renderer = new Renderer()
main()
async function main() {
if (!gl) {
console.log("你的浏览器不支持WebGL");
return;
}
const earthProgram = new Program(earthVS, earthFS)
const sphereGeometry = new SphereGeometry(gl, 1, 180, 90)
earthProgram.addUniform('test')
console.log('earthProgram,', earthProgram)
const texture = Texture2D.initTexture('./image/earth.jpg', 0)
const sphereMaterial = new Material({
program: earthProgram,
uniforms: {
texture: texture,
normalTexture: null,
test: 1.0
},
})
const earth = new Object3D(sphereGeometry, sphereMaterial)
scene.add(earth)
const program = new Program(VSHADER_SOURCE, FSHADER_SOURCE)
program.addAttribute('prevPosition')
program.addAttribute('nextPosition')
program.addAttribute('sides')
program.addUniform('resolution')
program.addUniform('color')
console.log(program)
const material = new Material({
program,
uniforms: {
resolution: new Vector2([canvas.clientWidth, canvas.clientHeight]),
color: new Vector3([1, 0, 0])
}
})
console.log(shanxiJSON)
const features = shanxiJSON.features
features.forEach(feature => {
const coordinates = feature.geometry.coordinates
coordinates.forEach(coordinate => {
console.log(coordinate[0])
const worldPosition = []
coordinate[0].forEach(coord => {
worldPosition.push(Cartesian3.fromDegrees(coord[0], coord[1], 0))
})
const geometry = new MeshLineGeometry(worldPosition)
const object3D = new Object3D(geometry, material)
scene.add(object3D)
})
})
const control = new Control(viewMatrix, canvas)
var tick = function () {
gl.clearColor(0.0, 0.0, 0.0, 1.0);
control.update()
renderer.render(scene, camera)
requestAnimationFrame(tick)
}
tick()
}
</script>
</html>