调整大小 window 导致我的 2D 光照拉伸
Resizing window cause my 2D Lighting to stretch
我正在尝试实现一个简单的人工 2D 照明。我没有使用像 Phong 那样的算法。但是,我在确保 window 调整大小时不会 stretch/squeeze 时遇到一些困难。任何提示和建议将不胜感激。我已经尝试将我的半径转换为 vec2,以便我可以根据纵横比相应地缩放它们,但是它不能正常工作。另外,我知道我的代码不是最有效的,任何反馈也很感激,因为我还在学习! :D
我有一个正交投影矩阵来变换光的位置,使其位于视口中的正确位置,这固定了位置而不是半径(因为我正在计算每个片段)。我将如何根据纵横比变换半径?
void LightSystem::Update(const OrthographicCamera& camera)
{
std::vector<LightComponent> lights;
for (auto& entity : m_Entities)
{
auto& light = g_ECSManager.GetComponent<LightComponent>(entity);
auto& trans = g_ECSManager.GetComponent<TransformComponent>(entity);
if (light.lightEnabled)
{
light.pos = trans.Position;
glm::mat4 viewProjMat = camera.GetViewProjectionMatrix();
light.pos = viewProjMat * glm::vec4(light.pos, 1.f);
// Need to store all the light atrributes in an array
lights.emplace_back(light);
}
// Create a function in Render2D.cpp, pass all the arrays as a uniform variable to the shader, call this function here
glm::vec2 res{ camera.GetWidth(), camera.GetHeight() };
Renderer2D::DrawLight(lights, camera, res);
}
}
这是我的着色器:
#type fragment
#version 330 core
layout (location = 0) out vec4 color;
#define MAX_LIGHTS 10
uniform struct Light
{
vec4 colour;
vec3 position;
float radius;
float intensity;
} allLights[MAX_LIGHTS];
in vec4 v_Color;
in vec2 v_TexCoord;
in float v_TexIndex;
in float v_TilingFactor;
in vec4 fragmentPosition;
uniform sampler2D u_Textures[32];
uniform vec4 u_ambientColour;
uniform int numLights;
uniform vec2 resolution;
vec4 calculateLight(Light light)
{
float lightDistance = length(distance(fragmentPosition.xy, light.position.xy));
//float ar = resolution.x / resolution.y;
if (lightDistance >= light.radius)
{
return vec4(0, 0, 0, 1); //outside of radius make it black
}
return light.intensity * (1 - lightDistance / light.radius) * light.colour;
}
void main()
{
vec4 texColor = v_Color;
vec4 netLightColour = vec4(0, 0, 0, 1);
if (numLights == 0)
color = texColor;
else
{
for(int i = 0; i < numLights; ++i) //Loop through lights
netLightColour += calculateLight(allLights[i]) + u_ambientColour;
color = texColor * netLightColour;
}
}
您必须在顶点着色器中使用正交投影矩阵。通过投影矩阵修改剪辑space位置
或者,在计算到光源的距离时考虑纵横比:
float aspectRatio = resolution.x/resolution.y;
vec2 pos = fragmentPosition.xy * vec2(aspectRatio, 1.0);
float lightDistance = length(distance(pos.xy, light.position.xy));
我要整理我的问题的所有答案,因为我问得不好,结果一团糟。
正如其他答案所建议的那样,首先我必须使用正交投影矩阵来确保光源位置显示在视口中的正确位置。
接下来,从我进行照明的方式来看,之前的投影矩阵不会修复拉伸效果,因为我的光不是用实际顶点制作的实际圆形对象。我必须将 radius 转换为 vec2 类型,表示沿 x 轴和 y 轴的半径向量。这样我就可以根据纵横比修改向量:
if (aspectRatio > 1.0)
light.radius.x /= aspectRatio;
else
light.radius.x /= aspectRatio;
我发布了另一个问题 ,修改我的照明算法以支持椭圆形状。这使我能够在纵横比发生变化时执行所需的缩放以抵消沿 x/y 轴的拉伸。谢谢大家的回答。
我正在尝试实现一个简单的人工 2D 照明。我没有使用像 Phong 那样的算法。但是,我在确保 window 调整大小时不会 stretch/squeeze 时遇到一些困难。任何提示和建议将不胜感激。我已经尝试将我的半径转换为 vec2,以便我可以根据纵横比相应地缩放它们,但是它不能正常工作。另外,我知道我的代码不是最有效的,任何反馈也很感激,因为我还在学习! :D
我有一个正交投影矩阵来变换光的位置,使其位于视口中的正确位置,这固定了位置而不是半径(因为我正在计算每个片段)。我将如何根据纵横比变换半径?
void LightSystem::Update(const OrthographicCamera& camera)
{
std::vector<LightComponent> lights;
for (auto& entity : m_Entities)
{
auto& light = g_ECSManager.GetComponent<LightComponent>(entity);
auto& trans = g_ECSManager.GetComponent<TransformComponent>(entity);
if (light.lightEnabled)
{
light.pos = trans.Position;
glm::mat4 viewProjMat = camera.GetViewProjectionMatrix();
light.pos = viewProjMat * glm::vec4(light.pos, 1.f);
// Need to store all the light atrributes in an array
lights.emplace_back(light);
}
// Create a function in Render2D.cpp, pass all the arrays as a uniform variable to the shader, call this function here
glm::vec2 res{ camera.GetWidth(), camera.GetHeight() };
Renderer2D::DrawLight(lights, camera, res);
}
}
这是我的着色器:
#type fragment
#version 330 core
layout (location = 0) out vec4 color;
#define MAX_LIGHTS 10
uniform struct Light
{
vec4 colour;
vec3 position;
float radius;
float intensity;
} allLights[MAX_LIGHTS];
in vec4 v_Color;
in vec2 v_TexCoord;
in float v_TexIndex;
in float v_TilingFactor;
in vec4 fragmentPosition;
uniform sampler2D u_Textures[32];
uniform vec4 u_ambientColour;
uniform int numLights;
uniform vec2 resolution;
vec4 calculateLight(Light light)
{
float lightDistance = length(distance(fragmentPosition.xy, light.position.xy));
//float ar = resolution.x / resolution.y;
if (lightDistance >= light.radius)
{
return vec4(0, 0, 0, 1); //outside of radius make it black
}
return light.intensity * (1 - lightDistance / light.radius) * light.colour;
}
void main()
{
vec4 texColor = v_Color;
vec4 netLightColour = vec4(0, 0, 0, 1);
if (numLights == 0)
color = texColor;
else
{
for(int i = 0; i < numLights; ++i) //Loop through lights
netLightColour += calculateLight(allLights[i]) + u_ambientColour;
color = texColor * netLightColour;
}
}
您必须在顶点着色器中使用正交投影矩阵。通过投影矩阵修改剪辑space位置
或者,在计算到光源的距离时考虑纵横比:
float aspectRatio = resolution.x/resolution.y;
vec2 pos = fragmentPosition.xy * vec2(aspectRatio, 1.0);
float lightDistance = length(distance(pos.xy, light.position.xy));
我要整理我的问题的所有答案,因为我问得不好,结果一团糟。
正如其他答案所建议的那样,首先我必须使用正交投影矩阵来确保光源位置显示在视口中的正确位置。
接下来,从我进行照明的方式来看,之前的投影矩阵不会修复拉伸效果,因为我的光不是用实际顶点制作的实际圆形对象。我必须将 radius 转换为 vec2 类型,表示沿 x 轴和 y 轴的半径向量。这样我就可以根据纵横比修改向量:
if (aspectRatio > 1.0)
light.radius.x /= aspectRatio;
else
light.radius.x /= aspectRatio;
我发布了另一个问题