我想问一个关于我在OpenGL中的照明效果的问题。

我正在尝试添加照明,但是我认为这不好,而且我看过一些2D照明图片,它们比我的要好得多。

问题:我已经做了一个聚光灯,但是我希望它能变暗,因为它的光线范围越来越小,更像自然光,但是我不知道解决方案。

我正在使用(800,600)作为窗口大小的正交矩阵,并使用真实的x,y坐标制作网格。我将lightPos和PlayerPos发送到片段着色器,并使用顶点作为网格的宽度和高度,以便可以为每个像素生成照明。

灯光只是一个基本的圆圈,我不知道如何使它看起来更好。这是一些图片。在片段着色器中,我使用勾股定理来计算两个点之间的距离。

c++ - 如何在OpenGL中使2D照明更好-LMLPHP

c++ - 如何在OpenGL中使2D照明更好-LMLPHP

这是顶点和片段着色器

阴影着色器

#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/

10-11 23:09