Files
fs2open.github.com/code/graphics/uniforms.cpp
T
asarium 357cd76252 Render hardpoint model outlines using geometry shaders
This adds support for rendering models using thick lines (that means
lines wider than 1 pixel) which is required by the hardpoint HUD gauge.
This feature was present before the switch to OpenGL code and had to be
removed since the core profile does not support rendering lines wider
than 1 pixel.

This uses a geometry shader for converting all the triangles from a
model to 3 quads along the triangle lines which are as thick as set by
the model renderer. Geometry shaders are quite slow if they generate a
lot of geometry (and this generates 4 times the usual amount of geometry
in the shader) so it's probably not a very fast rendering operation but
it is only needed once per frame so it shouldn't be too bad.

I also added support for the RenderDoc API since I needed that for
debugging and it might be useful in the future. It will only become
active if RenderDoc is actually attached to the process so in most cases
the new code will do nothing.
2018-06-07 16:44:41 +02:00

277 lines
8.5 KiB
C++

//
//
#include "uniforms.h"
#include "matrix.h"
#include "light.h"
#include "globalincs/systemvars.h"
#include "shadows.h"
namespace {
void scale_matrix(matrix4& mat, const vec3d& scale) {
mat.a2d[0][0] *= scale.xyz.x;
mat.a2d[0][1] *= scale.xyz.x;
mat.a2d[0][2] *= scale.xyz.x;
mat.a2d[1][0] *= scale.xyz.y;
mat.a2d[1][1] *= scale.xyz.y;
mat.a2d[1][2] *= scale.xyz.y;
mat.a2d[2][0] *= scale.xyz.z;
mat.a2d[2][1] *= scale.xyz.z;
mat.a2d[2][2] *= scale.xyz.z;
}
}
namespace graphics {
namespace uniforms {
void convert_model_material(model_uniform_data* data_out,
const model_material& material,
const matrix4& model_transform,
const vec3d& scale,
size_t transform_buffer_offset) {
auto shader_flags = material.get_shader_flags();
Assertion(gr_model_matrix_stack.depth() == 1, "Uniform conversion does not respect previous transforms! "
"Model matrix stack must be empty!");
matrix4 scaled_matrix = model_transform;
scale_matrix(scaled_matrix, scale);
data_out->modelMatrix = scaled_matrix;
data_out->viewMatrix = gr_view_matrix;
vm_matrix4_x_matrix4(&data_out->modelViewMatrix, &data_out->viewMatrix, &data_out->modelMatrix);
data_out->projMatrix = gr_projection_matrix;
data_out->textureMatrix = gr_texture_matrix;
data_out->color = material.get_color();
data_out->vpwidth = 1.0f / i2fl(gr_screen.max_w);
data_out->vpheight = 1.0f / i2fl(gr_screen.max_h);
if (shader_flags & SDR_FLAG_MODEL_ANIMATED) {
data_out->anim_timer = material.get_animated_effect_time();
data_out->effect_num = material.get_animated_effect();
}
if (shader_flags & SDR_FLAG_MODEL_CLIP) {
if (material.is_clipped()) {
auto& clip_info = material.get_clip_plane();
data_out->use_clip_plane = true;
vec4 clip_equation;
clip_equation.xyzw.x = clip_info.normal.xyz.x;
clip_equation.xyzw.y = clip_info.normal.xyz.y;
clip_equation.xyzw.z = clip_info.normal.xyz.z;
clip_equation.xyzw.w = -vm_vec_dot(&clip_info.normal, &clip_info.position);
data_out->clip_equation = clip_equation;
} else {
data_out->use_clip_plane = false;
}
}
if (shader_flags & SDR_FLAG_MODEL_LIGHT) {
int num_lights = MIN(Num_active_gr_lights, (int)graphics::MAX_UNIFORM_LIGHTS);
data_out->n_lights = num_lights;
std::copy(std::begin(gr_light_uniforms), std::end(gr_light_uniforms), std::begin(data_out->lights));
float light_factor = material.get_light_factor();
data_out->diffuseFactor.xyz.x = gr_light_color[0] * light_factor;
data_out->diffuseFactor.xyz.y = gr_light_color[1] * light_factor;
data_out->diffuseFactor.xyz.z = gr_light_color[2] * light_factor;
data_out->ambientFactor.xyz.x = gr_light_ambient[0] + gr_user_ambient;
data_out->ambientFactor.xyz.y = gr_light_ambient[1] + gr_user_ambient;
data_out->ambientFactor.xyz.z = gr_light_ambient[2] + gr_user_ambient;
CLAMP(data_out->ambientFactor.xyz.x, 0.02f, 1.0f);
CLAMP(data_out->ambientFactor.xyz.y, 0.02f, 1.0f);
CLAMP(data_out->ambientFactor.xyz.z, 0.02f, 1.0f);
if (material.get_light_factor() > 0.25f && !Cmdline_no_emissive) {
data_out->emissionFactor.xyz.x = gr_light_emission[0];
data_out->emissionFactor.xyz.y = gr_light_emission[1];
data_out->emissionFactor.xyz.z = gr_light_emission[2];
} else {
data_out->emissionFactor.xyz.x = gr_light_zero[0];
data_out->emissionFactor.xyz.y = gr_light_zero[1];
data_out->emissionFactor.xyz.z = gr_light_zero[2];
}
if (Gloss_override_set) {
data_out->defaultGloss = Gloss_override;
} else {
data_out->defaultGloss = 0.6f;
}
}
if (shader_flags & SDR_FLAG_MODEL_DIFFUSE_MAP) {
if (material.is_desaturated()) {
data_out->desaturate = 1;
} else {
data_out->desaturate = 0;
}
if (Basemap_color_override_set) {
data_out->overrideDiffuse = 1;
data_out->diffuseClr.xyz.x = Basemap_color_override[0];
data_out->diffuseClr.xyz.y = Basemap_color_override[1];
data_out->diffuseClr.xyz.z = Basemap_color_override[2];
} else {
data_out->overrideDiffuse = 0;
}
switch (material.get_blend_mode()) {
case ALPHA_BLEND_PREMULTIPLIED:
data_out->blend_alpha = 1;
break;
case ALPHA_BLEND_ADDITIVE:
data_out->blend_alpha = 2;
break;
default:
data_out->blend_alpha = 0;
break;
}
data_out->sBasemapIndex = bm_get_array_index(material.get_texture_map(TM_BASE_TYPE));
}
if (shader_flags & SDR_FLAG_MODEL_GLOW_MAP) {
if (Glowmap_color_override_set) {
data_out->overrideGlow = 1;
data_out->glowClr.xyz.x = Glowmap_color_override[0];
data_out->glowClr.xyz.y = Glowmap_color_override[1];
data_out->glowClr.xyz.z = Glowmap_color_override[2];
} else {
data_out->overrideGlow = 0;
}
data_out->sGlowmapIndex = bm_get_array_index(material.get_texture_map(TM_GLOW_TYPE));
}
if (shader_flags & SDR_FLAG_MODEL_SPEC_MAP) {
if (Specmap_color_override_set) {
data_out->overrideSpec = 1;
data_out->specClr.xyz.x = Specmap_color_override[0];
data_out->specClr.xyz.y = Specmap_color_override[1];
data_out->specClr.xyz.z = Specmap_color_override[2];
} else {
data_out->overrideSpec = 0;
}
if (material.get_texture_map(TM_SPEC_GLOSS_TYPE) > 0) {
data_out->sSpecmapIndex = bm_get_array_index(material.get_texture_map(TM_SPEC_GLOSS_TYPE));
data_out->gammaSpec = 1;
if (Gloss_override_set) {
data_out->alphaGloss = 0;
} else {
data_out->alphaGloss = 1;
}
} else {
data_out->sSpecmapIndex = bm_get_array_index(material.get_texture_map(TM_SPECULAR_TYPE));
data_out->gammaSpec = 0;
data_out->alphaGloss = 0;
}
if (shader_flags & SDR_FLAG_MODEL_ENV_MAP) {
if (material.get_texture_map(TM_SPEC_GLOSS_TYPE) > 0 || Gloss_override_set) {
data_out->envGloss = 1;
} else {
data_out->envGloss = 0;
}
data_out->envMatrix = gr_env_texture_matrix;
}
}
if ( shader_flags & SDR_FLAG_MODEL_NORMAL_MAP ) {
data_out->sNormalmapIndex = bm_get_array_index(material.get_texture_map(TM_NORMAL_TYPE));
}
if ( shader_flags & SDR_FLAG_MODEL_AMBIENT_MAP ) {
data_out->sAmbientmapIndex = bm_get_array_index(material.get_texture_map(TM_AMBIENT_TYPE));
}
if ( shader_flags & SDR_FLAG_MODEL_MISC_MAP ) {
data_out->sMiscmapIndex = bm_get_array_index(material.get_texture_map(TM_MISC_TYPE));
}
if (shader_flags & SDR_FLAG_MODEL_SHADOWS) {
data_out->shadow_mv_matrix = Shadow_view_matrix;
for (size_t i = 0; i < MAX_SHADOW_CASCADES; ++i) {
data_out->shadow_proj_matrix[i] = Shadow_proj_matrix[i];
}
data_out->veryneardist = Shadow_cascade_distances[0];
data_out->neardist = Shadow_cascade_distances[1];
data_out->middist = Shadow_cascade_distances[2];
data_out->fardist = Shadow_cascade_distances[3];
}
if (shader_flags & SDR_FLAG_MODEL_SHADOW_MAP) {
for (size_t i = 0; i < MAX_SHADOW_CASCADES; ++i) {
data_out->shadow_proj_matrix[i] = Shadow_proj_matrix[i];
}
}
if (shader_flags & SDR_FLAG_MODEL_TRANSFORM) {
data_out->buffer_matrix_offset = (int) transform_buffer_offset;
}
// Team colors are passed to the shader here, but the shader needs to handle their application.
// By default, this is handled through the r and g channels of the misc map, but this can be changed
// in the shader; test versions of this used the normal map r and b channels
if (shader_flags & SDR_FLAG_MODEL_TEAMCOLOR) {
auto& tm_clr = material.get_team_color();
vec3d stripe_color;
vec3d base_color;
stripe_color.xyz.x = tm_clr.stripe.r;
stripe_color.xyz.y = tm_clr.stripe.g;
stripe_color.xyz.z = tm_clr.stripe.b;
base_color.xyz.x = tm_clr.base.r;
base_color.xyz.y = tm_clr.base.g;
base_color.xyz.z = tm_clr.base.b;
data_out->stripe_color = stripe_color;
data_out->base_color = base_color;
data_out->team_glow_enabled = bm_has_alpha_channel(material.get_texture_map(TM_MISC_TYPE)) ? 1 : 0;
}
if (shader_flags & SDR_FLAG_MODEL_THRUSTER) {
data_out->thruster_scale = material.get_thrust_scale();
}
if (shader_flags & SDR_FLAG_MODEL_FOG) {
auto& fog_params = material.get_fog();
if (fog_params.enabled) {
data_out->fogStart = fog_params.dist_near;
data_out->fogScale = 1.0f / (fog_params.dist_far - fog_params.dist_near);
data_out->fogColor.xyzw.x = i2fl(fog_params.r) / 255.0f;
data_out->fogColor.xyzw.y = i2fl(fog_params.g) / 255.0f;
data_out->fogColor.xyzw.z = i2fl(fog_params.b) / 255.0f;
data_out->fogColor.xyzw.w = 1.0f;
}
}
if (shader_flags & SDR_FLAG_MODEL_NORMAL_ALPHA) {
data_out->normalAlphaMinMax.x = material.get_normal_alpha_min();
data_out->normalAlphaMinMax.y = material.get_normal_alpha_max();
}
if ( shader_flags & SDR_FLAG_MODEL_THICK_OUTLINES ) {
data_out->outlineWidth = material.get_outline_thickness();
}
}
}
}