diff --git a/ref_vk/shaders/ray.rchit b/ref_vk/shaders/ray.rchit index 534230cf..d56d1879 100644 --- a/ref_vk/shaders/ray.rchit +++ b/ref_vk/shaders/ray.rchit @@ -63,6 +63,10 @@ vec4 sampleTexture(uint tex_index, vec2 uv, vec4 uv_lods) { return textureGrad(textures[nonuniformEXT(tex_index)], uv, uv_lods.xy, uv_lods.zw); } +vec3 baryMix(vec3 v1, vec3 v2, vec3 v3, vec2 bary) { + return v1 * (1. - bary.x - bary.y) + v2 * bary.x + v3 * bary.y; +} + void main() { payload.t_offset += gl_HitTEXT; @@ -82,7 +86,7 @@ void main() { // TODO use already inverse gl_WorldToObject ? const mat3 matWorldRotation = mat3(gl_ObjectToWorldEXT); const mat3 normalTransformMat = transpose(inverse(matWorldRotation)); - const vec3 normal = normalize(normalTransformMat * (n1 * (1. - bary.x - bary.y) + n2 * bary.x + n3 * bary.y)); + vec3 normal = normalize(normalTransformMat * (n1 * (1. - bary.x - bary.y) + n2 * bary.x + n3 * bary.y)); const vec2 uvs[3] = { vertices[vi1].gl_tc, @@ -108,7 +112,7 @@ void main() { const float ray_cone_width = payload.pixel_cone_spread_angle * payload.t_offset; vec4 uv_lods; - computeAnisotropicEllipseAxes(hit_pos, normal, gl_WorldRayDirectionEXT, ray_cone_width, pos, uvs, texture_uv_stationary, uv_lods.xy, uv_lods.zw); + computeAnisotropicEllipseAxes(hit_pos, /* TODO geom_?*/ normal, gl_WorldRayDirectionEXT, ray_cone_width, pos, uvs, texture_uv_stationary, uv_lods.xy, uv_lods.zw); const uint tex_index = kusochki[kusok_index].tex_base_color; const vec4 tex_color = sampleTexture(tex_index, texture_uv, uv_lods); @@ -117,12 +121,24 @@ void main() { /* tex_color = pow(tex_color, vec4(2.)); */ /* const vec3 base_color = tex_color.rgb; */ + normal *= geom_normal_sign; + const uint tex_normal = kusochki[kusok_index].tex_normalmap; + vec3 T = baryMix(vertices[vi1].tangent, vertices[vi2].tangent, vertices[vi3].tangent, bary); + if (tex_normal > 0 && dot(T,T) > .5) { + T = normalize(normalTransformMat * T); + T = normalize(T - dot(T, normal) * normal); + const vec3 B = normalize(cross(normal, T)); + const mat3 TBN = mat3(T, B, normal); + const vec3 tnorm = sampleTexture(tex_normal, texture_uv, uv_lods).xyz * 2. - 1.; // TODO is this sampling correct for normal data? + normal = normalize(TBN * tnorm); + } + // FIXME read alpha from texture payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT); payload.base_color = base_color * kusochki[kusok_index].color.rgb; payload.transmissiveness = (1. - tex_color.a * kusochki[kusok_index].color.a); - payload.normal = normal * geom_normal_sign; + payload.normal = normal; payload.geometry_normal = geom_normal; payload.emissive = kusochki[kusok_index].emissive * base_color; // TODO emissive should have a special texture payload.kusok_index = kusok_index; diff --git a/ref_vk/shaders/ray.rgen b/ref_vk/shaders/ray.rgen index 2d894307..5bec8da1 100644 --- a/ref_vk/shaders/ray.rgen +++ b/ref_vk/shaders/ray.rgen @@ -422,6 +422,13 @@ void main() { imageStore(out_image_base_color, ivec2(gl_LaunchIDEXT.xy), vec4(payload_opaque.base_color, 0.)); imageStore(out_image_normals, ivec2(gl_LaunchIDEXT.xy), vec4(geometryNormal.xy, shadingNormal.xy)); payload_opaque.base_color = vec3(1.); + +#if 0 + imageStore(out_image_diffuse_gi, ivec2(gl_LaunchIDEXT.xy), vec4(0)); + imageStore(out_image_specular, ivec2(gl_LaunchIDEXT.xy), vec4(0.)); + imageStore(out_image_additive, ivec2(gl_LaunchIDEXT.xy), vec4(clamp(payload_opaque.normal, vec3(0.), vec3(1.)), 0.)); + return; +#endif } // TODO should we do this after reflect/transmit decision? diff --git a/ref_vk/shaders/ray_kusochki.glsl b/ref_vk/shaders/ray_kusochki.glsl index d2b512ab..157857a5 100644 --- a/ref_vk/shaders/ray_kusochki.glsl +++ b/ref_vk/shaders/ray_kusochki.glsl @@ -8,6 +8,7 @@ struct Vertex { vec3 pos; vec3 normal; + vec3 tangent; vec2 gl_tc; vec2 _unused_lm_tc; diff --git a/ref_vk/vk_brush.c b/ref_vk/vk_brush.c index 7de2a82a..b52934dc 100644 --- a/ref_vk/vk_brush.c +++ b/ref_vk/vk_brush.c @@ -456,6 +456,9 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) { vk_render_geometry_t *model_geometry = bmodel->render_model.geometries + num_geometries; const float sample_size = gEngine.Mod_SampleSizeForFace( surf ); int index_count = 0; + vec3_t pos[3]; + vec2_t uv[3]; + vec3_t tangent; if (!renderableSurface(surf, -1)) continue; @@ -511,6 +514,18 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) { vertex.gl_tc[0] = s; vertex.gl_tc[1] = t; + // TODO replace this with constructing tangent from surf->texinfo->vecs + if (k < 3) { + VectorCopy(vertex.pos, pos[k]); + Vector2Copy(vertex.gl_tc, uv[k]); + if (k == 2) { + computeTangent(tangent, pos[0], pos[1], pos[2], uv[0], uv[1], uv[2]); + VectorCopy(tangent, bvert[-1].tangent); + VectorCopy(tangent, bvert[-2].tangent); + } + } + VectorCopy(tangent, vertex.tangent); + // lightmap texture coordinates s = DotProduct( in_vertex->position, info->lmvecs[0] ) + info->lmvecs[0][3]; s -= info->lightmapmins[0]; diff --git a/ref_vk/vk_core.c b/ref_vk/vk_core.c index 8a9184d1..da1961ab 100644 --- a/ref_vk/vk_core.c +++ b/ref_vk/vk_core.c @@ -151,6 +151,9 @@ VkBool32 VKAPI_PTR debugCallback( (void)(messageTypes); (void)(messageSeverity); + if (Q_strcmp(pCallbackData->pMessageIdName, "VUID-vkMapMemory-memory-00683") == 0) + return VK_FALSE; + // TODO better messages, not only errors, what are other arguments for, ... if (messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { gEngine.Con_Printf(S_ERROR "Validation: %s\n", pCallbackData->pMessage); diff --git a/ref_vk/vk_light.c b/ref_vk/vk_light.c index dbf523d5..7158bdb9 100644 --- a/ref_vk/vk_light.c +++ b/ref_vk/vk_light.c @@ -594,7 +594,7 @@ static qboolean canSurfaceLightAffectAABB(const model_t *mod, const msurface_t * return retval; } -const vk_emissive_surface_t *VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const matrix3x4 *transform_row, qboolean static_map ) { +void VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const matrix3x4 *transform_row, qboolean static_map ) { APROF_SCOPE_BEGIN_EARLY(emissive_surface); const int texture_num = geom->texture; // Animated texture vk_emissive_surface_t *retval = NULL; @@ -699,7 +699,6 @@ const vk_emissive_surface_t *VK_LightsAddEmissiveSurface( const struct vk_render fin: APROF_SCOPE_END(emissive_surface); - return retval; } static void addLightIndexToleaf( const mleaf_t *leaf, int index ) { @@ -929,9 +928,8 @@ void VK_LightsLoadMapStaticLights( void ) { for (int i = 0; i < bmodel->render_model.num_geometries; ++i) { const vk_render_geometry_t *geom = bmodel->render_model.geometries + i; - if (!VK_LightsAddEmissiveSurface( geom, &xform, true )) { + VK_LightsAddEmissiveSurface( geom, &xform, true ); // TODO how to differentiate between this and non-emissive gEngine.Con_Printf(S_ERROR "Ran out of surface light slots, geom %d of %d\n", i, bmodel->render_model.num_geometries); - } } } @@ -948,6 +946,20 @@ void VK_LightsLoadMapStaticLights( void ) { } } +void XVK_GetEmissiveForTexture( vec3_t out, int texture_id ) { + ASSERT(texture_id >= 0); + ASSERT(texture_id < MAX_TEXTURES); + + { + vk_emissive_texture_t *const etex = g_lights.map.emissive_textures + texture_id; + if (etex->set) { + VectorCopy(etex->emissive, out); + } else { + VectorSet(out, 0, 0, 0); + } + } +} + void VK_LightsFrameFinalize( void ) { APROF_SCOPE_BEGIN_EARLY(finalize); const model_t* const world = gEngine.pfnGetModelByIndex( 1 ); diff --git a/ref_vk/vk_light.h b/ref_vk/vk_light.h index bd70f821..f574ece9 100644 --- a/ref_vk/vk_light.h +++ b/ref_vk/vk_light.h @@ -86,6 +86,7 @@ void VK_LightsFrameInit( void ); // b. kusochki now have emissive color, so it probably makes more sense to not store emissive // separately in emissive surfaces. struct vk_render_geometry_s; -const vk_emissive_surface_t *VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const matrix3x4 *transform_row, qboolean static_map ); +void VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const matrix3x4 *transform_row, qboolean static_map ); +void XVK_GetEmissiveForTexture( vec3_t out, int texture_id ); void VK_LightsFrameFinalize( void ); diff --git a/ref_vk/vk_materials.c b/ref_vk/vk_materials.c index 17d376ed..426ff33a 100644 --- a/ref_vk/vk_materials.c +++ b/ref_vk/vk_materials.c @@ -54,7 +54,7 @@ static void loadMaterialsFromFile( const char *filename ) { .base_color = -1, .metalness = tglob.blackTexture, .roughness = tglob.whiteTexture, - .normalmap = tglob.grayTexture, + .normalmap = 0, }; int current_material_index = -1; @@ -80,13 +80,15 @@ static void loadMaterialsFromFile( const char *filename ) { .base_color = -1, .metalness = tglob.blackTexture, .roughness = tglob.whiteTexture, - .normalmap = tglob.grayTexture, + .normalmap = 0, }; continue; } if (key[0] == '}') { - if (current_material_index >= 0 && current_material.base_color >= 0) { + if (current_material_index >= 0) { + if (current_material.base_color == -1) + current_material.base_color = current_material_index; g_materials.materials[current_material_index] = current_material; } continue; @@ -105,7 +107,7 @@ static void loadMaterialsFromFile( const char *filename ) { } else if (Q_stricmp(key, "normal_map") == 0) { if ((current_material.normalmap = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) { gEngine.Con_Printf(S_ERROR "Failed to load normal_map texture %s\n", value); - current_material.normalmap = tglob.grayTexture; + current_material.normalmap = 0; } } else if (Q_stricmp(key, "metal_map") == 0) { if ((current_material.metalness = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) { @@ -132,13 +134,13 @@ void XVK_ReloadMaterials( void ) { if (!tex) { mat->base_color = -1; - continue; + break; } mat->base_color = i; mat->metalness = tglob.blackTexture; mat->roughness = tglob.whiteTexture; - mat->normalmap = tglob.grayTexture; + mat->normalmap = 0; } loadMaterialsFromFile( "pbr/materials.mat" ); diff --git a/ref_vk/vk_math.c b/ref_vk/vk_math.c index 0a6adb13..e9d942a0 100644 --- a/ref_vk/vk_math.c +++ b/ref_vk/vk_math.c @@ -266,3 +266,19 @@ void Matrix4x4_ConcatScale3( matrix4x4 out, float x, float y, float z ) Matrix4x4_CreateScale3( temp, x, y, z ); Matrix4x4_Concat( out, base, temp ); } + +void computeTangent(vec3_t out_tangent, vec3_t v0, vec3_t v1, vec3_t v2, vec2_t uv0, vec2_t uv1, vec2_t uv2) { + vec3_t e1, e2; + vec2_t duv1, duv2; + float f; + + VectorSubtract(v1, v0, e1); + VectorSubtract(v2, v0, e2); + Vector2Subtract(uv1, uv0, duv1); + Vector2Subtract(uv2, uv0, duv2); + + f = 1.f / (duv1[0] * duv2[1] - duv1[1] * duv2[0]); + out_tangent[0] = f * (duv2[1] * e1[0] - duv1[1] * e2[0]); + out_tangent[1] = f * (duv2[1] * e1[1] - duv1[1] * e2[1]); + out_tangent[2] = f * (duv2[1] * e1[2] - duv1[1] * e2[2]); +} diff --git a/ref_vk/vk_math.h b/ref_vk/vk_math.h index b5dd4df7..aff87754 100644 --- a/ref_vk/vk_math.h +++ b/ref_vk/vk_math.h @@ -20,3 +20,5 @@ void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z ); void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar); void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar); void Matrix4x4_CreateModelview( matrix4x4 out ); + +void computeTangent(vec3_t out_tangent, vec3_t v0, vec3_t v1, vec3_t v2, vec2_t uv0, vec2_t uv1, vec2_t uv2); diff --git a/ref_vk/vk_ray_model.c b/ref_vk/vk_ray_model.c index 4aae95e4..5389a767 100644 --- a/ref_vk/vk_ray_model.c +++ b/ref_vk/vk_ray_model.c @@ -310,7 +310,6 @@ static void computeConveyorSpeed(const color24 rendercolor, int tex_index, vec2_ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render_model, const matrix3x4 *transform_row, const vec4_t color, color24 entcolor) { qboolean HACK_reflective = false; - qboolean force_emissive = false; vk_ray_draw_model_t* draw_model = g_ray_model_state.frame.models + g_ray_model_state.frame.num_models; ASSERT(vk_core.rtx); @@ -346,7 +345,6 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render // Additive blending: C = SRC * alpha + DST case kRenderGlow: case kRenderTransAdd: - force_emissive = true; draw_model->material_mode = MaterialMode_Additive; break; @@ -361,33 +359,29 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render for (int i = 0; i < render_model->num_geometries; ++i) { const vk_render_geometry_t *geom = render_model->geometries + i; - const vk_emissive_surface_t *esurf = render_model->static_map ? NULL : VK_LightsAddEmissiveSurface( geom, transform_row, false ); vk_kusok_data_t *kusok = (vk_kusok_data_t*)(g_ray_model_state.kusochki_buffer.mapped) + geom->kusok_index; const xvk_material_t *const mat = XVK_GetMaterialForTextureIndex( geom->texture ); ASSERT(mat); + if (!render_model->static_map) + VK_LightsAddEmissiveSurface( geom, transform_row, false ); + kusok->tex_base_color = mat->base_color; kusok->tex_roughness = mat->roughness; kusok->tex_metalness = mat->metalness; kusok->tex_normalmap = mat->normalmap; - // HACK until there is proper specular - // FIXME also this erases previour roughness unconditionally - // if (HACK_reflective) { - // kusok->roughness = 0.f; - // } else if (geom->material == kXVkMaterialChrome) { - // kusok->roughness = .1f; - // } else { - // kusok->roughness = 1.f; - // } + // HACK until there is a proper mechanism for patching materials, see https://github.com/w23/xash3d-fwgs/issues/213 + // FIXME also this erases previous roughness unconditionally + if (HACK_reflective) { + kusok->tex_roughness = tglob.blackTexture; + } else if (geom->material == kXVkMaterialChrome) { + kusok->tex_roughness = tglob.grayTexture; + } Vector4Copy(color, kusok->color); - if (esurf) { - VectorCopy(esurf->emissive, kusok->emissive); - } else if (force_emissive) { - VectorSet(kusok->emissive, 1.f, 1.f, 1.f); - } + XVK_GetEmissiveForTexture( kusok->emissive, geom->texture ); if (geom->material == kXVkMaterialConveyor) { computeConveyorSpeed( entcolor, geom->texture, kusok->uv_speed ); diff --git a/ref_vk/vk_render.h b/ref_vk/vk_render.h index 715a4613..68a675d6 100644 --- a/ref_vk/vk_render.h +++ b/ref_vk/vk_render.h @@ -51,6 +51,7 @@ typedef struct vk_vertex_s { // TODO padding needed for storage buffer reading, figure out how to fix in GLSL/SPV side vec3_t pos; float p0_; vec3_t normal; uint32_t flags; + vec3_t tangent; uint32_t p1_; vec2_t gl_tc; //float p2_[2]; vec2_t lm_tc; //float p3_[2]; diff --git a/ref_vk/vk_scene.c b/ref_vk/vk_scene.c index 714d75b6..f40aa265 100644 --- a/ref_vk/vk_scene.c +++ b/ref_vk/vk_scene.c @@ -42,6 +42,8 @@ void VK_SceneInit( void ) { g_lists.draw_list = g_lists.draw_stack; g_lists.draw_stack_pos = 0; + + gEngine.Cmd_AddCommand("vk_rtx_reload_materials", XVK_ReloadMaterials, "Reload PBR materials"); } #define R_ModelOpaque( rm ) ( rm == kRenderNormal )