directx11第十篇其他灯光类型——点光源

m雪夜m m雪夜m     2023-02-15     648

关键词:

      本系列文章主要翻译和参考自《Real-Time 3D Rendering with DirectX and HLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。
      这里是书中的代码和资源。

      本文所有的环境和工具使用都基于之前的文章,如有不明白的地方请先参考本系列之前的几篇文章。

本文索引:



关于灯光类型

       在前面的介绍光照模型的几篇文章中,主要为大家介绍了一些很基本的光照模型是如何实现的。文章中提到的计算方式都是在假定环境中只存在平行光的情况下计算的。之前我们有介绍过,灯光有很多种类型,包括点光源、平行光、聚光灯等……。下面将为大家介绍除平行光之外的这几种灯光。


Point Light: 什么是点光源

      点光源的效果类似电灯泡,会向所有方向均匀地放出光,在场景中的点光源是由具体位置的区别的。这些就和平行光不一样,平行光没有具体位置的区别,他是从无限远的地方照射过来的光,并且是有一个统一的光线方向的。总的来说,平行光没有移动光源位置的区别,而点光源没有旋转光源的区别。
      在模拟点光源的效果时,我们可以使用和平行光计算中一样的光照模型(包括漫反射光照模型和高光光照模型)。但是在点光源中,我们需要给出光源位置并计算光线方向。计算点光源的光线方向也很简单,就是取世界坐标系下的光源坐标减去世界坐标系下的物体坐标。下图表示了这个计算过程:

      另外,由于点光源是有具体的位置的,你可以通过距离调节物体表面的光线强弱。点光源距离物体越远,物体表面越暗。下面的代码实现了当场景中只有一个点光源的时候的效果:
Listing 7.1 PointLight.fx(关于include文件Common.fxh如何引用请参考第八篇文章)

#include "include\\\\Common.fxh"

/*************** Resources ***************/
cbuffer CBufferPerFrame

    float4 AmbientColor : AMBIENT
    <
        string UIName = "Ambient Light";
        string UIWidget = "Color";
    >  = 1.0f, 1.0f, 1.0f, 0.0f;

    float4 LightColor : COLOR 
    <
        string Object = "LightColor0";
        string UIName = "Light Color";
        string UIWidget = "Color";
    > = 1.0f, 1.0f, 1.0f, 1.0f;

    float3 LightPosition : POSITION
    <
        string Object = "PointLight0";
        string UIName = "Light Position";
        string Space = "World";
    > = 0.0f, 0.0f, 0.0f;

    float LightRadius
    <
        string UIName = "Light Radius";
        string UIWidget = "slider";
        float UIMin = 0.0;
        float UIMax = 100.0;
        float UIStep = 1.0;
    > = 10.0f;

    float3 CameraPosition : CAMERAPOSITION<string UIWidget="None";>;


cbuffer CBufferPerObject

    float4x4 WorldViewProjection : WORLDVIEWPROJECTION <string UIWidget="None";>;
    float4x4 World : WORLD <string UIWidget="None";>;

    float4 SpecularColor : SPECULAR
    <
        string UIName = "Specular Color";
        String UIWidget = "Color";
    > = 1.0f, 1.0f, 1.0f, 1.0f;

    float SpecularPower : SPECULARPOWER
    <
        string UIName = "Specular Power";
        string UIWidget = "Slider";
        float UIMin = 1.0;
        float UIMax = 255.0;
        float UIStep = 1.0;

    > = 25.0f;


Texture2D ColorTexture
<
    string ResourceName = "default_color.dds";
    string UIName = "Color Texture";
    string ResourceType = "2D";
>;

SamplerState ColorSampler

    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
;

RasterizerState DisableCulling

    CullMode = NONE;    
;

/*************** Data Structures ***************/
struct VS_INPUT

    float4 ObjectPosition : POSITION;
    float2 TextureCoordinate : TEXCOORD;
    float3 Normal : NORMAL;
;

struct VS_OUTPUT

    float4 Position : SV_Position;
    float3 Normal : NORMAL;
    float2 TextureCoordinate : TEXCOORD0;
    float4 LightDirection : TEXCOORD1;
    float3 ViewDirection : TEXCOORD2;
;

/*************** Vertex Shader ***************/
VS_OUTPUT vertex_shader(VS_INPUT IN)

    VS_OUTPUT OUT = (VS_OUTPUT)0;

    OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);
    OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);
    OUT.Normal = normalize(mul(float4(IN.Normal, 0), World).xyz);

    float3 worldPosition = mul(IN.ObjectPosition, World).xyz;
    float3 lightDirection = LightPosition - worldPosition;
    OUT.LightDirection.xyz = normalize(lightDirection);
    OUT.LightDirection.w = saturate(1.0f -(length(lightDirection)/LightRadius));//Attenuation

    OUT.ViewDirection = normalize(CameraPosition - worldPosition);

    return OUT;


/*************** Pixel Shader ***************/
float4 pixel_shader(VS_OUTPUT IN) : SV_Target

    float4 OUT = (float4)0;

    float3 normal = normalize(IN.Normal);
    float3 lightDirection = normalize(IN.LightDirection);
    float3 viewDirection = normalize(IN.ViewDirection);
    float n_dot_1 = dot(normal, lightDirection);
    float3 halfVector = normalize(lightDirection + viewDirection);
    float n_dot_h = dot(normal, halfVector);

    float4 color = ColorTexture.Sample(ColorSampler, IN.TextureCoordinate);
    float4 lightCoefficients = lit(n_dot_1, n_dot_h, SpecularPower);

    float3 ambient = get_vector_color_contribution(AmbientColor, color.rgb);
    float3 diffuse = get_vector_color_contribution(LightColor, lightCoefficients.y * color.rgb) * IN.LightDirection.w;
    float3 specular = get_scalar_color_contribution(SpecularColor, min(lightCoefficients.z, color.w)) * IN.LightDirection.w;

    OUT.rgb = ambient + diffuse + specular;
    OUT.a = 1.0f;

    return OUT;


/*************** Techniques ***************/
technique10 main10

    pass p0
    
        SetVertexShader(CompileShader(vs_4_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, pixel_shader()));

        SetRasterizerState(DisableCulling);

    
float3 specular = get_scalar_color_contribution(SpecularColor, min(lightCoefficients.z, color.w));

    OUT.rgb = ambient + diffuse + specular;
    OUT.a = 1.0f;

    return OUT;


/*************** Techniques ***************/
technique10 main10

    pass p0
    
        SetVertexShader(CompileShader(vs_4_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, pixel_shader()));

        SetRasterizerState(DisableCulling);

    

(1) Point Light Preamble : 点光源变量准备

      这段代码中的大部分代码是从上一篇文章中的blinn-phong模型下的代码复制过来的,如有不明白的代码可以翻看之前的文章。
      CBufferPerFrame代码块中的LightPosition表示点光源在场景中世界坐标系下的位置。LightRadius表示点光源的作用距离,超过这个距离,点光源将不会造成任何影响。
      与之前相比,顶点着色器输出结构体中的LightDirection从float3变成了float4,多出来的第四个通道是用来存储光线的强弱的。也就是说光线的强弱和方向都是在顶点着色器中计算出来的。

注意
      将光线强度保存在LightDirection中的w通道只是为了节省性能,在这个变量中,xyz足以表示光线方向,而w一般是不会再用到的了。因此,与其再为了这个数据多占用输出结构中的一个变量,不如直接将其保存在w中。但光线强弱和光线方向是没有任何关系的。

(2) Point Light Vertex and Pixel Shader : 点光源顶点及像素着色器的实现

      顶点着色器中,计算出了光线方向并将其保存在LightDirection变量的xyz中。光线强度通过以下公式计算得出:

      公式中的lightDirection是直接通过顶点坐标和光源位置计算出的,还没有单位化,因此可以通过除以lightRadius得出光线强弱比例。计算得出的attenuation通过saturate函数保证其结果不会小于0。
      像素着色器中并不需要做特殊处理,直接将顶点着色器中计算出的光线强度加入到漫反射和高光的计算中。

(3) Point Light Output : 点光源输出效果

      下图展示了一个只带有点光源的场景的显示效果,左图中的球体离点光源距离较近,右图中则较远。图中黄色线框所表示的就是一个点光源的位置:

(4) Point Light Modifications : 修改点光源的实现

      从下面的左右两张图中可以发现高光点效果的不同,这是因为之前使用顶点着色器计算点光源的时候会产生的一些瑕疵。这种瑕疵只会出现在当点光源距离模型表面十分接近时,这个时候光向量在根据顶点计算时顶点间的向量差异会更大,而顶点间的这些像素会继续使用顶点上计算出的这些光向量数据。

代码段Listing 7.2 PointLight-Imp.fx

#include "include\\\\Common.fxh"

/*************** Resources ***************/
cbuffer CBufferPerFrame

    float4 AmbientColor : AMBIENT
    <
        string UIName = "Ambient Light";
        string UIWidget = "Color";
    >  = 1.0f, 1.0f, 1.0f, 0.0f;

    float4 LightColor : COLOR 
    <
        string Object = "LightColor0";
        string UIName = "Light Color";
        string UIWidget = "Color";
    > = 1.0f, 1.0f, 1.0f, 1.0f;

    float3 LightPosition : POSITION
    <
        string Object = "PointLight0";
        string UIName = "Light Position";
        string Space = "World";
    > = 0.0f, 0.0f, 0.0f;

    float LightRadius
    <
        string UIName = "Light Radius";
        string UIWidget = "slider";
        float UIMin = 0.0;
        float UIMax = 100.0;
        float UIStep = 1.0;
    > = 10.0f;

    float3 CameraPosition : CAMERAPOSITION<string UIWidget="None";>;


cbuffer CBufferPerObject

    float4x4 WorldViewProjection : WORLDVIEWPROJECTION <string UIWidget="None";>;
    float4x4 World : WORLD <string UIWidget="None";>;

    float4 SpecularColor : SPECULAR
    <
        string UIName = "Specular Color";
        String UIWidget = "Color";
    > = 1.0f, 1.0f, 1.0f, 1.0f;

    float SpecularPower : SPECULARPOWER
    <
        string UIName = "Specular Power";
        string UIWidget = "Slider";
        float UIMin = 1.0;
        float UIMax = 255.0;
        float UIStep = 1.0;

    > = 25.0f;


Texture2D ColorTexture
<
    string ResourceName = "default_color.dds";
    string UIName = "Color Texture";
    string ResourceType = "2D";
>;

SamplerState ColorSampler

    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = WRAP;
    AddressV = WRAP;
;

RasterizerState DisableCulling

    CullMode = NONE;    
;

/*************** Data Structures ***************/
struct VS_INPUT

    float4 ObjectPosition : POSITION;
    float2 TextureCoordinate : TEXCOORD;
    float3 Normal : NORMAL;
;

struct VS_OUTPUT

    float4 Position : SV_Position;
    float3 Normal : NORMAL;
    float2 TextureCoordinate : TEXCOORD0;
    float3 WorldPosition : TEXCOORD1;
    float3 Attenuation : TEXCOORD2;
;

/*************** Vertex Shader ***************/
VS_OUTPUT vertex_shader(VS_INPUT IN)

    VS_OUTPUT OUT = (VS_OUTPUT)0;

    OUT.Position = mul(IN.ObjectPosition, WorldViewProjection);
    OUT.WorldPosition = mul(IN.ObjectPosition, World).xyz;
    OUT.TextureCoordinate = get_corrected_texture_coordinate(IN.TextureCoordinate);
    OUT.Normal = normalize(mul(float4(IN.Normal, 0), World).xyz);

    float3 lightDirection = LightPosition - OUT.WorldPosition;

    OUT.Attenuation = saturate(1.0f - (length(lightDirection)/LightRadius));

    return OUT;


/*************** Pixel Shader ***************/
float4 pixel_shader(VS_OUTPUT IN) : SV_Target

    float4 OUT = (float4)0;

    float3 normal = normalize(IN.Normal);
    float3 lightDirection = normalize(LightPosition - IN.WorldPosition);
    float3 viewDirection = normalize(CameraPosition - IN.WorldPosition);

    float n_dot_1 = dot(normal, lightDirection);
    float3 halfVector = normalize(lightDirection + viewDirection);
    float n_dot_h = dot(normal, halfVector);

    float4 color = ColorTexture.Sample(ColorSampler, IN.TextureCoordinate);
    float4 lightCoefficients = lit(n_dot_1, n_dot_h, SpecularPower);

    float3 ambient = get_vector_color_contribution(AmbientColor, color.rgb);
    float3 diffuse = get_vector_color_contribution(LightColor, lightCoefficients.y * color.rgb) * IN.Attenuation;
    float3 specular = get_scalar_color_contribution(SpecularColor, min(lightCoefficients.z, color.w)) * IN.Attenuation;

    OUT.rgb = ambient + diffuse + specular;
    OUT.a = 1.0f;

    return OUT;


/*************** Techniques ***************/
technique10 main10

    pass p0
    
        SetVertexShader(CompileShader(vs_4_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, pixel_shader()));

        SetRasterizerState(DisableCulling);

    

      在这段代码中,将光向量和视线向量移到像素着色器中计算,这样加大了计算量,但同时也是显示结果更为精细。但并没有将光线强度也加入到像素着色器中,因为当距离足够近时,两个顶点间的光线强度并不会差很多。虽然这样计算了两次光线方向,一次是在顶点着色器中为了计算光线强度的,一次是在像素着色器中计算每个像素点上的光线方向。但这样也比把所有计算都移到像素着色器中要更能节省一点性能。

directx11第七篇光照模型——环境光

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

directx11第八篇光照模型——漫反射

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

第十篇:上下文表示

目录词向量/嵌入RNN语言模型大纲ELMoELMO:EmbeddingsfromLanguageModels提取上下文表示ELMO有多好?其他发现BERTRNN的缺点BERT:BidirectionalEncoderRepresentationsfromTransformers目标1:掩码语言模型目标2:下一句预测训练/模型详细信息如何... 查看详情

第十篇:装饰器

三、装饰器1、装饰器是在函数调用之上的修饰2、这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用3、使用装饰器的情形有:3.1引入日志3.2增加计时逻辑来检测性能3.3给函数加入事务的能力 装饰器基础:1... 查看详情

3dmax场景导入unity3d中怎么看不到灯光了?完全没有显示出来呢?该用哪种灯光?

不支持max里的灯光系统,你要在unity里重新创建灯光,unity总共有四种灯光类型,其实和max里的差不多的,在Hierarchy面板点Create创建,DirectionalLight是平行光,PointLight是点光源,SpotLight是聚光灯,AreaLight是区域光,光源属性都是在... 查看详情

directx11第九篇光照模型——高光

...    本系列文章主要翻译和参考自《Real-Time3DRenderingwithDirectXandHLSL》一书(感谢原书作者),同时会加上一点个人理解和拓展,文章中如有错误,欢迎指正。      这里是书中的代码和资源。      本文... 查看详情

点光源随相机移动

...问题描述】:我目前正在使用OpenGL在我的场景中添加一些灯光(定向光、点光源和聚光灯)。我的定向灯和聚光灯似乎可以工作,但我的点灯仍然跟随相机。我想将该点光源的位置设置在任意位置,例如(10,5,2)。因此,我创建了... 查看详情

第十篇:杂货铺

一、内置函数  2版本内置函数:3版本的内置函数:2、我们可以在idle里面使用命令dir(__builtins__)查看Python的所有内置函数  标准类型函数mp(num1,num2)–num1大于num2结果为正值–num1小于num2结果为负值–num1等于num2结果... 查看详情

零基础学python第十课,容器类型的公共方法

〝古人学问遗无力,少壮功夫老始成〞容器类型的公共方法,常码字不易,出精品更难,没有特别幸运,那么请先特别努力,别因为懒惰而失败,还矫情地将原因归于自己倒霉。你必须特别努力,才能显得毫不费力。如果这篇文... 查看详情

unityscene视图怎么不显示灯光效果

参考技术A不支持max里的灯光系统,你要在unity里重新创建灯光,unity总共有四种灯光类型,其实和max里的差不多的,在Hierarchy面板点Create创建,DirectionalLight是平行光,PointLight是点光源,SpotLight是聚光灯,AreaLight是区域光本回答... 查看详情

unity光照系统

...统叫EnLighten,作为引擎渲染的一部分,负责构建场景中的灯光。(1)Light组件简介  Unity的灯光组件大致分为:光源组件和烘焙组件  光源:自己能发光,分为DirectionalLight,PointLignt,SpotLight。(2)常见光源类型  a、Direct... 查看详情

unity3d中四种光源有啥区别

...到场景,从定向光发出来的光线是互相平行的,也不会像其他种光源会分岔,结果就是不管对象离定向光源多远,投射出来的阴影看起来都一样,这其实对户外场景的照明很有利。定向光没有真正的光源坐标,放置在场景任何地... 查看详情

grafana之tablepanel使用(第十篇)

参考技术ATable Panel也是Grafana的原生插件。TablePanel支持将基于时间序列的多种数据以表格式形式展示,TablePanel灵活且相对复杂。Table Panel配置①Data,包括TableTransform(表格转换)和Columns。TableTransform可设置为:Timeseriestorows、... 查看详情

第十篇googlenet——模型精讲

文章目录摘要 查看详情

第十篇googlenet——模型精讲

文章目录摘要 查看详情

java基础第十篇之异常

1.1接口概念 类:具有相同属性和功能的事物集合 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”。 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口... 查看详情

第十篇:非均衡分类问题的思考与问题与解决思路

前言      在前面的文章中,讨论了一些分类算法。然后,有一点一直忽视了,就是非均衡的分类问题。      分均衡分类有两种情形           &nb... 查看详情

第十篇io流技术(代码片段)

packagecom.zzp.commons;importjava.io.File;importorg.apache.commons.io.FileUtils;/****大小*@authorjava**/publicclassCIOTest01publicstaticvoidmain(String[]args)//文件的大小longlen=FileUtils.sizeOf(newFile("s 查看详情