Kingdom-water

2018-04-29  本文已影响0人  Foo_d488

基本思路:根据环境(风,光,基础运动)动态生成一张置换贴图用于倒影变化

Flash版本关键代码如下:
声明置换滤镜

//mapBitmap 基于这个对象扭曲目标图像
//mapPoint 一个值,它包含目标显示对象的左上角相对于映射图像左上角的偏移量。
//componentX 通过这个参数将mapBitmap中的颜色或alpha通道设置为映射图像,并基于这个映射图像在x轴方向置换像素。
//componentY 通过这个参数将mapBitmap中的颜色或alpha通道设置为映射图像,并基于这个映射图像在y轴方向置换像素。
//scaleX 这个参数定义了应用置换后在x轴上的偏移量,数值越大,置换效果越明显
//scaleY 这个参数定义了应用置换后在y轴上的偏移量,数值越大,置换效果越明显
//mode 定义滤镜效果超出图像大小时,该部分像素的处理方式。它的可能值为DisplacementMapFilterMode常量。
//     WRAP表示置换值折返到图像的另一侧;
//     CLAMP的意义和ConvolutionFilter一样,表示置换值重复图像边缘的像素;
//     IGNORE表示忽略置换并使用源像素;
//     COLOR同样和ConvolutionFilter类似,用指定的颜色和透明度替换置换值。
//color 指定对于超出范围的替换应用什么颜色。置换的有效范围是 0.0 到 1.0。如果 mode 设置为 DisplacementMapFilterMode.COLOR,则使用此参数。
//alpha 指定对于超出范围的替换应用什么 Alpha 值。它被指定为 0.0 到 1.0 之间的标准值。例如,0.25 设置透明度值为 25%。如果 mode 设置为 DisplacementMapFilterMode.COLOR,则使用此参数。
//ex: Offx = (mapBitmap[componentX][x,y]-128)/128*scaleX;
displacementFilter = new DisplacementMapFilter(displacementBitmap, zeroPoint, 1, 2, 256, 256, DisplacementMapFilterMode.COLOR, baseColor, 0.5);

每帧逻辑,加入了风和夜色的影响:

  override public function update():void
 {
    timer += FlxG.elapsed;
    if (weather.changed > weatherChanged)
    {
      //interpolateColor 插值运算 baseColor*(1- weather.darkness)+ weather.darknessColor*weather.darkness
      currentBase = 0xFF000000 | Utils.interpolateColor(baseColor, weather.darknessColor, weather.darkness)
                
      //涟漪幅度    WIND_RIPPLE_MULTIPLIER:Number = 25;
      var rippleScale:int = int(weather.wind*WIND_RIPPLE_MULTIPLIER);
      var xscale:int = rippleScale/2;
      var yscale:int = rippleScale;
      if(xscale != 2)
          xscale = xscale;
      //噪声矩阵   rMul, gMul, bMul, aMul, rOff, gOff, bOff, aOff NOISE_BIAS:int = 100;
      noiseRange = new ColorTransform(xscale/128,yscale/128,1,1,(128-xscale+(NOISE_BIAS*xscale/128)),(128-yscale+(NOISE_BIAS*yscale/128)),1,1)
      weatherChanged = weather.t
     }
}

渲染部分:
BitmapData.perlinNoise(baseX:Number, baseY:Number, numOctaves:uint, randomSeed:int, stitch:Boolean, fractalNoise:Boolean, channelOptions:uint=7, grayScale:Boolean=false, offsets:Array=null):void
是FLASH自带的生成柏林噪声的方法。生成多张噪点图叠加得到最终的结果。
baseX, baseY分别是沿X,Y轴生成的杂点频率。
numOctaves 噪点图的张数。
randomSeed 要使用的随机种子数。如果您保持使所有其他参数不变,可以通过改变随机种子值来生成不同的伪随机结果。
stitch 一个布尔值。如果该值为 true,则该方法将尝试平滑图像的转变边缘以创建无缝的纹理,用于作为位图填充进行平铺。
fractalNoise 一个布尔值。如果该值为 true,则该方法将生成碎片杂点;否则,它将生成湍流。带有湍流的图像具有可见的不连续性渐变,可以使其具有更接近锐化的视觉效果,例如火焰或海浪。
channelOptions 一个数字,可以是四个颜色通道值(BitmapDataChannel.RED、BitmapDataChannel.BLUE、BitmapDataChannel.GREEN 和 BitmapDataChannel.ALPHA)的任意组合。您可以使用 logical OR (|) 运算符来组合通道值。
grayScale 一个布尔值。如果该值为 true,则通过将红色、绿色和蓝色通道的每一个值都设置为相同的值来创建一个灰度图像。如果此值设置为 true,则 Alpha 通道值将不会受到影响。
offsets 与每个 octave 的 x 和 y 偏移量相对应的点数组。通过操作这些偏移量值,您可以平滑滚动 perlinNoise 图像的图层。偏移数组中的每个点将影响一个特定的 octave 杂点函数。

  override public function draw():void
        {
            if (timer > 0.1)
            { // Update the water ripple
                perlinOffset.y += 1/5;
                perlinOffset.x = FlxG.camera.scroll.x*1.5;
                displacementBitmap.perlinNoise(32, 4, 1, 12312, false, false, 1|2, true, [perlinOffset]);
                displacementBitmap.colorTransform(rect,noiseRange);
                // Adjust the base color according to the weather.
                displacementFilter.color = currentBase;
                timer = 0;
            }
            var px:BitmapData = pixels;
            matrix.identity();
            matrix.scale(1, -1);
            getScreenXY(_point);
            matrix.translate(-_point.x, _point.y);
            // Clear the reflection
            px.fillRect(rect, currentBase);
            Utils.gradientOverlay(px, [0x00000000,0x66000000], 90, 4);
            // Flip the screen and copy it to the reflection
            px.draw(FlxG.camera.buffer, matrix, transform);
            
            // Draw the lights
            var l:Light;
            for (var i:int = 0; i < lights.length; i++){
                l = lights.members[i] as Light;
                l.getScreenXY(_point);
                if(l.visible && -64 < _point.x && _point.x < FlxG.width + 64){
                    l.reflected.alpha = weather.darkness * 0.8;
                    l.reflected.alpha *= Math.min(1.0, (weather.wind * 10));
                    l.reflected.drawFrame();
                    stamp(l.reflected, _point.x - l.reflected.width/2 + 4, (y - l.y) * 0.3);
                }
            }
            
            // Apply the ripple filter
            px.applyFilter(px, rect, zeroPoint, displacementFilter); 
            dirty = true;
            super.draw()
        }

unity中的水实现思路:
1.在每个像素点上用Mathf.Perlin(float x, float y)产生随机值,生成柏林噪声贴图
2.通过shader取贴图通道值作变换


    void CalcNoise(float dx, float dy)
    {
        float y = 0.0F;
        while(y < noiseTex.height)
        {
            float x = 0.0F;
            float sample = 0;
            while(x < noiseTex.width)
            {
                
                float xCoord = x / noiseTex.width * scale;
                float yCoord = y / noiseTex.height * scale;
                sample = Mathf.PerlinNoise(xCoord + dx, yCoord + dy);//*_force;
                pix[(int)(y * noiseTex.width + x)] = new Color(sample, sample, sample);
                x++;
            }
            y++;
        }
        noiseTex.SetPixels(pix);
        noiseTex.Apply();
    }

    float n = 0;
    void Update()
    {
        n += deltaY;
        CalcNoise(0, n);
        rend.material.SetTexture("_NoiseTex", noiseTex);
    }

比较特殊的一点是因为游戏是像素风的,在取坐标的时候取了下整,保证同一个像素格内的偏移是gg


Shader "ProjZombie/WaterSprite"
{
    Properties
    {
        [PerRendererData] _MainTex ("Texture", 2D) = "white" {}
        _NoiseTex ("Noise Texture (RG)", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        _HeatForce  ("Heat Force", range (0,0.1)) = 0.1
        _width  ("Heat Force", range (1.0,1024.0)) = 256.0
        _height  ("Heat Force", range (1.0,1024.0)) = 256.0

    }
    SubShader
    {
        Tags
            { 
                "Queue"="Transparent" 
                "IgnoreProjector"="True" 
                "RenderType"="Transparent" 
                "PreviewType"="Plane"
                "CanUseSpriteAtlas"="True"
            }
        // No culling or depth
    ZWrite Off
    Cull Off
    Blend Off

        Pass
        {
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float4 color    : COLOR;
            };
            
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                fixed4 color    : COLOR;
            };
            
            fixed4 _Color;
            sampler2D _NoiseTex;
                        float _HeatForce;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.color = v.color * _Color;
                #ifdef PIXELSNAP_ON
                o.vertex = UnityPixelSnap (OUT.vertex);
                #endif
                return o;
            }
            
            sampler2D _MainTex;
            float _width;
            float _height;
            //It is executed for each pixel and the output is the color info of the pixel.
            fixed4 frag (v2f i) : SV_Target
            {

                half4 offsetColor1 = tex2D(_NoiseTex, i.uv);
                i.uv.x = ceil(i.uv.x*_width)/_width;
                i.uv.y = ceil(i.uv.y*_height)/_height;
                i.uv.x += offsetColor1.r  * _HeatForce;
                i.uv.y += offsetColor1.g * _HeatForce;
                fixed4 col = tex2D( _MainTex, i.uv);
                col.rgb *= col.a;
                return col;
            }
            ENDCG
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读