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. 效果如下

相关推荐
mldong7 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排7 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60618 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰9 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi11 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen11 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马12 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu12 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss