Шейдер деформирующий объект используя карту высот террейна

Для экспериментальных разработок и тем "я нашел чужой исходник, почему он не работает?"

Шейдер деформирующий объект используя карту высот террейна

Сообщение yursiv 12 сен 2012, 09:36

Хочу сделать свой инструмент для высаживания травы\деревьев.Траву хочу высаживать патчами 6 - 10м в диаметре. Патчи из-за размеров дадут малое количество дровколов. А вписыватся в террейн должы при помощи специального шейдера, который деформирует патч используя нижележашие полики террейна.
Приблизительно так:

Изображение
http://clip2net.com/clip/m164771/1347430676-007d4-292kb.jpg

Этот шейдер мне и надо сделать.
Затруднение в том, что я не знаю как получить данные террейна в шейдере(это вообще возможно?).

Другой вариант который рассматриваю - передача переменных в материал(9 флоат векторов должно хватить) скриптом,
но для этого потребуется инстацировать материал на каждом меше насколько я понимаю. Как такой вариант в плане производительности?

Еще один вариант - записать в каждый вертекс его высоту над террейном и записать в вертексный цвет меша
Так как rgb каналы уже заняты под неравномерную деформацию веток(уже есть заготовка шейдера для листвы), то можно записать в альфу.

В общем жду советов по этим или вами предложенным вариантам.
Аватара пользователя
yursiv
UNIт
 
Сообщения: 130
Зарегистрирован: 09 ноя 2010, 11:51
Откуда: Харьков

Re: Шейдер деформирующий объект используя карту высот террейна

Сообщение Battle Angel Alita 13 сен 2012, 11:45

Берём террэйн, вытаскиваем из него текстуру с картой высот, передаём текстуру в шэйдер(можно через Shader.SetGlobalTexture), в шэйдере через VTF двигаем вертексы.
Мозг рака
Изображение
Аватара пользователя
Battle Angel Alita
UNIверсал
 
Сообщения: 476
Зарегистрирован: 25 ноя 2009, 14:52

Re: Шейдер деформирующий объект используя карту высот террейна

Сообщение yursiv 13 сен 2012, 11:59

Battle Angel Alita писал(а):(можно через Shader.SetGlobalTexture)

Спасибо вот это мне и надо было... и как это я проглядел этот метод)?
Аватара пользователя
yursiv
UNIт
 
Сообщения: 130
Зарегистрирован: 09 ноя 2010, 11:51
Откуда: Харьков

Re: Шейдер деформирующий объект используя карту высот террейна

Сообщение Diab10 02 окт 2012, 01:27

Не поделитесь получившимся шейдером? (popcorn)
Аватара пользователя
Diab10
Адепт
 
Сообщения: 3401
Зарегистрирован: 17 мар 2011, 20:42
Откуда: 123 RUS
Skype: diab1023

Re: Шейдер деформирующий объект используя карту высот террейна

Сообщение yursiv 03 окт 2012, 03:24

В процессе написания шейдера решил, что лучше буду деформировать скриптом.
Скрипт пока совсем не оптимизирован, написан для "пока и так сойдет".

Если вы не сможете допилить его - не советую использовать.
Синтаксис:
Используется csharp

using UnityEngine;
using System;
using System.Collections.Generic;
using System.Collections;

[ExecuteInEditMode]
public class VegDeformer : MonoBehaviour {

    public Mesh OriginalMesh;
    public bool OriginalMeshStored = false;
    public MeshFilter Filter;
    public bool Deformed = false;
    public float Range = 50f;
    public bool InRange = false;
    public WaitForSeconds Wait_ = new WaitForSeconds(0.5f);

    void OnDisable() {
        if (!Application.isPlaying && Application.isEditor && OriginalMeshStored && Deformed) { Restore(); return; }
        if (Application.isPlaying) StopAllCoroutines();
    }

    void OnEnable() {
        if (!Application.isPlaying && Application.isEditor && !Deformed) {
            if (!OriginalMeshStored) StoreOrigMesh();
            StartCoroutine(Deform());
        }
    }

    void OnBecameVisible() {
        if (Application.isPlaying && !Deformed) {
            if (!OriginalMeshStored) StoreOrigMesh();
            StartCoroutine(Deform());
        }
    }

    void OnBecameInvisible() {
        if (Application.isPlaying) {
            if (Deformed && OriginalMeshStored) Restore();
        }
    }

    void CalcRange() {
        InRange = Vector3.Distance(transform.position, Camera.mainCamera.transform.position) < Range;
    }

    void Update() {
        if (Filter == null) Filter = GetComponent<MeshFilter>();
        if (Application.isPlaying || !Application.isEditor) return;

        if (!OriginalMeshStored && !Deformed) StoreOrigMesh();
        if (renderer.isVisible)
            StartCoroutine(Deform());
        else
            Restore();
    }


    void StoreOrigMesh() {
        //        Debug.Log("Mesh stored" + gameObject.name + Time.time);
        Filter = GetComponent<MeshFilter>();
        OriginalMesh = Filter.sharedMesh;
        DestroyImmediate(Filter);
        Filter = gameObject.AddComponent<MeshFilter>();
        Filter.sharedMesh = CopyMesh(OriginalMesh);
        OriginalMeshStored = true;
    }

    IEnumerator Deform() {
        //        Debug.Log("Deforming" + gameObject.name + Time.time);
        Terrain terrain = FindClosestTerrain(transform);
        float terrainPosY = terrain.transform.position.y;

        var mesh = CopyMesh(OriginalMesh);
        var vertices = mesh.vertices;
        var size = vertices.Length;

        for (int i = 0; i < size; i++) {
            Vector3 locPos = vertices[i];
            Vector3 wrldPos = transform.TransformPoint(locPos);

            float yOffset = (terrain.SampleHeight(wrldPos) + terrainPosY) - (wrldPos.y - locPos.y);
            locPos = new Vector3(locPos.x, locPos.y + yOffset, locPos.z);
            vertices[i] = locPos;
        }
        mesh.vertices = vertices;

        //        if (Application.isPlaying) Destroy(Filter.sharedMesh);
        //        else
        //            if (Application.isEditor) DestroyImmediate(Filter.sharedMesh);
        DestroyImmediate(Filter.sharedMesh);

        Filter.sharedMesh = mesh;
        Filter.sharedMesh.RecalculateBounds();

        Deformed = true;
        yield return null;
    }

    IEnumerator RestoreIfOutRange() {
        CalcRange();
        while (InRange) {
            if (renderer.isVisible ) break;
            yield return Wait_;
            CalcRange();
        }
        if (renderer.isVisible) yield break;

        DestroyImmediate(Filter.sharedMesh);
        Filter.sharedMesh = OriginalMesh;
        Deformed = false;
        OriginalMeshStored = false;
        Debug.Log(gameObject.name + "   restored");
        yield return null;
    }
    void Restore() {
        DestroyImmediate(Filter.sharedMesh);
        Filter.sharedMesh = OriginalMesh;
        Deformed = false;
        OriginalMeshStored = false;
    }


    static Mesh CopyMesh(Mesh sharedMesh) {
        var mesh = new Mesh();
        mesh.vertices = sharedMesh.vertices;
        mesh.triangles = sharedMesh.triangles;
        mesh.uv = sharedMesh.uv;
        mesh.normals = sharedMesh.normals;
        mesh.tangents = sharedMesh.tangents;
        mesh.colors32 = sharedMesh.colors32;
        return mesh;
    }

    static Terrain FindClosestTerrain(Transform transform) {
        Vector3 pos = transform.position;
        Terrain result = null;
        var terrains = FindObjectsOfType(typeof(Terrain)) as Terrain[];

        if (terrains != null)
            if (terrains.Length == 1)
                return terrains[0];
            else {
                result = terrains[0];
                float lastCalcDist = Vector3.Distance(result.transform.position, pos);
                for (int i = 1; i < terrains.Length; i++) {
                    var dist = Vector3.Distance(terrains[i].transform.position, pos);
                    if (dist < lastCalcDist)
                        result = terrains[i];
                }
            }
        return result;
    }
}




 
Аватара пользователя
yursiv
UNIт
 
Сообщения: 130
Зарегистрирован: 09 ноя 2010, 11:51
Откуда: Харьков

Re: Шейдер деформирующий объект используя карту высот террейна

Сообщение Diab10 06 окт 2012, 21:12

Спасибо! Как нибудь посмотрю
Аватара пользователя
Diab10
Адепт
 
Сообщения: 3401
Зарегистрирован: 17 мар 2011, 20:42
Откуда: 123 RUS
Skype: diab1023


Вернуться в Шейдерная кузня

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1