2012-05-18 3 views
2

Я посмотрел на Google, но единственное, что я мог найти, это учебник о том, как создать его с помощью Photoshop. Нет интереса! Мне нужна логика. (и мне не нужна логика того, как «использовать» рельефную карту, я хочу знать, как ее сделать!)Какова логика создания нормальной карты из текстуры?

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

Я хочу сделать это в режиме реального времени, так что, когда текстура изменится, также работает bumpmap.

Thanks

+0

Я не уверен, если это возможно. На самом деле вы хотите создать 3D-модель (нормальную карту) 2D-текстуры. – Ondra

ответ

0

Быстрый ответ: Это невозможно.
Простая общая (диффузная) текстура просто не содержит эту информацию. Я не совсем точно выглядел, как это делает Photoshop (когда-то он использовался художником), но я думаю, что они просто делают что-то вроде «depth = r + g + b + a», который в основном возвращает высоту/градиент. А затем преобразование карты высот в нормальную карту с помощью простого эффекта обнаружения края, чтобы получить нормальную карту Касательного пространства.

Просто имейте в виду, что в большинстве случаев вы используете обычную карту для имитации сетки 3D-геометрии с высоким разрешением, так как она заполняет пустое место, а вершины-нормали оставляют позади. Если ваша сцена в значительной степени зависит от освещения, это нехорошо, но если это простой направленный свет, это «может» работать. Конечно, это мой опыт, вы также можете работать над совершенно другим типом проекта.

2

Пробоотборник для чтения карты высоты или глубины.

/// same data as HeightMap, but in a format that the pixel shader can read 
/// the pixel shader dynamically generates the surface normals from this. 
extern Texture2D HeightMap; 
sampler2D HeightSampler = sampler_state 
{ 
    Texture=(HeightMap); 
    AddressU=CLAMP; 
    AddressV=CLAMP; 
    Filter=LINEAR; 
}; 

Обратите внимание, что моя входная карта представляет собой однокомпонентную текстуру в оттенках серого размером 512x512. Вычисление нормалей из это довольно просто:

#define HALF2 ((float2)0.5) 
#define GET_HEIGHT(heightSampler,texCoord) (tex2D(heightSampler,texCoord+HALF2)) 
///calculate a normal for the given location from the height map 
/// basically, this calculates the X- and Z- surface derivatives and returns their 
/// cross product. Note that this assumes the heightmap is a 512 pixel square for no particular 
/// reason other than that my test map is 512x512. 
float3 GetNormal(sampler2D heightSampler, float2 texCoord) 
{ 

     /// normalized size of one texel. this would be 1/1024.0 if using 1024x1024 bitmap. 
    float texelSize=1/512.0; 

    float n = GET_HEIGHT(heightSampler,texCoord+float2(0,-texelSize)); 
    float s = GET_HEIGHT(heightSampler,texCoord+float2(0,texelSize)); 
    float e = GET_HEIGHT(heightSampler,texCoord+float2(-texelSize,0)); 
    float w = GET_HEIGHT(heightSampler,texCoord+float2(texelSize,0)); 


    float3 ew = normalize(float3(2*texelSize,e-w,0)); 
    float3 ns = normalize(float3(0,s-n,2*texelSize)); 
    float3 result = cross(ew,ns); 

    return result; 
} 

и пиксельные шейдеры назвать:

#define LIGHT_POSITION (float3(0,2,0)) 

float4 SolidPS(float3 worldPosition : NORMAL0, float2 texCoord : TEXCOORD0) : COLOR0 
{ 
    /// calculate a normal from the height map  
    float3 normal = GetNormal(HeightSampler,texCoord); 
    /// return it as a color. (Since the normal components can range from -1 to +1, this 
     /// will probably return a lot of "black" pixels if rendered as-is to screen. 
    return float3(normal,1);   
} 

LIGHT_POSITION может (и, вероятно, должны) быть введены из кода хозяина, хотя я изменял и использовал константу здесь.

Обратите внимание, что для этого метода требуется 4 поиска текстур на нормальный, не считая одного, чтобы получить цвет. Возможно, это не проблема для вас (в зависимости от того, что вы делаете). Если это слишком сильно влияет на производительность, вы можете просто называть его всякий раз, когда текстура изменяется, отображает цель и фиксирует результат как обычную карту.

Альтернативой может быть нарисовать квадрат с выравниванием по экрану с текстурой высот до цели рендеринга и использовать свойства HLSL ddx/ddy для генерации нормалей без необходимости повторной выборки исходной текстуры. Очевидно, что вы сделаете это на этапе предварительного прохода, прочитайте полученную нормальную карту назад, а затем используйте ее как вход для своих последующих этапов.

В любом случае, это оказалось достаточно быстрым для меня.

0

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

Более длинный ответ:

Если вы предположить, что поверхность были фактически постоянным цветом, то любые изменения в цвете или яркости должны быть из-за эффектов затенения из-за тряски. Вычислите, насколько ярче/темнее каждый пиксель от фактического цвета поверхности; более яркие значения указывают на части поверхности, которые обращены к «источнику света», а более темные значения указывают на части поверхности, которые «отходят» от источника света. Если вы также укажете направление света, вы можете рассчитать нормальную поверхность в каждой точке текстуры таким образом, чтобы это привело к вычисляемому значению затенения.

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

Обычно обычные карты создаются из реальных 3D-моделей поверхности, которые «проецируются» на геометрию с более низким разрешением. Нормальные карты - это всего лишь методика подделывания этой геометрии с высоким разрешением.