我想问一个关于我在OpenGL中的照明效果的问题。
我正在尝试添加照明,但是我认为这不好,而且我看过一些2D照明图片,它们比我的要好得多。
问题:我已经做了一个聚光灯,但是我希望它能变暗,因为它的光线范围越来越小,更像自然光,但是我不知道解决方案。
我正在使用(800,600)作为窗口大小的正交矩阵,并使用真实的x,y坐标制作网格。我将lightPos和PlayerPos发送到片段着色器,并使用顶点作为网格的宽度和高度,以便可以为每个像素生成照明。
灯光只是一个基本的圆圈,我不知道如何使它看起来更好。这是一些图片。在片段着色器中,我使用勾股定理来计算两个点之间的距离。
这是顶点和片段着色器
阴影着色器
#version 330
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 tCoord;
uniform mat4 mat;
out vec2 tCoord0;
out vec2 vPos;
void main(){
tCoord0 = vec2(tCoord.x, 1 - tCoord.y);
gl_Position = mat * vec4(pos, 1.0);
vPos = vec2(pos.x, pos.y);
}
片段着色器
#version 330
out vec4 color;
uniform sampler2D sampler;
in vec2 tCoord0;
uniform vec3 objColor;
uniform vec2 lightPos;
uniform vec2 xyPos;
in vec2 vPos;
void main(){
vec4 textureColor = texture2D(sampler, tCoord0);
vec3 ambientLight = vec3(0.3f, 0.3f, 0.3f);
float dx = lightPos.x - (xyPos.x + vPos.x);
float dy = lightPos.y - (xyPos.y + vPos.y);
float dist = sqrt(dx * dx + dy * dy);
if(dist > 0 && dist < 50){
ambientLight = vec3(0.7f, 0.7f, 0.7f) * 0.6f;
}
else if(dist > 50 && dist < 70){
ambientLight = vec3(0.4f, 0.4f, 0.4f) * 0.6f;
}
else{
discard;
}
if((textureColor.x == 0 && textureColor.y == 0 && textureColor.z == 0) || textureColor.a <= 0){
color = vec4(objColor, 1.0) * vec4(ambientLight, 1.0);
}
else{
color = textureColor * vec4(ambientLight, 1.0) * vec4(objColor, 1.0);
}
}
抽屉.cpp
#include <graphics\shader.h>
#include <graphics\texture.h>
#include <graphics\shape.h>
#include <GL\glew.h>
#include <graphics\light.h>
#include <core\TSAContainer.h>
#include <core\drawer.h>
namespace GE{
namespace core{
std::vector<graphics::GraphicComponent*> Drawer::drawables;
GLuint Drawer::buffer;
void Drawer::init(){
glGenFramebuffers(1, &buffer);
}
std::vector<graphics::GraphicComponent*>& Drawer::getAllGraphicComponents(){
return drawables;
}
void Drawer::addDrawable(graphics::GraphicComponent* drawable){
drawables.push_back(drawable);
}
void Drawer::destroy(){
for (unsigned int i = 0; i < drawables.size(); i++)
delete drawables[i];
drawables.clear();
}
void Drawer::render(){
for (std::vector<graphics::GraphicComponent*>::iterator it = drawables.begin(); it != drawables.end(); it++){
if ((*it)->isDraw()){
(*it)->getShader().bind();
int color = getColor(static_cast<graphics::Shape*>(*it)->getColor());
int r = (color >> 16) & 0xff;
int g = (color >> 8) & 0xff;
int b = (color)& 0xff;
(*it)->getShader().setUniform("mat", (*it)->getTransformation().getTransformationMatrix());
(*it)->getShader().setUniform("objColor", r, g, b);
(*it)->getShader().setUniform("xyPos", (*it)->getTransformation().getPosition());
(*it)->getShader().setUniform("sampler", 1);
if (static_cast<graphics::Shape*>(*it)->getLight() != NULL){
static_cast<graphics::Shape*>(*it)->getLight()->update();
}
//(*it)->getShader().setUniform("ambientLight", static_cast<graphics::Shape*>(*it)->getAmbientLight());
glActiveTexture(GL_TEXTURE1);
if ((*it)->getTexture() != NULL)
(*it)->getTexture()->bind();
(*it)->getMesh().draw();
if ((*it)->getTexture() != NULL)
(*it)->getTexture()->unbind();
(*it)->getShader().unbind();
}
}
}
int Drawer::getColor(colorType color){
int col = 0;
if (color == GE_COLOR_BLUE){
col = 0 << 16 | 0 << 8 | 1;
}
else if (GE_COLOR_GREEN == color){
col = 0 << 16 | 1 << 8 | 0;
}
else if (GE_COLOR_RED == color){
col = 1 << 16 | 0 << 8 | 0;
}
else{
col = 1 << 16 | 1 << 8 | 1;
}
return col;
}
Drawer::Drawer(){
}
Drawer::~Drawer(){
}
}
}
最佳答案
float dx = lightPos.x - (xyPos.x + vPos.x);
float dy = lightPos.y - (xyPos.y + vPos.y);
float dist = sqrt(dx * dx + dy * dy);
if(dist > 0 && dist < 50)
{
ambientLight = vec3(0.7f, 0.7f, 0.7f) * 0.6f;
}
else if(dist > 50 && dist < 70)
{
ambientLight = vec3(0.4f, 0.4f, 0.4f) * 0.6f;
}
在这里,您使用一种基于距离的恒定衰减。这将使明亮的内圈和暗淡的外圈之间具有不自然的硬边效果。
如果要使用柔和的渐变效果,则要避免此处的分支和常量。我们可以从线性衰减开始:
float dx = lightPos.x - (xyPos.x + vPos.x);
float dy = lightPos.y - (xyPos.y + vPos.y);
float dist = sqrt(dx * dx + dy * dy);
float max_dist = 70.0f;
float percent = clamp(1.0f - dist / max_dist, 0.0, 1.0f);
ambientLight = vec3(percent, percent, percent);
但是,在中心周围有一个尖点,这对您来说可能看起来很难看。我们可以改为使用指数曲线,如下所示:
...
percent *= percent;
ambientLight = vec3(percent, percent, percent);
为了使它更“全面”,您可以再次相乘:
...
percent *= percent * percent;
ambientLight = vec3(percent, percent, percent);
如果这与您在视觉上想要的相反,则可以尝试
sqrt
:float percent = clamp(1.0f - dist / max_dist, 0.0, 1.0f);
percent = sqrt(percent);
由于我从视觉上无法确切地知道您要做什么,因此这些是最初需要尝试的一些方法。玩这两个,看看你是否喜欢得到的东西。
如果您真的想最大程度地控制效果,三次贝塞尔曲线插值可能会派上用场:
float bezier4(float p1, float p2, float p3, float p4, float t)
{
const float mum1 = 1.0f - t;
const float mum13 = mum1 * mum1 * mum1;
const float mu3 = t * t * t;
return mum13 * p1 + 3 * t * mum1 * mum1 * p2 + 3 * t * t * mum1 * p3 + mu3 * p4;
}
...
float percent = clamp(1.0f - dist / max_dist, 0.0, 1.0f);
// Can play with the first four arguments to achieve the desired effect.
percent = bezier4(0.0f, 0.25f, 0.75f, 1.0f, percent);
ambientLight = vec3(percent, percent, percent);
这将使您对效果有很多控制权,但可能会导致过大杀伤力。首先尝试其他方法。
关于c++ - 如何在OpenGL中使2D照明更好,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33972699/