mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	renderer_opengl: Initial implementation of basic specular lighting.
This commit is contained in:
		
							parent
							
								
									e34fa6365f
								
							
						
					
					
						commit
						bf89870437
					
				@ -659,6 +659,8 @@ struct Regs {
 | 
			
		||||
 | 
			
		||||
    enum class LightingLutInput {
 | 
			
		||||
        NH = 0, // Cosine of the angle between the normal and half-angle vectors
 | 
			
		||||
        VH = 1, // Cosine of the angle between the view and half-angle vectors
 | 
			
		||||
        NV = 2, // Cosine of the angle between the normal and the view vector
 | 
			
		||||
        LN = 3, // Cosine of the angle between the light and the normal vectors
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
@ -709,7 +711,11 @@ struct Regs {
 | 
			
		||||
        LightColor global_ambient; // emission + (material.ambient * lighting.ambient)
 | 
			
		||||
        INSERT_PADDING_WORDS(0x1);
 | 
			
		||||
        BitField<0, 3, u32> src_num; // number of enabled lights - 1
 | 
			
		||||
        INSERT_PADDING_WORDS(0x1);
 | 
			
		||||
 | 
			
		||||
        union {
 | 
			
		||||
            BitField< 4, 4, u32> config;
 | 
			
		||||
            BitField<27, 1, u32> clamp_highlights;
 | 
			
		||||
        } light_env;
 | 
			
		||||
 | 
			
		||||
        union {
 | 
			
		||||
            // Each bit specifies whether distance attenuation should be applied for the
 | 
			
		||||
 | 
			
		||||
@ -297,6 +297,58 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
 | 
			
		||||
        SyncCombinerColor();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    // Fragment lighting specular 0 color
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_0, 0x140 + 0 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(0);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_0, 0x140 + 1 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(1);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_0, 0x140 + 2 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(2);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_0, 0x140 + 3 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(3);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_0, 0x140 + 4 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(4);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_0, 0x140 + 5 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(5);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_0, 0x140 + 6 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(6);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_0, 0x140 + 7 * 0x10):
 | 
			
		||||
        SyncLightSpecular0(7);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    // Fragment lighting specular 1 color
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[0].specular_1, 0x141 + 0 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(0);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[1].specular_1, 0x141 + 1 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(1);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[2].specular_1, 0x141 + 2 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(2);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[3].specular_1, 0x141 + 3 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(3);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[4].specular_1, 0x141 + 4 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(4);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[5].specular_1, 0x141 + 5 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(5);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[6].specular_1, 0x141 + 6 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(6);
 | 
			
		||||
        break;
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[7].specular_1, 0x141 + 7 * 0x10):
 | 
			
		||||
        SyncLightSpecular1(7);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    // Fragment lighting diffuse color
 | 
			
		||||
    case PICA_REG_INDEX_WORKAROUND(lighting.light[0].diffuse, 0x142 + 0 * 0x10):
 | 
			
		||||
        SyncLightDiffuse(0);
 | 
			
		||||
@ -835,6 +887,22 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncLightSpecular0(int light_index) {
 | 
			
		||||
    auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_0);
 | 
			
		||||
    if (color != uniform_block_data.data.light_src[light_index].specular_0) {
 | 
			
		||||
        uniform_block_data.data.light_src[light_index].specular_0 = color;
 | 
			
		||||
        uniform_block_data.dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncLightSpecular1(int light_index) {
 | 
			
		||||
    auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].specular_1);
 | 
			
		||||
    if (color != uniform_block_data.data.light_src[light_index].specular_1) {
 | 
			
		||||
        uniform_block_data.data.light_src[light_index].specular_1 = color;
 | 
			
		||||
        uniform_block_data.dirty = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncLightDiffuse(int light_index) {
 | 
			
		||||
    auto color = PicaToGL::LightColor(Pica::g_state.regs.lighting.light[light_index].diffuse);
 | 
			
		||||
    if (color != uniform_block_data.data.light_src[light_index].diffuse) {
 | 
			
		||||
 | 
			
		||||
@ -87,6 +87,10 @@ struct PicaShaderConfig {
 | 
			
		||||
            res.light_src[light_index].dist_atten_scale = Pica::float20::FromRawFloat20(light.dist_atten_scale).ToFloat32();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        res.lighting_lut.d0_abs = (regs.lighting.abs_lut_input.d0 == 0);
 | 
			
		||||
        res.lighting_lut.d0_type = (Pica::Regs::LightingLutInput)regs.lighting.lut_input.d0.Value();
 | 
			
		||||
        res.clamp_highlights = regs.lighting.light_env.clamp_highlights;
 | 
			
		||||
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -118,6 +122,12 @@ struct PicaShaderConfig {
 | 
			
		||||
 | 
			
		||||
        bool lighting_enabled = false;
 | 
			
		||||
        unsigned num_lights = 0;
 | 
			
		||||
        bool clamp_highlights = false;
 | 
			
		||||
 | 
			
		||||
        struct {
 | 
			
		||||
            bool d0_abs = false;
 | 
			
		||||
            Pica::Regs::LightingLutInput d0_type = Pica::Regs::LightingLutInput::NH;
 | 
			
		||||
        } lighting_lut;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -231,6 +241,10 @@ private:
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct LightSrc {
 | 
			
		||||
        std::array<GLfloat, 3> specular_0;
 | 
			
		||||
        INSERT_PADDING_WORDS(1);
 | 
			
		||||
        std::array<GLfloat, 3> specular_1;
 | 
			
		||||
        INSERT_PADDING_WORDS(1);
 | 
			
		||||
        std::array<GLfloat, 3> diffuse;
 | 
			
		||||
        INSERT_PADDING_WORDS(1);
 | 
			
		||||
        std::array<GLfloat, 3> ambient;
 | 
			
		||||
@ -316,6 +330,12 @@ private:
 | 
			
		||||
    /// Syncs the specified light's position to match the PICA register
 | 
			
		||||
    void SyncLightPosition(int light_index);
 | 
			
		||||
 | 
			
		||||
    /// Syncs the specified light's specular 0 color to match the PICA register
 | 
			
		||||
    void SyncLightSpecular0(int light_index);
 | 
			
		||||
 | 
			
		||||
    /// Syncs the specified light's specular 1 color to match the PICA register
 | 
			
		||||
    void SyncLightSpecular1(int light_index);
 | 
			
		||||
 | 
			
		||||
    /// Syncs the remaining OpenGL drawing state to match the current PICA state
 | 
			
		||||
    void SyncDrawState();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,8 +35,7 @@ static void AppendSource(std::string& out, TevStageConfig::Source source,
 | 
			
		||||
        out += "primary_fragment_color";
 | 
			
		||||
        break;
 | 
			
		||||
    case Source::SecondaryFragmentColor:
 | 
			
		||||
        // HACK: Until we implement fragment lighting, use zero
 | 
			
		||||
        out += "vec4(0.0)";
 | 
			
		||||
        out += "secondary_fragment_color";
 | 
			
		||||
        break;
 | 
			
		||||
    case Source::Texture0:
 | 
			
		||||
        out += "texture(tex[0], texcoord[0])";
 | 
			
		||||
@ -334,6 +333,8 @@ in vec3 view;
 | 
			
		||||
out vec4 color;
 | 
			
		||||
 | 
			
		||||
struct LightSrc {
 | 
			
		||||
    vec3 specular_0;
 | 
			
		||||
    vec3 specular_1;
 | 
			
		||||
    vec3 diffuse;
 | 
			
		||||
    vec3 ambient;
 | 
			
		||||
    vec3 position;
 | 
			
		||||
@ -358,6 +359,7 @@ uniform sampler2D tex[3];
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
vec4 primary_fragment_color = vec4(0.0);
 | 
			
		||||
vec4 secondary_fragment_color = vec4(0.0);
 | 
			
		||||
)";
 | 
			
		||||
 | 
			
		||||
    if (config.lighting_enabled) {
 | 
			
		||||
@ -367,41 +369,97 @@ vec4 primary_fragment_color = vec4(0.0);
 | 
			
		||||
        out += "    1.f - 2.f*(normquat.x*normquat.x + normquat.y*normquat.y)));\n";
 | 
			
		||||
        out += "vec4 secondary_color = vec4(0.0);\n";
 | 
			
		||||
        out += "vec3 diffuse_sum = vec3(0.0);\n";
 | 
			
		||||
        out += "vec3 specular_sum = vec3(0.0);\n";
 | 
			
		||||
        out += "vec3 fragment_position = -view;\n";
 | 
			
		||||
        out += "vec3 light_vector = vec3(0.0);\n";
 | 
			
		||||
        out += "float dist_atten = 1.0;\n";
 | 
			
		||||
 | 
			
		||||
        // Gets the index into the specified lookup table for specular lighting
 | 
			
		||||
        auto GetLutIndex = [&](unsigned light_num, Regs::LightingLutInput input, bool abs) {
 | 
			
		||||
            const std::string half_angle = "normalize(view + light_vector)";
 | 
			
		||||
            std::string index;
 | 
			
		||||
            switch (input) {
 | 
			
		||||
            case Regs::LightingLutInput::NH:
 | 
			
		||||
                index  = "dot(normal, " + half_angle + ")";
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case Regs::LightingLutInput::VH:
 | 
			
		||||
                index = std::string("dot(view, " + half_angle + ")");
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case Regs::LightingLutInput::NV:
 | 
			
		||||
                index = std::string("dot(normal, view)");
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case Regs::LightingLutInput::LN:
 | 
			
		||||
                index  = std::string("dot(light_vector, normal)");
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                LOG_CRITICAL(HW_GPU, "Unknown lighting LUT input %d\n", (int)input);
 | 
			
		||||
                UNIMPLEMENTED();
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (abs) {
 | 
			
		||||
                // In the range of [ 0.f, 1.f]
 | 
			
		||||
                index = config.light_src[light_num].two_sided_diffuse ? "abs(" + index + ")" : "max(" + index + ", 0.f)";
 | 
			
		||||
                return "clamp(int(" + index + " * 256.0), 0, 255)";
 | 
			
		||||
            } else {
 | 
			
		||||
                // In the range of [-1.f, 1.f]
 | 
			
		||||
                index = "clamp(" + index + ", -1.0, 1.0)";
 | 
			
		||||
                return std::string("uint(int(" + index + " * 127.f) & 0xff)");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return std::string();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        for (unsigned light_index = 0; light_index < config.num_lights; ++light_index) {
 | 
			
		||||
            unsigned num = config.light_src[light_index].num;
 | 
			
		||||
            std::string light_src = "light_src[" + std::to_string(num) + "]";
 | 
			
		||||
 | 
			
		||||
            std::string light_vector;
 | 
			
		||||
            if (config.light_src[light_index].directional)
 | 
			
		||||
                light_vector = "normalize(-" + light_src + ".position)";
 | 
			
		||||
                out += "light_vector = normalize(-" + light_src + ".position);\n";
 | 
			
		||||
            else
 | 
			
		||||
                light_vector = "normalize(" + light_src + ".position - fragment_position)";
 | 
			
		||||
                out += "light_vector = normalize(" + light_src + ".position - fragment_position);\n";
 | 
			
		||||
 | 
			
		||||
            std::string dot_product;
 | 
			
		||||
            if (config.light_src[light_index].two_sided_diffuse)
 | 
			
		||||
                dot_product = "abs(dot(" + light_vector + ", normal))";
 | 
			
		||||
                dot_product = "abs(dot(light_vector, normal))";
 | 
			
		||||
            else
 | 
			
		||||
                dot_product = "max(dot(" + light_vector + ", normal), 0.0)";
 | 
			
		||||
                dot_product = "max(dot(light_vector, normal), 0.0)";
 | 
			
		||||
 | 
			
		||||
            std::string dist_atten = "1.0";
 | 
			
		||||
            // Compute distance attenuation value
 | 
			
		||||
            out += "dist_atten = 1.0;\n";
 | 
			
		||||
            if (config.light_src[light_index].dist_atten_enabled) {
 | 
			
		||||
                std::string scale = std::to_string(config.light_src[light_index].dist_atten_scale);
 | 
			
		||||
                std::string bias = std::to_string(config.light_src[light_index].dist_atten_bias);
 | 
			
		||||
                std::string lut_index = "(" + scale + " * length(fragment_position - " + light_src + ".position) + " + bias + ")";
 | 
			
		||||
                std::string clamped_lut_index = "((clamp(int(" + lut_index + " * 256.0), 0, 255)))";
 | 
			
		||||
 | 
			
		||||
                unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num);
 | 
			
		||||
 | 
			
		||||
                dist_atten = "lighting_lut_" + std::to_string(lut_num /4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]";
 | 
			
		||||
                const unsigned lut_num = ((unsigned)Regs::LightingSampler::DistanceAttenuation + num);
 | 
			
		||||
                out += "dist_atten = lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "];\n";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * " + dist_atten + ";\n";
 | 
			
		||||
            // Compute primary fragment color (diffuse lighting) function
 | 
			
		||||
            out += "diffuse_sum += ((light_src[" + std::to_string(num) + "].diffuse * " + dot_product + ") + light_src[" + std::to_string(num) + "].ambient) * dist_atten;\n";
 | 
			
		||||
 | 
			
		||||
            // Compute secondary fragment color (specular lighting) function
 | 
			
		||||
            std::string clamped_lut_index = GetLutIndex(num, config.lighting_lut.d0_type, config.lighting_lut.d0_abs);
 | 
			
		||||
            const unsigned lut_num = (unsigned)Regs::LightingSampler::Distribution0;
 | 
			
		||||
            std::string lut_lookup = "lighting_lut_" + std::to_string(lut_num / 4) + "[" + clamped_lut_index + "][" + std::to_string(lut_num & 3) + "]";
 | 
			
		||||
 | 
			
		||||
            out += "specular_sum += (" + lut_lookup + " * light_src[" + std::to_string(num) + "].specular_0 * dist_atten);\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        out += "float clamp_highlights = 1.0;\n";
 | 
			
		||||
        if (config.clamp_highlights) {
 | 
			
		||||
            out += "if (dot(light_vector, normal) <= 0.0) clamp_highlights = 0.0;\n";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        out += "diffuse_sum += lighting_global_ambient;\n";
 | 
			
		||||
        out += "primary_fragment_color = vec4(clamp(diffuse_sum, vec3(0.0), vec3(1.0)), 1.0);\n";
 | 
			
		||||
        out += "secondary_fragment_color = vec4(clamp(clamp_highlights * specular_sum, vec3(0.0), vec3(1.0)), 1.0);\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user