OpenGL的基础光照和计算

OpenGL学习笔记:基础光照 #include <glad/glad.h> #include <GLFW/glfw3.h> #include <iostream> #include <windows.h> #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include <glm/glm.hpp> ... 阅读详情

1. 简介

OpenGL的光照是开启真实世界的一扇窗,由于光照的引入可以带来更大的真实场景模拟,更加强烈的视觉冲击。

2. 光的本质

我们日常说的光实际上是狭义上的可见光,广义上的光范围更广,包括了人眼不可见的红外、紫外等,光实际是一种电磁波,电磁波图如下所示
这里写图片描述

3. 颜色

说完了光,我们再说说颜色。现实世界中有无数种颜色,每个物体都有它自己的颜色。在计算机中我们只能通过数字模拟出有限种的颜色,尽管如此,对于人眼来说这种模拟已经足够了。因为数字世界模拟出的颜色种类已经远远超过人眼的辨识极限了。在数字世界中我们通过红、绿、蓝(也称为三原色),通过RGB的不同取值可以模拟出几乎所有的颜色。

我们经常说一个物体是什么颜色的,但是实际上物体真正并没有那种颜色,真实情况是物体反射的颜色。物体不接受的颜色成分恰恰是它所表现的颜色。如,太阳光被认为是由许多不同的颜色组合成的白色光。如果我们将白光照在一个蓝色的玩具上,这个蓝色的玩具会吸收白光中除了蓝色以外的所有颜色,不被吸收的蓝色光被反射到我们的眼中,使我们看到了一个蓝色的玩具。
下图显示的是一个珊瑚红的玩具,它以不同强度的方式反射了几种不同的颜色。
反射颜色
白色的阳光是一种所有可见颜色的集合,上面的物体吸收了其中的大部分颜色,它仅反射了那些代表这个物体颜色的部分,这些被反射颜色的组合就是我们感知到的颜色(此例中为珊瑚红)。

3.1 未开启光照的情形

在我们开始讲光照之前,先了解一下未开启光照的情况。默认情况下OpenGL并没有开启光照,当我们使用glColor函数设置绘制颜色的时候,我们实际上指定的是物体的最终渲染的颜色。示例程序如下:

//Legecy Code:
#pragma comment(lib, "glew32.lib")
#pragma comment(lib, "freeglut.lib")

#include <stdio.h>
#include <gl/glew.h>
#include <gl/glut.h>
#include <iostream>

int windowWidth = 0;
int windowHeight = 0;

bool leftMouseDown = false;
float mouseX, mouseY;
float cameraAngleX, cameraAngleY;
float xRot, yRot;

void drawCube()
{
    // Draw six quads
    glBegin(GL_QUADS);
    // Front Face
    // White
    glColor3ub((GLubyte)255, (GLubyte)255, (GLubyte)255);
    glVertex3f(1.0f, 1.0f, 1.0f);

    // Yellow
    glColor3ub((GLubyte)255, (GLubyte)255, (GLubyte)0);
    glVertex3f(1.0f, -1.0f, 1.0f);

    // Red
    glColor3ub((GLubyte)255, (GLubyte)0, (GLubyte)0);
    glVertex3f(-1.0f, -1.0f, 1.0f);

    // Magenta
    glColor3ub((GLubyte)255, (GLubyte)0, (GLubyte)255);
    glVertex3f(-1.0f, 1.0f, 1.0f);

    // Back Face
    // Cyan
    glColor3f(0.0f, 1.0f, 1.0f);
    glVertex3f(1.0f, 1.0f, -1.0f);

    // Green
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, -1.0f, -1.0f);

    // Black
    glColor3f(0.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, -1.0f);

    // Blue
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 1.0f, -1.0f);

    // Top Face
    // Cyan
    glColor3f(0.0f, 1.0f, 1.0f);
    glVertex3f(1.0f, 1.0f, -1.0f);

    // White
    glColor3f(1.0f, 1.0f, 1.0f);
    glVertex3f(1.0f, 1.0f, 1.0f);

    // Magenta
    glColor3f(1.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 1.0f, 1.0f);

    // Blue
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 1.0f, -1.0f);

    // Bottom Face
    // Green
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, -1.0f, -1.0f);

    // Yellow
    glColor3f(1.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, -1.0f, 1.0f);

    // Red
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 1.0f);

    // Black
    glColor3f(0.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, -1.0f);

    // Left face
    // White
    glColor3f(1.0f, 1.0f, 1.0f);
    glVertex3f(1.0f, 1.0f, 1.0f);

    // Cyan
    glColor3f(0.0f, 1.0f, 1.0f);
    glVertex3f(1.0f, 1.0f, -1.0f);

    // Green
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, -1.0f, -1.0f);

    // Yellow
    glColor3f(1.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, -1.0f, 1.0f);

    // Right face
    // Magenta
    glColor3f(1.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 1.0f, 1.0f);

    // Blue
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 1.0f, -1.0f);

    // Black
    glColor3f(0.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, -1.0f);

    // Red
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -1.0f, 1.0f);
    glEnd();
}


void SetupRC()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glEnable(GL_DEPTH_TEST);
}

void RenderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslated(0, 0, -5);
    glRotated(cameraAngleY*0.5, 1, 0, 0);
    glRotated(cameraAngleX*0.5, 0, 1, 0);
    drawCube();

    glutSwapBuffers();
}


void ChangeSize(int w, int h)
{
    windowWidth = w;
    windowHeight = h;

    if (h == 0)
        h = 1;
    glViewport(0, 0, w, h);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, w*1.0 / h, 0.01, 1000.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}


void MouseFuncCB(int button, int state, int x, int y)
{
    mouseX = x;
    mouseY = y;

    if (button == GLUT_LEFT_BUTTON)
    {
        if (state == GLUT_DOWN)
        {
            leftMouseDown = true;
        }
        else if (state == GLUT_UP)
        {
            leftMouseDown = false;
        }
    }

}

void MouseMotionFuncCB(int x, int y)
{
    if (leftMouseDown)
    {
        cameraAngleX += (x - mouseX);
        cameraAngleY += (y - mouseY);

        mouseX = x;
        mouseY = y;
    }

    glutPostRedisplay();
}


int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
    glutCreateWindow("OpenGL");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutMouseFunc(MouseFuncCB);
    glutMotionFunc(MouseMotionFuncCB);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();

    glutMainLoop();
    return 0;
}

程序中通过使用glColor系列函数指定渲染最后呈现的颜色,运行结果如下:
ColorCube

我们通过指定每一个顶点的不同颜色,最终得到了上图所示的效果。现在有一个问题是:我们指定的只有顶点的颜色,那两个顶点间的颜色是怎么计算的呢?OpenGL通过设置着色模式来达到计算指定顶点间颜色的插值。设置函数

glShaderMode(GLenum     mode)
mode:设置模式,取值有GL_SMOOTH和GL_FLAT两种

SMOOTH插值使用的是一种线性的插值方式,如下图所示:
SMOOTH
vertex1和vertex2之间点的颜色是两者颜色的线性插值。
FLAT模式仅仅使用所绘制几何图元最后一点的颜色来给图元内部着色(Polygon是使用第一个点的颜色为内部着色)

3.2 开启光照的情形

如果仅仅使用不开启光照时候的情形,我们很难模拟真实的场景颜色。因为真实场景的颜色变幻莫测,不使用光照的模式使用的线性插值不可能模拟真实的场景。那么究竟应该怎么模拟呢?其实这是一个开放性的问题,每个人都可以有自己的模拟方式,都可以提出自己的算法(但是如果使用固定管线LegacyOpenGL,你难以实现自己所想,对于可编程的OpenGL,你可以大胆用自己的方式来实现光照的效果)。OpenGL有自己的一套模拟方式,称为Phong lighting model,这种模拟方式将光分成了三个成分:环境光(ambient)、散射光(diffuse)和镜面光(specular),如下图所示:
光照模型

3.2.1 三种光成分介绍
  1. 环境光:环境光不来自任何特定的方向,它来自某个光源,但是光线却是在场景中四处反射,没有方向可言。环境光照射的物体表面都是均匀照亮的。
  2. 散射光:散射光具有方向性,来自于一个特定的方向。它根据入射光线的角度在表面均匀地反射开来。因此,如果光线直接指向物体表面,它看上去更明亮一些。如果光线是从一个较大的角度照射到物体表面,那么它看上去显得暗一些。
  3. 镜面光:和散射光一样,镜面光也具有很强的方向性,但是它的反射角度很锐利,只有沿着一个特定的方向反射。高强度的镜面光倾向于在它照射物体的表面形成一个亮点。由于高度方向性的特点,能否被看到取决于观察者的位置。
3.2.2 物体的材质

在OpenGL中开启光照时,我们通过各种OpenGL的函数调用可以设定光的成分。当进行光照计算的时候,还需要指定物体的“颜色”。通过上面的介绍,读者可以知道物体的“颜色”是由它所反射的光来定义的。一个蓝色的球反射了光中大部分蓝色的光子,并吸收其他光子。如果照射光并不包含蓝色成分,那么这个蓝色的球在观察者眼中呈现黑色。
OpenGL光照计算的时候也是使用这么一种设定,我们并不把物体描述为具有一种特定的颜色,而是认为它由一些具有某种反射属性的材料所组成。在指定反射属性的时候,我们同样也指定这种材料对于环境光、散射光以及镜面光的反射属性。(正好和入射光的三种成分相对应)。

4. OpenGL光照API

下文我们分析OpenGL中怎么使用光照的API来得到光照的效果,分成两部分介绍。

4.1 Legecy OpenGL 光照

在Legecy OpenGL中光照计算需要通过设置光的成分以及物体的材质来完成,包括如下的API

光照计算函数描述
glEanble(GL_LIGHTING)开启光照计算(默认情况下OpenGL关闭光照计算)
glDisable(GL_LIGHTING)关闭光照计算
glLightModel设置光照模型
glLight设置光的参数
glMaterial设置物体材质
glColorMaterial设置物体材质
glNormal设置光照计算中物体表面的法线

上文中的代码演示了一个使用glColor指定颜色的立方体,并没有开启光照。当我们开启光照之后(只需要在SetupRC函数中添加一句代码glEnable(GL_LIGHTING);),可以发现场景完全变了,运行之后如下图所示:
WithoutLighting
这是由于当开启光照计算之后,glColor指定的颜色并没有任何作用。物体的颜色是通过计算光照计算来完成的。之所以会出现暗灰色,是因为当前场景中存在这一个默认的微弱的环境光,可以通过修改glLightModel修改它。

float globalAmbient[4] = { 0.5, 0.5, 0.5, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globalAmbient);

通过修改之后物体显得更亮了一些。当我们仅仅开启了光照计算并没有做任何设置的时候,OpenGL事实上使用了默认的设置。这个时候我们几何体的材质的环境光反射RGBA值是(0.2,0.2,0.2,1.0),由于不存在其他光的成分,因此其他的材质特性不起作用。(参与计算的是光的环境光成分和物体的环境光反射成分)

4.2 Core Profile中 光照的计算公式

4.2.1 环境光计算公式

环境光的计算相对简单,由于环境光对几何体的每个顶点的影响都是一样的。它仅仅将光源的环境光成分与材质的环境光成分相乘后叠加即可:计算的伪代码如下

光(R,G,B) x 材质(R',G',B') = (RxR', GxG', BxB')

4.2.2 散射光计算公式

当开启光照之后,指定几何体的散射材质,那么计算公式如下:
散射光 x 散射材质 = 散射的颜色
当散射光照射物体表面的时候,物体表面呈现的亮度与光线的入射角有很大的关系,如下图所示:
AoI
关于入射角的解释:
入射角
也就是说入射角为0时,物体表面最亮,入射角为90度是,物体表面最暗。
如果我们以一个值来定义亮度,0.0是最暗,1.0是最亮。那么可以简单的定义亮度由入射角的余弦值来表示。
入射角
计算两个角的余弦值只需要获得两个向量单位化之后进行点乘就可以了。
也就是说,为了计算散射光,我们需要获取两个向量
1. 顶点的法线向量
2. 光线照射到顶点的方向
在OpenGL中使用点的法线这种方式可能有些奇怪,因为按照数学上来说,点并没有发现,只有面才有法线。对于顶点的法线,一般来说我们需要提供一个顶点法线数组作为顶点的属性的输入数据。另外也可以通过计算面个法线,并把该法线作为所有组成面点的法线。(OpenGL中有时候为了做一些特殊的效果,常常会人为让一个平整表面的法线不一致,这些都不在本文讨论的范围之内,日后再表),法线坐标一般也是在物体的局部坐标下指定的。因为光线方向在相机坐标系下计算,因此法线也必须转换到相机坐标系下。法线的转换需要乘以法线转换矩阵(Normal Matrix),这个矩阵是模型视图矩阵的左上角3x3矩阵的逆的转置,具体的推导过程可以参考:OpenGL Normal Vector Transformation

另一个需要计算的是光源到顶点的方向,一般来说光源的位置是我们在程序中指定的,那么另一个位置是顶点的位置,顶点一般指定的是局部坐标下的位置(法线也是局部坐标下的法线方向)。在OpenGL固定管线中,当我们调用glLight设置光源的位置时,光源位置立刻被转换到相机坐标系中(使用模型视图矩阵),因此光照计算都是在相机坐标系中计算的。[在shader中,可以将这些计算过程放到世界坐标系中进行]。

现在我们可以计算散射成分了,它的计算公式可以表示如下:
DiffuseLight
其中N是顶点单位化的法线方向,L是光线方向,Cmat是几何体的材质中设置的散射成分,Cli是灯光中的散射光成分。

4.2.3 镜面光计算公式

镜面光让物体表面看起来像镜子一样明亮,当光线入射时,镜面反射的效果如下图:
Specular
当计算镜面光时,与计算散射光有点不同,它需要考虑观察者的位置(相机位置),当光线完全反射到相机中时,可以看到物体表面的亮点。
这里写图片描述

计算镜面光的过程如下:
1. 计算入射光方向
2. 计算反射光方向
3. 计算顶点到相机的方向
4. 计算反射光与顶点-相机方向的夹角
这个夹角基本上反映了镜面光能被看到的强度,因此如何处理最后的强度是一个需要讨论的问题。当角度很小是,我们看到的强度应该很大,当角度很大时,我们看到的强度应该很小。但是镜面光不同于散射光,镜面光的一致性很高,稍微角度大一点几乎完全看不到它。于是这个角度怎么设置才比较好呢?OpenGL使用了这样一种算法,通过计算两者夹角的余弦值,并为它设置一个指数项来模拟这种效果。这个指数项,是我们在固定管线中设置的shinness参数。它的效果需要根据情况自己调整。下图是设置不同的参数的一个初步的效果:
shinness
最终的算法如下所示:

//计算入射光方向
vec3 incidenceVector = -surfaceToLight; //a unit vector
//计算反射光方向(根据入射光方向和法线方向)
vec3 reflectionVector = reflect(incidenceVector, normal); //also a unit vector
//计算顶点到相机的方向
vec3 surfaceToCamera = normalize(cameraPosition - surfacePosition); //also a unit vector
//计算顶点-相机方向与反射光方向夹角的余弦值
float cosAngle = max(0.0, dot(surfaceToCamera, reflectionVector));
//引用镜面光的指数(shinness)
float specularCoefficient = pow(cosAngle, materialShininess);
//计算镜面光成分
vec3 specularComponent = specularCoefficient * materialSpecularColor * light.intensities;

4.2.4 光的衰减

在现实的光照中,当我们将光源远离物体表面时,物体表面看起来会更暗。一般来说光线的衰减和光源到物体表面的距离的二次方成反比,也就是:

i∝1d2

i是光照强度,d是光源到顶点的距离
当距离为0时,为了避免出现除数为0的情况,我们修改了一下分母
a=11+d2

a是衰减量,d是光源到顶点的距离
为了控制衰减的速度,再添加一个衰减的系数,最终公式变为:
a=11+kd2

4.2.5 平行光照

平行光可以被看作是光源在无穷远处的点光源,假设我们把这一特性应用于衰减的方程中,可以很容易知道物体表面应该越暗。这与现实情况不太相符(现实情况中我们假设太阳光是平行光,它事实上并没有根据它距地球的距离而有所衰减)于是OpenGL中在计算平行光的时候不考虑衰减。
和点光源不同,平行光并不需要一个位置,它只有一个方向。在齐次坐标中,为了表明它是一个方向,我们只需要设置它的第四维度是0就可以了。假设我们设定光源的位置在(1,0,0,0)处,也就是说光源在X轴正方向的无穷远处,于是平行光的方向是对该值取负,也就是(-1,0,0)说明光照方向是朝着X轴负方向。
计算的算法:只需要修改之前散射光和镜面光的光的方向向量即可

4.2.6 聚光灯

聚光灯和点光源类似,只是有一个不同点,聚光灯的光照被限制在一个圆锥形状内。聚光灯相比点光源多了两个变量,第一个是圆锥形的角度,第二个是圆锥中线的方向,如下图所示:
ConeDirection
计算的过程只需要得到聚光灯到顶点与圆锥中线方向的夹角小于ConeAngle,就可以使用点光源的计算方法,否则就让让衰减量最大。

// 1. 获取圆锥中心线的方向
vec3 coneDirection = normalize(light.coneDirection);

// 2. 获取顶点到聚光灯灯源的方向
vec3 rayDirection = -surfaceToLight;

// 3.计算二者的角度
float lightToSurfaceAngle = degrees(acos(dot(rayDirection, coneDirection)))

// 4. 判断是否在聚光灯照射下,如果超出,那么衰减最大
if(lightToSurfaceAngle > light.coneAngle){
  attenuation = 0.0;
}
OpenGL学习脚印: 光照基础(basic lighting) 写在前面 上一节坐标变换过程,总结了OpenGL中顶点的处理过程。有了前面的基础,从本节开始,我们可以开始学习OpenGL中包括光照、模型加载等主题。光照是一个复杂的主题,本节学习简单的Phong reflection model.本节示例程序均可以在我的github下载。 本节内容整理自: 1. learnopengl.com Basic Lighting 2.Modern 阅读详情

相关推荐

Opengl之基础光照

现在我们已经把法向量从顶点着色器传到了片段着色器。可是,目前片段着色器里的计算都是在世界空间坐标中进行的。所以,我们是不是应该把法向量也转换为世界空间坐标?基本正确,但是这不是简单地把它乘以一个模型矩阵就能搞定的。首先,法向量只是一个方向向量,不能表达空间中的特定位置。同时,法向量没有齐次坐标(顶点位置中的w分量)。这意味着,位移不应该影响到法向量。

qq_44632658的博客 200

OpenGL-光照

OpenGL 光照

weixin_45054115的博客 3260

OpenGL(十一) 可编程管线 基础光照 的实现

在OpenGL中创建 基础光照 ,主要的工作将模型中的法线信息和法线空间运算矩阵传入到shader中。另一方面,LightDir,ViewDir通常是在shader中从引擎参数获取的,为了简化光照模型的实现,这里我们可以在shader中写死...

阿修罗道 3408

【OpenGL】基础光照

现实世界中的光照是极其复杂,难以计算的,因此OpenGL的光照使用的是简化的模型,其中一个模型被称为冯氏光照模型环境(Ambient)光照漫反射(Diffuse)光照镜面(Specular)光照。

qq_38243831的博客 1543

零基础学习OpenGL——实现光照效果

OpenGL是一种强大的图形编程接口,它提供了广泛的功能来创建令人惊叹的实时图形效果。其中一个重要的功能是光照,通过光照可以模拟光的传播和反射,为场景增添逼真的效果。接下来,我们通过调用一些OpenGL函数来设置默认的渲染状态,包括清空颜色缓冲区的背景色、启用深度测试、启用光照和启用材质颜色跟踪。当然,这只是一个简单的例子,你可以根据自己的需求和兴趣进一步扩展和改进光照效果。现在,我们已经完成了一个简单的OpenGL光照效果的实现。然后,我们定义了一个光源的颜色和位置,并通过调用。接下来,我们通过调用。

NckyPytorch的博客 610

OpenGL 高级光照:实现高级光照效果的编程详解

通过以上的代码修改,我们可以实现基本的环境光照、漫反射光照和镜面反射光照效果。镜面反射光照是指光线照射到物体表面后,按照光线的方向和物体表面法线的方向,以镜面反射的方式来产生的光照效果。为了实现镜面反射光照效果,我们需要设置光源的镜面反射参数和物体的高光参数。漫反射光照是指光线照射到物体表面后,按照物体表面法线的方向,以一定程度的散射来产生的光照效果。环境光照是指物体表面在没有直接光照的情况下,由于环境中的间接光照而产生的一种均匀的光照效果。这个简单的程序将使用一个光源和一个材质参数来实现基本的光照效果。

ByteKnight的博客 232

OpenGL ES之glLight函数

名称: glLight —— 设置光源参数 函数原型: void glLightf(GLenum light,  GLenum pname,  GLfloat param); void glLightx(GLenum light,  GLenum pname,  GLfixed param); 函数参数: light        指定

飞鱼 3815

Docker部署 SRS rtmp/flv流媒体服务器

SRS(Simple Realtime Server)是一款开源的流媒体服务器,具有高性能、高可靠性、高灵活性的特点,能够支持直播、点播、转码等多种流媒体应用场景。SRS 不仅提供了流媒体服务器,还提供了适用于多种平台的客户端 SDK 和在线转码等辅助服务,是一款十分强大的流媒体解决方案。

m0_56659620的博客 4869

Learn OpenGL In Qt之基础光照

OpenGL中基础光照~

记录点滴,终成江河! 815

告别Qt Creator!VSCode + QMake + MinGW:从零搭建高效Qt开发环境

本文详细介绍了如何使用VSCode替代Qt Creator搭建高效的Qt开发环境,涵盖VSCode配置、QMake与MinGW集成、智能提示优化及构建调试技巧。通过实战案例展示如何提升开发效率30%以上,特别适合中大型Qt项目开发。

weixin_30466039的博客 244

手把手教你用VCS+Verdi在Linux下仿真蜂鸟E203 RISC-V核(附波形调试技巧)

本文详细介绍了在Linux环境下使用VCS和Verdi工具链对蜂鸟E203 RISC-V核进行仿真验证的完整流程。从环境配置、工程结构解析到VCS编译优化和Verdi波形分析技巧,提供了实战性强的调试方法和性能优化策略,帮助工程师高效完成数字IC验证工作。

weixin_42531163的博客 417

OpenGL ES 入门之旅 -- GLSL光照计算

冯氏光照模型 首先,在现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是我们有限的计算能力所无法模拟的。因此OpenGL的光照使用的是简化的模型,对现实的情况进行近似,这样处理起来会更容易一些。这些光照模型都是基于我们对光的物理特性的理解。其中一个模型被称为冯氏光照模型(Phong Lighting Model)。冯氏光照模型的主要结构由3个元素组成:环境(Ambient)光照、漫反射(D...

weixin_33712987的博客 619

centos7 清理缓存

一、系统环境 系统版本 CentOS Linux release 7.3.1611 (Core) 内核版本 Linux xx-user 3.10.0-514.el7.x86_64 #1 SMP 背景 服务器分配的账号是普通用户,只能执行sudo命令 二、缓存查看及基本概念 查看内存使用情况 [user01@xx-user ~]$ free -h total used free shared buff/cache availabl

sunzq55的博客 4007

谈OpenGL光照基础-基础光照

还有就是,环境光照总是存在的。当我们讲到材质一节的时候,物体材质的环境光照就等于其漫反射光照。所以可以将物体本身的环境光照忽略。同时要注意一点,求一个物体的光照,我们应该要考虑的是环境光照+漫反射光照+镜面光照,这样会更加的真实。环境光照:环境光照=环境光*环境因子*物体光(环境因子可理解为控制环境光的强度)漫反射:漫反射光照=环境光照*(入射光与法线的余弦值)*物体光照;镜面光照:镜面光照=环境光*镜面光照因子*反光度*物体光。以上光照相加就是我们要的作用在物体身上的总光照啦!下图为漫反射角度图形理解。

2301_80961698的博客 314

从零搭建高通8255车载开发环境:QNX SDP、SDK配置与镜像编译全流程

本文详细介绍了如何从零搭建高通SA8255P车载开发环境,涵盖QNX SDP部署、SDK工具链配置到多系统镜像编译的全流程。特别针对SAIL安全岛镜像构建、QNX系统优化及Android系统资源分配等关键技术点提供实战指导,帮助开发团队高效完成车载系统开发与调试。

weixin_33582311的博客 367

osg中显示3dtiles和cesiumIon

如下图为CesiumTilesetNode数据更新相关代码,将OSG对应的ViewMatrix、ProjectionMatrix和窗口信息传递给tileset->updateView()实现Cesium-native的场景更新。整体结构,其中 CesiumTilesetNode依赖Cesium3DTilesSelection::Tileset,实现数据的更新以及确定需要绘制的节点。1.1 CesiumNative3DTileslayer图层。

CPWWHSU的博客 889

OpenGL学习之光照基础

OpenGL光着基础

qq_33335724的博客 391

Centos 7 Linux 离线安装单机 Kafka:下载、安装、配置、使用

本文详细介绍了在 CentOS 7 系统上离线安装单机版 Apache Kafka 的完整流程,包括环境准备(JDK 安装)、Kafka 安装包上传与解压、关键配置修改(如监听地址)、ZooKeeper 与 Kafka 服务的启动,以及 Topic 的创建、消息的生产和消费等基础操作。适用于无网络环境下的 Kafka 快速部署与学习,为后续开发或测试提供本地消息队列支持。

寒水馨 · 轻量级技术文档 · hanshuixin.org 1319

【learnOpenGL学习笔记_9】OpenGL光照基础:从零开始的保姆级实战指南

在3D图形的世界里,光照是赋予场景灵魂的关键要素。今天,我们就来深入探讨一下OpenGL中的光照基础,帮助初学者快速上手实操。完整代码在文末。

同学小张的博客 882

【YOLOv8改进-卷积Conv】 SAConv(Switchable Atrous Convolution):可切换的空洞卷积

许多现代目标检测器通过采用二次观察和思考机制展示了卓越的性能。在本文中,我们在目标检测的主干设计中探索了这一机制。在宏观层面上,我们提出了递归特征金字塔(Recursive Feature Pyramid),该金字塔将特征金字塔网络(Feature Pyramid Networks)的额外反馈连接融入到底层的自下而上主干层中。在微观层面上,我们提出了可切换空洞卷积(Switchable Atrous Convolution),该卷积通过不同的空洞率卷积特征,并使用切换函数汇集结果。

专注于图像领域,主要研究内容包括计算机视觉和深度学习,特别是在图像分类、目标检测和图像生成等方面有深入的研究和实践经验。 1528

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Opengl-光照-颜色(其实要想做出好看的东西这章最重要了)

前言 前面的基础章节说了下Opengl入门的一些基础知识,通过这些基础知识你可以制作Camera或者让物体移动啊又或者放一张图片上去当做纹理贴图丰富物体的显示 但是其实不论怎么折腾你会发现略微呆板,没有鲜活的感觉。为什么呢?就是因为我们其实想让显示的东西像真实世界一样,然而却忽略了世界上最重要的东西-光!是的没有错,生活中你睁开眼闭上眼都可以感受到光的存在,看到任何东西都会因为光的...

alex1992azh的博客 1063

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

OpenGL的基础光照知识

面片着色的环面是通过在顶点着色器和片段着色器中将 flat 插值限定符添加到相应的法向量属性声明中得到的。对模型中每个多边形的一个顶点进行光照计算,然后以每个多边形或每个三角形为基础,将计算结果的光照值复制到相邻的像素中。位置光在 3D 场景中具有特定位置,用以体现靠近场景的光源,位置光的效果取决于照射角度;使用L+V得到角平分线向量,再将其点乘法向量N,得到夹角,夹角的值的2倍和V与反射角的夹角相等。光照计算是按像素而非顶点完成的,其中 N 和 L 在顶点着色器中进行计算,并在栅格化期间插值。

DoorToZen的博客 701

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

LearnOpenGL-光照-2.基础光照

问题引出当前片段着色器里的计算都是在世界空间坐标中进行,所以将法向量、顶点位置从顶点着色器传到了片段着色器,顶点位置使用了model矩阵转为世界空间的坐标,但是法向量没有转!如何转法向量为世界空间不完全正确法线乘以一个模型矩阵,模型model矩阵包含平移、旋转、缩放解释法向量只是一个方向向量,不能表达空间中的特定位置法向量没有齐次坐标(顶点位置中的w分量)这意味着,位移不应该影响到法向量,Model矩阵有位移且乘了法线就不正确那该如何做若乘以一个模型矩阵。

qq_34060370的博客 743

零基础小白如何自学OpenGL

学习OpenGL的过程是渐进的,需要从基础的C++编程、计算机图形学基础学起,然后逐步深入现代OpenGL的使用,掌握着色器编程、3D渲染技术、性能优化等高级技能。在掌握基础后,进一步深入到OpenGL的高级特性,会使你能够处理更加复杂的图形渲染、优化程序性能,并拓展你的应用范围。GLFW和SDL是两种常用的开源工具库,它们提供了OpenGL的窗口管理、输入处理、事件循环等功能,简化了OpenGL的开发。通过不断实践和学习,你将能够掌握OpenGL,开发出复杂的图形应用程序,如游戏、可视化工具等。

小宝哥Code的专栏 1305
上一篇: OpenGL图像格式
下一篇: OpenGL像素格式
csxiaoshui
博客等级 码龄16年 873粉丝 158原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值