Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Иван Андреев
andreev. *****@***com
Основы 3Д. Точечные источники света
В рамках данной работы учащийся должен разработать шейдер для освещения объекта от точечных источников света.
Задание на работу:
Использую библиотеку графических примитивов отобразить на экране несколько моделей чайников.
Разработать шейдер освещения от точечных источников света.
Расположить 3 точечных источника света с разными цветами.
Теоретическая часть:
Основной теоретический материал, необходимый для данного задания, подробно описан в лекционных и практических занятиях.
Типы источников света
Источники направленного света (directional light sources)
Источник направленного света находится в бесконечно-удаленной точке. В этом случае допустимо считать, что все лучи света от него распространяются параллельно и для всех точек можно использовать один и тот же вектор направления освещения. Хорошим примером такого источника света является Солнце.

Для источников направленного света использование модели Блинна-Фонга оказывается весьма выгодным. В предположении о постоянстве вектора взгляда
, вектор полупути
может быть вычислен единожды для источника и, далее использоваться на протяжении всех вычислений. В этом случае расчет зеркальной компоненты освещенности будет почти так же прост, как для рассеянной составляющей.
Параметры и расчетная формула
Параметрами источника направленного света будут вектор направления
(для расчета рассеянной компоненты) и вектор полупути
(для расчета зеркальной компоненты). Суммарный вклад в освещение от источника направленного света рассчитывается по формуле:
![]()
Точечные источники света (point light sources)
В отличие от источников направленного света, точечные источники находятся в определенной точке пространства с конечными координатами, и свет от них распространяется равномерно по всем направлениям. При расчете освещенности в точке будет учитываться направление на такой источник.

Также для точечных источников учитывается эффект поглощения света, когда интенсивность излучения уменьшается с расстоянием (distance attenuation). Убывание интенсивности излучения с расстоянием задается следующей формулой:
![]()
где
- расстояние от освещаемой точки до источника света.
Параметры и расчетная формула
Параметрами точечного источника света будут его положение в пространстве и три коэффициента для расчета затухания. Суммарный вклад в освещение от точечного источника света рассчитывается по формуле:
![]()
Прожекторы (spot light sources)
Такие источники света являются простой имитацией реальных прожекторов, которые используются, к примеру, в театре для создания мощного луча света в определенном направлении. Свет от такого источника распространяется лишь в определенном направлении и получается конус света. Обеспечивается это с помощью наложения ограничений на вектор направления
от освещаемой точки до источника света.


У прожекторов, по сравнению с точечными источниками света добавляются два новых параметра: направление центрального освещения
, половинный угол отсечения ц и коэффициент поглощения kspotatt. Далее вычисляется величина fspotatt:

Прим. Косинус в первой четверти убывающая функция, поэтому приведенные выше условия будут верными, хотя для углов стоят противоположные знаки в неравенствах. Угол отсечения ц Є (0; 90°). Если ц = 90°, то прожектор вырождается в точечный источник света.
Параметры и расчетная формула
Параметрами прожектора будут его положение в пространстве, три коэффициента для расчета затухания, направление центрального освещения, половинный угол отсечения и коэффициент поглощения.
Суммарный вклад в освещение от прожектора рассчитывается по формуле:
![]()
Суммарное освещение
На сцене может находиться несколько источников освещения. В этом случае суммарное освещение создаваемое источниками света будет равно сумме вкладов, вносимых каждым источником:
![]()
где Ij – вклад вносимый j-м источником света. Если учесть способность материала излучать свет и глобальную фоновую освещенность сцены, то итоговая формула будет:
![]()
После расчета величин IR, IG, IB в конкретной вершине эти значения могут быть больше единицы. В этом случае существует три способа нормализации:
Отсечение (clamping): если компонента больше единицы, то она приравнивается единице. Если компонента меньше нуля, то она приравнивается нулю. Нормализация в вершине: считается минимум и максимум из IR, IG, IB в конкретной вершине. После этого диапазон [Imin; Imax] линейным преобразованием переводится в диапазон [max(0, Imin); min(Imax, 1)] (для конкретной вершины). Нормализация по всем вершинам: считается минимум и максимум из IR, IG, IB во всех вершинах. После этого диапазон [Imin; Imax] линейным преобразованием переводится в диапазон [max(0, Imin); min(Imax, 1)] (для всех вершин).[http://pgraphics. info/3D/lighting/light_sources. php]
Реализация:
using System;
using System. Collections. Generic;
using System. Linq;
using Microsoft. Xna. Framework;
using Microsoft. Xna. Framework. Audio;
using Microsoft. Xna. Framework. Content;
using Microsoft. Xna. Framework. GamerServices;
using Microsoft. Xna. Framework. Graphics;
using Microsoft. Xna. Framework. Input;
using Microsoft. Xna. Framework. Media;
using Microsoft. Xna. ;
using Microsoft. Xna. Framework. Storage;
using Primitives3D;
namespace Lab8
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft. Xna. Framework. Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
TeapotPrimitive teapot;
Effect effect;
SpherePrimitive pointLight;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content. RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base. Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
teapot = new TeapotPrimitive(GraphicsDevice);
pointLight = new SpherePrimitive(GraphicsDevice, 0.1f, 20);
base. Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this. Content to load your game content here
effect = Content. Load<Effect>("light");
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad. GetState(PlayerIndex. One).Buttons. Back == ButtonState. Pressed)
this. Exit();
// TODO: Add your update logic here
base. Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice. Clear(Color. Black);
// TODO: Add your drawing code here
Vector3 cameraPosition = new Vector3(0, 0, 8);
Matrix world = Matrix. CreateRotationY((float)gameTime. TotalGameTime. TotalSeconds);
Matrix view = Matrix. CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
Matrix proj = Matrix. CreatePerspectiveFieldOfView(MathHelper. ToRadians(45), GraphicsDevice. Viewport. AspectRatio, 0.1f, 20);
Vector3 lightPos0 = new Vector3(0, -1, 1);
Vector3 lightPos1 = new Vector3(1, 1, 1);
Vector3 lightPos2 = new Vector3(-2, 0, 0);
// Источники света
pointLight. Draw(Matrix. CreateTranslation(lightPos0), view, proj, Color. Blue);
pointLight. Draw(Matrix. CreateTranslation(lightPos1), view, proj, Color. Blue);
pointLight. Draw(Matrix. CreateTranslation(lightPos2), view, proj, Color. Blue);
effect. CurrentTechnique = effect. Techniques["Phong"];
effect. Parameters["LightPosition0"].SetValue(lightPos0);
effect. Parameters["LightPosition1"].SetValue(lightPos1);
effect. Parameters["LightPosition2"].SetValue(lightPos2);
effect. Parameters["AmbientColor0"].SetValue(new Vector4(0.1f, 0.1f, 0.1f, 1));
effect. Parameters["DiffuseColor0"].SetValue(new Vector4(0.5f, 0f, 0f, 1));
effect. Parameters["SpecularColor0"].SetValue(new Vector4(1, 0, 0, 1));
effect. Parameters["AmbientColor1"].SetValue(new Vector4(0.1f, 0.1f, 0.1f, 1));
effect. Parameters["DiffuseColor1"].SetValue(new Vector4(0, 0.5f, 0.5f, 1));
effect. Parameters["SpecularColor1"].SetValue(new Vector4(0, 1, 1, 1));
effect. Parameters["AmbientColor2"].SetValue(new Vector4(0.1f, 0.1f, 0.1f, 1));
effect. Parameters["DiffuseColor2"].SetValue(new Vector4(0.5f, 0.5f, 0.5f, 1));
effect. Parameters["SpecularColor2"].SetValue(new Vector4(1, 1, 1, 1));
effect. Parameters["Eye"].SetValue(cameraPosition);
effect. Parameters["World"].SetValue(world);
effect. Parameters["View"].SetValue(view);
effect. Parameters["Projection"].SetValue(proj);
effect. Parameters["Color"].SetValue(new Vector4(1, 1, 0, 1));
teapot. Draw(effect);
effect. Parameters["World"].SetValue(world * Matrix. CreateTranslation(0, 2, 0));
teapot. Draw(effect);
effect. Parameters["World"].SetValue(world * Matrix. CreateTranslation(-3, 0, 0));
teapot. Draw(effect);
base. Draw(gameTime);
}
}
}
Шейдер light. fx:
float4x4 World;
float4x4 View;
float4x4 Projection;
float ka = 1;
float kd = 0.5;
float ks = 1;
float SpecularPower = 4;
// Собственный цвет объекта
float4 Color = float4(1, 0, 0, 1);
float4 AmbientColor0 = float4(0.1, 0.1, 0.1, 1);
float4 DiffuseColor0 = float4(1,1,1,1);
float4 SpecularColor0 = float4(1,1,1,1);
float4 AmbientColor1 = float4(0.1, 0.1, 0.1, 1);
float4 DiffuseColor1 = float4(1,1,1,1);
float4 SpecularColor1 = float4(1,1,1,1);
float4 AmbientColor2 = float4(0.1, 0.1, 0.1, 1);
float4 DiffuseColor2 = float4(1,1,1,1);
float4 SpecularColor2 = float4(1,1,1,1);
// Предполагается, что координаты источников света заданы в мировых координатах
float3 LightPosition0 = float3(0,0,2);
float3 LightPosition1 = float3(2,0,0);
float3 LightPosition2 = float3(-2,0,0);
float3 Eye;
// TODO: add effect parameters here.
struct VertexShaderInputPhong
{
float4 Position : POSITION0;
float3 Normal : NORMAL;
// TODO: add input channels such as texture
// coordinates and vertex colors here.
};
struct VertexShaderOutputPhong
{
float4 Position : POSITION0;
float3 WorldPosition : TEXCOORD0;
float3 Normal : TEXCOORD1;
// TODO: add vertex shader outputs such as colors and texture
// coordinates here. These values will automatically be interpolated
// over the triangle, and provided as input to your pixel shader.
};
VertexShaderOutputPhong VertexShaderFunctionPhong(VertexShaderInputPhong input)
{
VertexShaderOutputPhong output;
float4 worldPosition = mul(input. Position, World);
float4 viewPosition = mul(worldPosition, View);
float3 worldNormal = normalize(mul(input. Normal, World));
output. Position = mul(viewPosition, Projection);
output. WorldPosition = worldPosition;
output. Normal = worldNormal;
// TODO: add your vertex shader code here.
return output;
}
float4 PointLight(float3 LightPosition, float3 worldPosition, float3 worldNormal, float4 AmbientColor, float4 DiffuseColor, float4 SpecularColor)
{
float4 Ambient = ka * AmbientColor;
float3 lightDirection = normalize(LightPosition - worldPosition);
float4 Diffuse = kd * max(0, dot(worldNormal, lightDirection)) * DiffuseColor;
float3 eyeDirection = normalize(Eye - worldPosition);
float3 reflectedLight = normalize(reflect(-lightDirection, worldNormal));
float4 Specular = ks * pow(max(0, dot(eyeDirection, reflectedLight)), SpecularPower) * SpecularColor;
// для упрощения коэффициент затухания равен 1/d^2
return (Ambient + Diffuse + Specular) / pow(length(worldPosition-LightPosition), 2);
}
float4 PixelShaderFunctionPhong(VertexShaderOutputPhong input) : COLOR0
{
// TODO: add your pixel shader code here.
float3 worldPosition = input. WorldPosition;
float3 worldNormal = normalize(input. Normal);
float4 light0 = PointLight(LightPosition0, worldPosition, worldNormal, AmbientColor0, DiffuseColor0, SpecularColor0);
float4 light1 = PointLight(LightPosition1, worldPosition, worldNormal, AmbientColor1, DiffuseColor1, SpecularColor1);
float4 light2 = PointLight(LightPosition2, worldPosition, worldNormal, AmbientColor2, DiffuseColor2, SpecularColor2);
return Color * (light0 + light1 + light2);
}
technique Phong
{
pass Pass1
{
// TODO: set renderstates here.
VertexShader = compile vs_1_1 VertexShaderFunctionPhong();
PixelShader = compile ps_3_0 PixelShaderFunctionPhong();
}
}


