Всем привет. Сделал pbr текстуры и сделал тайл плитку. Я не знаю какой код вам присылать, так что покажу картинку, а вы напишите код чего предоставить. Координаты и позиция света передается в шейдеры, посмотрел через renderdoc.
Эта модель как будто прозрачная.
За основу брал opengl шейдер https://www.programmersought.com/article/91679709226/
Тут в шейдере дело как я понял, но в чём может быть проблема? Выложу шейдеры сюда.
struct VS_INPUT { float3 pos: POSITION; float2 tex: TEXCOORD; float3 norm: NORMAL; }; struct PS_INPUT { float4 pos: SV_POSITION; float2 tex: TEXCOORD; float3 norm: NORMAL; float3 WorldPos: POSITION0; }; cbuffer MVP : register(b0) { matrix mvp; } PS_INPUT main( VS_INPUT p) { PS_INPUT o; o.norm = p.norm; o.tex = p.tex; float4 ps = float4( p.pos, 1.0); float4 resultPos = mul( ps, mvp); o.pos = resultPos; o.WorldPos = p.pos; return o; }
struct PS_INPUT { float4 pos: SV_POSITION; float2 tex: TEXCOORD; float3 norm: NORMAL; float3 WorldPos: POSITION0; }; static const int sizeLight = 1; struct LIGHT { float3 pos; float power; }; cbuffer Light: register(b1) { LIGHT light[sizeLight]; } cbuffer CamPos : register( b2) { float4 cam_pos; } static const float PI = 3.14159265359; #define MEDIUMP_FLT_MAX 65504.0 #define MEDIUMP_FLT_MIN 0.00006103515625 #define saturateMediump( x) min( x, MEDIUMP_FLT_MAX) // ---------------------------------------------------------------------------- float DistributionGGX( float3 N, float3 H, float roughness) { // float a = roughness*roughness; // float a2 = a*a; // float NdotH = max(dot(N, H), 0.0); // float NdotH2 = NdotH*NdotH; // // float nom = a2; // float denom = (NdotH2 * (a2 - 1.0) + 1.0); // denom = PI * denom * denom; // // return saturateMediump(nom / denom); // better ndf with spot light shape float3 NxH = cross( N, H); float oneMinusNoHSquared = dot( NxH, NxH); float NoH = max( dot( N, H), 0.0); float a = NoH * roughness; float k = roughness / ( oneMinusNoHSquared + a * a); float d = k * k * ( 1.0 / PI); // return saturateMediump(d,MEDIUMP_FLT_MAX); return min( d, MEDIUMP_FLT_MAX); } // ---------------------------------------------------------------------------- float GeometrySchlickGGX( float NdotV, float roughness) { float r = ( roughness + 1.0); float k = ( r * r) / 8.0; float nom = NdotV; float denom = NdotV * ( 1.0 - k) + k; // return saturateMediump(nom / denom,MEDIUMP_FLT_MAX); return min( nom / denom, MEDIUMP_FLT_MAX); } // ---------------------------------------------------------------------------- float GeometrySmith( float3 N, float3 V, float3 L, float roughness) { float NdotV = max( dot( N, V), 0.0); float NdotL = max( dot( N, L), 0.0); float ggx2 = GeometrySchlickGGX( NdotV, roughness); float ggx1 = GeometrySchlickGGX( NdotL, roughness); // saturateMediump(ggx1 * ggx2,MEDIUMP_FLT_MAX); return min( ggx1 * ggx2, MEDIUMP_FLT_MAX); } // ---------------------------------------------------------------------------- float3 fresnelSchlick( float cosTheta, float3 F0) { return F0 + ( 1.0 - F0) * pow( 1.0 - cosTheta, 5.0); } // ---------------------------------------------------------------------------- float3 fresnelSchlickRoughness( float cosTheta, float3 F0, float roughness) { float a = 1.0 - roughness; return F0 + ( max( float3( a, a, a), F0) - F0) * pow( 1.0 - cosTheta, 5.0); } float3 EnvDFGLazarov( float3 specularColor, float gloss, float ndotv) { //# [ Lazarov 2013, "Getting More Physical in Call of Duty: Black Ops II" ] //# Adaptation to fit our G term. float4 p0 = float4( 0.5745, 1.548, -0.02397, 1.301); float4 p1 = float4( 0.5753, -0.2511, -0.02066, 0.4755); float4 t = gloss * p0 + p1; float bias = clamp( t.x * min( t.y, exp2( -7.672 * ndotv)) + t.z, 0.0, 1.0); float delta = clamp( t.w, 0.0, 1.0); float scale = delta - bias; bias *= clamp( 50.0 * specularColor.y, 0.0, 1.0); return specularColor * scale + bias; } Texture2D albedoMap: register( t0); Texture2D heightMap: register( t1); Texture2D metallicMap: register( t2); Texture2D aoMap: register( t3); Texture2D normalMap: register( t4); Texture2D roughnessMap: register( t5); SamplerState colorSampler_: register( s0); float4 main( PS_INPUT p) : SV_TARGET { float3 albedo = pow( albedoMap.Sample( colorSampler_, p.tex).rgb, float3( 2.2, 2.2, 2.2)); float metallic = metallicMap.Sample( colorSampler_, p.tex).r; float roughness = roughnessMap.Sample( colorSampler_, p.tex).r; //float ao = aoMap.Sample(colorSampler_, p.tex).r; float ao = 1.0; float3 camPos = float3( cam_pos.r, cam_pos.g, cam_pos.b); // vec3 N = getNormalFromMap(); float3 N = normalize( p.norm); float3 V = normalize( camPos - p.WorldPos); float3 R = reflect( -V, N); // calculate reflectance at normal incidence; if dia-electric (like plastic) use F0 // of 0.04 and if it's a metal, use the albedo color as F0 (metallic workflow) float3 F0 = float3( 0.04, 0.04, 0.04); F0 = lerp( F0, albedo, metallic); // reflectance equation float3 Lo = float3( 0.0, 0.0, 0.0); int i = 0; // point light //for (int i = 0; i < sizeLight; ++i) { // calculate per-light radiance float3 L = normalize( light[i].pos - p.WorldPos); float3 H = normalize( V + L); float distance = length( light[i].pos - p.WorldPos); float attenuation = 1.0 / ( distance * distance); float3 radiance = light[i].pos * attenuation; // Cook-Torrance BRDF float NDF = DistributionGGX( N, H, roughness); float G = GeometrySmith( N, V, L, roughness); float3 F = fresnelSchlick( clamp( dot( H, V), 0.0, 1.0), F0); float3 nominator = NDF * G * F; float denominator = 4.0 * max( dot( N, V), 0.0) * max( dot( N, L), 0.0); float3 specular = nominator / max( denominator, 0.001); // prevent divide by zero for NdotV=0.0 or NdotL=0.0 // kS is equal to Fresnel float3 kS = F; // for energy conservation, the diffuse and specular light can't // be above 1.0 (unless the surface emits light); to preserve this // relationship the diffuse component (kD) should equal 1.0 - kS. float pw = 1.0; float3 kD = float3( pw, pw, pw) - kS; // multiply kD by the inverse metalness such that only non-metals // have diffuse lighting, or a linear blend if partly metal (pure metals // have no diffuse light). kD *= 1.0 - metallic; // scale light by NdotL float NdotL = max( dot( N, L), 0.0); // add to outgoing radiance Lo Lo += ( kD * albedo / PI + specular) * radiance * NdotL; // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again //} // ambient lighting (note that the next IBL tutorial will replace // this ambient lighting with environment lighting). float apw = 0.1; float3 ambient = float3( apw, apw, apw); float3 ambientColor = ambient * albedo * ao; float3 color = ambientColor + Lo; // HDR tonemapping float3 cv = float3( 1.0, 1.0, 1.0); color = color / ( color + cv); // gamma correct float cz = 1.0 / 2.2; color = pow( color, float3( cz, cz, cz)); return float4( color, 1.0); }
v7
Большой шейдер
Толстый ч бы даже сказал бы
innuendo
Я попробовал сделать по простому и отправить так.
float4 main(PS_INPUT p) : SV_TARGET { return albedoMap.Sample( colorSampler_, p.tex);
И всё-равно такое, только цвет сменился на белый. Возможно что-то в текстуре не так.
Теперь вот так показывает. Текстура вроде полностью считывается.
Немного поработал с кодом, но всё равно. Вот как сейчас выглядит. Хотя текстура не так выглядит. Нижняя часть левая правильно, а остальное нет.
Вот код инициализации текстуры.
void Downloader::LoadTextureFile(ObjectData* obj, std::string& filepath) { FILE* fp = nullptr; const char* filename = filepath.c_str( ); fopen_s( &fp, filepath.c_str( ), "r+b"); if ( fp == nullptr) exit( 0); int i; int total; uint32_t width; uint32_t height; fread( &i, 1, sizeof( int), fp); fread( &total, 1, sizeof( int), fp); fread( &width, 1, sizeof( int), fp); fread( &height, 1, sizeof( int), fp); if ( i != 1) { i = BytesOperation::bites_swap_little_big_engian_uint( i); total = BytesOperation::bites_swap_little_big_engian_uint( total); width = BytesOperation::bites_swap_little_big_engian_uint( width); height = BytesOperation::bites_swap_little_big_engian_uint( height); } if ( i != 1) { exit( 0); } switch ( total) { case N_PBR_HEADER: obj->texture_data = new uint8_t * [N_PBR_HEADER]; break; default: obj->texture_data = new uint8_t * [total]; break; } obj->texture_width = width; obj->texture_height = height; obj->total = total; uint64_t sizeBuffer = ( uint64_t) width * ( uint64_t) height * ( uint64_t)4; for ( int i = 0; i < total; i++) { obj->texture_data[i] = new uint8_t[sizeBuffer]; int ret = fread( obj->texture_data[i], 1, sizeBuffer, fp); int a = 0; } fclose( fp); obj->countTextures = total; } void Downloader::GenerateBuffers( ObjectData* obj) { D3D11_BUFFER_DESC bufferDesc; ZeroMemory( &bufferDesc, sizeof( D3D11_BUFFER_DESC)); bufferDesc.Usage = D3D11_USAGE_DEFAULT; bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bufferDesc.ByteWidth = sizeof( float) * obj->f_size * 24; D3D11_SUBRESOURCE_DATA resourceData; ZeroMemory( &resourceData, sizeof( D3D11_SUBRESOURCE_DATA)); resourceData.pSysMem = obj->vao_data; resourceData.SysMemPitch = 0; Graphics* gr = Graphics::GetInstance( ); obj->v_buffer = nullptr; HRESULT res = gr->d3d11Device->CreateBuffer( &bufferDesc, &resourceData, &obj->v_buffer); int a = 0; obj->colorMap = new ID3D11Texture2D * [obj->total]( ); D3D11_TEXTURE2D_DESC tx2d; ZeroMemory( &tx2d, sizeof( tx2d)); tx2d.Height = obj->texture_height; tx2d.Width = obj->texture_width; tx2d.MipLevels = 1; tx2d.ArraySize = 1; tx2d.Format = DXGI_FORMAT_R8G8B8A8_UNORM; tx2d.Usage = D3D11_USAGE_DEFAULT; tx2d.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; tx2d.SampleDesc.Count = 1; obj->textureView = new ID3D11ShaderResourceView * [obj->total]( ); for ( int i = 0; i < obj->countTextures; i++) { obj->colorMap[i] = nullptr; D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; ZeroMemory( &srvDesc, sizeof( D3D11_SHADER_RESOURCE_VIEW_DESC)); srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srvDesc.Texture2D.MipLevels = 1; D3D11_SUBRESOURCE_DATA dt; ZeroMemory( &dt, sizeof( dt)); dt.pSysMem = obj->texture_data[i]; dt.SysMemPitch = obj->texture_width * 4; dt.SysMemSlicePitch = 0; ID3D11Texture2D* buffer = nullptr; HRESULT result = gr->d3d11Device->CreateTexture2D( &tx2d, &dt, &buffer); if ( buffer) { obj->textureView[i] = nullptr; result = gr->d3d11Device->CreateShaderResourceView( buffer, &srvDesc, &obj->textureView[i]); //buffer->Release(); } } }
Капец, непонятно почему искажена текстура.
Это просто трагедия
Как жить дальше я не знаю
Я делал модель в blender и сохранял её в obj формате. Потом в substance painter открывал как directx graphical api и разрисовывал и сохранял в 1024x1024. Потом перегонял в свой формат текстур и оттуда загружал. Текстура искаженная. Я думаю это отличие в том, что в blender opengl, а не directx и он не так координаты сохраняет текстур.
Перешел в linux, сделал подобную модель в blender, в substance painter открыл как opengl и сохранил в 1024x1024. Перевел в формат текстур и открыл и всё нормально отображается, а в windows нет.
Зачем амбиент колор считать с альбедо?
innuendo
Я не разбираюсь в таких расчетах и просто взял шейдер для opengl копипаст. Кстати, я справился и теперь текстура правильно рисуется.