// ==UserScript==
// @name WebGL (Shaders优化工具)
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 优化 WebGl 着色器性能(动态调整复杂度、纹理优化、视锥裁剪等)
// @author KiwiFruit
// @match *://*/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// 1. 动态调整着色器复杂度(根据设备 DPI)
function getShaderPrecision() {
const dpi = window.devicePixelRatio;
return dpi >= 2 ? 'highp' : 'mediump'; // 高 DPI 使用高精度 [[3]]
}
// 2. 创建顶点着色器
function createVertexShader(gl) {
const precision = getShaderPrecision();
const vertexShaderSource = `
attribute vec4 a_Position;
attribute vec3 a_Normal;
uniform mat4 u_ModelViewMatrix;
uniform mat4 u_ProjectionMatrix;
varying vec3 v_Normal;
void main() {
v_Normal = normalize((u_ModelViewMatrix * vec4(a_Normal, 0.0)).xyz);
gl_Position = u_ProjectionMatrix * u_ModelViewMatrix * a_Position;
}
`;
return compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
}
// 3. 创建片元着色器(动态精度)
function createFragmentShader(gl) {
const precision = getShaderPrecision();
const fragmentShaderSource = `
precision ${precision} float; // 动态精度 [[3]]
varying vec3 v_Normal;
uniform vec3 u_LightColor;
uniform vec3 u_LightDirection;
void main() {
float light = max(dot(v_Normal, u_LightDirection), 0.0);
gl_FragColor = vec4(u_LightColor * light, 1.0);
}
`;
return compileShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
}
// 4. 编译着色器通用函数
function compileShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compile failed:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
// 5. 预编译并缓存着色器程序
let shaderProgramCache = null;
async function preloadShaders(gl) {
if (shaderProgramCache) return shaderProgramCache;
const vs = createVertexShader(gl);
const fs = createFragmentShader(gl);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Program link failed:', gl.getProgramInfoLog(program));
return null;
}
shaderProgramCache = program;
return program;
}
// 6. 创建带 Mipmap 的纹理 [[10]]
function createMipmapTexture(gl, image) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
return texture;
}
// 7. 视锥裁剪逻辑 [[5]]
function isObjectVisible(object, camera) {
const distance = Math.sqrt(
(object.position.x - camera.position.x) ** 2 +
(object.position.y - camera.position.y) ** 2 +
(object.position.z - camera.position.z) ** 2
);
return distance < camera.far; // 根据摄像机远裁剪面剔除 [[5]]
}
// 8. 静态分辨率适配(根据设备 DPI)[[2]]
function adjustResolutionByDPI(canvas) {
const dpi = window.devicePixelRatio;
const targetDpi = 1.0; // 固定目标 DPI
const scale = dpi > targetDpi ? targetDpi / dpi : 1.0;
canvas.width = Math.floor(canvas.clientWidth * scale);
canvas.height = Math.floor(canvas.clientHeight * scale);
canvas.getContext('webgl').viewport(0, 0, canvas.width, canvas.height);
}
// 9. 主函数:初始化 WebGL 并应用优化
function initWebGL() {
const canvas = document.createElement('canvas');
adjustResolutionByDPI(canvas); // 静态分辨率适配 [[2]]
document.body.appendChild(canvas);
const gl = canvas.getContext('webgl');
if (!gl) {
console.error('WebGL not supported');
return;
}
// 预编译着色器 [[3]]
preloadShaders(gl).then(program => {
if (!program) return;
// 示例:绘制一个简单立方体
const vertices = new Float32Array([
// 顶点坐标
-1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1,
-1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1,
]);
const normals = new Float32Array([
// 法线向量
0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1,
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
]);
// 创建缓冲区
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const normalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
// 绑定属性
gl.useProgram(program);
const aPosition = gl.getAttribLocation(program, 'a_Position');
const aNormal = gl.getAttribLocation(program, 'a_Normal');
gl.enableVertexAttribArray(aPosition);
gl.enableVertexAttribArray(aNormal);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0);
// 设置统一变量
const uModelViewMatrix = gl.getUniformLocation(program, 'u_ModelViewMatrix');
const uProjectionMatrix = gl.getUniformLocation(program, 'u_ProjectionMatrix');
const uLightColor = gl.getUniformLocation(program, 'u_LightColor');
const uLightDirection = gl.getUniformLocation(program, 'u_LightDirection');
gl.uniform3f(uLightColor, 1.0, 1.0, 1.0);
gl.uniform3f(uLightDirection, 0.5, 0.5, 1.0);
// 渲染循环
function render() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // 绘制立方体面
requestAnimationFrame(render);
}
render();
});
}
// 10. 监听页面加载完成
window.addEventListener('load', () => {
try {
initWebGL(); // 初始化 WebGL 渲染 [[3]]
} catch (error) {
console.error('WebGL 初始化失败:', error);
}
});
})();