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

Обводка объекта, полученного комбинированием

СообщениеДобавлено: 16 фев 2017, 17:01
Friend123
Коллеги, добрый день.
Вот уже N-ую неделю бьюсь над решением поставленной задачи, создал несколько тем (например тут: http://unity3d.ru/distribution/viewtopic.php?f=35&t=41637), но безрезультатно.

А цель вроде бы простая: необходимо обвести объект по границе, например черными линиями (например как в цивилизации или европе). Объект собирается из нескольких единиц/десятков гексагонов с помощью функции CombineMesh. Пробовал что-то подобное для решения сделать шейдером, но не получилось. Максимум, что помогло - это использование эффекта на камеру из нативного пакета эффектов - Edge Detection - он обводит объекты нормально, но если у соседних объектов одинаковый материал, то граница между ними не рисуется (а рисовать ее нужно).

Возможно, не стоит совсем использовать эти шейдеры. Возможно есть более простое решение.

Буду весьма благодарен за помощь!!!

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 16 фев 2017, 17:30
Paul Siberdt
А дефолтовая обводка от ShaderForge не работает?

Синтаксис:
Используется glsl
// Shader created with Shader Forge v1.34
// Shader Forge (c) Neat Corporation / Joachim Holmer - http://www.acegikmo.com/shaderforge/
// Note: Manually altering this data may prevent you from opening it in Shader Forge
/*SF_DATA;ver:1.34;sub:START;pass:START;ps:flbk:,iptp:0,cusa:False,bamd:0,lico:1,lgpr:1,limd:1,spmd:1,trmd:0,grmd:0,uamb:True,mssp:True,bkdf:False,hqlp:False,rprd:False,enco:False,rmgx:True,rpth:0,vtps:0,hqsc:True,nrmq:1,nrsp:0,vomd:0,spxs:False,tesm:0,olmd:1,culm:0,bsrc:0,bdst:1,dpts:2,wrdp:True,dith:0,atcv:False,rfrpo:True,rfrpn:Refraction,coma:15,ufog:True,aust:True,igpj:False,qofs:0,qpre:1,rntp:1,fgom:False,fgoc:False,fgod:False,fgor:False,fgmd:0,fgcr:0.5,fgcg:0.5,fgcb:0.5,fgca:1,fgde:0.01,fgrn:0,fgrf:300,stcl:False,stva:128,stmr:255,stmw:255,stcp:6,stps:0,stfa:0,stfz:0,ofsf:0,ofsu:0,f2p0:False,fnsp:False,fnfb:False;n:type:ShaderForge.SFN_Final,id:4013,x:33043,y:32745,varname:node_4013,prsc:2|diff-1304-RGB,olwid-6213-OUT,olcol-1026-RGB;n:type:ShaderForge.SFN_Color,id:1304,x:32443,y:32712,ptovrint:False,ptlb:Color,ptin:_Color,varname:node_1304,prsc:2,glob:False,taghide:False,taghdr:False,tagprd:False,tagnsco:False,tagnrm:False,c1:1,c2:1,c3:1,c4:1;n:type:ShaderForge.SFN_Color,id:1026,x:32443,y:33031,ptovrint:False,ptlb:node_1026,ptin:_node_1026,varname:node_1026,prsc:2,glob:False,taghide:False,taghdr:False,tagprd:False,tagnsco:False,tagnrm:False,c1:1,c2:0.007352948,c3:0.007352948,c4:1;n:type:ShaderForge.SFN_ValueProperty,id:6213,x:32443,y:32925,ptovrint:False,ptlb:node_6213,ptin:_node_6213,varname:node_6213,prsc:2,glob:False,taghide:False,taghdr:False,tagprd:False,tagnsco:False,tagnrm:False,v1:0.2;proporder:1304-1026-6213;pass:END;sub:END;*/

Shader "Shader Forge/testShader" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _node_1026 ("node_1026", Color) = (1,0.007352948,0.007352948,1)
        _node_6213 ("node_6213", Float ) = 0.2
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "Outline"
            Tags {
            }
            Cull Front
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma fragmentoption ARB_precision_hint_fastest
            #pragma multi_compile_shadowcaster
            #pragma multi_compile_fog
            #pragma only_renderers d3d9 d3d11 glcore gles
            #pragma target 3.0
            uniform float4 _node_1026;
            uniform float _node_6213;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                UNITY_FOG_COORDS(0)
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.pos = mul(UNITY_MATRIX_MVP, float4(v.vertex.xyz + v.normal*_node_6213,1) );
                UNITY_TRANSFER_FOG(o,o.pos);
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                return fixed4(_node_1026.rgb,0);
            }
            ENDCG
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
           
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDBASE
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma multi_compile_fog
            #pragma only_renderers d3d9 d3d11 glcore gles
            #pragma target 3.0
            uniform float4 _LightColor0;
            uniform float4 _Color;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD0;
                float3 normalDir : TEXCOORD1;
                LIGHTING_COORDS(2,3)
                UNITY_FOG_COORDS(4)
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.normalDir = UnityObjectToWorldNormal(v.normal);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                float3 lightColor = _LightColor0.rgb;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex );
                UNITY_TRANSFER_FOG(o,o.pos);
                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                i.normalDir = normalize(i.normalDir);
                float3 normalDirection = i.normalDir;
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
                float3 lightColor = _LightColor0.rgb;
////// Lighting:
                float attenuation = LIGHT_ATTENUATION(i);
                float3 attenColor = attenuation * _LightColor0.xyz;
/////// Diffuse:
                float NdotL = max(0.0,dot( normalDirection, lightDirection ));
                float3 directDiffuse = max( 0.0, NdotL) * attenColor;
                float3 indirectDiffuse = float3(0,0,0);
                indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb; // Ambient Light
                float3 diffuseColor = _Color.rgb;
                float3 diffuse = (directDiffuse + indirectDiffuse) * diffuseColor;
/// Final Color:
                float3 finalColor = diffuse;
                fixed4 finalRGBA = fixed4(finalColor,1);
                UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
                return finalRGBA;
            }
            ENDCG
        }
        Pass {
            Name "FORWARD_DELTA"
            Tags {
                "LightMode"="ForwardAdd"
            }
            Blend One One
           
           
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #define UNITY_PASS_FORWARDADD
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog
            #pragma only_renderers d3d9 d3d11 glcore gles
            #pragma target 3.0
            uniform float4 _LightColor0;
            uniform float4 _Color;
            struct VertexInput {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
            };
            struct VertexOutput {
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD0;
                float3 normalDir : TEXCOORD1;
                LIGHTING_COORDS(2,3)
                UNITY_FOG_COORDS(4)
            };
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.normalDir = UnityObjectToWorldNormal(v.normal);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                float3 lightColor = _LightColor0.rgb;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex );
                UNITY_TRANSFER_FOG(o,o.pos);
                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                i.normalDir = normalize(i.normalDir);
                float3 normalDirection = i.normalDir;
                float3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
                float3 lightColor = _LightColor0.rgb;
////// Lighting:
                float attenuation = LIGHT_ATTENUATION(i);
                float3 attenColor = attenuation * _LightColor0.xyz;
/////// Diffuse:
                float NdotL = max(0.0,dot( normalDirection, lightDirection ));
                float3 directDiffuse = max( 0.0, NdotL) * attenColor;
                float3 diffuseColor = _Color.rgb;
                float3 diffuse = directDiffuse * diffuseColor;
/// Final Color:
                float3 finalColor = diffuse;
                fixed4 finalRGBA = fixed4(finalColor * 1,0);
                UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
                return finalRGBA;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
    CustomEditor "ShaderForgeMaterialInspector"
}

 

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 16 фев 2017, 17:39
waruiyume
Она вроде вдоль нормалей распердоливает вершины, а у него плоскость.

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 16 фев 2017, 17:43
Paul Siberdt
а.. те самые гесагоны... нууу.. у меня пока мысли не родилось, как и чем их обыграть, разве что строить поверх еще одну карту из граничных гексагонов-обводок.

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 16 фев 2017, 17:49
waruiyume
https://drive.google.com/file/d/0B0dncz ... 4170146208
Взято отсюда(https://www.youtube.com/watch?v=_IwlpwEJ3lE)
нужна та часть которая делает Reject. Не знаю получится ли что-то или нет но это единственное что пришло в голову, кроме рендера в текстуру Id объекта с последующей обрисовкой в постэффекте.
----
Можно попробовать запхнуть координаты центров ячеек в дополнительный UV канал, а потом просто вытолкнуть вершины из центра(в шереных вершинах может получиться (полная Ж) а на границе может и прохляет)

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 16 фев 2017, 20:19
bojlahg
сгенерируй меш с обводкой вот и все дела. и рендерь ее потом хоть в хвост хоть в гриву.

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 17 фев 2017, 10:12
Friend123
Paul Siberdt писал(а):А дефолтовая обводка от ShaderForge не работает?

Попробовал ее, фигня получается какая-то, не четко обводит и совсем не разделяет границы
Изображение

bojlahg писал(а):сгенерируй меш с обводкой вот и все дела. и рендерь ее потом хоть в хвост хоть в гриву.

У меня сначала генерируются гексы, а потом они комбинируются в меш (разной формы).

Код генерации меша (на вход подается объект, дочками которого и являются гексы):
Синтаксис:
Используется csharp
    private void CombineSectorsInRegions(Transform region) {
        MeshFilter[] meshFilters  = region.GetComponentsInChildren<MeshFilter>();
        CombineInstance[] combine = new CombineInstance[meshFilters.Length];

        int n = 0;
        while(n < meshFilters.Length) {
            combine[n].mesh      = meshFilters[n].sharedMesh;
            combine[n].transform = meshFilters[n].transform.localToWorldMatrix;
            meshFilters[n].gameObject.SetActive(false);
            n++;
        }

        region.gameObject.AddComponent<MeshFilter>();
        region.gameObject.AddComponent<MeshRenderer>();        
        region.gameObject.AddComponent<MeshCollider>();

        region.GetComponent<MeshFilter>().mesh = new Mesh();
        region.GetComponent<MeshFilter>().mesh.CombineMeshes(combine);
        region.GetComponent<MeshFilter>().mesh.RecalculateNormals();
        region.GetComponent<MeshFilter>().mesh.RecalculateBounds();
        region.GetComponent<MeshCollider>().sharedMesh = region.GetComponent<MeshFilter>().mesh;
       
        region.gameObject.SetActive(true);        
    }
 

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 21 фев 2017, 11:35
Friend123
Совершенно случайно нашел в сети шейдер, который практически решает задачу. Границы появились (не смотря на гигантское значение outline width), даже между одинаковыми материалами, но какие-то они нереалистичные.
Изображение

Сам шейдер:
Синтаксис:
Используется csharp
Shader "Outlined/Silhouetted Bumped Mobile" {
     Properties {
         _Color ("Main Color", Color) = (.5,.5,.5,1)
         _OutlineColor ("Outline Color", Color) = (0,0,0,1)
         _Outline ("Outline width", Float) = 4
         _MainTex ("Base (RGB)", 2D) = "white" { }
         _BumpMap ("Bumpmap", 2D) = "bump" {}
     }
 
 CGINCLUDE
 #include "UnityCG.cginc"
 
 struct appdata {
     float4 vertex : POSITION;
     float3 normal : NORMAL;
 };
 
 struct v2f {
     float4 pos : POSITION;
     float4 color : COLOR;
 };
 
 uniform float _Outline;
 uniform float4 _OutlineColor;
 
 v2f vert(appdata v) {
 ////////////////////////////////REPLACE THIS SECTION WITH.../////////////////////////////
 //    // just make a copy of incoming vertex data but scaled according to normal direction
 //    v2f o;
 //    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
 //
 //     float3 norm   = mul ((float3x3)UNITY_MATRIX_IT_MV, v.normal);
 //    float2 offset = TransformViewToProjection(norm.xy);
 //
 //    o.pos.xy += offset * o.pos.z * _Outline;
 
 /////////////////////////////////////////////...THIS PART///////////////////////////
     v2f o;
     o.pos = v.vertex;
     o.pos.xyz += v.normal.xyz *_Outline*0.01;
     o.pos = mul(UNITY_MATRIX_MVP, o.pos);
 
     o.color = _OutlineColor;
     return o;
 }
 ENDCG
 
     SubShader {
         Tags { "Queue" = "Transparent" }
 
         // note that a vertex shader is specified here but its using the one above
         Pass {
             Name "OUTLINE"
             Tags { "LightMode" = "Always" }
             Cull Off
             ZWrite Off
             //ZTest Always //This is what allows the outline to be seen through other objects
 
             // you can choose what kind of blending mode you want for the outline
             Blend SrcAlpha OneMinusSrcAlpha // Normal
             //Blend One One // Additive
             //Blend One OneMinusDstColor // Soft Additive
             //Blend DstColor Zero // Multiplicative
             //Blend DstColor SrcColor // 2x Multiplicative
 
 CGPROGRAM
 #pragma vertex vert
 #pragma fragment frag
 
 half4 frag(v2f i) : COLOR {
     return i.color;
 }
 ENDCG
         }
 
 
 CGPROGRAM
 #pragma surface surf Lambert
 struct Input {
     float2 uv_MainTex;
     float2 uv_BumpMap;
 };
 sampler2D _MainTex;
 sampler2D _BumpMap;
 uniform float3 _Color;
 void surf(Input IN, inout SurfaceOutput o) {
     o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
     o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
 }
 ENDCG
 
     }
 
     SubShader {
         Tags { "Queue" = "Transparent" }
 
         Pass {
             Name "OUTLINE"
             Tags { "LightMode" = "Always" }
             Cull Front
             ZWrite Off
             //ZTest Always
             Offset 15,15
 
             // you can choose what kind of blending mode you want for the outline
             Blend SrcAlpha OneMinusSrcAlpha // Normal
             //Blend One One // Additive
             //Blend One OneMinusDstColor // Soft Additive
             //Blend DstColor Zero // Multiplicative
             //Blend DstColor SrcColor // 2x Multiplicative
 
             CGPROGRAM
             #pragma vertex vert
             #pragma exclude_renderers gles xbox360 ps3
             ENDCG
             SetTexture [_MainTex] { combine primary }
         }
 
 CGPROGRAM
 #pragma surface surf Lambert
 struct Input {
     float2 uv_MainTex;
     float2 uv_BumpMap;
 };
 sampler2D _MainTex;
 sampler2D _BumpMap;
 uniform float3 _Color;
 void surf(Input IN, inout SurfaceOutput o) {
     o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
     o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
 }
 ENDCG
 
     }
 
     Fallback "Outlined/Silhouetted Diffuse"
 }
 


Подскажите, кто знаком с шейдерами - какие параметры нужно покрутить или поменять что-то где-то чтобы привести в нормальный человеческий вид границы?

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 21 фев 2017, 12:49
Tolking
За это время уже раз 10 можно было было сделать чтобы по краям ставились гексагоны с текстурой нужной обводки...

Re: Обводка объекта, полученного комбинированием

СообщениеДобавлено: 21 фев 2017, 13:18
Friend123
Tolking писал(а):За это время уже раз 10 можно было было сделать чтобы по краям ставились гексагоны с текстурой нужной обводки...

Хм, интересный вариант. Спасибо за наводку.