CocosCreator1.x实现水流动的效果

CocosCreator1.x实现水流动的效果

Cocos Creator版本:1.10.2

运行结果:(H5和原生都支持)
在这里插入图片描述

场景:
在这里插入图片描述

脚本:
HelloWorld.js:

let shader = require(`shader`);

cc.Class({
    extends: cc.Component,
    properties: {
        water: cc.Node,
        waterNormalMap: cc.SpriteFrame,
    },

    onLoad() {
        // 加载所有着色器程序
        shader.loadShaderPrograms();

        // 初始化水的着色器程序
        this._time = 0;
        this._waterSpeed = 0.1;
        shader.setGLProgramForNode(`water`, this.water);
        shader.use(`water`);
        shader.setUniformTexture(`water`, `normalMap`, this.waterNormalMap.getTexture());
        shader.setUniformFloat(`water`, `v_offset`, 0);
    },

    update(dt) {
        // 更新水的着色器程序
        this._time += dt;
        shader.use(`water`);
        shader.setUniformFloat(`water`, `v_offset`, (this._time * this._waterSpeed) % 1);
    },
});

shader.js

let WaterShader = require(`WaterShader`);

module.exports = {
    // 加载所有的着色器程序
    loadShaderPrograms() {
        this.createGLProgram(`water`, WaterShader.vert, WaterShader.frag);
    },

    ///////////////////////////////////////////////
    // 存放所有着色器程序
    gLProgramDict: {},

    // 创建一个着色器程序
    createGLProgram(glProgramName, vertStr, fragStr) {
        let glProgram = this.gLProgramDict[glProgramName];
        if (glProgram) {
            cc.error(`${glProgramName}这个glProgram已经注册过了!!!`);
            return;
        }
        glProgram = new cc.GLProgram();
        if (cc.sys.isNative) {
            glProgram.initWithString(vertStr, fragStr);
        } else {
            glProgram.initWithVertexShaderByteArray(vertStr, fragStr);
            glProgram.addAttribute(cc.macro.ATTRIBUTE_NAME_POSITION, cc.macro.VERTEX_ATTRIB_POSITION);
            glProgram.addAttribute(cc.macro.ATTRIBUTE_NAME_COLOR, cc.macro.VERTEX_ATTRIB_COLOR);
            glProgram.addAttribute(cc.macro.ATTRIBUTE_NAME_TEX_COORD, cc.macro.VERTEX_ATTRIB_TEX_COORDS);
        }
        glProgram.link();
        glProgram.updateUniforms();
        glProgram.use();
        this.gLProgramDict[glProgramName] = glProgram;
    },

    // 设置指定的着色器程序于指定node上
    setGLProgramForNode(glProgramName, node) {
        let glProgram = this.gLProgramDict[glProgramName];
        if (!glProgram) {
            cc.error(`${glProgramName}这个glProgram未注册!!!`);
            return;
        }
        let sprite = node.getComponent(cc.Sprite);
        if (!sprite) {
            cc.error(`这个node没有Sprite组件啊!!!`);
            return;
        }
        let sgNode = sprite._sgNode;
        if (cc.sys.isNative) {
            let glProgramState = cc.GLProgramState.getOrCreateWithGLProgram(glProgram);
            sgNode.setGLProgramState(glProgramState);
        } else {
            sgNode.setShaderProgram(glProgram);
        }
    },

    // 应用指定着色器程序
    use(glProgramName) {
        let glProgram = this.gLProgramDict[glProgramName];
        if (!glProgram) {
            cc.error(`${glProgramName}这个glProgram未注册!!!`);
            return;
        }
        glProgram.use();
    },

    // 为指定着色器程序设置uniform值
    setUniformFloat(glProgramName, uniformName, uniformValue) {
        if (typeof uniformValue !== `number`) {
            cc.error(`setUniformTexture 输入的值不是数字类型 @`, glProgramName, uniformName);
            return;
        }
        this.setUniformCommon(glProgramName, uniformName, uniformValue, `setUniformFloat`, `setUniformLocationWith1f`);
    },
    setUniformTexture(glProgramName, uniformName, uniformValue) {
        if (!(uniformValue instanceof cc.Texture2D)) {
            cc.error(`setUniformTexture 输入的值不是纹理类型 @`, glProgramName, uniformName);
            return;
        }
        if (cc.sys.isNative) {
            this.setUniformCommon(glProgramName, uniformName, uniformValue, `setUniformTexture`, `setUniformLocationWith1f`);
        } else {
            let glProgram = this.gLProgramDict[glProgramName];
            if (!glProgram) {
                cc.error(`${glProgramName}这个glProgram未注册!!!`);
                return;
            }
            let uniformLocation = glProgram.getUniformLocationForName(uniformName);
            glProgram.setUniformLocationWith1i(uniformLocation, 1);
            cc.gl.bindTexture2DN(1, uniformValue);
        }
    },


    setUniformCommon(glProgramName, uniformName, uniformValue, jsbFnName, h5fnName) {
        let glProgram = this.gLProgramDict[glProgramName];
        if (!glProgram) {
            cc.error(`${glProgramName}这个glProgram未注册!!!`);
            return;
        }
        if (cc.sys.isNative) {
            let glProgramState = cc.GLProgramState.getOrCreateWithGLProgram(glProgram);
            glProgramState[jsbFnName](uniformName, uniformValue);
        } else {
            let uniformLocation = glProgram.getUniformLocationForName(uniformName);
            glProgram[h5fnName](uniformLocation, uniformValue);
        }
    }
};

WaterShader.js

module.exports = {
    vert: `
    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    attribute vec4 a_color;
    varying vec2 v_texCoord;
    void main()
    {
        gl_Position = CC_PMatrix * a_position;
        v_texCoord = a_texCoord;
    }      
    `,

    frag: `
    varying vec2 v_texCoord;
    uniform sampler2D normalMap;      // 法线贴图
    uniform float v_offset;           // 法线贴图v坐标偏移

    // 纠正纹理坐标 (当采样坐标超出范围时,从另一边出来,比如 1.1纠正为0.1,-0.1纠正为0.9 等)
    vec2 get_fixuv_by_uv(vec2 uv) {
        if (uv.x > 1.0) {
            uv.x -= 1.0;
        }
        if (uv.x < 0.0) {
            uv.x += 1.0;
        }
        if (uv.y > 1.0) {
            uv.y -= 1.0;
        }
        if (uv.y < 0.0) {
            uv.y += 1.0;
        }
        return uv;
    }

    // 获取法向
    vec3 get_normal() {
        vec2 uv = v_texCoord + vec2(0, v_offset);
        uv = get_fixuv_by_uv(uv);
        return normalize(texture2D(normalMap, uv).xyz * 2.0 - 1.0);  
    }

    // 根据 折射方向 获取新的纹理坐标
    vec2 get_uv_by_refract(vec3 refractVec) {
        vec2 uv = v_texCoord + vec2(refractVec) * 0.5;
        return uv;
    }

    void main() {
        // 视点位置
        vec3 eyePos = vec3(0.5, 0.5, 10.0);                                     
        // 入射方向
        vec3 inVec = normalize(vec3(v_texCoord, 0.0) - eyePos);                          
        // 获取法线
        vec3 normal = get_normal();                  
        // 根据 入射方向,法线,折射率 获取折射方向
        vec3 refractVec = refract(inVec, normal, 0.7);                          
        // 根据 折射方向 获取新的纹理坐标
        vec2 v_texCoord2 = get_uv_by_refract(refractVec);  
        // 最终颜色
        gl_FragColor = texture2D(CC_Texture0, v_texCoord2);                     
    }
    `,
};
发布了24 篇原创文章 · 获赞 0 · 访问量 401

猜你喜欢

转载自blog.csdn.net/qq_18138105/article/details/105355678