Unidade: como aplicar alterações programáticas ao Terrain SplatPrototype?


8

Eu tenho um script ao qual adiciono um objeto Terreno (arrasto e solto o terreno no campo Terreno público).

O Terrain já está configurado no Unity para ter 2 PaintTextures: 1 é um quadrado (configurado com um tamanho de ladrilho para formar um padrão quadriculado) e o segundo é uma imagem de grama:

Captura de tela do Unity

Além disso, a força alvo da primeira PaintTexture é reduzida para que o padrão quadriculado também revele parte da grama embaixo.

Agora eu quero, em tempo de execução, alterar o tamanho do bloco da primeira PaintTexture, ou seja, ter mais ou menos verificadores, dependendo de várias condições de tempo de execução. Examinei a documentação do Unity e vi que você tem a Terrain.terrainData.SplatPrototypematriz que permite alterar isso. Também há um RefreshPrototypes()método no terrainDataobjeto e um Flush()método no Terrainobjeto. Então eu fiz um script como este:

public class AStarTerrain : MonoBehaviour {

    public int aStarCellColumns, aStarCellRows; 

    public GameObject aStarCellHighlightPrefab;
    public GameObject aStarPathMarkerPrefab;
    public GameObject utilityRobotPrefab;
    public Terrain aStarTerrain;

    void Start () {
            //I've also tried NOT drag and dropping the Terrain on the public field 
            //and instead just using the commented line below, but I get the same results
        //aStarTerrain = this.GetComponents<Terrain>()[0];
        Debug.Log ("Got terrain "+aStarTerrain.name);

        SplatPrototype[] splatPrototypes = aStarTerrain.terrainData.splatPrototypes;
        Debug.Log("Terrain has "+splatPrototypes.Length+" splat prototypes");
        SplatPrototype aStarCellSplat = splatPrototypes[0];
        Debug.Log("Re-tyling splat prototype "+aStarCellSplat.texture.name);
        aStarCellSplat.tileSize = new Vector2(2000,2000);
        Debug.Log("Tyling is now "+aStarCellSplat.tileSize.x+"/"+aStarCellSplat.tileSize.y);
        aStarTerrain.terrainData.RefreshPrototypes();
        aStarTerrain.Flush();
    }

//...

O problema é que nada é alterado, o mapa do verificador não é remarcado. As saídas do console me dizem corretamente que eu tenho o objeto Terrain com o nome certo, que possui o número certo de protótipos de splat e que estou modificando o tileSize no objeto SplatPrototype correspondente à textura correta. Também me diz que o valor mudou. Mas nada é atualizado na visualização gráfica real.

Então, por favor, o que estou perdendo?


se você tem um shader cusom e deseja fazer uma grade de linhas azuis no mapa com valores diferentes, a maneira mais barata é fazê-lo no shader ... as linhas azuis são: round (frac (x * .1) ... Parreira doente colocá-lo em uma resposta
com.prehensible

Respostas:


1

Parece que você esqueceu de reatribuir a textura Splat de volta:

public class AStarTerrain : MonoBehaviour {

public int aStarCellColumns, aStarCellRows; 

public GameObject aStarCellHighlightPrefab;
public GameObject aStarPathMarkerPrefab;
public GameObject utilityRobotPrefab;
public Terrain aStarTerrain;

void Start () {
        //I've also tried NOT drag and dropping the Terrain on the public field 
        //and instead just using the commented line below, but I get the same results
    //aStarTerrain = this.GetComponents<Terrain>()[0];
    Debug.Log ("Got terrain "+aStarTerrain.name);

    SplatPrototype[] splatPrototypes = aStarTerrain.terrainData.splatPrototypes;
    Debug.Log("Terrain has "+splatPrototypes.Length+" splat prototypes");
    SplatPrototype aStarCellSplat = splatPrototypes[0];
    Debug.Log("Re-tyling splat prototype "+aStarCellSplat.texture.name);
    aStarCellSplat.tileSize = new Vector2(2000,2000);
    splatPrototypes[0] = aStarCellSplat; // <- here
    Debug.Log("Tyling is now "+aStarCellSplat.tileSize.x+"/"+aStarCellSplat.tileSize.y);
    aStarTerrain.terrainData.RefreshPrototypes();
    aStarTerrain.Flush();
}

//...

Que, a propósito, você poderia ter feito desta maneira:

splatPrototypes[0].tileSize = new Vector2(2000,2000); //No referencing issue this way

(E depois atualize, mas não tenho certeza se é necessário nesse estado)

EDIT:

Existem alguns parâmetros em objetos que não podem ser referenciados e acredito

splatPrototype.tileSize

é um deles, então se você fizer:

SplatPrototype aStarCellSplat = splatPrototypes[0];

então aStarCellSplat é um clone de splatPrototypes [0], mas não faz referência a ele. Às vezes, a clonagem para obter o valor inicial e iterar é bom, especialmente quando você modifica uma estrutura complexa, mas, nesse caso, uma simples chamada de parâmetro é mais fácil.

E acompanhe seus clones, se você clonar, não esqueça de atribuir de volta


-1

para fazer linhas azuis via sombreador, você precisa ter o texture_uv na função de superfície ou na função de fratura ...

para criar linhas de grade azul / cinza no shaderlab, você deve adicionar um total de 4-5 linhas ao shader, dentro da função de surf:

xline = ceil (frac (uv.x * .1) - 75); yline = o mesmo para y

grade = max (xline, yline);

o.albedo.blueval = grade.

então você pode alterar o tamanho da grade usando 1 chamada para o sombreador, para alterar o valor do sombreador. .

em seguida, ajuste a cor, adicionando matemática à mesma usada na versão anterior / mapa de splat.


Ao fornecer algumas informações úteis, isso realmente não responde à pergunta diretamente feita. Se o OP realmente quisesse saber como fazer isso via shader, ele teria perguntado.
Pip
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.