WebGL - 示例 通过鼠标操作物体

该博客介绍了如何在WebGL中通过鼠标操作实现3D立方体的旋转和缩放。内容包括创建立方体、设置着色器,以及详细解析如何添加鼠标事件监听来处理旋转(计算旋转角度并应用矩阵变换)和缩放(控制物体和相机的平移)。提供了完整的示例代码链接。
摘要由CSDN通过智能技术生成

案例实现功能如下:

  • 鼠标左右键移动旋转
  • 滑动滑轮实现缩放

示例:通过鼠标操作物体

首先物体的旋转是通过对模型矩阵的旋转计算modelMatrix.rotate(angle, x, y, z)这个方法可以让物体绕某个轴进行旋转多少度,进而变换顶点坐标,normalMatrix、mvpMatrix...都是可以进行一些列的矩阵变换的,计算过后在清空颜色缓存以及深度缓存,重新绘制页面;

因此使用鼠标去控制物体就是通过监听鼠标的各种事件来进行矩阵变换即可

基本步骤如下:

  • 首先鼠标左右键按下,获取一个点,并记录下来 如v(x,y)
  • 当鼠标开始移动的时候计算此时需要旋转的角度
  • 通过矩阵转换来实现旋转
  • 控制缩放可以控制相机和物体的平移变换

1、创建一个立方体

着色器部分

// 顶点着色器
var v_shader_source = '' +
    'attribute vec4 a_Position;' +
    'attribute vec4 a_Normal;' +
    'uniform mat4 u_MvpMatrix;' +
    'uniform mat4 u_ModelMatrix;' +// 模型矩阵
    'uniform mat4 u_NormalMatrix;' +// 法向量旋转矩阵
    'varying vec4 v_Color;' +
    'varying vec3 v_Normal;' +
    'varying vec3 v_Position;' +
    'void main(){' +
    '   vec4 color = vec4(1.0, 1.0, 1.0, 1.0);' + // 物体颜色
    '   gl_Position = u_MvpMatrix * a_Position;' +
    '   v_Position = vec3(u_ModelMatrix * a_Position);' +
    '   v_Normal = normalize(vec3(u_NormalMatrix * a_Normal));' +
    '   v_Color = color;' +
    '}';
// 片元着色器
var f_shader_source = '' +
    'precision mediump float;' +
    'uniform vec3 u_LightColor;' + // 灯光颜色
    'uniform vec3 u_LightPosition;' + // 灯光位置
    'uniform vec3 u_AmbientLight;' + // 环境光颜色
    'varying vec3 v_Normal;' +
    'varying vec3 v_Position;' +
    'varying vec4 v_Color;' +
    'void main(){' +
    // 对法线进行归一化,因为其内插之后长度不一定是1.0
    '   vec3 normal = normalize(v_Normal);' +
    // 计算光线方向并归一化
    '   vec3 lightDirection = normalize(u_LightPosition - v_Position);' +
    // 计算光线方向和法向量的点积
    '   float nDotL = max(dot(lightDirection, normal), 0.0);' +
    // 计算漫反射和环境反射以及最终的颜色值
    '   vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;' +
    '   vec3 ambient = u_AmbientLight * v_Color.rgb;' +
    '   gl_FragColor = vec4(diffuse + ambient, v_Color.a);' +
    '}';

2、添加鼠标事件监听

1、旋转处理
// 添加鼠标事件监听处理
function initEventHandles(domElement, currentAngle) {

    var dragging = false;

    var lastX = -1;
    var lastY = -1;

    // 添加事件监听的dom元素
    domElement = (domElement !== undefined) ? domElement : document;

    // 角度默认值位0.0
    currentAngle = (currentAngle !== undefined) ? currentAngle : [0.0, 0.0];

    // 鼠标按下事件
    domElement.onmousedown = function (event) {

        event.preventDefault();

        // 鼠标点击位置
        var x = event.clientX;
        var y = event.clientY;

        lastX = x;
        lastY = y;

        dragging = true;

    }

    domElement.onmouseleave = function (event) {

        event.preventDefault();
        dragging = false;

    }

    // 鼠标抬起事件
    domElement.onmouseup = function (event) {

        event.preventDefault();
        dragging = false;

    }

    // 鼠标移动事件
    domElement.onmousemove = function (event) {

        event.preventDefault();

        var x = event.clientX, y = event.clientY;

        if (dragging) {

            // 旋转比例--速度
            var factor = 100 / domElement.height;

            var dx = factor * (x - lastX);
            var dy = factor * (y - lastY);

            // 限制 x轴的旋转角度 -90 --- 90
            currentAngle[0] = Math.max(Math.min(currentAngle[0] + dy, 90.0), -90.0)
            currentAngle[1] = currentAngle[1] + dx;

        }

        lastX = x, lastY = y;
    }

}

上面的代码是处理旋转

2、缩放处理
// 滑轮缩放处理
canvas.addEventListener('wheel', onMouseWheel, false);

function onMouseWheel(event) {

    vpMatrix.translate(0.0, 0.0, -event.deltaY * 0.004);

    mvpMatrix.set(vpMatrix).multiply(modelMatrix);

    gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);

    renderer();

}
3、重复绘制方法
// 重新绘制
function renderer() {

    // 设置灯光的逆转置矩阵,让modelMatrix 转成为modelMatrix 的逆矩阵
    normalMatrix.setInverseOf(modelMatrix);
    normalMatrix.transpose();
    gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);

}

3、示例链接

示例:通过鼠标操作物体

具体案例代码所在仓库如下
https://gitee.com/ithanmang/webgl-notes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值