WebGl 使用uniform变量动态修改点的颜色

在WebGL中,uniform变量用于在顶点着色器和片元着色器之间传递全局状态信息,这些信息在渲染过程中不会随着顶点的变化而变化。uniform变量可以用来设置变换矩阵、光照参数、材料属性等。由于它们在整个渲染过程中共享,因此可以被所有使用该着色器程序的顶点和片元访问。

1. 声明uniform变量

javascript 复制代码
// 片源着色器源码
const fragmentShaderSource = `
    // 声明uniform变量,一定要加分号!!!
    uniform vec4 uColor;

    void main() {
        gl_FragColor = uColor; // r, g, b, a
    }`

2. 获取 uniform 变量存储地址

javascript 复制代码
// gl.getUniformLocation(program, name)
// 此方法使用和入参与 gl.getAttribLocation 相同
// program: 包含顶点和片元着色器的程序对象
// name:uniform 变量的名称

const ucolor = gl.getUniformLocation(program, 'ucolor');

3. 给uniform变量赋值

javascript 复制代码
// gl.uniform4f(location, vO, v1, v2, v3 )  v1, v2, v3,v4分别代表r, g, b, a
// location:变量
// v1:第一个分量的值
// v2:第二个分量的值
// v3:第三个分量的值
// v4:第四个分量的值

gl.uniform4f(uColor,1.0, 0.0, 0.0, 1.0);

赋值需要注意的点:声明和赋值是对应的,同时main()中的gl_FragColor也需要对应修改。

  1. uniform float uColor 对应 gl.uniform1f(uColor,1.0, 0.0, 0.0, 1.0);
  2. uniform vec2 uColor 对应 gl.uniform2f(uColor,1.0, 0.0);
  3. uniform ve34 uColor 对应 gl.uniform3f(uColor,1.0, 0.0, 0.0);
  4. uniform vec4 uColor 对应 gl.uniform4f(uColor,1.0, 0.0, 0.0, 1.0);
javascript 复制代码
uniform float uColor;
void main() {
    gl_FragColor = vec(uColor, 0.0, 0.0, 1.0);
}

uniform vec2 uColor;
void main() {
    gl_FragColor = vec(uColor.r, uColor.g, 0.0, 1.0);
}

uniform vec3 uColor;
void main() {
    gl_FragColor = vec(uColor.r, uColor.g, uColor.b, 1.0);
}

uniform vec4 uColor;
void main() {
    gl_FragColor = uColor;
}

4. 设置精度

javascript 复制代码
// 高精度:highp
// 中精度:mediump
// 低精度:lowp
const fragmentShaderSource = `   
    precision mediump float;// 设置精度
    uniform vec4 uColor;
    void main() {
        gl_FragColor = uColor; // r, g, b, a
    }`

5. 完整代码

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        canvas {
            margin: 50px auto;
            display: block;
            background: pink;
        }
    </style>
    <title>修改点的颜色</title>
</head>

<body>
    <canvas id="canvas" width="400" height="400">
        此浏览器不支持canvas
    </canvas>
    <script src="./js/index.js"></script>
    <script>
        const ctx = document.getElementById('canvas')
        const gl = ctx.getContext('webgl')
        // 顶点着色器源码
        const vertexShaderSource = `
            attribute vec4 aPosition;
            void main() {
                gl_Position = aPosition; 
                gl_PointSize = 5.0;
            }`

        // 片源着色器源码
        const fragmentShaderSource = `
            // 4.设置精度
            precision mediump float;
            // 1.声明uniform变量,一定要加分号!!!
            uniform vec4 uColor;
            void main() {
                gl_FragColor = uColor; // r, g, b, a
            }`

        const program = initShader(gl, vertexShaderSource, fragmentShaderSource)
        const aPosition = gl.getAttribLocation(program, 'aPosition');
        // 2.获取返回变量的存储地址
        const uColor = gl.getUniformLocation(program, 'uColor');

        const points = [];
        ctx.onclick = function (e) {
            const x = e.clientX;
            const y = e.clientY;
            const domPosition = e.target.getBoundingClientRect();
            const domx = x - domPosition.left;
            const domy = y - domPosition.top;
            const halfWidth = ctx.offsetWidth / 2;
            const halfHeigth = ctx.offsetHeight / 2;
            const clickX = (domx - halfWidth) / halfWidth;
            const clickY = (halfHeigth - domy) / halfHeigth;
            points.push({ clickX, clickY })
            points.forEach(element => {
                gl.vertexAttrib2f(aPosition, element.clickX, element.clickY)
                // 3.给uniform变量赋值
                gl.uniform4f(uColor, element.clickX, element.clickY, 0.0, 1.0);
                gl.drawArrays(gl.POINTS, 0, 1);
            });
        }
        // 着色器 
        function initShader(gl, vertexShaderSource, fragmentShaderSource) {
            const vertexShader = gl.createShader(gl.VERTEX_SHADER);
            const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
            gl.shaderSource(vertexShader, vertexShaderSource);
            gl.shaderSource(fragmentShader, fragmentShaderSource);
            gl.compileShader(vertexShader);
            gl.compileShader(fragmentShader);
            const program = gl.createProgram();
            gl.attachShader(program, vertexShader);
            gl.attachShader(program, fragmentShader);
            gl.linkProgram(program);
            gl.useProgram(program);
            return program;
        }
    </script>
</body>

</html>

6. 效果如下

相关推荐
meilindehuzi_a6 小时前
从零理解并实现 RAG:用 LangChain.js 构建语义检索问答系统
开发语言·javascript·langchain
世界哪有真情7 小时前
拿人类意识卡 AI?等于用 bug 验收正式产品
前端·人工智能·后端
鱼樱前端7 小时前
别再自己拼凑了!这款 Vue 3.5+ 严肃产品级组件库,把 AI 对话、工作流和复杂数据全包了!
javascript·vue.js·github
Listen·Rain8 小时前
Vue3:setup详解
前端·javascript·vue.js
Patrick_Wilson8 小时前
修好 bug 只是开始:一次由监控需求反向重构日志结构的复盘
前端·监控·数据可视化
kyriewen9 小时前
面试官让我优化一个卡死的表格,我打开 Claude 五秒重写,他放下咖啡问我要不要来当组长
前端·javascript·面试
小粉粉hhh9 小时前
React(二)——dom、组件间通信、useEffect
前端·javascript·react.js
Csvn10 小时前
🤖 AI 生成前端代码的 5 个典型翻车现场及修复指南
前端
IT_陈寒11 小时前
SpringBoot自动装配坑了我一天,原来问题出在这
前端·人工智能·后端
索西引擎11 小时前
【React】key 属性:协调算法中的元素标识机制与最佳实践
前端·javascript·react.js