Well,
I’m a newbie with shaders, I’m just trying to paint a mesh depending on the vertex attribute passed with one or another texture.
The idea is to achieve this, for example:
For this, I have been reading some documentation.
So, if I understand fine, I need a vertex subshader with the following structure:
struct Input
{
float2 uv_MainTex;
float arrayIndex;
};
Then pass its information from the vert out parameter of type Input, to be used in the surf shader as an Input IN
param:
void vert(inout appdata_full v, out Input o)
{
o.uv_MainTex = v.texcoord.xy;
o.arrayIndex = v.texcoord.z;
}
void surf(Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_Top, float3(IN.uv_MainTex, IN.arrayIndex)) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
The full code of the shader:
Shader "Custom/z3nth10n/MultiTriplanar"
{
Properties
{
_Top("Top Main Texture", 2DArray) = "" { }
_Color("Color", Color) = (1,1,1,1)
_Glossiness("Smoothness", Range(0,1)) = 0.5
_Metallic("Metallic", Range(0,1)) = 0.0
_ZOffset("Z Buffer Offset", Float) = 0
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 200
Offset[_ZOffset],[_ZOffset]
CGPROGRAM
#pragma surface surf Standard fullforwardshadows vertex:vert
#pragma vertex vert
#pragma require 2darray
struct Input
{
float2 uv_MainTex;
float arrayIndex;
};
UNITY_DECLARE_TEX2DARRAY(_Top);
half _Glossiness;
half _Metallic;
fixed4 _Color;
void vert(inout appdata_full v, out Input o)
{
o.uv_MainTex = v.texcoord.xy;
o.arrayIndex = v.texcoord.z;
}
void surf(Input IN, inout SurfaceOutputStandard o)
{
fixed4 c = UNITY_SAMPLE_TEX2DARRAY(_Top, float3(IN.uv_MainTex, IN.arrayIndex)) * _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"
}
This is the full project: https://drive.google.com/file/d/1wJ9QyvkSA_rBAXfN1rFowDpWY5EhqEDV/view?usp=sharing
If you open the Custom/z3nth10n/MultiTriplanar
shader you will notice that there is more code, I want to achieve tri-planar implementation with NativeArrays and VertexAttributes later, but now I’m focusing on this part.
As you can see the mesh is showing like this:
It has no tiling and any information has passed through the VertexAttribute Mesh Data Buffers.
Also, there is my implementation in C# to show you how I pass the vertex data to the mesh buffers:
using System.Linq;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.Rendering;
public class PlaneVerticesTest : MonoBehaviour
{
[StructLayout(LayoutKind.Sequential)]
private struct BiomeVertexLayout
{
public Vector3 texcoord;
}
public Texture2DArray texArray;
// Start is called before the first frame update
private void Start()
{
//var texArray = Resources.Load<Texture2DArray>("TextureArrays/Biome1DiffuseTextureArray");
var textureCount = texArray.depth;
var mesh = GetComponent<MeshFilter>().mesh;
Debug.Log(SystemInfo.SupportsVertexAttributeFormat(VertexAttributeFormat.Float32, 4));
var layout = new[]
{
new VertexAttributeDescriptor(VertexAttribute.TexCoord0) //, VertexAttributeFormat.Float32, 4)
};
mesh.SetVertexBufferParams(mesh.vertexCount, layout);
var data = Enumerable.Range(0, mesh.vertexCount).Select(i => new Vector3(mesh.uv[i].x, mesh.uv[i].y, i % textureCount)).ToArray();
mesh.SetVertexBufferData(data, 0, 0, mesh.vertexCount);
}
// Update is called once per frame
private void Update()
{
}
}
As you can see I’m using var data = Enumerable.Range(0, mesh.vertexCount).Select(i => new Vector3(mesh.uv[i].x, mesh.uv[i].y, i % textureCount)).ToArray();
That means that per each vertex index, I’m just passing the same arrayIndex to the shader Input object (treating the textureCount part with a modulus operator).
Can anyone give me some guidance on this?