58 WebGL在平面绘制透视纹理效果

2018-03-04 03:55:39 人阅读

案例查看有问题?
全屏试试!

案例源代码


                        
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Title</title>
    <style>
        body {
            margin: 0;
            text-align: center;
        }
 
        #canvas {
            display: block;
        }
        #div{
            width:800px;
            height:800px;
            position: relative;
            margin: 0 auto;
        }
    </style>
</head>
<body onload="main()">
<div id="div">
    <canvas id="canvas" height="800" width="800"></canvas>
</div>
</body>
<script src="/lib/webgl-utils.js"></script>
<script src="/lib/webgl-debug.js"></script>
<script src="/lib/cuon-utils.js"></script>
<script src="/lib/cuon-matrix.js"></script>
<script>
    /*第一部分顶点着色器接收顶点的纹理坐标,传递给片元着色器*/
    var VSHADER_SOURCE = "" +
        "attribute vec4 a_Position;\n" +//
        "varying vec2 v_Position;\n" +
        "void main(){\n" +
        "   gl_Position = a_Position;\n" +
        "   v_Position = vec2(a_Position);\n" +
        "}\n";
 
    var FSHADER_SOURCE = "" +
        "precision mediump float;\n" +//
        "uniform sampler2D u_Sampler;\n" +//
        "varying vec2 v_Position;\n" +
        "uniform vec2 u_point0;\n" +
        "uniform vec2 u_point1;\n" +
        "uniform vec2 u_point2;\n" +
        "uniform vec2 u_point3;\n"  +
        "float calc(vec2 p1,vec2 p2,vec2 p3,vec2 p4,vec2 p0){\n" +
        //如果不是平行的两条直线
        "   float p12Xlen = p2.x-p1.x;\n" +
        "   float p12Ylen = p2.y-p1.y;\n" +
        "   float p34Xlen = p4.x-p3.x;\n" +
        "   float p34Ylen = p4.y-p3.y;\n" +
        "   float a = p12Xlen*p34Ylen-p12Ylen*p34Xlen;\n" +
        "   float b = p1.x*p34Ylen+p3.y*p12Xlen-p0.y*p12Xlen-p3.x*p12Ylen+p0.y*p34Xlen-p1.y*p34Xlen+p0.x*(p12Ylen-p34Ylen);\n" +
        "   float c = p3.x*p0.y-p3.x*p1.y+p1.x*p3.y-p1.x*p0.y+p0.x*(p1.y-p3.y);\n" +
        //两条线都垂直于x轴或者y轴的情况下
        "   if(a == 0.0){\n" +
        "       return -c/b;\n" +
        "   }\n" +
        //两条线不平行的情况下
        "   float endA = (-b+sqrt(b*b-4.0*a*c))/(2.0*a);\n" +
        "   float endB = (-b-sqrt(b*b-4.0*a*c))/(2.0*a);\n" +
        "   if(endA > 0.0 && endA < 1.0){\n" +
        "       return endA;\n" +
        "   }\n" +
        "   if(endB > 0.0 && endB < 1.0){\n" +
        "       return endB;\n" +
        "   }\n" +
        "   else {\n" +
        "       return -c/b;\n" +
        "   }\n" +
        "}\n" +
        ""+
        //两个点的位置,第一个calc(v0,v2,v1,v3,p0) 第二个calc(v1,v0,v3,v2,p0)
        "void main(){\n" +
        "   gl_FragColor = texture2D(u_Sampler,vec2(calc(u_point0,u_point2,u_point1,u_point3,v_Position),calc(u_point1,u_point0,u_point3,u_point2,v_Position)));\n" +//
        "}\n";
 
    //四个顶点的位置
    var v0 = {x:-0.5,y:0.5};
    var v1 = {x:-0.5,y:-0.5};
    var v2 = {x:0.5,y:0.5};
    var v3 = {x:0.5,y:-0.5};
    //图片的地址设置
    var imgSrc = "/lib/textures/758px-Canestra_di_frutta_(Caravaggio).jpg";
    var gl;
 
    /*第二部分 main()方法 初始化着色器,设置顶点信息,调用配置纹理方法*/
    function main() {
        var canvas = document.getElementById("canvas");
        gl = getWebGLContext(canvas);
        if(!gl){
            console.log("你的电脑不支持WebGL!");
            return;
        }
        if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
            console.log("初始化着色器失败!");
            return;
        }
 
        //设置顶点的相关信息
        var n = initVertexBuffers(gl);
 
        if(n < 0){
            console.log("无法获取到点的数据");
            return;
        }
 
        //配置纹理
        if(!initTextures(gl,n)){
            console.log("无法配置纹理");
            return;
        }
 
    }
 
    /*第三部分 initVertexBuffers() 设置顶点坐标和纹理坐标 调用initTextures()进行下一步处理*/
    function initVertexBuffers(gl) {
        /*
            *   v0-------v2
            *   |         |
            *   |         |
            *   |         |
            *   v1-------v3
            *
            *   [v0.x,v0.y,v1.x,v1.y,v2.x,v2.y,v3.x,v3.y]
            *   config.Positions[0].Config 数组由八个数据组成,代表四个点的位置,距离中心点的偏移量
            * */
        var verticesSizes = new Float32Array([
            //四个顶点的位置
            v0.x,v0.y,
            v1.x,v1.y,
            v2.x,v2.y,
            v3.x,v3.y
        ]);
 
        initArrayBuffer(gl, verticesSizes, 2, gl.FLOAT, "a_Position");
 
        //将四个顶点位置传入
        var point0 = gl.getUniformLocation(gl.program, "u_point0");
        var point1 = gl.getUniformLocation(gl.program, "u_point1");
        var point2 = gl.getUniformLocation(gl.program, "u_point2");
        var point3 = gl.getUniformLocation(gl.program, "u_point3");
        if(point0 < 0){
            alert("无法获取到存储的位置");
        }
        gl.uniform2f(point0,v0.x,v0.y);
        gl.uniform2f(point1,v1.x,v1.y);
        gl.uniform2f(point2,v2.x,v2.y);
        gl.uniform2f(point3,v3.x,v3.y);
 
        var indexSize = new Uint8Array([0,1,3,0,2,3]);
 
        //将索引写入缓冲区对象
        var indexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indexSize, gl.STATIC_DRAW);
 
        return indexSize.length;
    }
 
    //创建变量缓冲区
    function initArrayBuffer(gl, data, num, type, attribute) {
        //创建缓冲区对象
        var buffer = gl.createBuffer();
        if (!buffer) {
            console.log("无法创建缓冲区对象");
            return -1;
        }
 
        //绑定缓冲区对象并写入数据
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
 
        //获取顶点位置变量位置
        var a_attribue = gl.getAttribLocation(gl.program, attribute);
        if (a_attribue < 0) {
            console.log("无法获取顶点位置的存储变量");
            return -1;
        }
 
        //对位置的顶点数据进行分配,并开启
        gl.vertexAttribPointer(a_attribue, num, type, false, 0, 0);
        gl.enableVertexAttribArray(a_attribue);
    }
 
    /*第四部分 initTextures() 创建纹理对象 并调用纹理绘制方法*/
    function initTextures(gl,n) {
        var texture = gl.createTexture();//创建纹理对象
        if(!texture){
            console.log("无法创建纹理对象");
            return;
        }
 
        //获取u_Sampler的存储位置
        var u_Sampler = gl.getUniformLocation(gl.program,"u_Sampler");
        if(u_Sampler < 0){
            console.log("无法获取变量的存储位置");
            return;
        }
 
        //创建Image对象,并绑定加载完成事件
        var image = new Image();
        image.onload = function () {
            loadTexture(gl,n,texture,u_Sampler,image);
            //初始化交互事件
            initMoveBtn();
        };
 
        image.src = imgSrc;
        return true;
    }
 
    function initMoveBtn() {
        var canvas = document.querySelector("#canvas");
        var div = document.querySelector("#div");
        var canvasWidth = canvas.width;
        var canvasHeight = canvas.height;
 
        addBtn(v0);
        addBtn(v1);
        addBtn(v2);
        addBtn(v3);
 
        function addBtn(obj) {
            var x = (obj.x+1)/2;
            var y = 1-(obj.y+1)/2;
 
            var btn = document.createElement("div");
            btn.style.cssText = "height:10px; width:10px; transform:translate(-50%,-50%); position:absolute; background:green; cursor:pointer;";
            btn.style.left = x *canvasWidth+"px";
            btn.style.top = y * canvasHeight +"px";
            div.appendChild(btn);
 
            var downX,downY,btnX,btnY;
 
            btn.addEventListener("mousedown",function (event) {
                //鼠标按下时的位置
                downX = event.clientX;
                downY = event.clientY;
 
                //按下时btn的位置
                btnX = parseFloat(btn.style.left);
                btnY = parseFloat(btn.style.top);
 
                document.addEventListener("mousemove",move,true);
                document.addEventListener("mouseup",up,true);
            },true);
 
            function move(event) {
                event.preventDefault();
                var moveX = event.clientX;
                var moveY = event.clientY;
 
                var x = moveX-downX + btnX;
                var y = moveY - downY + btnY;
 
                btn.style.left = x+"px";
                btn.style.top = y + "px";
 
                obj.x = x/canvasWidth*2-1;
                obj.y = (1-y/canvasHeight)*2-1;
 
                //重新绘制
                reload();
            }
 
            function up() {
                document.removeEventListener("mousemove",move,true);
                document.removeEventListener("mouseup",up,true);
            }
        }
    }
 
    /*第五部分 设置纹理相关信息供WebGL使用,并进行绘制*/
    function loadTexture(gl,n,texture,u_Sampler,image) {
        //对纹理图像进行y轴反转
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);
        //开启0号纹理单元
        gl.activeTexture(gl.TEXTURE0);
        //向target绑定纹理对象
        gl.bindTexture(gl.TEXTURE_2D,texture);
        //配置纹理参数
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        //配置纹理图像
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
        //将0号纹理传递给着色器
        gl.uniform1i(u_Sampler,0);
 
        draw(n);
 
    }
 
    //重新绘制的方法
    function reload(){
 
        var n = initVertexBuffers(gl);
 
        //绘制
        draw(n);
    }
 
    function draw(n) {
        //绘制
        gl.clearColor(0.0,0.0,0.0,1.0);
 
        gl.clear(gl.COLOR_BUFFER_BIT);
 
        gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    }
 
</script>
</html>
展开内容

联系我们

一个人的力量不如两个人的,两个人的力量不如一群人的。欢迎加入大家庭一起共同学习,共同进步。

查看更多