Страница 1 из 2

Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 27 окт 2010, 18:32
gnoblin
Чуть улучшенный EdgeDetect, теперь накладывается поверх основной текстуры объекта и получается что-то типа эффекта Borderlands (хотя не уверен как конкретно это реализовано в самой игре).
Конечно же, намного оптимальнее сделать текстуру сразу с таким эффектом :D.

При удалении от объекта смотрится намного хуже, интересно какими способами можно это бороть :-w.

Синтаксис:
Используется glsl
Shader "ImageProc EdgeDetectionSobel_BorderLands" {
 Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert
          #pragma target 3.0
               
      struct Input {
          float2 uv_MainTex;
      };
     
      sampler2D _MainTex;
      void surf (Input IN, inout SurfaceOutput o)
      {
         
          float off = 1.0/1024;
          // Sample the neighbor pixels
                        float s00 = tex2D(_MainTex, IN.uv_MainTex + float2(-off, -off));
                        float s01 = tex2D(_MainTex, IN.uv_MainTex + float2( 0, -off));
                        float s02 = tex2D(_MainTex, IN.uv_MainTex + float2( off, -off));
                        float s10 = tex2D(_MainTex, IN.uv_MainTex + float2(-off, 0));
                        float s12 = tex2D(_MainTex, IN.uv_MainTex + float2( off, 0));
                        float s20 = tex2D(_MainTex, IN.uv_MainTex + float2(-off, off));
                        float s21 = tex2D(_MainTex, IN.uv_MainTex + float2( 0, off));
                        float s22 = tex2D(_MainTex, IN.uv_MainTex + float2( off, off));
                        // Sobel filter in X and Y direction
                        float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
                        float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
                        // Find edge using a threshold of 0.07 which works generally
                        // well for general edge detection.
                        float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
                       
                        float threshold = 0.0049;//0.07*0.07;
                       
                        half3 tmp = half3(0,0,0);
                        half3 one = half3(1,1,1);
                        if(edgeSqr > threshold)
                        {
                                tmp = one;
                        }
                                                                       
                        o.Albedo = one-tmp;    
                        half4 color = tex2D(_MainTex, IN.uv_MainTex);
                       
                        if(o.Albedo.r > 0.2)
                        {
                                                        o.Albedo = color;
                        }
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 27 окт 2010, 18:45
antonio
В Borderlands текстуры рисованные - разбирал.

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 27 окт 2010, 20:03
gnoblin
Ок).

Типа такого, только без обводки по контурам объекта.
Ещё скрины из игры тут:
http://games.1c.ru/borderlands/?type=gallery

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 27 окт 2010, 20:07
Neodrop
(3A4OT)

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 28 окт 2010, 15:59
antonio
Покрутил.
Да зд`орово.
Может сэмплер не дефолтовый использовать sampler2D, а покрутить самому.
Синтаксис:
Используется glsl
sampler Samp = sampler_state
{
    Texture   = (_MainTex);
    MipFilter = none;
    MinFilter = point;
    MagFilter = point;
    AddressU  = CLAMP;
    AddressV = CLAMP;
};

(popcorn1)

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 28 окт 2010, 18:38
gnoblin
А можно чуть подробнее про семплеры и чем вот этот приведенный лучше?

Я думал в юнити нельзя пользоваться "нестандартными".

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 28 окт 2010, 18:42
Neodrop
А я бы и полный код шейдера попросил :ymdaydream:

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 28 окт 2010, 19:32
Battle Angel Alita
1. Строчка float s00 = tex2D(_MainTex, IN.uv_MainTex + float2(-off, -off)); возвращает красный канал текстуры. Т.е ты детектируешь грань по красному каналу, а было-бы правильней допустим по яркости.
2. Просто собель на текстуре это не так интересно, его можно и в фотошопе наложить. Гораздо интереснее завязать его на яркость освещения и/или на NdotV(фреснель).

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 28 окт 2010, 21:03
gnoblin
Две отличные идеи!

Сделаю, только без понятия как завязать на освещение.

Ещё была мысль детектить маской 2x2 в надежде, что это всё станет работать на sm 2.0

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 29 окт 2010, 08:49
antonio
да с сэмплером я не туда завернул.
Может threshold = 0.0049 сделать не статичным а привязать к COMPUTE_EYEDEPTH(o.threshold) и умножать на thresholdCustom вынесеный в интерфейс для доводки. Примерно как реализован аутлайн в тун шейдере. Я попытался расcчитать COMPUTE_EYEDEPTH в вертексном шейдере, а потом отправить threshold в пиксел шейдер. Но пока что-то не очень смотриться (Видимо надо еще подрезать минимумом и максимумом) и потерял заливку светом. Не думаю что стоит выставлять итак сочинение написал(. С шейдерами только стал разбираться вдохновился творческим порывом gnoblina.

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 30 окт 2010, 01:04
gnoblin
Ещё можно результат edge detect'а использовать как маску для спекуляра\отражений (наверное) :D

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 30 окт 2010, 01:27
gnoblin
Свежий вариант шейдера.
Края считаются по яркости изображения, плюс вместо костыля 1.0/1024.0 используется _MainTex_TexelSize :).

Синтаксис:
Используется glsl
Shader "BorderLands2" {
 Properties {
      _MainTex ("Texture", 2D) = "white" {}
      //_FPOW("FPOW", Float) = 5.0
      //_R0("R0", Float) = 0.05
    }
    SubShader {
         
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #include "UnityCG.cginc"
      #pragma surface surf Lambert
      #pragma target 3.0
         
      struct Input {
          float2 uv_MainTex;
          float3 viewDir;
      };
     
      sampler2D _MainTex;
      float2 _MainTex_TexelSize;
         // float _FPOW;
         // float _R0;
         
          float Brightness(half3 color)
          {
             return 0.299*color.r + 0.587*color.g + 0.184*color.b;
          }
         
      void surf (Input IN, inout SurfaceOutput o)
      {
                        //dot(o.Normal, normalize(IN.viewDir)
         
                        //half fresnel = saturate(1.0 - dot(o.Normal, normalize(IN.viewDir)));
                        //fresnel = pow(fresnel, _FPOW);
                        //fresnel = _R0 + (1.0 - _R0) * fresnel;
                        //reflcol = lerp(c, reflcol, fresnel);
         
                        float2 off = _MainTex_TexelSize;
         
                        // Sample the neighbor pixels
                        float s00 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, -off.y)).rgb);
                        float s01 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( 0, -off.y)).rgb);
                        float s02 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, -off.y)).rgb);
                        float s10 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, 0)).rgb);
                        float s12 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, 0)).rgb);
                        float s20 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, off.y)).rgb);
                        float s21 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( 0, off.y)).rgb);
                        float s22 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, off.y)).rgb);
                        // Sobel filter in X and Y direction
                        float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
                        float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
                        // Find edge using a threshold of 0.07 which works generally
                        // well for general edge detection.
                        float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
               
                        float threshold = 0.0049;//0.07*0.07;
               
                        half3 tmp = half3(0,0,0);
                        half3 one = half3(1,1,1);
                        if(edgeSqr > threshold)
                        {
                                        tmp = one;
                        }
                                                               
                        o.Albedo = one-tmp;    
                        half4 color = tex2D(_MainTex, IN.uv_MainTex);
                       
                        float brightness = Brightness(o.Albedo.rgb);
                       
                        //if(o.Albedo.r > 0.2)
                        if(brightness > 0.2)
                        {
                                o.Albedo = color;
                        }
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 30 окт 2010, 01:45
gnoblin
Вариант с френелем, но здесь я похоже перемудрил :-\

Синтаксис:
Используется glsl
Shader "BorderLands2" {
 Properties {
      _MainTex ("Texture", 2D) = "white" {}
      _FPOW("FPOW", Float) = 5.0
      _R0("R0", Float) = 0.05
    }
    SubShader {
         
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #include "UnityCG.cginc"
      #pragma surface surf Lambert
      #pragma target 3.0
         
      struct Input {
          float2 uv_MainTex;
          float3 viewDir;
      };
     
      sampler2D _MainTex;
      float2 _MainTex_TexelSize;
          float _FPOW;
          float _R0;
         
          float Brightness(half3 color)
          {
             return 0.299*color.r + 0.587*color.g + 0.184*color.b;
          }
         
      void surf (Input IN, inout SurfaceOutput o)
      {
                        float2 off = _MainTex_TexelSize;
         
                        // Sample the neighbor pixels
                        float s00 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, -off.y)).rgb);
                        float s01 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( 0, -off.y)).rgb);
                        float s02 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, -off.y)).rgb);
                        float s10 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, 0)).rgb);
                        float s12 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, 0)).rgb);
                        float s20 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, off.y)).rgb);
                        float s21 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( 0, off.y)).rgb);
                        float s22 = Brightness(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, off.y)).rgb);
                        // Sobel filter in X and Y direction
                        float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
                        float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
                        // Find edge using a threshold of 0.07 which works generally
                        // well for general edge detection.
                        float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
               
                        float threshold = 0.0049;//0.07*0.07;
               
                        half3 tmp = half3(0,0,0);
                        half3 one = half3(1,1,1);
                        if(edgeSqr > threshold)
                        {
                                tmp = one;
                        }
                                                               
                        o.Albedo = one-tmp;    
                        half4 color = tex2D(_MainTex, IN.uv_MainTex);
                       
                        float brightness = Brightness(o.Albedo.rgb);
                       
                        float NdotV = dot(o.Normal, normalize(IN.viewDir));
                        half fresnel = saturate(1.0 - NdotV);
                        fresnel = pow(fresnel, _FPOW);
                        fresnel = _R0 + (1.0 - _R0) * fresnel;
                               
                        o.Albedo = lerp(o.Albedo, color, fresnel);
                       
                        if(brightness > 0.2)
                                o.Albedo = color;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 30 окт 2010, 09:29
Battle Angel Alita
gnoblin
Синтаксис:
Используется glsl
Shader "BorderLands2+"
{
        Properties
        {
                _MainTex ("Texture", 2D) = "white" {}
                _thr("threshold", Float) = 0.15
                _tweak("???", Float) = -20.0
        }
        SubShader
        {
                Tags { "RenderType" = "Opaque" }
CGPROGRAM
#include "UnityCG.cginc"
#pragma surface surf Lambert
#pragma target 3.0

sampler2D _MainTex;
float2 _MainTex_TexelSize;
float _thr;
float _tweak;

struct Input
{
        float2 uv_MainTex;
        float3 viewDir;
};

void surf (Input IN, inout SurfaceOutput o)
{
        float2 off = _MainTex_TexelSize;
       
        // Sample the neighbor pixels
        float s00 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, -off.y)).rgb);
        float s01 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2( 0, -off.y)).rgb);
        float s02 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, -off.y)).rgb);
        float s10 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, 0)).rgb);
        float s12 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, 0)).rgb);
        float s20 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2(-off.x, off.y)).rgb);
        float s21 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2( 0, off.y)).rgb);
        float s22 = Luminance(tex2D(_MainTex, IN.uv_MainTex + float2( off.x, off.y)).rgb);
        // Sobel filter in X and Y direction
        float sobelX = s00 + 2 * s10 + s20 - s02 - 2 * s12 - s22;
        float sobelY = s00 + 2 * s01 + s02 - s20 - 2 * s21 - s22;
        // Find edge using a threshold of 0.07 which works generally
        // well for general edge detection.
        float edgeSqr = (sobelX * sobelX + sobelY * sobelY);
       
        edgeSqr = (edgeSqr - _thr) * _tweak;
        edgeSqr = saturate(edgeSqr);
       
        o.Emission = tex2D(_MainTex, IN.uv_MainTex);
        o.Emission = o.Emission * edgeSqr;

        /*
        o.Normal = half3(0.0, 0.0, 1.0);
        float NdotV = dot(o.Normal, normalize(IN.viewDir));
        //mad with NdotV
        NdotV = saturate(NdotV * 1.5);
        NdotV = pow(NdotV, 2.0);
        NdotV = clamp(NdotV, 0.0, 0.9);
       
        o.Emission = lerp(o.Emission * edgeSqr, o.Emission, NdotV);
        */

}
ENDCG

        }
Fallback "Diffuse"
}
 

Re: Borderlands (EdgeDetection поверх текстуры)

СообщениеДобавлено: 30 окт 2010, 09:59
Battle Angel Alita
Вот такая зависимость хорошо смотрится

Синтаксис:
Используется glsl
        o.Normal = half3(0.0, 0.0, 1.0);
        float NdotV = dot(o.Normal, normalize(IN.viewDir));
       
        edgeSqr = (edgeSqr - _thr * NdotV) * _tweak;
        edgeSqr = saturate(edgeSqr);