• Шейдер для создания эффекта ветра на листьях, кустах и т.д.

    Первая версия моего шейдера, всё вроде бы хорошо, но в зоне тумана не работает.
    Подсмотрел на https://ru.stackoverflow.com/questions/945023/Деформация-анимация-картинки-на-unity

    Shader "wind"
    {
            Properties
            {
                    [PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
                    _Color("Tint", Color) = (1,1,1,1)
                    [MaterialToggle] PixelSnap("Pixel snap", Float) = 0
            }
    
                    SubShader
                    {
                            Tags
                            {
                                    "Queue" = "Transparent"
                                    "IgnoreProjector" = "True"
                                    "RenderType" = "Transparent"
    //                              "RenderType" = "Opaque"
                                    "PreviewType" = "Plane"
                                    "CanUseSpriteAtlas" = "True"
                            }
    
                            Cull Off
                            Lighting Off
                            ZWrite Off
                            Blend One OneMinusSrcAlpha
    
                            Pass
                            {
                            CGPROGRAM
                                    #pragma vertex vert
                                    #pragma fragment frag
                                    #pragma multi_compile _ PIXELSNAP_ON
                                    #pragma multi_compile_fog
                                    #include "UnityCG.cginc"
    
                                    struct appdata_t
                                    {
                                            float4 vertex   : POSITION;
                                            float4 color    : COLOR;
                                            float2 texcoord : TEXCOORD0;
                                    };
    
                                    struct v2f
                                    {
                                            float4 vertex   : SV_POSITION;
                                            fixed4 color : COLOR;
                                            float2 texcoord  : TEXCOORD0;
                                            UNITY_FOG_COORDS(1)
                                    };
    
                                    fixed4 _Color;
    
                                    v2f vert(appdata_t IN)
                                    {
                                            v2f OUT;
                                            OUT.vertex = UnityObjectToClipPos(IN.vertex);
                                            OUT.texcoord = IN.texcoord;
                                            OUT.color = IN.color * _Color;
                                            #ifdef PIXELSNAP_ON
                                            OUT.vertex = UnityPixelSnap(OUT.vertex);
                                            #endif
                                            UNITY_TRANSFER_FOG(OUT, OUT.vertex);
    
                                            return OUT;
                                    }
    
                                    sampler2D _MainTex;
                                    sampler2D _AlphaTex;
                                    float _AlphaSplitEnabled;
    
                                    fixed4 SampleSpriteTexture(float2 uv)
                                    {
                                            uv.x;
                                            fixed4 color = tex2D(_MainTex, uv);
    
            #if UNITY_TEXTURE_ALPHASPLIT_ALLOWED
                                            if (_AlphaSplitEnabled)
                                                    color.a = tex2D(_AlphaTex, uv).r;
            #endif //UNITY_TEXTURE_ALPHASPLIT_ALLOWED
    
                                            return color;
                                    }
    
                                    fixed4 frag(v2f IN) : SV_Target
                                    {
                                            IN.texcoord.x += _SinTime.a * 0.05 * IN.texcoord.y;
                                            fixed4 c = SampleSpriteTexture(IN.texcoord) * IN.color;
    
                                            UNITY_APPLY_FOG(IN.fogCoord, c);
    
                                            c.rgb *= c.a;
    
                                            return c;
                                    }
                            ENDCG
                            }
                    }
    }
     
    

    Еще я нашел подходящий шейдер, который работает, как надо:
    http://josemariaolea.com/create-grass-with-wind-effect-in-unity/

    Shader "Custom/WindGrass" {
    Properties {
    // Surface shader parameters
    _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
     
    // Wind effect parameteres
    _WindFrecuency("Wind Frecuency",Range(0.001,100)) = 1
    _WindStrength("Wind Strength", Range( 0, 2 )) = 0.3
    _WindGustDistance("Distance between gusts",Range(0.001,50)) = .25
    _WindDirection("Wind Direction", vector) = (1,0, 1,0)
     
    }
    SubShader {
    Tags { "Queue"="Transparent"
    "RenderType"="TransparentCutout"
    }
    LOD 200
     
    CGPROGRAM
     
    #pragma surface surf Standard vertex:vert alpha:fade
    //#pragma target 3.0
     
    sampler2D _MainTex;
     
    struct Input {
    float2 uv_MainTex;
    };
     
    half _Glossiness;
    half _Metallic;
    fixed4 _Color;
     
    half _WindFrecuency;
    half _WindGustDistance;
    half _WindStrength;
    float3 _WindDirection;
     
    // our vert modification function
    void vert( inout appdata_full v )
    {
    float4 localSpaceVertex = v.vertex;
    // Takes the mesh′s verts and turns it into a point in world space
    // this is the equivalent of Transform.TransformPoint on the scripting side
    float4 worldSpaceVertex = mul( unity_ObjectToWorld, localSpaceVertex );
     
    // Height of the vertex in the range (0,1)
    float height = (localSpaceVertex.y/2 + .5);
     
    worldSpaceVertex.x += sin( _Time.x * _WindFrecuency + worldSpaceVertex.x * _WindGustDistance) * height * _WindStrength * _WindDirection.x;
    worldSpaceVertex.z += sin( _Time.x * _WindFrecuency + worldSpaceVertex.z * _WindGustDistance) * height * _WindStrength * _WindDirection.z;
     
    // takes the new modified position of the vert in world space and then puts it back in local space
    v.vertex = mul( unity_WorldToObject, worldSpaceVertex );
     
    }
     
    void surf (Input IN, inout SurfaceOutputStandard o) {
    // Albedo comes from a texture tinted by color
    fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    o.Albedo = c.rgb;
    // Metallic and smoothness come from slider variables
    o.Metallic = _Metallic;
    o.Smoothness = _Glossiness;
    o.Alpha = c.a;
    }
    ENDCG
     
    }
    FallBack "Diffuse"
    }
    
    

    На всякий случай, выкладываю файлы шейдеров в виде архива:
    https://blackrid.ru/upload/files/29_08_2021/wind.zip



  • Движок Unity. Обучаемся всему заново.

    Если вкратце, то в прошлом году я начал осваивать Unity 3D. Поскольку, в программировании я не новичок, то довольно быстро разобрался, что к чему.

    За основу я взял игру "S.T.A.L.K.E.R. Тени Чернобыля". Почему её? Потому что все доступные ресурсы из неё уже давно выдраны и существует гигантское комьюнити мододелов. Для своего обучения решил попробовать собрать уровень, используя контент из этой игры.

    В общем, дело пошло, я собрал тестовую локацию, было готово следующее:

    1. Инвентарь. Там были только патроны для автомата, но сама система инвентаря работала
    2. Земля была раскрашена тремя текстурами, которые перемешивались по маске, был плавный переход земля-бетон-песок
    3. Система стрельбы, перезарядка, просчет попаданий пули, определение материала, в который попала пуля, вылетающие от попадания куски штукатурки/или дерева
    4. Фонарик
    5. Сидящий у себя в бункере Сидорович. Он здоровался и прощался, когда мы выходили
    6. Открытие-закрытие дверей. Тестировал на двери бункера Сидоровича
    7. Смена дня и ночи, динамический туман, не дефолтный, а самописный, менее ресурсоемкий
    8. Ветер. Опять же не дефолтный, а свой. Трава и листья деревьев плавно колыхались
    9. Предметы, раскиданные по уровню (коробки с патронами, аптечки и т.п.)
    10. Миникарта с позицией игрока
    11. Динамический прицел, который менял форму и цвет, показывал имя NPC при наведении или название предмета
    12. Удобное мобильное управление, кнопки и тач-панель
    13. Определение типа поверхности, по которой мы ходим (для воспроизведения разного звука шагов по металлу, бетону, земле)
    14. Динамическое расставление кустов и травы, настройка плотности растительности

    Еще какие-то фишки были в разработке, но... внезапно умер винт. К сожалению, как это очень часто бывает, никаких бэкапов не осталось, только в моей голове )

    Вот несколько видео, которые я успел сделать перед этим:

    Unity3D. Пробуем сделать FPS на основе ресурсов STALKER

    Unity3D: анимация mesh-травы. Движение от ветра

    Unity3D: триггер на вход-выход

    Unity3D: настроил анимацию и звук двери бункера

    Unity3D: игры с туманом и освещением сцены


    После полугодового перерыва придется вспоминать все заново. Оно, наверное, к лучшему - сейчас я могу более четко просчитать структуру и иерархию кода, более вдумчиво подойти к моментам, которые тогда реализовал не полностью.

    В общем, буду публиковать свои успехи. Ждите обновлений )



  • Converting timestamp...

    How to get the current epoch time in ...

    PHP time() More PHP
    Python import time; time.time() Source
    Ruby Time.now (or Time.new). To display the epoch: Time.now.to_i
    Perl time More Perl
    Java long epoch = System.currentTimeMillis()/1000; Returns epoch in seconds.
    C# DateTimeOffset.Now.ToUnixTimeSeconds() (.NET Framework 4.6+/.NET Core), older versions: var epoch = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
    Objective-C [[NSDate date] timeIntervalSince1970]; (returns double) or NSString *currentTimestamp = [NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]];
    C++11 double now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count();
    Lua epoch = os.time([date])
    VBScript/ASP See the examples
    AutoIT _DateDiff(′s′, "1970/01/01 00:00:00", _NowCalc())
    Delphi Epoch := DateTimetoUnix(Now); Tested in Delphi 2010.
    R as.numeric(Sys.time())
    Erlang/OTP erlang:system_time(seconds). (version 18+), older versions: calendar:datetime_to_gregorian_seconds(calendar:universal_time())-719528*24*3600.
    MySQL SELECT unix_timestamp(now()) More MySQL examples
    PostgreSQL SELECT extract(epoch FROM now());
    SQLite SELECT strftime(′%s′, ′now′);
    Oracle PL/SQL SELECT (CAST(SYS_EXTRACT_UTC(SYSTIMESTAMP) AS DATE) - TO_DATE(′01/01/1970′,′DD/MM/YYYY′)) * 24 * 60 * 60 FROM DUAL;
    SQL Server SELECT DATEDIFF(s, ′1970-01-01 00:00:00′, GETUTCDATE())
    IBM Informix SELECT dbinfo(′utc_current′) FROM sysmaster:sysdual;
    JavaScript Math.floor(new Date().getTime()/1000.0) The getTime method returns the time in milliseconds.
    Visual FoxPro DATETIME() - {^1970/01/01 00:00:00} Warning: time zones not handled correctly
    Go time.Now().Unix() More Go 
    Adobe ColdFusion
    Tcl/Tk clock seconds
    Unix/Linux Shell date +%s
    Solaris /usr/bin/nawk ′BEGIN {print srand()}′ Solaris doesn′t support date +%s, but the default seed value for nawk′s random-number generator is the number of seconds since the epoch.
    PowerShell [int][double]::Parse((Get-Date (get-date).touniversaltime() -UFormat %s))
    Other OS′s Command line: perl -e "print time" (If Perl is installed on your system)

    Под катом еще...



  • Хабр: Как я создал собственный алгоритм YouTube (чтобы не тратить время впустую)

    Взято отсюда



    Побег от алгоритма YouTube


    Я люблю смотреть видео на YouTube, осязаемым образом улучшающие мою жизнь. К сожалению, алгоритм YouTube с этим не согласен. Он любит кормить меня кликбэйтом и прочим мусором.

    Всё это неудивительно: алгоритм отдаёт приоритет кликам и времени просмотра.

    Поэтому я поставил перед собой задачу: Смогу ли я написать код, который автоматически будет находить ценные видео, избавив меня от привязанности к алгоритму YouTube?

    Вот так всё и началось.

    Оптимально выстроенные планы


    Я начал с визуализации того, что должен делать мой инструмент. Мне нужна была программа, которая будет (i) ранжировать видео на основании вероятной релевантности для меня и (ii) автоматически отправлять мне предлагаемые видео, из которых я смогу выбирать.

    Я решил, что смогу серьёзно повысить продуктивность, если буду пакетно выбирать наборы видео для просмотра на каждую неделю и избавлюсь от необходимости бесконечного скроллинга YouTube.

    Остальное - под катом.



  • Подводные камни WebDav #2

    В продолжение темы "Подводные камни WebDav". Скрипт подключения работает, и как бы все нормально, но раздражает 2 вещи:

    1. При работе скрипта открывается несколько дополнительных окошек, которые мозолят глаза
    2. После монтирования диска он виден в консоли и в Far manager, но в проводнике появляется примерно через минуту

    Первый вопрос решился так:

    start "" powershell -command "&{start-process -filepath C:autoloadWC_register.cmd -windowstyle hidden -verb RunAs}" %*

    Теперь новые окошки запускаются в свернутом виде и не мешают работе.

    Для решения второго вопроса придумал пока только один вариант - перезапускать службу explorer. На секунду пропадает панель задач, но других вариантов я, к сожалению, пока не вижу.

    taskkill /F /IM explorer.exe
    start explorer

    P.S. Визивиг опять похерил обратный слэш. Путь к файлу надо поправить.



  • Подводные камни WebDav

    Подключили файловый облачный сервер Nextcloud. Все вроде бы хорошо, файлы доступны с любого устройства, через приложение и через веб-интерфейс. Скорость иногда печалит, особенно при открытии каталога с большим количеством файлов, но с этим вряд ли что-то можно сделать.

    Возникла следующая проблема - одной из полезных функций сервера является то, что облачную папку можно подключить по WebDav, как сетевой диск. И тут проблем как бы нет, но Windows (в моем случае, 10) после перезагрузки не подключает диск автоматически. Я не глубокий специалист в этом, но тем не менее заметил несколько моментов:

    1. При перезапуске службы "Веб-клиент" соединение восстанавливается. Кстати, по дефолту эта служба почему-то выключена.
    2. Попытка подключения происходит один раз, в момент, когда компьютер еще не увидел сеть, и, соответственно, ничего не подключается.

    В общем, встала задача написать скрипт, который будет помещен в автозагрузку. При включении компьютера он будет мониторить состояние сети, и когда хост nextcloud станет пинговаться, подключит сетевой диск и перезапустит службу WebClient.

    Одним файлом сделать пока не получилось, и вот почему: 

    • когда мы размонтируем или монтируем диск, эта команда должна выполняться от имени обычного пользователя. Если выполнить ее, как администратор, то пользователь этот диск не увидит
    • перезапуск службы, напротив, должен запускаться с правами админа, так же как и работа с реестром (именно так я собирался добавлять скрипт в автозагрузку)

    Файл connect.cmd, который будет добавляться в автозагрузку:

    @echo off
    net use Y: /delete
    start "" powershell -command "&{start-process -filepath C:autoloadWC_register.cmd -verb RunAs}" %*
    :LOOP
    ping -n 1 mynextcloudhost.ru | find "TTL=" >nul
    if errorlevel 1 (
    ping 127.0.0.1 -n 10 > nul & goto LOOP
    ) else (
    start "" powershell -command "&{start-process -filepath C:autoloadWC_restart.cmd -verb RunAs}" %* & goto connect
    )
    :connect
    Set Login=User121
    Set Password=jkhe3re#
    net use Y: https://mynextcloudhost.ru/remote.php/dav/files/%Login% /user:%Login% %Password% /persistent:no
    if errorlevel 1 ping 127.0.0.1 -n 10 > nul & goto connect

    Да, я захардкодил путь к скрипту, и это нехорошо. Но это я добавил в список дел, с которыми буду разбираться потом.

    В самом начале демонтируется том Y, если он подключен. Запускается скрипт WC_register.cmd, в котором я сделал проверку, есть ли наш скрипт в автозагрузке. Если нет, добавляем в реестр нужную запись. Скрипт запускается с правами администратора.

    Файл WC_register.cmd:

    @echo off
    For /F "tokens=1" %%a in (′reg query "HKLMSOFTWAREMicrosoftWindowsCurrentVersionRun" /v "Netcloud"′) do set regpath=%%a
    If DEFINED regpath ( exit ) Else (
    reg add "HKLMSOFTWAREMicrosoftWindowsCurrentVersionRun" /v Netcloud /t REG_SZ /d "C:autoloadconnect.cmd"
    )
    exit

    Потом мы в цикле пингуем наш хост, пока не добьемся успеха. В этом случае мы вызываем (опять же с правами админа) скрипт WC_restart.cmd, который перезапускает WebClient и передаем выполнение скрипта подпрограмме connect.

    Файл WC_restart.cmd:

    @echo off
    net stop webclient
    net start webclient
    exit

    Потом заново монтируется сетевой диск на томе Y.

    Вот, в принципе, и все. Скрипт работает, и это сейчас самое главное. Немного раздражает, что после перезагрузки компа всплывают prompt-окошки. Это надо будет "допилить" потом. Еще в планах сделать скрипт универсальным, поскольку пользователей много, а хардкодить имя и пароль, а также путь к скрипту - не комильфо. Короче, пока так, а потом буду доделывать.

    P.S. Визивиг режет обратный слэш ( Внимательней с урлами и путем к реестру.



  • Как определить местоположение пользователя, не спрашивая разрешение на геолокацию?

    Конечно, самый удобный способ узнать, где торчит пользователь, использовать свойство navigator.geolocation. Правда, при этом браузер обязательно спросит его разрешения. Лично я почти всегда отказываюсь, только если зашел на проверенные сайты строительных супермаркетов или дискаунтеров типа Ситилинк. Значит, этот способ будет работать с малой эффективностью - данное окошко вызывает подозрение, и, впрочем, оно подозрительное и есть. Как избавиться?

    1. Нельзя, это часть интерфейса браузера.
    2. Попап выводится в тот момент, когда вы из своего кода вызываете Geolocation.getCurrentPosition() или Geolocation.watchPosition(), если данная страница еще не получила разрешение/отказ.
    3. 3. В вышеупомянутые методы вы передаете два коллбека, на успех и на ошибку. Определить, какую кнопку юзер нажал можно только косвенно исходя из результата.
    4. Дело в том, что спецификация определяет только API, доступное программисту из JS, а как это выглядит со стороны пользователя - личные фантазии браузерописателей. Где-то попап, где-то галочки в настройках, где-то надо с бубном сплясать. Поэтому никаких гарантий про кнопки дать нельзя.
    5. Если navigator.geolocation является false, значит у пользователя не поддерживается геолокация (например, старый браузер или еще что-то).

    Так что делать?? Неужели все-таки придется напрягать пользователя окошком подтверждения? Есть еще один вариант.

    API Yandex Maps позволяет определять координаты пользователя, используя свои сервисы. Код довольно простой. Подключаем Yandex Api со своим ключом, и пишем в коде:

    var location = ymaps.geolocation.get();

    // Асинхронная обработка ответа.
    location.then( function(result) {
    // Добавление местоположения на карту.
    myMap.geoObjects.add(result.geoObjects)
    }, function(err) {
    console.log(′Ошибка: ′ + err)
    } );

    В свойстве result.geoObjects.position - координаты местонахождения пользователя.

    Конечно, инициализация библиотек Яндекса занимает время, и синхронного результата мы не получим, но все-таки это единственный, на мой взгляд, вариант. Возможно, похожее есть у гугла или еще у кого, но гуглокарты нынче платные, а с другими сервисами надо еще смотреть.

    P.S. Практика показала, что это все полная херня. Точности никакой. А иногда Яндекс может "зашвырнуть" пользователя из Самарской области в Казахстан...



  • Как определить, что клиент зашел на сайт через браузер iPhone?

    searching on the net there are two common ways of achieving this. My favorite though is in PHP its just so clean? wow. :D

    In PHP you can write

    <?php function isIphone($user_agent=NULL) { if(!isset($user_agent)) { $user_agent = isset($_SERVER[′HTTP_USER_AGENT′]) ? $_SERVER[′HTTP_USER_AGENT′] : ′′; } return (strpos($user_agent, ′iPhone′) !== FALSE); } if(isIphone()) { header(′Location: http://www.yourwebsite.com/phone′); exit(); } // ...THE REST OF YOUR CODE HERE ?>

    and in javascript you can write

    var agent = navigator.userAgent; var isIphone = ((agent.indexOf(′iPhone′) != -1) || (agent.indexOf(′iPod′) != -1)) ; if (isIphone) { window.location.href = ′http://www.yourwebsite.com/phone′; }



  • Доступность Moodle по двум доменным именам или IP-адресам

    НЕ МОЁ. Оригинал статьи тут:

    Возникла необходимость, чтобы Moodle был доступен по двум доменным именам, на самом деле, в моем случае, нужно было сделать, чтобы Moodle был доступен по двум разным IP адресам. Да, соглашусь, что лучше сделать доступ по одному доменному имени. Читал о том, что на сервере удобно иметь две сетевые карты и т.д.

    Я решил сделать небольшую настройку, которая бы позволяла работать moodle на любом IP адресе или домене, осознаю, что это может быть не совсем безопасно, ведь это даст возможность отправить данные с любого хостинга и повышает вероятность взлома... Но, на данный момент это единственный выход для меня.

    Вся загвоздка в значении свойства wwwroot объекта  $CFG в файле config.php. Во время установки туда сохраняется имя домена или IP адрес, к которому обратился пользователь и произвел установку Moodle.

    Лечится (ломается) все следующим образом:

    находим строку типа:

    $CFG->wwwroot =′http://my-domain.ru/′;

    заменяем на:

    $CFG->wwwroot =′http://′.$_SERVER[′HTTP_HOST′];

    Так же значение wwwroot интересно тем людям, которые переносят Moodle с локального хостинга на арендуемый сервер. Или когда необходимо иметь доступ к LMS Moodle из внутренней сети учебного заведения и внешней (многие учебные заведения создавая свой сервер сталкиваются с такой необходимостью).

    Другие способы решения проблемы, но придется поплясать с бубном:



Загрузка...

Войти на сайт

Регистрация