Ответы пользователя по тегу Шейдеры
  • Как сделать тёмные стороны полигона видимыми в Unity?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Двусторонний шейдер делается легко, за это отвечает инструкция Cull Off, подробнее про куллинг можно почитать здесь. Нужную вам прозрачность можно получить с помощью alpha:fade, если говорить про surface-шейдеры, с другими шейдерами будет немного сложнее. Ниже обычный шаблон шейдера, который я немного подчистил и добавил две недостающие инструкции.
    Shader "Custom/NewSurfaceShader"
    {
        Properties
        {
            _Color("Color", Color) = (1,1,1,1)
            _MainTex("Albedo (RGB)", 2D) = "white" {}
            _Glossiness("Smoothness", Range(0,1)) = 0.5
            _Metallic("Metallic", Range(0,1)) = 0.0
        }
        SubShader
        {
            Tags { "RenderType"="Opaque" }
            LOD 200
            // Выключаем куллинг, чтобы меш рисовался с двух сторон
            Cull Off
    
            CGPROGRAM
            // По с равнению со стандартным шаблоном в конце добавилось "alpha:fade" для получения прозрачности
            #pragma surface surf Standard fullforwardshadows alpha:fade
            #pragma target 3.0
    
            struct Input
            {
                float2 uv_MainTex;
            };
    
            fixed4 _Color;
            sampler2D _MainTex;
            half _Glossiness;
            half _Metallic;
    
            void surf(Input IN, inout SurfaceOutputStandard o)
            {
                fixed4 color = tex2D (_MainTex, IN.uv_MainTex)*_Color;
                o.Albedo = color.rgb;
                o.Metallic = _Metallic;
                o.Smoothness = _Glossiness;
                o.Alpha = color.a;
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

    Если хотите побольше узнать про шейдеры, то можете почитать The Book of Shaders и соответствующий раздел мануала. Ещё есть хорошая серия туториалов на эту тему.
    Ответ написан
    Комментировать
  • Можно ли организовать мат. вычисления ч/з шейдер и передать рез-т в скрипт (Unity)?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Можно, но не для всех случаев это будет быстрее, и в конечном итоге вам всё равно придётся профайлить, чтобы понять выигрыш. Видеокарты хорошо умеют работать с векторами и имеют специальные инструкции, которые позволяют совершать несколько арифметических операций за раз, соответственно и ваш алгоритм должен использовать эти сильные стороны, если вам просто нужно факториал посчитать, то возиться с видеокартой смысла нету, вы больше потеряете на загрузке/выгрузке данных с GPU.

    Что касается реализации, то это можно сделать либо с помощью вычислительных шейдеров, либо с помощью обычных шейдеров, всё зависит от возможностей целевой платформы. На компе, если очень хочется, можно и CUDA прикрутить. Если с шейдерами раньше не работали, то могу посоветовать The Book of Shaders, там не про Unity, но достаточно толково.

    К слову говоря, если у вас задача стоит не в переносе на видеокарту, а в оптимизации, то процессоры тоже не лыком шиты, у них есть SIMD, может быть это вам больше подойдёт.
    Ответ написан
    1 комментарий
  • Как умножить текстуры в шейдере Unity?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Шейдеры для прожекторов работают точно так же, просто uv-карта рассчитывается по-другому:
    Projector/Multiply
    Shader "Projector/Multiply"
    {
        Properties
        {
            _ShadowTex("Cookie", 2D) = "gray" {}
            _FalloffTex("FallOff", 2D) = "white" {}
            // Добавляем свойство
            _MaskTex("Mask", 2D) = "white" {}
        }
        Subshader
        {
            Tags {"Queue"="Transparent"}
            Pass
            {
                ZWrite Off
                ColorMask RGB
                Blend DstColor Zero
                Offset -1, -1
    
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_fog
                #include "UnityCG.cginc"
                
                struct v2f
                {
                    float4 uvShadow : TEXCOORD0;
                    float4 uvFalloff : TEXCOORD1;
                    UNITY_FOG_COORDS(2)
                    float4 pos : SV_POSITION;
                };
                
                float4x4 unity_Projector;
                float4x4 unity_ProjectorClip;
                
                v2f vert (float4 vertex : POSITION)
                {
                    v2f o;
                    o.pos = UnityObjectToClipPos(vertex);
                    o.uvShadow = mul(unity_Projector, vertex);
                    o.uvFalloff = mul(unity_ProjectorClip, vertex);
                    UNITY_TRANSFER_FOG(o,o.pos);
                    return o;
                }
                
                sampler2D _ShadowTex;
                sampler2D _FalloffTex;
                // Добавляем переменную, чтобы использовать текстуру внутри прохода
                sampler2D _MaskTex;
                
                fixed4 frag (v2f i) : SV_Target
                {
                    fixed4 texS = tex2Dproj(_ShadowTex, UNITY_PROJ_COORD(i.uvShadow));
                    texS.a = 1.0 - texS.a;
    
                    fixed4 texF = tex2Dproj(_FalloffTex, UNITY_PROJ_COORD(i.uvFalloff));
                    fixed4 res = lerp(fixed4(1, 1, 1, 0), texS, texF.a);
    
                    // Сэмплируем текстуру
                    fixed4 mask = tex2Dproj(_MaskTex, UNITY_PROJ_COORD(i.uvShadow));
                    // Применяем маску
                    res *= mask;
    
                    UNITY_APPLY_FOG_COLOR(i.fogCoord, res, fixed4(1, 1, 1, 1));
                    return res;
                }
                ENDCG
            }
        }
    }

    Чтобы лучше понять что из себя представляют uvShadow и uvFalloff, можете вывести их на экран во фрагментном шейдере:
    fixed4 frag (v2f i) : SV_Target
    {
        float2 uvShadow = UNITY_PROJ_COORD(i.uvShadow);
        float2 uvFalloff = UNITY_PROJ_COORD(i.uvFalloff);
        return fixed4(uvShadow, 0.0, 1.0);
        //return fixed4(uvFalloff, 0.0, 1.0);
    }
    Ответ написан
    1 комментарий
  • Unity, нужно ли менять шейдеры для мобильной игры(2d)?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Шейдеры нужно менять, если они на мобилках тормозят. Если игра летает, то делать ничего не надо. Подобные решения надо принимать исходя из данных профайлера, а не ответов на тостере.
    Ответ написан
  • Как объеденить шейдеры?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    В первую очередь открываете мануал и читаете:
    https://docs.unity3d.com/Manual/SL-SurfaceShaders.html
    https://docs.unity3d.com/Manual/SL-SurfaceShaderEx...
    После прочтения оказывается, что "My Shader3" это диффузный шейдер с картой нормалей, "My Shader2" это PBR шейдер с вынесенными параметрами металличности и гладкости, а "My Shader" это диффузный шейдер, который текстурирует только поверхности, у которых нормали смотрят вверх.
    Теперь, если мы хотим эти шейдеры объединить, то получается, что нужно сделать PBR шейдер, добавить в него карту нормалей и ползунки гладкости и металличности, а потом вставить условие проверки нормалей.
    void surf (Input IN, inout SurfaceOutput o)
    {
        o.Albedo = _Color;
        // Металличность и гладкость указываем либо здесь, либо внутри условия
        if(abs(IN.worldNormal.z)>0.5)
        {
            o.Albedo *= tex2D (_MainTex, IN.uv_MainTex).rgb;
            // Применяем диффузную текстуру, карту нормалей и тому подобное
            ...
        }
    }

    Дополнительно ещё можно скачать архив со встроенными шейдерами с сайта юнити и посмотреть как они работают.
    Ответ написан
  • Как перевести шейдер в среду Unity?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Начните с чтения мануала "Writing vertex and fragment shaders", там хорошие примеры. Потом просто перенесите код из статьи во фрагментный шейдер.
    Ответ написан
    Комментировать
  • Можно ли в игре, написанной с PyGame, как-нибудь использовать шейдеры (GLSL)?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    PyGame для игр сложнее пасьянса не предназначен, поэтому шейдеров в нём нет. Обёртки с шейдерами есть для pyglet и pyopengl, но вы с ними замучаетесь, быстрее будет разобраться с Unity или Unreal Engine.
    Ответ написан
    Комментировать
  • Шейдер в Unity3D, в чем смысл перемножения rgb на альфу?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    У альфы самой по себе смысла нет, это просто ещё один канал для передачи информации. Как автор шейдера захотел, такой смысл и будет. В общем случае умножение rgb-канала на число влияет на интенсивность цвета. Белый цвет помноженный на 0.5 превратится в серый, на ноль - в чёрный. Если судить по названию переменной, в формуле считается яркость звёздного неба, а в альфе хранятся веса звёзд разного типа, т. е. степень их влияния на общую яркость.
    Ответ написан
    Комментировать
  • Как вычислить gl_normalmatrix для шейдера в opengl es 2.0?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Здесь написано, что gl_NormalMatrix это transpose(inverse(gl_ModelViewMatrix))
    Ответ написан
    Комментировать
  • Какие могут быть отличия в работе пиксельного шейдера в веб плеере по сравнению с редактором?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    Читал, что с tex2Dlod бывают проблемы, которые решаются добавлением
    #pragma target 3.0
    и/или
    #pragma glsl
    Ответ написан
  • Как передать в шейдер массив float длиной n?

    BasmanovDaniil
    @BasmanovDaniil
    Геймдизайнер-телепат
    А сколько знаков перед запятой?

    Обычно в таких ситуациях берут текстуру, отключают мипмапы, кодируют нужные данные и забирают в шейдере. В UnityCG.cginc для этого есть пара полезных методов:

    // Encoding/decoding [0..1) floats into 8 bit/channel RGBA. Note that 1.0 will not be encoded properly.
    inline float4 EncodeFloatRGBA( float v )
    {
    	float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 16581375.0);
    	float kEncodeBit = 1.0/255.0;
    	float4 enc = kEncodeMul * v;
    	enc = frac (enc);
    	enc -= enc.yzww * kEncodeBit;
    	return enc;
    }
    inline float DecodeFloatRGBA( float4 enc )
    {
    	float4 kDecodeDot = float4(1.0, 1/255.0, 1/65025.0, 1/16581375.0);
    	return dot( enc, kDecodeDot );
    }
    Ответ написан