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); }`,
};