Entre los muchos juegos independientes lanzados en los últimos 10 años, uno de mis favoritos es definitivamente
Journey . Gracias a su estética impresionante y hermosa banda sonora,
Journey se ha convertido en un ejemplo de excelencia en casi todos los aspectos del desarrollo.
Soy un desarrollador de juegos y artista técnico, por lo que me intrigó mucho la forma en que se renderizó la arena. No solo es hermoso, sino que también está directamente relacionado con el juego básico y el juego en su conjunto.
Journey está literalmente construido de arena, y sin un efecto tan sorprendente, el juego en sí mismo simplemente no podría existir.
En este artículo, dividido en dos publicaciones, rendiré homenaje al legado de
Journey al enseñarle cómo recrear exactamente la misma representación de arena usando sombreadores. Independientemente de si se necesitan dunas de arena en su juego, esta serie de tutoriales le permitirá aprender cómo recrear una estética específica en su propio juego. Si desea recrear el hermoso sombreador de arena utilizado en
Journey , primero debe comprender cómo se construyó. Y aunque parece extremadamente complejo, en realidad consiste en varios efectos relativamente simples. Este enfoque para escribir sombreadores es necesario para convertirse en un artista técnico exitoso. Por lo tanto, espero que hagas este
viaje conmigo, en el que no solo exploremos la creación de sombreadores, sino que también aprendamos a combinar la estética y el juego.
Análisis de arena en Journey
Este artículo, como muchos otros intentos de recrear el renderizado de arena de
Journey , se basa en un informe de GDC que el ingeniero líder de la compañía John Edwards tituló "
Renderizado de arena en Journey ". En esta charla, John Edwards habla sobre todas las capas de efectos añadidos a las dunas de arena de
Journey para lograr el aspecto correcto.
El informe es muy útil, pero en el contexto de este tutorial, muchas de las limitaciones y decisiones tomadas por John Edwards no son importantes. Intentaremos recrear los sombreadores de arena, que recuerdan al sombreador
Journey , principalmente por referencias visuales.
Comencemos con una simple malla 3D de una duna perfectamente lisa. La credibilidad de la reproducción de arena depende de dos aspectos: iluminación y grano. Un
modelo de iluminación modificado proporciona una forma interesante de reflejar la luz de la arena. En el contexto de la codificación del sombreador, el modelo de iluminación determina las sombras y los reflejos en función de las propiedades del modelo y las condiciones de iluminación de la escena.
Sin embargo, todo esto no es suficiente para crear la ilusión de realismo. El problema es que la arena simplemente no se puede modelar con superficies planas. Se debe considerar el grano de arena. Es por eso que hay dos efectos separados que funcionan directamente con lo
normal a la superficie , que se pueden usar para simular pequeñas partículas de arena en la superficie de la duna.
El siguiente diagrama muestra todos los efectos que aprenderemos en este tutorial. Desde un punto de vista técnico, los cálculos normales se realizan antes de procesar la iluminación. Para facilitar el estudio, los efectos se describirán en un orden diferente.
Color difuso
El efecto de sombreador de arena más simple es su
color difuso , que describe aproximadamente el componente
opaco de la apariencia general. El color difuso se calcula en función del color
real del objeto y las condiciones de iluminación. Una esfera pintada de blanco no será perfectamente blanca en todas partes, porque el color difuso depende de la luz que incide sobre ella. Los colores difusos se calculan utilizando un modelo matemático que se aproxima al reflejo de la luz de una superficie. Gracias a un informe de John Edwards con el GDC, sabemos exactamente la ecuación utilizada, que él llama
reflectancia de contraste difuso ; Se basa en el conocido modelo de
reflexiones de
Lambert .
Antes y después de aplicar la ecuación.Arena normal
La geometría original es completamente lisa. Para compensar esto, la
superficie normal del modelo se cambia utilizando una técnica llamada
mapeo de relieve . Le permite usar una textura para simular geometrías más complejas.
Iluminación de borde
Cada nivel de
viaje utiliza una paleta de colores limitada. Debido a esto, es bastante difícil entender dónde termina una duna y dónde comienza otra. Para aumentar la legibilidad, se utiliza la técnica de resaltado pequeño de lo que es visible solo a lo largo del borde de la duna. Se llama
iluminación de llanta , y hay muchas formas de implementarla. Para este tutorial, elegí un método basado
en reflexiones de
Fresnel que modela reflexiones sobre superficies pulidas en los llamados
ángulos de incidencia .
Espejo reflejo del océano
Uno de los aspectos más divertidos
del juego de
Journey es la capacidad de "surfear" las dunas de arena. Esta es probablemente la razón por la que esa compañía del juego quería que la arena se sintiera más como un líquido que como un sólido. Para esto, se utilizó una fuerte reflexión, que a menudo se puede encontrar en sombreadores de agua. John Edwards llama a este efecto
océano especular , y en el tutorial lo implementamos usando la
reflexión Blinn-Fong .
Reflejo de deslumbramiento
Agregar un componente especular oceánico al sombreador de arena le da un aspecto más fluido. Sin embargo, todavía no permite que se transmita uno de los aspectos visuales más importantes de la arena: los reflejos que ocurren al azar. En las dunas reales, este efecto ocurre porque cada grano de arena refleja la luz en su dirección y muy a menudo uno de estos rayos reflejados ingresa a nuestro ojo. Tal
reflejo de brillo (reflejo de reflejos) ocurre incluso en lugares donde la luz solar directa no cae; complementa el océano especular y mejora el sentido de credibilidad.
Olas de arena
Cambiar las normales nos permitió simular el efecto de pequeños granos de arena que cubren la superficie de la duna. En las dunas del mundo real, a menudo aparecen olas causadas por el viento. Su forma varía según la pendiente y la posición de cada duna en relación con la dirección del viento. Potencialmente, tales patrones se pueden crear a través de una textura rugosa, pero en este caso será imposible cambiar la forma de las dunas en tiempo real. La solución propuesta por John Edwards es similar a una técnica llamada
sombreado triplanar : utiliza cuatro texturas diferentes, mezcladas según la posición y la pendiente de cada duna.
Journey Sand Shader Anatomy
Unity tiene muchas plantillas de sombreadores para comenzar. Como estamos interesados en materiales que puedan recibir iluminación y proyectar sombras, debemos comenzar con el
sombreador de superficie (sombreador de superficie).
Todos
los sombreadores de superficie se realizan en dos etapas. Primero, se llama
una función de superficie que recolecta las propiedades de la superficie que necesita ser renderizada, por ejemplo, su
albedo ,
rugosidad ,
propiedades del metal ,
transparencia y
dirección normal . Luego, todas estas propiedades se transfieren a
la función de iluminación , que tiene en cuenta la influencia de las fuentes de luz externas y calcula el sombreado y la iluminación.
Función de superficie
Comencemos con lo que se convierte en el núcleo de nuestra función de superficie, llamada en el código de
surf
continuación. Las únicas propiedades que necesitamos establecer son el
color de la arena y lo
normal a la superficie . La normalidad de un modelo 3D es un vector que indica la posición de la superficie. La función de iluminación utiliza vectores normales para calcular cómo se reflejará la luz. Por lo general, se calculan durante la importación de la malla. Sin embargo, se pueden modificar para simular una geometría más compleja. Es aquí donde la
arena normal y
los efectos
normales de las olas de arena distorsionan la norma de arena para simular su aspereza.
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _SandColor; o.Alpha = 1; float3 N = float3(0, 0, 1); N = RipplesNormal(N); N = SandNormal (N); o.Normal = N; }
Al escribir normales en
o.Normal
deben expresarse en
espacio tangente . Esto significa que el vector se selecciona en relación con la superficie del modelo 3D. Es decir,
float3(0, 0, 1)
realidad significa que no se realizan cambios en el modelo 3D normal.
Ambas funciones,
RipplesNormal
y
SandNormal
reciben el vector normal y lo modifican. Más adelante veremos cómo se puede hacer esto.
Función de iluminación
Es en la función de iluminación que se implementan todos los demás efectos. El siguiente código muestra cómo se calcula cada componente individual en funciones separadas (color difuso, iluminación de borde, especular oceánico y reflejo de brillo). Entonces se combinan todos.
#pragma surface surf Journey fullforwardshadows float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi) { float3 diffuseColor = DiffuseColor (); float3 rimColor = RimLighting (); float3 oceanColor = OceanSpecular (); float3 glitterColor = GlitterSpecular (); float3 specularColor = saturate(max(rimColor, oceanColor)); float3 color = diffuseColor + specularColor + glitterColor; return float4(color * s.Albedo, 1); }
El método de combinar componentes es bastante arbitrario y nos permite cambiarlo para estudiar posibilidades artísticas.
Típicamente, los reflejos especulares se acumulan sobre el color difuso. Dado que aquí no tenemos uno, sino tres reflejos especulares (
luz del borde ,
especular oceánico y
especular brillante ), debemos ser más cuidadosos para no hacer que la arena parpadee
demasiado . Dado que la luz de borde y el especular oceánico son parte del mismo efecto, podemos elegir solo el valor máximo de ellos. El brillo especular se agrega por separado porque este componente crea arena parpadeante.
Parte 2. Color difuso
En la segunda parte de la publicación, nos centraremos en el modelo de iluminación utilizado en el juego y en eso. Cómo recrearlo en Unity.
En la parte anterior, sentamos las bases para lo que gradualmente se convertirá en nuestra versión del sombreador de arena Journey. Como se mencionó anteriormente,
la función de iluminación se usa en
sombreadores de superficie para calcular el efecto de la iluminación, de modo que aparezcan sombras y luces en la superficie. Descubrimos que Journey tiene varios efectos que entran en esta categoría. Comenzaremos con el efecto más básico (y más simple) que se encuentra en el núcleo de este sombreador: su
iluminación difusa (
iluminación difusa / difusa).
Por ahora, omitimos todos los demás efectos y componentes, centrándonos en
iluminar la arena .
La función de iluminación que
DiffuseColor
en la parte anterior de la publicación llamada
LightingJourney
simplemente delega el cálculo del color difuso de la arena a una función llamada
DiffuseColor
.
float4 LightingJourney (SurfaceOutput s, fixed3 viewDir, UnityGI gi) {
Debido al hecho de que cada efecto es autónomo y se almacena en su propia función, nuestro código será más modular y limpio.
Reflexión Lambert
Antes de crear una iluminación difusa "como en Journey", es bueno ver cómo se ve la función de iluminación difusa "básica". La técnica de sombreado más simple para materiales mate se llama
reflectancia lambertiana . Este modelo se aproxima a la apariencia de la mayoría de las superficies no brillantes y no metálicas. Lleva el nombre del científico enciclopédico suizo
Johann Heinrich Lambert , quien propuso su concepto en 1760.
El concepto de reflexión de Lambert se basa en una idea simple: el
brillo de una superficie depende de la cantidad de luz que incide sobre ella . Geométricamente, esto se puede mostrar en el siguiente diagrama, donde la esfera está iluminada por una fuente de luz remota. Aunque las áreas rojas y verdes de la esfera reciben la misma cantidad de iluminación, sus áreas de superficie son significativamente diferentes. Si la luz en la región roja se distribuye en un área más grande, esto significa que cada unidad del cuadrado rojo recibe menos luz que la verde.
Teóricamente, la reflexión de Lambert depende del ángulo relativo entre la
superficie y la
luz incidente . Desde un punto de vista matemático, decimos que esta es una función de lo
normal a la superficie y la
dirección de la iluminación . Estas cantidades se expresan usando dos vectores de longitud unitaria (llamados
vectores unitarios )
N y
L . Los vectores individuales son una forma estándar de especificar
direcciones en el contexto de la codificación de sombreadores.
El valor de N y LNormal a la superficie N Es un vector unitario dirigido lejos de la superficie misma.
Por analogía, podemos suponer que la dirección de la iluminación L apunta desde la fuente de luz y sigue en la dirección en que se mueve la luz. Pero esto no es así: la dirección de la iluminación es un solo vector que apunta en la dirección de la dirección de donde vino la luz.
Esto puede ser confuso, especialmente si eres nuevo en la creación de sombreadores. Sin embargo, gracias a dicha notación, las ecuaciones se vuelven más simples.
Reflexión de Lambert en la UnidadAntes del
sombreador estándar Unity 5, el reflejo de Lambert era el modelo estándar para sombrear superficies iluminadas.
Todavía puede acceder a él en el Inspector de materiales: en el
sombreador Legacy, se llama
Diffuse .
Si escribe su propio sombreador de superficie, la reflexión de Lambert está disponible como una función de iluminación llamada
Lambert
:
#pragma surface surf Lambert fullforwardshadows
Su implementación se puede encontrar en la función
LightingLambert
definida en el archivo
CGIncludes\Lighting.cginc
.
Reflexión y clima de LambertLa reflexión de Lambert es un modelo bastante antiguo, pero proporciona una comprensión de conceptos complejos como el sombreado de la superficie. También se puede usar para explicar muchos otros fenómenos. Por ejemplo, el mismo diagrama explica por qué hace más frío en los polos del planeta que en el ecuador.
Después de mirar más de cerca, podemos ver que la superficie recibe la máxima cantidad de iluminación cuando su normalidad es paralela a la dirección de la iluminación. Y viceversa: no hay luz si dos vectores unitarios son perpendiculares entre sí.
Obviamente, el ángulo entre
N y
L crítico para la reflexión según Lambert. Además, el brillo es máximo e igual a
100% cuando el ángulo es
0 y mínimo (
0% ) cuando el ángulo tiende a
90 circ . Si está familiarizado con
el álgebra vectorial , podría entender que una cantidad que representa el reflejo de Lambert
I es igual a
N cdotL donde esta el operador
cdot llamado un
producto escalar .
(1)
$$ display $$ \ begin {ecation *} I = N \ cdot L \ end {ecation *} $$ display $$
El producto escalar es una medida de la "coincidencia" de dos vectores entre sí, y varía en el intervalo de
+1 (para dos vectores idénticos) a
−1 (para dos vectores opuestos). Un producto escalar es la base del sombreado, que examiné en detalle en el tutorial de
Modelos de iluminación y renderizado basados físicamente .
Implementación
Y a
N y para
L Puede acceder fácilmente a las funciones de iluminación del sombreador de superficie a través de
s.Normal
y
gi.light.dirin
. Por simplicidad, los cambiaremos de nombre en el código del sombreador a
N
y
L
float3 DiffuseColor(float3 N, float3 L) { float NdotL = saturate( dot(N, L) ); return NdotL; }
saturate
función de
saturate
limita el valor de
0 antes
1 . Sin embargo, dado que el producto escalar está en el rango de
−1 antes
+1 , necesitaremos trabajar solo con sus valores negativos. Es por eso que la reflexión de Lambert a menudo se implementa de la siguiente manera:
float NdotL = max(0, dot(N, L) );
Contraste reflejo de la luz ambiental
Aunque el reflejo de Lambert sombrea bien la mayoría de los materiales, no es ni físicamente exacto ni fotorrealista. En juegos antiguos, los sombreadores Lambert se usaban ampliamente. Los juegos que usan esta técnica a menudo
parecen viejos porque pueden reproducir inadvertidamente la estética de los juegos antiguos. Si no se esfuerza por esto, entonces debe evitarse la reflexión de Lambert y utilizar tecnología más moderna.
Uno de estos modelos es
el Modelo de reflexión de Oren-Nayyar , que se describió originalmente en el artículo
Generalización del modelo de reflectancia de Lambert , publicado en 1994 por Michael Oren y Sri C. Nayyar. El modelo Oren-Nayyar es una generalización del reflejo de Lambert y está especialmente diseñado para superficies rugosas. Inicialmente, los desarrolladores de Journey querían usar la reflexión de Oren-Nayyar como base para su sombreador de arena. Sin embargo, esta idea fue abandonada debido a los altos costos informáticos.
En su informe de 2013, el artista técnico John Edwards explica que el modelo de reflexión creado para la arena Journey se basó en una serie de prueba y error. Los desarrolladores intentaron no recrear la representación fotorrealista del desierto, sino dar vida a una estética concreta, inmediatamente reconocible.
Según él, el modelo de sombreado resultante corresponde a esta ecuación:
(2)
$$ display $$ \ begin {ecation *} I = 4 * \ left (\ left (N \ odot \ left [1, 0.3, 1 \ right] \ right) \ cdot L \ right) \ end {ecuación *} $$ display $$
donde
odot -
elemento -
producto sabio de dos vectores.
float3 DiffuseColor(float3 N, float3 L) { Ny *= 0.3; float NdotL = saturate(4 * dot(N, L)); return NdotL; }
Modelo de reflexión (2) John Edwards llama
contraste difuso , por lo que utilizaremos este nombre a lo largo del tutorial.
La siguiente animación muestra la diferencia en el sombreado de Lambert (izquierda) y el contraste difuso de Journey (derecha).
¿Cuál es el significado de 4 y 0.3?Aunque el contraste difuso no fue diseñado para ser físicamente preciso, aún podemos tratar de entender lo que hace.
En esencia, todavía usa la reflexión de Lambert. La primera diferencia obvia es que el resultado general se multiplica por 4 . Esto significa que todos los píxeles que normalmente se recibieron 25% la iluminación ahora brillará como si recibiera 100% iluminación Multiplicando todo por 4 El sombreado débil según Lambert se vuelve mucho más fuerte, y la región de transición entre la oscuridad y la luz es más pequeña. En este caso, la sombra se vuelve más nítida.
Efecto de la multiplicación del componente y
en la dirección normal 0.3 explicar es mucho más difícil. A medida que cambian los componentes del vector, cambia la dirección general en la que apunta. Reduciendo el componente y
a todo 30% desde su valor original, el reflejo del contraste difuso hace que las sombras se vuelvan más verticales.
Nota: un producto escalar mide directamente el ángulo entre dos vectores solo si ambos tienen longitud 1 . El cambio realizado reduce la longitud normal N que ya no es un vector unitario.
De tonos de gris a color.
Todas las animaciones que se muestran arriba tienen sombras de gris, porque muestran los valores de su modelo de reflexión, variando en el intervalo de
0 antes
1 ". Podemos agregar colores fácilmente usando
NdotL
como el coeficiente de interpolación entre dos colores: uno para arena completamente sombreada y otro para arena completamente iluminada.
float3 _TerrainColor; float3 _ShadowColor; float3 DiffuseColor(float3 N, float3 L) { Ny *= 0.3; float NdotL = saturate(4 * dot(N, L)); float3 color = lerp(_ShadowColor, _TerrainColor, NdotL); return color; }
Parte 3. Arena normal
En la tercera parte, nos centraremos en crear mapas normales que conviertan modelos 3D suaves en dunas de arena.
En la parte anterior del tutorial, implementamos la iluminación difusa de la arena Journey. Cuando se usa solo este efecto, las dunas del desierto parecerán bastante planas y aburridas.
Uno de los efectos más intrigantes de Journey es la granulosidad de la arena. Al observar cualquier captura de pantalla, nos parece que las dunas no son lisas y homogéneas, sino que se crean a partir de millones de granos microscópicos de arena.
Este efecto se puede lograr utilizando una técnica llamada
mapeo de relieve , que permite que la luz rebote en una superficie plana como si fuera más compleja. Vea cómo este efecto cambia la apariencia del renderizado:
Se pueden ver pequeñas diferencias al aumentar:
Nos ocupamos de los mapas normales.
La arena consiste en innumerables granos de arena, cada uno de los cuales tiene su propia forma y composición (ver más abajo). Cada partícula individual refleja la iluminación en una dirección potencialmente aleatoria. Una forma de realizar este efecto es crear un modelo 3D que contenga todos estos granos microscópicos de arena. Pero debido a la increíble cantidad de polígonos requeridos, este enfoque no es factible.
Pero hay otra solución que a menudo se usa para simular una geometría más compleja en comparación con un modelo 3D real. Cada vértice o cara del modelo 3D está asociado con un parámetro llamado su
dirección normal . Este es un vector de longitud unitaria utilizado para calcular la reflexión de la luz en la superficie de un modelo 3D. Es decir, para simular arena, debe simular esta distribución aparentemente aleatoria de granos de arena y, por lo tanto, cómo afectan las normales de la superficie.
Esto se puede hacer de innumerables maneras. Lo más simple es crear una textura que cambie la dirección de las normales originales del modelo de duna.
Normal a la superficie N en el caso general, se calcula por la geometría del modelo 3D. Sin embargo, puede modificarlo usando el
mapa normal . Los mapas normales son texturas que le permiten simular geometrías más complejas cambiando la orientación local de las normales a la superficie. Esta técnica a menudo se llama
mapeo de relieve .
Cambiar las normales es una tarea bastante simple que se puede realizar en la función de
navegación del sombreador de superficie . Esta función toma dos parámetros, uno de los cuales es una
struct
llamada
SurfaceOutput
. Contiene todas las propiedades necesarias para representar una parte de un modelo 3D, desde su color (
o.Albedo
) hasta la transparencia (
o.Alpha
). Otro parámetro que contiene es la dirección normal (
o.Normal
), que puede reescribirse para cambiar la forma en que la luz se refleja en el modelo.
De acuerdo con la documentación de Unity sobre
Surface Shaders , todas las normales escritas en la estructura
o.Normal
deben expresarse en
espacio tangente :
struct SurfaceOutput { fixed3 Albedo;
Por lo tanto, podemos informar que los vectores unitarios deben expresarse en el sistema de coordenadas relativo a la malla normal. Por ejemplo, al escribir en
o.Normal
valores de
float3(0, 0, 1)
normal permanecerán sin cambios.
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _SandColor; o.Alpha = 1; o.Normal = float3(0, 0, 1); }
Esto se debe a que el vector
float3(0, 0, 1)
es en realidad un vector normal expresado en relación con la geometría del modelo 3D.
Entonces, para cambiar la normalidad a la superficie en el
sombreador de superficie , solo necesitamos escribir un nuevo vector en
la función de superficie en
o.Normal
:
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _SandColor; o.Alpha = 1; o.Normal = ...
En el resto de la publicación, crearemos la aproximación inicial, que complicaremos en la sexta parte del tutorial.
Arena normal
La parte más problemática es comprender
cómo los granos de arena cambian de forma normal a la superficie. Aunque individualmente cada grano de arena puede dispersar la luz en cualquier dirección, en general, sucede algo más. Cualquier enfoque físicamente preciso debe estudiar la distribución de los vectores normales en la superficie de la arena y modelarla matemáticamente. Tales modelos realmente existen, pero la solución presentada en nuestro tutorial es mucho más simple y al mismo tiempo es muy efectiva.
En cada punto del modelo,
se muestrea un
vector unitario aleatorio a partir de la textura. Entonces, lo normal a la superficie se inclina una cierta cantidad hacia este vector. Con la creación correcta de una textura aleatoria y la selección de una cantidad apropiada de mezcla, podemos cambiar la normalidad a la superficie de tal manera que creemos una sensación de grano, sin perder la curvatura general de las dunas.
Los valores aleatorios se pueden muestrear usando una textura llena de colores aleatorios. Los componentes R, G y B de cada píxel se usan como componentes X, Y y Z del vector normal. Los componentes de color están en el rango
left[0,1 right] , por lo que deben convertirse en intervalo
left[−1,+1 right] . Luego, el vector resultante se normaliza para que su longitud sea igual a
1 .
Crea texturas aleatoriasHay muchas formas de generar texturas aleatorias. Para obtener el efecto deseado, lo más importante es la distribución general de vectores aleatorios que se pueden muestrear a partir de la textura.
En la imagen de arriba, cada píxel es completamente aleatorio. No existe una dirección general (color) que prevalezca en la textura, porque cada valor tiene la misma probabilidad que todos los demás. Esta textura nos da un tipo de arena que dispersa la luz en todas las direcciones.
Durante una charla de GDC, John Edwards dejó en claro que la textura aleatoria utilizada para la arena en Journey se generó a partir de una distribución gaussiana. Esto asegura que la dirección predominante coincida con la normal a la superficie.
¿Los vectores aleatorios necesitan ser normalizados?La imagen que utilicé para muestrear vectores aleatorios se generó mediante un proceso completamente aleatorio. No solo cada píxel se genera individualmente: los componentes R, G y B de un píxel también son independientes entre sí. Es decir, en el caso general, no se garantizará que los vectores muestreados a partir de esta textura tengan una longitud igual a 1 .
Por supuesto, puede generar una textura en la que cada píxel al convertir de left[0,1 right] en left[−1,+1 right] y de hecho tendrá que tener una longitud 1 . Sin embargo, aquí surgen dos problemas.
, . -, mip-, .
, .
Implementación
« »,
surf
. , , , Journey . (
) , (
) .
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = _SandColor; o.Alpha = 1; float3 N = float3(0, 0, 1); N = RipplesNormal(N);
(bump mapping), , (
uv_SandTex
).
, , . ,
UV- , , . 3D- UV-, UV .
N = WavesNormal(IN.uv_SandTex.xy, N); N = SandNormal (IN.uv_SandTex.xy, N);
(
IN.worldPos
) .
-
SandNormal
. , ( ) .
sampler2D_float _SandTex; float3 SandNormal (float2 uv, float3 N) {
?UV- 3D- , . , .
, Unity . ,
_SandText_ST
. Unity ( )
_SandTex
.
_SandText_ST
: . ,
Tiling Offset :
,
TRANSFORM_TEX
:
sampler2D_float _SandTex; float4 _SandTex_ST; float3 SandNormal (float2 uv, float3 N) {
, . : , . , , , — .
. , , . , - .
. . , ,
, :
slerp ,
spherical linear interpolation ( ).
Slerp , lerp, — , .
, slerp . , , .
slerp,
p0 y
p1 , . Entonces
slerp :
(1)
Ω —
p0 y
p1 , :
(2)
,
, :
Lerp . , , ,
1 0 .
, lerp , , slerp:
float3 nlerp(float3 n1, float3 n2, float t) { return normalize(lerp(n1, n2, t)); }
,
nlerp , slerp.
,
The Witness . ,
Understanding Slerp. Then Not Using It Math Magician – Lerp, Slerp, and Nlerp .
nlerp ,
_SandTex
:
sampler2D_float _SandTex; float _SandStrength; float3 SandNormal (float2 uv, float3 N) {
:
Que sigue
, .
Agradecimientos
Journey Thatgamecompany Sony Computer Entertainment . PC (
Epic Store ) PS4 (
PS Store ).
3D-
Jiadi Deng .
3D- Journey ( ) FacePunch.
Unity
, Unity
Patreon . , 3D-.