Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Поддерживаемые компоненты векторовСодержание книги
Поиск на нашем сайте
Несмотря на малый размер нижеследующего материала, он довольно важен. Не следует это забывать, это база каждого пиксельного шейдера.
FAQ
1. Как узнать расстояние до камеры в вершинном шейдере? vec3 vPos = (gl_ModelViewMatrix*gl_Vertex).xyz; float DistToCam = length(vPos);
2. Как узнать глобальные координаты вершины? vec3 GPos = (gl_ModelViewMatrix*gl_Vertex).xyz;
3. Как получить направления взгляда камеры на вершину? float view_vec = gl_Vertex.xyz-gl_ModelViewMatrixInverse[3].xyz;
4. А наоборот, направление взгляда вершины на камеру? float view_vec = gl_ModelViewMatrixInverse[3].xyz-gl_Vertex.xyz;
5. Как получить вектор направления зрения? vec3 viewVec = gl_ModelViewMatrixInverse[3].xyz - gl_Vertex.xyz;
vec3 camPos = gl_ModelViewMatrixInverse[3].xyz;
7. Как получить координату фрагмента (тексела), который сейчас обрабатывается пиксельным шейдером? gl_FragCoord.x Глава 39. Шейдеры GLSL. Использование без компонентов. Все шейдеры в этой главе соответствуют стандартам GLSL 1.00 — 1.20.
Существует два общеизвестных метода освещения. Это пиксельное и вершинное (вертексное). Вертексное освещение реализуется проще и работает быстрее, зато уступает пиксельному в реалистичности. Также советуем посмотреть главы 8 «Работа с материалами» и 37 «Шейдеры. История и компоненты», а именно разделы про освещение. Ну что же, давайте реализуем пиксельное освещение по Фонгу. Описание этого метода смотрите здесь: http://compgraph.ad.cctpu.edu.ru/fong.htm. Снова нам придётся поместить необходимые для успешной работы компоненты. GLScene1 (инспектор объектов сцены), GLSceneViewer. В инспекторе объектов создайте камеру, ее Position.Z присвойте значение 2; свойству GLSceneViewer. Camera присвойте GLCamera. Так же в инспекторе объектов создайте GLDirectOpenGL. Подключите модули VectorGeometry и GLContext, чтобы можно было иметь доступ к TGLProgramHandle. И напоследок подключите OpenGL1x. Теперь объявите в программе константы для хранения вершинного и фрагментного шейдера: const _vp = ‘uniform vec3 LightPosition;’+ ‘uniform vec3 EyePosition;’+ ‘varying vec3 ViewDirection;’+ ‘varying vec3 LightDirection;’+ ‘varying vec3 Normal;’+ ‘void main(void)’+ ‘{‘+ ‘gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;’+ ‘vec4 ObjectPosition = gl_ModelViewMatrix * gl_Vertex;’+ ‘ViewDirection = EyePosition - ObjectPosition.xyz;’+ ‘LightDirection = LightPosition - ObjectPosition.xyz;’+ ‘Normal = gl_NormalMatrix * gl_Normal;’+ ‘}’; Думаю, ничего особенного в этом шейдере нет. EyePosition — координаты взгляда, LightPosition — координаты источника света, ViewDirection и LightDirection вектора взгляда и источника света. const _fp = ‘uniform vec4 SpecularColor;’+ ‘uniform vec4 DiffuseColor;’+ ‘uniform vec4 AmbientColor;’+ ‘uniform float SpecularPower;’+ ‘varying vec3 ViewDirection;’+ ‘varying vec3 LightDirection;’+ ‘varying vec3 Normal;’+ ‘void main(void)’+ ‘{‘+ ‘vec3 fvLightDirection = normalize(LightDirection);’+ ‘vec3 fvNormal = normalize(Normal);’+ ‘float fNDotL = dot(fvNormal, fvLightDirection);’+ ‘vec3 fvReflection = normalize(((2.0 * fvNormal) * fNDotL) fvLightDirection);’+ ‘vec3 fvViewDirection = normalize(ViewDirection);’+ ‘float fRDotV = max(0.0, dot(fvReflection, fvViewDirection));’+ ‘vec4 fvTotalAmbient = AmbientColor;’+ ‘vec4 fvTotalDiffuse = DiffuseColor * fNDotL;’+ ‘vec4 fvTotalSpecular = SpecularColor * (pow(fRDotV, SpecularPower));’+ ‘gl_FragColor = fvTotalAmbient + fvTotalDiffuse + fvTotalSpecular;’+ ‘}’; Даю вам самим разобраться, что и как делает этот шейдер. Описание всех функций находится в предыдущей главе. Объявите глобальные переменные: var GLSLHandle: TGLProgramHandle; InitDGL: boolean; MySphere: TGLSphere; На этой сфере мы будет тестировать шейдер. В событии FormCreate нужно создавать сферу. Делаем это как обычно — без инспектора объектов: procedure TForm1.FormCreate(Sender: TObject); begin MySphere:=TGLSphere.Create(nil); end; Необходимо создать два события OnRender у GLDirectOpenGL: одно — GLDirectOpenGLInit — для инициализации шейдеров и передачи неизменяемых uniform, второе — GLDirectOpenGLRender — для применения шейдеров. После создания тела процедур, назначьте GLDirectOpenGL.OnRender = GLDirectOpenGLInit в design time или проведите присвоение в OnCreate формы. Вот как должно выглядеть событие GLDirectOpenGLInit: procedure TForm1.GLDirectOpenGLInit(Sender: TObject; var rci: TRenderContextInfo); begin if not(GL.ARB_shader_objects and GL.ARB_vertex_program and GL.ARB_vertex_shader and GL.ARB_fragment_shader) then begin ShowMessage(‘Ваша видеокарта не поддерживает GLSL шейдеры!’); Halt; end; GLSLHandle:= TGLProgramHandle.CreateAndAllocate; GLSLHandle.AddShader(TGLVertexShaderHandle, _vp); GLSLHandle.AddShader(TGLFragmentShaderHandle, _fp); if not GLSLHandle.LinkProgram then raise Exception.Create(GLSLHandle.InfoLog); if not GLSLHandle.ValidateProgram then raise Exception.Create(GLSLHandle.InfoLog); GL.CheckError;
with GLSLHandle do begin UseProgramObject; Uniform1f[‘SpecularPower’]:= 2.0; Uniform3f[‘LightPosition’]:= VectorTransform(AffineVectorMake(1.0, 0.0, 5.0), GLScene1.CurrentBuffer.ViewMatrix); Uniform3f[‘EyePosition’]:=AffineVectorMake(GLCamera.Position.X, GLCamera.Position.Y, GLCamera.Position.Z); Uniform4f[‘AmbientColor’]:= VectorMake(0.1, 0.2, 0.2, 1.0); Uniform4f[‘DiffuseColor’]:= VectorMake(1.0, 0.3, 0.1, 1.0); Uniform4f[‘SpecularColor’]:= VectorMake(0.2, 1.0, 0.3, 1.0); EndUseProgramObject; end;
GLDirectOpenGL.OnRender:= GLDirectOpenGLRender; GLDirectOpenGL.BuildList(rci); end;
Теперь нужно привести событие GLDirectOpenGLRender к такому виду: procedure TForm1.GLDirectOpenGLRender(Sender: TObject; var rci: TRenderContextInfo); begin with GLSLHandle do begin UseProgramObject; Uniform3f[‘LightPosition’]:=VectorTransform( AffineVectorMake(1.0, 0.0, 5.0), GLScene1.CurrentBuffer.ViewMatrix); MySphere.Render(rci); EndUseProgramObject; end; end; Здесь при передачи юниформа EyePosition использовалось умножение вектора, в котором содержатся непосредственно координаты взгляда, на видовую матрицу. Поздравляю, вы успешно реализовали пиксельное освещение Ambient + Diffuse + Specular. Готовый пример пиксельного освещения берите здесь: http://narod.ru/... Чувствую, что назрел обстоятельные рассказ о камере и матрицах в OpenGL. Если вы хорошо владеете английским, то можете прочитать вот эту статью: http://www.songho.ca/opengl/gl_transform.html. Если нет, то мы сами расскажим вам. Мы (т.е. каждый, кто использует шейдеры) задаём координаты наших вершин в так называемом object space, т.е. в пространстве объектов. Вот мы задали вершины нашей сферы в пространстве объектов, а потом решили использовать шейдер для каких-то своих целей. Тогда в нём нам понадобится перевести координаты из object space в пространство камеры. Зачем это делать? В статье, что я привёл выше, это объяснено: «OpenGL определяет, что камера всегда расположена в точке (0, 0, 0) и повёрнута по оси -Z в координатах взгляда, и не может быть трансформирована». Тут можно привести неоднозначное сравенение камеры с инвалидом. Этот инвалид полностью парализован, и чтобы его глаза увидели куб, нужно поставить этот куб прямо перед ним: Теперь прошу вас вернуться к юниформ переменной LightPosition. Позиция источника света должна задаваться в пространстве камеры. Зачем мы передавали её в шейдер таким стрёмным образом (а именно VectorTransform(AffineVectorMake(1.0, 0.0, 5.0), GLScene1.CurrentBuffer.ViewMatrix)) да ещё и передавали на каждом кадре, надеюсь, понятно. Ещё нет? Камера двигается, её матрица меняется, поэтому на каждом кадре передаём новую… Должен вас предупредить. Описанный способ далеко не лучший вариант использования для сцен с большим количеством света или сложной геометрией, и вот почему. Согласно спецификации OpenGL 3.0, вы не можете иметь больше 16 юниформ в шейдере (в предыдущих версиях 8 юниформ). Поэтому, при необходимости передать больше 16 переменных, возникает необходимость нескольких шейдерных проходов. Каждый такой проход это существенное снижение производительности. Да ещё и чем сложнее геометрия, тем больше в ней нормалей и тем больше будет расчётов в шейдере. Но не стоит паниковать: по сравнению с GLLightSource этот метод и более качественный и более современный. Чтобы обойти эти проблемы, разработчики придумали несколько принципиально отличающихся от данного способа методов расчёта освещения. Например: deffered shading, light pre pass. Эти технологии очень сложны, требуют получение глубины сцены, двух шейдерных проходов. Даже нам пока не удалось реализовать ни один из этих альтернативных способов.
Кстати, существует адрес: http://www.ozone3d.net/tutorials/glsl_lighting_phong.php. Там приводятся различные вариации алгоритма Фонга: точечный свет (Point Light in GLSL), свет прожектора (Spot Light in GLSL), алгоритм затухания света (Lighting Attenuation).
|
||||||||||||
Последнее изменение этой страницы: 2016-04-19; просмотров: 303; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.137.200.56 (0.006 с.) |