LearnGL - 14 - MultiLight - 多光源

49 篇文章 0 订阅
4 篇文章 0 订阅


LearnGL - 学习笔记目录

前些篇:

这些演示光照计算中,分别对 方向光点光源聚光灯 类型的光源实现

这篇:我们将实现给 多光源 ,演示在场景中将摆放好 三种光源 的多个光源的效果

本人才疏学浅,如有什么错误,望不吝指出。


C++ 应用层的代码改动和核心代码


修改前

已成为历史的单光源代码:

    int Camera::render(std::vector<GameObject*>* render_vec_helper) {

        std::vector<MeshRenderer*> renderers;

        // 提取 renderers
        std::vector<GameObject*>::iterator begin = render_vec_helper->begin();
        register size_t count = render_vec_helper->size();
        int ret = 0;
        for (register size_t i = 0; i < count; i++) {
            GameObject* go = *(begin + i);
            if (!go->getActivedInherited()) continue;
            MeshRenderer* renderer = go->getComp<MeshRenderer>();
            if (renderer != NULL && renderer->getActivedInherited()) {
                renderers.push_back(renderer);
            }
        }

        // 排序 renderers
        std::sort(renderers.begin(), renderers.end(), rendererCmp);

        // 处理 renderers
        count = renderers.size();
        for (register size_t i = 0; i < count; i++) {
            MeshRenderer* renderer = renderers[i];
            Material* mat = renderer->getAttachMaterial();

            // retrive lights
            std::vector<Component*>* lights = Component::getComps<Light>();
            if (lights != NULL) {
                std::vector<Component*>::iterator begin = lights->begin();
                register size_t count = lights->size();
                // 先使用,再设置
                renderer->getAttachMaterial()->getShader()->use();


                for (size_t i = 0; i < count; i++) {
                    Light* light = (Light*)*(begin + i);
                    if (!light->getActivedInherited()) {
                        mat->getShader()->setVec4("LightPos", 0, 0, 0, 0);
                        mat->getShader()->setVec4("LightColor", 0, 0, 0, 0);
                        continue;
                    }
                    switch (light->getType())
                    {
                        // 方向光假设为平行光,就想太阳一样,超级远都一样照射着
                        // 所以不用判断
                    case LightType::Directional:
                    {
                        // light world direction
                        vec3 light_world_dir = -light->getDir();
                        mat->getShader()->setVec4("LightPos",
                            light_world_dir.x, light_world_dir.y, light_world_dir.z, 0);
                        //mat->getShader()->setVec4("LightPos",
                        //    0.0f,0.0f,1.0f, 0.0f);
                        // light color
                        mat->getShader()->setVec4("LightColor",
                            light->color.x, light->color.y, light->color.z, light->intensity);
                        break;
                    }
                    // TODO : 点光源 需要判断是否有作用交集,才设置
                    case LightType::Point:
                    {
                        // light world position
                        vec3 light_world_pos = light->getWPos();
                        mat->getShader()->setVec4("LightPos",
                            light_world_pos.x, light_world_pos.y, light_world_pos.z, 1);
                        mat->getShader()->setVec4("LightColor",
                            light->color.x, light->color.y, light->color.z, light->intensity);
                        mat->getShader()->setFloat("ATTEN_Kc", light->point_light_constantK);
                        mat->getShader()->setFloat("ATTEN_Kl", light->point_light_linearK);
                        mat->getShader()->setFloat("ATTEN_Kq", light->point_light_quadraticK);
                        mat->getShader()->setVec2("ATTEN_Range", light->point_or_spot_light_range,
                            (light->point_or_spot_light_range == 0.0f ? 0.0f : 1.0f / light->point_or_spot_light_range));
                        break;
                    }
                    // TODO : 聚光灯 需要判断是否有作用交集,才设置
                    case LightType::Spot:
                    {
                        // light world position
                        vec3 light_world_pos = light->getWPos();
                        mat->getShader()->setVec4("LightPos",
                            light_world_pos.x, light_world_pos.y, light_world_pos.z, 0.5f);
                        mat->getShader()->setVec4("LightColor",
                            light->color.x, light->color.y, light->color.z, light->intensity);
                        mat->getShader()->setFloat("ATTEN_Kc", light->point_light_constantK);
                        mat->getShader()->setFloat("ATTEN_Kl", light->point_light_linearK);
                        mat->getShader()->setFloat("ATTEN_Kq", light->point_light_quadraticK);
                        mat->getShader()->setVec2("ATTEN_Range", light->point_or_spot_light_range,
                            (light->point_or_spot_light_range == 0.0f ? 0.0f : 1.0f / light->point_or_spot_light_range));

                        vec3 light_world_dir = light->getDir();
                        mat->getShader()->setVec3("SpotLightDir",
                            light_world_dir.x, light_world_dir.y, light_world_dir.z);
                        mat->getShader()->setFloat("SpotLightFOL", D2R(light->spot_light_FOL * 0.5f));
                        if (light->fade_out_using_FOL_percent) {
                            mat->getShader()->setFloat("SpotLightFOL_FadeOut", D2R((light->spot_light_FOL * light->fade_out_FOL_percent) * 0.5f));
                        }
                        else {
                            mat->getShader()->setFloat("SpotLightFOL_FadeOut", D2R(light->spot_light_FOL_fade_out * 0.5f));
                        }
                        mat->getShader()->setFloat("SpotLightExp", light->spot_light_exp);
                        break;
                    }
                    default:
                        std::cerr << "unimplements light type : " << (int)light->getType() << "\n";
                        assert(false);
                        break;
                    }
                }
            }

            // camera pos
            vec3 wp = trans->get_world_pos();
            //vec3 wp = trans->local_position;
            mat->getShader()->setVec3("_CamWorldPos", wp.x, wp.y, wp.z);
            // projection matrix
            Camera::mesh_renderer_data_helper.proj = getProjectionMatrix();
            // view matrix
            Camera::mesh_renderer_data_helper.view = getViewMatrix();
            // camera pos
            Camera::mesh_renderer_data_helper.camWorldPos = wp;
            // render
            renderer->render(Camera::mesh_renderer_data_helper);
            ret++;
        }

        return ret;
    }

修改后

    int Camera::render(std::vector<GameObject*>* render_gos) {

        glClearColor(clearColor.x, clearColor.y, clearColor.z, clearColor.w);   // 设置清理颜色缓存时,填充的颜色值
        glClearDepthf(clearDepth);		                                        // 设置清理深度缓存时,填充的深度值
        glClear(clearFlag);				                                        // 清理颜色缓存 与 深度缓存

        std::vector<MeshRenderer*> renderers;

        // 提取 renderers
        std::vector<GameObject*>::iterator begin = render_gos->begin();
        register size_t count = render_gos->size();
        int ret = 0;
        for (register size_t i = 0; i < count; i++) {
            GameObject* go = *(begin + i);
            if (!go->getActivedInherited()) continue;
            MeshRenderer* renderer = go->getComp<MeshRenderer>();
            if (renderer != NULL && renderer->getActivedInherited()) {
                renderers.push_back(renderer);
            }
        }

        // 排序 renderers
        std::sort(renderers.begin(), renderers.end(), rendererCmp);

        // uniform 的名字缓存,128个字节应该够用了
        char uniform_name[128];
        // 灯光属性的 uniform 字符格式
        const char* uniform_format = "Lights[%d].%s";

        // 处理 renderers
        count = renderers.size();
        for (register size_t i = 0; i < count; i++) {
            MeshRenderer* renderer = renderers[i];
            Material* mat = renderer->getAttachMaterial();

            // retrive lights
            std::vector<Component*>* lights = Component::getComps<Light>();
            if (lights != NULL) {
                std::vector<Component*>::iterator begin = lights->begin();
                register size_t count = lights->size();
                // 先使用,再设置
                renderer->getAttachMaterial()->getShader()->use();

                size_t validatedLightCount = 0;
                for (size_t i = 0; i < count; i++) {
                    Light* light = (Light*)*(begin + i);
                    // 没有启用
                    if (!light->getActivedInherited()) {
                        continue;
                    }
                    switch (light->getType())
                    {
                        // 方向光假设为平行光,就想太阳一样,超级远都一样照射着
                        // 所以不用判断
                    case LightType::Directional: {
                        break;
                    }
                    case LightType::Point: {
                        // TODO : 点光源 需要判断是否有作用交集,才设置
                        break;
                    }
                    case LightType::Spot:
                    {
                        // TODO : 聚光灯 需要判断是否有作用交集,才设置
                        // 张角
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "SpotFOL");
                        mat->getShader()->setFloat(uniform_name, D2R(light->spot_light_FOL * 0.5f));

                        if (light->fade_out_using_FOL_percent) {
                            // 淡出张角角度
                            sprintf_s(uniform_name, uniform_format, validatedLightCount, "SpotFOL_FadeOut");
                            mat->getShader()->setFloat(uniform_name, D2R((light->spot_light_FOL * light->fade_out_FOL_percent) * 0.5f));
                        }
                        else {
                            // 淡出张角角度
                            sprintf_s(uniform_name, uniform_format, validatedLightCount, "SpotFOL_FadeOut");
                            mat->getShader()->setFloat(uniform_name, D2R(light->spot_light_FOL_fade_out * 0.5f));
                        }
                        break;
                    }
                    default:
                        std::cerr << "unimplements light type : " << (int)light->getType() << "\n";
                        assert(false);
                        break;
                    }

                    if (light->getType() == LightType::Directional || light->getType() == LightType::Spot) {
                        // 方向
                        vec3 light_world_dir = -light->getDir();
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "Direction");
                        mat->getShader()->setVec3(uniform_name, light_world_dir.x, light_world_dir.y, light_world_dir.z);
                    }

                    if (light->getType() == LightType::Point || light->getType() == LightType::Spot) {
                        // 坐标
                        vec3 light_world_pos = light->getWPos();
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "Position");
                        mat->getShader()->setVec3(uniform_name, light_world_pos.x, light_world_pos.y, light_world_pos.z);
                        // 常数项系数
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "ATTEN_Kc");
                        mat->getShader()->setFloat(uniform_name, light->point_light_constantK);
                        // 一次项系数
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "ATTEN_Kl");
                        mat->getShader()->setFloat(uniform_name, light->point_light_linearK);
                        // 二次项系数
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "ATTEN_Kq");
                        mat->getShader()->setFloat(uniform_name, light->point_light_quadraticK);
                        // 范围
                        sprintf_s(uniform_name, uniform_format, validatedLightCount, "ATTEN_Range");
                        mat->getShader()->setVec2(uniform_name, light->point_or_spot_light_range,
                            (light->point_or_spot_light_range == 0.0f ? 0.0f : 1.0f / light->point_or_spot_light_range));
                    }

                    // 颜色
                    sprintf_s(uniform_name, uniform_format, validatedLightCount, "Color");
                    mat->getShader()->setVec3(uniform_name, light->color.x, light->color.y, light->color.z);
                    // 强度
                    sprintf_s(uniform_name, uniform_format, validatedLightCount, "Intensity");
                    mat->getShader()->setFloat(uniform_name, light->intensity);
                    // 类型
                    sprintf_s(uniform_name, uniform_format, validatedLightCount, "Type");
                    mat->getShader()->setInt(uniform_name, (GLint)light->getType());
                    // 启用
                    sprintf_s(uniform_name, uniform_format, validatedLightCount, "Enabled");
                    mat->getShader()->setInt(uniform_name, 1);

                    validatedLightCount++;
                }
                // 如果没有满灯光数量,则给最后一个索引的设置没启用,这样 shader 判断后面灯光的都不用处理
                if (validatedLightCount < 10) {
                    sprintf_s(uniform_name, uniform_format, validatedLightCount, "Enabled");
                    mat->getShader()->setInt(uniform_name, 0);
                }
            }

            // camera pos
            vec3 wp = trans->get_world_pos();
            //vec3 wp = trans->local_position;
            mat->getShader()->setVec3("_CamWorldPos", wp.x, wp.y, wp.z);
            // projection matrix
            Camera::mesh_renderer_data_helper.proj = getProjectionMatrix();
            // view matrix
            Camera::mesh_renderer_data_helper.view = getViewMatrix();
            // camera pos
            Camera::mesh_renderer_data_helper.camWorldPos = wp;
            // render
            renderer->render(Camera::mesh_renderer_data_helper);
            ret++;
        }

        return ret;
    }

可以看到前后改动的地方就只是原来的单光源属性的 uniform 设置变成了光源数组中的 uniform 的设置

另外,我们可以看到有两个 TODO:

  • // TODO : 点光源 需要判断是否有作用交集,才设置
  • // TODO : 聚光灯 需要判断是否有作用交集,才设置

后续可以将其改为先检测光源的范围 BB 与渲染几何体的 BB (其中,BB的意思:Bounding Box包围盒)有交集后才传入该对象 shader 中来处理。

(目前我们的 Material 材质是 单个 shader 的,后续会再修改为:多个 pass ,类似 Unity 中的 ShaderLab 中的 Pass的作用)


Shader - my_lighting.glsl 核心改动


改动前

可以参考 LearnGL - 13.1 - SpotLight - 聚光灯 文章的完整 shader


改动后

// jave.lin - my_lighting.glsl - 光照模型处理

#include "/Include/my_global.glsl"

#ifndef _MY_LIGHTING__GLSL__
#define _MY_LIGHTING__GLSL__

#define DIRECTIONAL_LIGHT_TYPE 0
#define POINT_LIGHT_TYPE 1
#define SPOT_LIGHT_TYPE 2

// scene uniform
uniform vec4 _Ambient;		// .xyz 环境光颜色, .w 环境光系数
uniform int AmbientType;	// 环境光类别,[测试用]

// 材质属性 - 很多的属性可以合并到其他没有满4个分量的属性,但学习目的,为了可读性高,可以分开来
struct Material_t {
	float Glossy;			// 光滑度
	vec3 Emission;			// 自发光颜色
	vec3 DiffuseK;			// 漫反射系数
	vec3 SpecularK;			// 高光系数
};
uniform Material_t Material;

// 灯光属性 - 很多的属性可以合并到其他没有满4个分量的属性,但学习目的,为了可读性高,可以分开来
// 灯光属性也可以按类型来分为不同的材质结构体
// 但是为了编写方便,就没有分开了
struct LightData_t {
	// common properties
	int 	Enabled;		// 是否开启
	int 	Type;			// 灯光类似
	vec3 	Color;			// 灯光颜色
	float 	Intensity;		// 强度
	// directional or spot light
	vec3 	Direction;		// 方向光 或 聚光灯 照射方向
	// point or spot light
	vec3 	Position;		// 点光源 或 聚光灯 灯光世界坐标位置
	float 	ATTEN_Kc;		// 点光源 常数项系数
	float 	ATTEN_Kl;		// 点光源 一次项系数
	float 	ATTEN_Kq;		// 点光源 二次项系数
	vec2 	ATTEN_Range;	// 点光源 有效范围, .x == range, .y == 1.0 / range
	// spot light
	float 	SpotFOL; 		// 聚光灯的张角量,Field Of Light(弧度)
	float 	SpotFOL_FadeOut;// 这个边缘淡出的角度,必须小于 SpotFOL,否则没有效果
};
const uint MaxLightNum = 10;
uniform LightData_t Lights[MaxLightNum];

// ambient
vec3 getAmbient(vec3 albedo) {
	if (AmbientType == 0) 	return _Ambient.rgb * _Ambient.a;
	else 					return mix(_Ambient.rgb * _Ambient.a, albedo, _Ambient.a);
}

// point or spot light 的光距离衰减
float getDistanceAtten(float dist, LightData_t light) {		// 获取距离衰减
	// 由原来的 atten = 1 / (kc + kl * dist + kq * dist * dist) 改为只用一个 sommthstep就够了
	// smoothstep 的曲线取反,即:1 - smoothstep,结果的曲线也不错
	return 1 - smoothstep(0, light.ATTEN_Range.x, dist);
}

void phong_illumination(
    in vec3 worldNormal,
    in vec3 viewDir,
    in vec3 worldPos,
    out vec3 diffuse,
    out vec3 specular
    ) {
	for	(int i = 0; i < MaxLightNum; ++i) {
		LightData_t light = Lights[i];
		// 如何有一个没开启,则后面都没开启,这是需要应用层配合使用的规则
		if (light.Enabled == 0) break;
		// 光源的方向
		vec3 lightDir;
		// 衰减
		float atten = 1;
		// 方向光
		if (light.Type == DIRECTIONAL_LIGHT_TYPE) {
			lightDir = light.Direction;
		}
		// 点光源
		else {
			// 点光源 或是 聚光灯 都需要处理的
			lightDir = light.Position - worldPos; // 片段到光源的方向,简称:灯光方向
			float dist = length(lightDir);		// 片段到光源的距离
			lightDir *= dist == 0 ? 1 : 1.0 / dist; // 归一化
			atten = getDistanceAtten(dist, light);		// 获取距离衰减
			// 聚光灯
			if (light.Type == SPOT_LIGHT_TYPE) {
				float LdotSD = dot(lightDir, light.Direction);
				float angle = acos(LdotSD);
				if (angle < light.SpotFOL) {
					// 在 FOL 张角内
					if (angle > light.SpotFOL_FadeOut) {
						// 平滑边缘
						atten *= 1 - smoothstep(light.SpotFOL_FadeOut, light.SpotFOL, angle);
					}
				} else {
					// 不在 FOL 张角内
					atten = 0;
				}
			}
		}
		float D = max(0, dot(lightDir, worldNormal));
		diffuse += light.Color * light.Intensity * D * Material.DiffuseK * atten;
		vec3 H = normalize(lightDir + viewDir);
		float S = 0;
		if (D > 0) S = pow(max(0, dot(H, worldNormal)), Material.Glossy);
		specular += light.Color * light.Intensity * S * Material.SpecularK * atten;
	}
}

#endif

我这里的 多光源 的模型也比较的简单,就是之前的 Phong 模型的变种:
I = I a ⋅ K a + ∑ i = 0 n ( I d ⋅ K d ⋅ d o t ( N , L i ) + I s ⋅ K s ⋅ p o w ( d o t ( n o r m a l i z e ( L i + V ) , N ) , G l o s s y ) ) I=\green{I_a\cdot K_a}+\red{\sum_{i=0}^n} \blue{(}I_d\cdot K_d\cdot dot(N,L_i) + I_s\cdot K_s\cdot pow(dot(normalize(L_i + V),N),Glossy)\blue{)} I=IaKa+i=0n(IdKddot(N,Li)+IsKspow(dot(normalize(Li+V),N),Glossy))

留意到前面的 环境光 I a ⋅ K a \green{I_a\cdot K_a} IaKa 不参数叠加,之后后面的 漫反射高光 都参与了叠加,使用了一个累加和: ∑ i = 0 n \red{\sum_{i=0}^n} i=0n


注意: 在 for 循环里我们做了一些优化

// 如何有一个没开启,则后面都没开启,这是需要应用层配合使用的规则
if (light.Enabled == 0) break;

对应着上面 C++ 层改动后的:

// 如果没有满灯光数量,则给最后一个索引的设置没启用,这样 shader 判断后面灯光的都不用处理
if(validatedLightCount < 10) {
    sprintf_s(uniform_name, light_format, validatedLightCount, "Enabled");
    mat->getShader()->setInt(uniform_name, 0);
}

效果


放置多个光源

  • 一个 方向光
  • 两个 点光源
  • 两个 聚光灯

C++ 应用接口就相当简单了,接口的设计参考了 Unity 的接口(我没有 Unity 源码,只是自己更具使用 Unity 习惯来设计)

目前没去制作 场景导出导入,先将就用用:

	// load scene
	SceneMgr::inst()->loadScene(new Scene());

	mainCamera->addComp(new Camera());
	mainCamera->getComp<Transform>()->local_position = vec3(0.0f, 2.0f, 10.0f);
	mainCamera->getTrans()->set_world_pos(vec3(-10.0f, 2.0f, 12.0f));
	mainCamera->getTrans()->set_world_rot(vec3(0.0, -21.0f, 0.0f));

	GameObject* camParentGO = new GameObject("Cam parent GO");
	camParentGO->add(mainCamera);

	SceneMgr::inst()->getRoot()->add(camParentGO);

	char name[128];

	// 一个 方向光
	{
		GameObject* lightGO = new GameObject();
		sprintf_s(name, "%s##%d", "DirectionalLight", lightGO->id());
		lightGO->set_name_copy_from(name);

		Light* lightComp = new Light();
		lightGO->addComp(lightComp);
		lightComp->setType(LightType::Directional);
		lightGO->addComp(new MyLightVisual());

		lightGO->getTrans()->set_world_pos(vec3(0.0f, 1.0f, 0.0f));

		SceneMgr::inst()->getRoot()->add(lightGO);
	}

	// 两个 点光源
	{
		vec3 offset[2] = {
			vec3(0, 2.0f, 2.0f),
			vec3(0, 2.0f, 4.0f)
		};
		vec3 color[2] = {
			vec3(1.0f, 0.0f, 0.0f),
			vec3(0.0f, 1.0f, 0.0f),
		};
		for (size_t i = 0; i < 2; i++) {
			GameObject* lightGO = new GameObject();
			sprintf_s(name, "%s##%d", "PointLight", lightGO->id());
			lightGO->set_name_copy_from(name);

			Light* lightComp = new Light();
			lightGO->addComp(lightComp);
			lightComp->setType(LightType::Point);
			lightComp->color = vec4(color[i], 0.5f);
			lightGO->addComp(new MyLightVisual());

			lightGO->getTrans()->set_world_pos(offset[i]);

			SceneMgr::inst()->getRoot()->add(lightGO);
		}
	}

	// 两个 聚光灯
	{
		vec3 offset[2] = {
			vec3(-2.0f, 0.0f, 0.0f),
			vec3(-2.0f, 0.0f, 2.0f)
		};
		vec3 rotate[2] = {
			vec3(0.0, -90.0f, 0.0f),
			vec3(0.0, -60.0f, 0.0f),
		};
		vec3 color[2] = {
			vec3(1.0f, 0.0f, 1.0f),
			vec3(1.0f, 1.0f, 0.0f),
		};
		for (size_t i = 0; i < 2; i++) {
			GameObject* lightGO = new GameObject();
			sprintf_s(name, "%s##%d", "SpotLight", lightGO->id());
			lightGO->set_name_copy_from(name);

			Light* lightComp = new Light();
			lightGO->addComp(lightComp);
			lightComp->setType(LightType::Spot);
			lightComp->color = vec4(color[i], 0.5f);
			lightGO->addComp(new MyLightVisual());

			lightGO->getTrans()->set_world_pos(offset[i]);
			lightGO->getTrans()->set_world_rot(rotate[i]);

			SceneMgr::inst()->getRoot()->add(lightGO);
		}
	}

	// geometry
	{
		for (size_t i = 0; i < 10; i++) {
			// in fs
			{
				// sphere
				GameObject* temp_go = new GameObject();
				sprintf_s(name, "%s##%d", "sphere", temp_go->id());
				temp_go->set_name_copy_from(name);
				temp_go->getTrans()->local_position = vec3(0, 0, i);
				MySphere_Testing_Includes* temp_comp = new MySphere_Testing_Includes();
				temp_go->addComp(temp_comp);
				SceneMgr::inst()->getRoot()->add(temp_go);
			}

			{
				// balloon cat
				GameObject* temp_go = new GameObject();
				sprintf_s(name, "%s##%d", "Balloon cat", temp_go->id());
				temp_go->set_name_copy_from(name);
				temp_go->getTrans()->local_position = vec3(1.2f, 0, i);
				temp_go->getTrans()->local_scale = vec3(3, 3, 3);
				MyBalloonCat_Testing_Includes* temp_comp = new MyBalloonCat_Testing_Includes();
				temp_go->addComp(temp_comp);
				SceneMgr::inst()->getRoot()->add(temp_go);
			}
		}
	} // end blinn phong

效果

在这里插入图片描述

咋一看,眼花缭乱!


添加了灯光 Gizmos 显示控制

所以我们添加了一个 ImGui 的编辑选项,让选中的光源对象才显示:

	// 灯光 Gizmos 显示方式
	enum class LightVisualType {
		ShowSelected,	// 显示选中
		ShowAll,		// 实现所有
		HideAll,		// 隐藏所有

		MAX_NUM			// 枚举最大数量
	};
	struct LightVisual {
	public:
		static const char* name[(size_t)LightVisualType::MAX_NUM];
		static LightVisualType value[(size_t)LightVisualType::MAX_NUM];
	};
	const char* LightVisual::name[(size_t)LightVisualType::MAX_NUM] = {
		"ShowSelected",
		"ShowAll",
		"HideAll",
	};
	LightVisualType LightVisual::value[(size_t)LightVisualType::MAX_NUM] = {
		LightVisualType::ShowSelected,	// 显示选中
		LightVisualType::ShowAll,		// 实现所有
		LightVisualType::HideAll,		// 隐藏所有
	};

...
	void MyLightVisual::update() {
		Component::update();
		...
		switch (MyLightVisual::visualType) {
		case LightVisualType::ShowSelected: {
			renderer->setActived(getOwner()->id() == Editing_Info::hierarchy_info.obj_id);
			break;
		}
		case LightVisualType::ShowAll: {
			renderer->setActived(true);
			break;
		}
		case LightVisualType::HideAll: {
			renderer->setActived(false);
			break;
		}
		default:
			break;
		}
	}

	void MyLightVisual::imgui_content() {
		Component::imgui_content();

		ImGui::Combo("Light Gizmos ShowType", (int*)&MyLightVisual::visualType, LightVisual::name, (int)LightVisualType::MAX_NUM);
	}

对应 GIF:
在这里插入图片描述

这也是临时的方案,后续会封装 Gizmos,因为,正确的处理是会对所有 GameObject 的 Gizmos 的同样处理。


添加了渲染队列控制

因为我们的灯光可视 Gizmos 是半透明的,所以我们也封装了一些临时处理的:渲染队列
在这里插入图片描述
设置方式可以是数值,也可以是枚举值,枚举值参考了 Unity 的数值:

	enum class RenderQueueType {
		Background	= 1000,	// 天空盒子
		Gemoetry	= 2000, // 不透明几何体
		AlphaTest	= 2500, // FS 带有 discard 的
		Transprent	= 3000, // 透明的几何体
		Gizmos		= 3500, // 开发调式用的 Gizmos 绘制
		Overlay		= 4000, // UI 
	};

如果不处理渲染队列问题,我们半透明对象可能会出现融混(Blending)效果不对的问题,所以才添加了这些功能。


渲染状态

在这里插入图片描述
目前只有小部分:线框模式、面向剔除、深度测试、深度写入、融混

上面说明半透明是上图的:Blend 选项部分的内容,可以设置 Factor 与 Equation

以后还会不全所有的参数设置:如:glPolygonOffset (类似Unity ShaderLab Pass 中的 Offset[u] [m])、模板测试、等等,以后用到再添加。

所有这些渲染状态配置类的,后面会添加一章单独简述一篇。这里因为有些功能需要,而提前用到,顺便在此说明一下。


整体操作演示

在这里插入图片描述
在这里插入图片描述

References

  • 多光源 - 它里面的光照模型和我的不太一样,我的是自己在 Phong 模型上总结的变种经验模型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值