279 lines
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @description 创建着色器对象
* @param {WebGL2RenderingContext} gl
* @param {'VERTEX_SHADER' | 'FRAGMENT_SHADER'} type
* @param {string} source
* @return { WebGLShader | undefined }
*/
function makeShader(gl, type, source) {
// 创建 shader
const shader = gl.createShader(gl[type]);
// 给 shader 提供 glsl 代码
gl.shaderSource(shader, source);
// 编译 glsl 生成 shader
gl.compileShader(shader);
const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS)
// 如果成功,则返回 shader否则返回 undefined
return ok ? shader : gl.deleteShader(shader);
}
/**
*
* @param {string} path
* @return {string}
*/
async function getSource(path) {
const response = await fetch(path);
const source = await response.text();
return source;
}
window.onload = async () => {
const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl2');
if (!(gl instanceof WebGL2RenderingContext)) {
console.log('浏览器不支持 webgl2');
return;
}
const vertexSource = await getSource('./vertex.shader.glsl');
const fragementSource = await getSource('./fragment.shader.glsl');
const vertexShader = makeShader(gl, 'VERTEX_SHADER', vertexSource);
const fragmentShader = makeShader(gl, 'FRAGMENT_SHADER', fragementSource);
if (!vertexShader || !fragmentShader) {
console.log('着色器创建失败');
return;
}
const program = createProgram(gl, vertexShader, fragmentShader);
if (!program) {
console.log('着色程序创建失败');
return;
}
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
const points = [
0, -0.5,
0.5, -0.5,
];
drawMask(gl, program, points, { width: 0.06 });
drawLine2D(gl, program, points, { width: 0.06 });
}
function onTheSameLine(x0, y0, x1, y1, x2, y2) {
const slope1 = (x1 - x0) !== 0 ? (y1 - y0) / (x1 - x0) : Infinity;
const slope2 = (x2 - x0) !== 0 ? (y2 - y0) / (x2 - x0) : Infinity;
return slope1 === slope2;
}
function sgn(value) {
if (value === 0) return 0;
return value > 0 ? 1 : -1;
}
/**
*
* @param {WebGL2RenderingContext} gl
* @param {WebGLProgram} program
* @param {number[]} points
* @param {{
* width: number
* color: string
* }} config
*/
function drawLine2D(gl, program, points, config) {
const pointNum = points.length >> 1;
const w = config.width;
const shift = w / 2;
const positions = [];
for (let i = 0; i < pointNum; ++ i) {
const x1 = points[(i << 1)];
const y1 = points[(i << 1) + 1];
if (i === 0) {
const x2 = points[((i + 1) << 1)];
const y2 = points[((i + 1) << 1) + 1];
if (y1 === y2) {
// console.log('enter i = 0');
positions.push(
x1, y1 + shift, // v0
x1, y1 - shift // v1
);
} else if (x1 === x2) {
positions.push(
x1 + shift, y1, // v1
x1 - shift, y1, // v0
);
}
} else if (i === pointNum - 1) {
const x0 = points[((i - 1) << 1)];
const y0 = points[((i - 1) << 1) + 1];
if (y1 === y0) {
// console.log('enter i = pointNum - 1');
positions.push(
x1, y1 + shift, // v0
x1, y1 - shift // v1
);
} else if (x1 === x0) {
positions.push(
x1 + shift, y1, // v1
x1 - shift, y1, // v0
);
}
} else {
const x0 = points[((i - 1) << 1)];
const y0 = points[((i - 1) << 1) + 1];
const x2 = points[((i + 1) << 1)];
const y2 = points[((i + 1) << 1) + 1];
if (x0 !== x1 && y0 === y1 && x1 === x2 && y1 !== y2) {
const d = sgn(y2 - y1);
if (y2 > y1) {
positions.push(
x1 - shift, y1 + shift,
x1 + shift, y1 - shift
);
} else {
positions.push(
x1 + shift, y1 + shift,
x1 - shift, y1 - shift,
);
}
} else if (x0 === x1 && y0 !== y1 && x1 !== x2 && y1 === y2) {
const d = sgn(y1 - y0);
if (y1 > y0) {
positions.push(
x1 - shift, y1 + shift,
x1 + shift, y1 - shift,
);
} else {
positions.push(
x1 + shift, y1 + shift,
x1 - shift, y1 - shift,
);
}
}
}
}
const positionFloat32 = new Float32Array(positions);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, positionFloat32, gl.STATIC_DRAW);
gl.useProgram(program);
const positionLocation = gl.getAttribLocation(program, 'a_position');
const colorLocation = gl.getUniformLocation(program, 'a_color');
gl.uniform4f(colorLocation, 0.4, 0.0, 1.0, 1.0);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, positionFloat32.length >> 1);
}
/**
*
* @param {WebGL2RenderingContext} gl
* @param {WebGLProgram} program
* @param {number[]} times
* @param {{
* width: number
* color: string
* }} config
* @param {number} yshift
*/
function drawBlock(gl, program, times, config, yshift) {
}
/**
*
* @param {WebGL2RenderingContext} gl
* @param {WebGLProgram} program
* @param {number[]} points
* @param {{
* width: number
* color: string
* }} config
*/
function drawMask(gl, program, points, config) {
const positions = [];
const pointNum = points.length >> 1;
const w = config.width;
const shift = w / 2;
for (let i = 0; i < pointNum; ++ i) {
const x1 = points[(i << 1)];
const y1 = points[(i << 1) + 1];
if (i + 1 < pointNum) {
const x2 = points[((i + 1) << 1)];
const y2 = points[((i + 1) << 1) + 1];
if (y2 > y1 && i + 2 < pointNum) {
const x3 = points[((i + 2) << 1)];
const y3 = points[((i + 2) << 1) + 1];
const p1 = [x1, y1 - shift];
const p2 = [x2, y2 - shift];
const p3 = [x3, y3 - shift];
const p4 = [x3, y1 - shift];
positions.push(
...p1,
...p2,
...p3,
...p1,
...p3,
...p4
);
}
}
}
const positionFloat32 = new Float32Array(positions);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, positionFloat32, gl.STATIC_DRAW);
gl.useProgram(program);
const aPostionLocation = gl.getAttribLocation(program, 'a_position');
const colorLocation = gl.getUniformLocation(program, 'a_color');
gl.uniform4f(colorLocation, 0.4, 0.0, 1.0, 0.2);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enableVertexAttribArray(aPostionLocation);
gl.vertexAttribPointer(aPostionLocation, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, positionFloat32.length >> 1);
}
/**
* @description 创建着色器
* @param {WebGL2RenderingContext} gl
* @param {WebGLShader} vertexShader
* @param {WebGLShader} fragmentShader
* @return { WebGLProgram | undefined }
*/
function createProgram(gl, vertexShader, fragmentShader) {
// 创建着色程序
const program = gl.createProgram();
// 加载着色器到着色程序
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 连接着色程序
gl.linkProgram(program);
const ok = gl.getProgramParameter(program, gl.LINK_STATUS);
return ok ? program : gl.deleteProgram(program);
}