diff options
| author | bunnei <bunneidev@gmail.com> | 2015-11-25 20:49:48 -0500 | 
|---|---|---|
| committer | bunnei <bunneidev@gmail.com> | 2016-02-05 17:20:19 -0500 | 
| commit | 9dfb223d26a7d700e38a4c0eec9d32d78c42f91d (patch) | |
| tree | dcd826661707d299319483a261df469469e375ac | |
| parent | 449902b5583d6a2dbb1e4aea9802da5ad2493981 (diff) | |
gl_rasterizer: Initial implementation of bump mapping.
| -rw-r--r-- | src/video_core/pica.h | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 32 | 
3 files changed, 42 insertions, 5 deletions
| diff --git a/src/video_core/pica.h b/src/video_core/pica.h index 267070e45..809b16d2b 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -702,6 +702,12 @@ struct Regs {          LN = 3, // Cosine of the angle between the light and the normal vectors      }; +    enum class LightingBumpMode : u32 { +        None = 0, +        NormalMap = 1, +        TangentMap = 2, +    }; +      union LightColor {          BitField< 0, 10, u32> b;          BitField<10, 10, u32> g; @@ -775,7 +781,10 @@ struct Regs {          union {              BitField< 2, 2, LightingFresnelSelector> fresnel_selector;              BitField< 4, 4, LightingConfig> config; +            BitField<22, 2, u32> bump_selector; // 0: Texture 0, 1: Texture 1, 2: Texture 2              BitField<27, 1, u32> clamp_highlights; // 1: GL_TRUE, 0: GL_FALSE +            BitField<28, 2, LightingBumpMode> bump_mode; // 1: GL_TRUE, 0: GL_FALSE +            BitField<30, 1, u32> bump_renorm; // 0: GL_TRUE, 1: GL_FALSE          };          union { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 62a4d8953..d7eac5213 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -119,6 +119,9 @@ struct PicaShaderConfig {          res.lighting.config = regs.lighting.config;          res.lighting.fresnel_selector = regs.lighting.fresnel_selector; +        res.lighting.bump_mode = regs.lighting.bump_mode; +        res.lighting.bump_selector = regs.lighting.bump_selector; +        res.lighting.bump_renorm = regs.lighting.bump_renorm == 0;          res.lighting.clamp_highlights = regs.lighting.clamp_highlights != 0;          return res; @@ -153,6 +156,9 @@ struct PicaShaderConfig {              bool enable = false;              unsigned src_num = 0; +            Pica::Regs::LightingBumpMode bump_mode = Pica::Regs::LightingBumpMode::None; +            unsigned bump_selector = 0; +            bool bump_renorm = false;              bool clamp_highlights = false;              Pica::Regs::LightingConfig config = Pica::Regs::LightingConfig::Config0; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index d59f2054b..ee4b54ab9 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -326,11 +326,28 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {             "vec3 light_vector = vec3(0.0);\n"             "vec3 refl_value = vec3(0.0);\n"; -    // Convert interpolated quaternion to a GL fragment normal -    out += "vec3 normal = normalize(vec3(\n"; -    out += "          2.f*(normquat.x*normquat.z + normquat.y*normquat.w),\n"; -    out += "          2.f*(normquat.y*normquat.z + normquat.x*normquat.w),\n"; -    out += "    1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n"; +    // Compute fragment normals +    if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::NormalMap) { +        // Bump mapping is enabled using a normal map, read perturbation vector from the selected texture +        std::string bump_selector = std::to_string(config.lighting.bump_selector); +        out += "vec3 surface_normal = 2.0 * texture(tex[" + bump_selector + "], texcoord[" + bump_selector + "]).rgb - 1.0;\n"; + +        // Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher precision result +        if (config.lighting.bump_renorm) { +            std::string val = "(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))"; +            out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n"; +        } +    } else if (config.lighting.bump_mode == Pica::Regs::LightingBumpMode::TangentMap) { +        // Bump mapping is enabled using a tangent map +        LOG_CRITICAL(HW_GPU, "unimplemented bump mapping mode (tangent mapping)"); +        UNIMPLEMENTED(); +    } else { +        // No bump mapping - surface local normal is just a unit normal +        out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n"; +    } + +    // Rotate the surface-local normal by the interpolated normal quaternion to convert it to eyespace +    out += "vec3 normal = normalize(quaternion_rotate(normquat, surface_normal));\n";      // Gets the index into the specified lookup table for specular lighting      auto GetLutIndex = [config](unsigned light_num, Regs::LightingLutInput input, bool abs) { @@ -516,6 +533,11 @@ layout (std140) uniform shader_data {  uniform sampler2D tex[3];  uniform sampler1D lut[6]; +// Rotate the vector v by the quaternion q +vec3 quaternion_rotate(vec4 q, vec3 v) { +    return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); +} +  void main() {  vec4 primary_fragment_color = vec4(0.0);  vec4 secondary_fragment_color = vec4(0.0); | 
