Урок 172. OpenGL. Perspective. Frustum. Ortho.
Урок 172. OpenGL. Perspective. Frustum. Ortho.
В этом уроке:
- используем perspective-режим
- описываем frustum
- используем ortho-режим
Click here to read this article!
- используем perspective-режим
- описываем frustum
- используем ortho-режим
Click here to read this article!
Последний раз редактировалось damager82 06 июн 2017, 23:09, всего редактировалось 13 раз.
-
- Сообщения: 42
- Зарегистрирован: 25 янв 2015, 18:57
Re: Урок 172. Perspective. Frustum. Ortho.
damager82, спасибо огромное за Ваш труд! Если не трудно, подскажите, пожалуйста:
1)Почему размер массива mProjectionMatrix=16? Почему 16?
2)В уроке вы говорите, что z-буфер рисует тот треугольник видимым, который был нарисован позже. Почему тогда у нас зеленый спереди, а синий за ним? Ведь по коду у нас для одинаковых z синий после зеленого рисуется:
3) По поводу расчета ratio: данная формула справедлива, только когда у нас задается видимый объем в переделах от -1 до 1. Поэтому, я считаю, должна быть такая формула:
4) Мне кажется, что в этой строчке опечатка:
Должно быть:
-так как нам нужно брать с 3 элемента массива 3 координаты, а не 6.
P.S. УРААА!! Я наконец-то Вас догнал!! Я полтора года шел, шел, и наконец-то дошел до самого последнего урока!! Спасибо Вам за все!
1)Почему размер массива mProjectionMatrix=16? Почему 16?
2)В уроке вы говорите, что z-буфер рисует тот треугольник видимым, который был нарисован позже. Почему тогда у нас зеленый спереди, а синий за ним? Ведь по коду у нас для одинаковых z синий после зеленого рисуется:
Код: Выделить всё
// зеленый треугольник
glUniform4f(uColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, 3);
// синий треугольник
glUniform4f(uColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 3, 3);
Код: Выделить всё
if (width > height) {
ratio = (float) width / height;
left = -ratio*Math.abs(left);
right = ratio*Math.abs(right);
} else {
ratio = (float) height / width;
bottom =-ratio*Math.abs(bottom);;
top = ratio*Math.abs(top);
}
Код: Выделить всё
// синий треугольник
...
glDrawArrays(GL_TRIANGLES, 3, 6);
Код: Выделить всё
// синий треугольник
...
glDrawArrays(GL_TRIANGLES, 3, 3);
P.S. УРААА!! Я наконец-то Вас догнал!! Я полтора года шел, шел, и наконец-то дошел до самого последнего урока!! Спасибо Вам за все!
Re: Урок 172. Perspective. Frustum. Ortho.
1) Потому что матрица имеет размерность 4 на 4. А вот почему матрица имеет такую размерность, я уже не объясню. Это надо в геометрию углубляться.
2) В уроке я как раз пытался сказать, что z-bufer смотрит на "удаленность точки". И рисует ту, которая должна располагаться "ближе" к нам. А вот по умолчанию, без z-буфера, мы увидим на экране ту точку, которая была нарисована последней.
3) Верно, если больше единицы, то моя формула не сработает. Поправлю завтра.
4) Тоже верно, поправил.
Спасибо за замечания!
2) В уроке я как раз пытался сказать, что z-bufer смотрит на "удаленность точки". И рисует ту, которая должна располагаться "ближе" к нам. А вот по умолчанию, без z-буфера, мы увидим на экране ту точку, которая была нарисована последней.
3) Верно, если больше единицы, то моя формула не сработает. Поправлю завтра.
4) Тоже верно, поправил.
Спасибо за замечания!
-
- Сообщения: 42
- Зарегистрирован: 25 янв 2015, 18:57
Re: Урок 172. Perspective. Frustum. Ortho.
damager82, да, я уже вспоминаю лекции по OpenGL в универе) Вот как выглядит матрица перспективного проецирования(glFrustum),нашел в лекциях:
- Вложения
-
- матрица.png (2.79 КБ) 18030 просмотров
-
- Сообщения: 42
- Зарегистрирован: 25 янв 2015, 18:57
Re: Урок 172. Perspective. Frustum. Ortho.
damager82, на счет z-буфера. У нас треугольники рисуются с одинаковым z=1.0 - зеленый и синий. Мы в коде рисуем синий после зеленого. Если у нас одинаковый z, то по z-буферу мы должны увидеть тот, который был последним нарисован. Но я вижу наоборот-зеленый сверху, а должен быть синий. Почему так происходит?
Re: Урок 172. Perspective. Frustum. Ortho.
В данном случае просто когда рисуется вторая фигура происходит проверка на буфер глубины, видит что на этом уровне уже есть пиксель, и вторая фигура не рисуется в данном месте. т.е. еще раз как работает - если в буфере уже что-то записано, то пиксель не рисуется.danek130995 писал(а):damager82, на счет z-буфера. У нас треугольники рисуются с одинаковым z=1.0 - зеленый и синий. Мы в коде рисуем синий после зеленого. Если у нас одинаковый z, то по z-буферу мы должны увидеть тот, который был последним нарисован. Но я вижу наоборот-зеленый сверху, а должен быть синий. Почему так происходит?
Поэтому с точки зрения производительности следует отрисовывать сначала ближние объекты - потом дальние (тогда получится что дальние фрагменты отбрасываются, а если делать наоборот от дальних к ближним , то будут обрабатываться все пиксели объекта рассчитываться, потом поверх них обсчитываться следующие пиксели, и т.д.)
А если бы у нас обе фигуры рисовались за один вызов draw, при одинаковом depth-buffer на самом деле может результат быть любой, вплоть до того что один пиксель с одной фигуры, а другой пиксель из другой, для этого специально смещают координату объектов на минимальную величину, например на 0.01f чтобы точно не было такой ситуации.
-
- Сообщения: 42
- Зарегистрирован: 25 янв 2015, 18:57
Re: Урок 172. Perspective. Frustum. Ortho.
Draz1w, спасибо Вам большое, теперь понял. Я просто не знал, что если на данном уровне уже пиксель есть нарисованный, т.е. в z - буфере уже что-то записано, то новый не будет рисоваться. Спасибо!
Re: Урок 172. Perspective. Frustum. Ortho.
Я не очень понимаю механизм работы. Мы создаем массив вершин и проекцию в самом начале, на этапе инициализации. Но разве это не должно делаться при отрисовке кадра, ведь в реальных задачах объекты перемещаются и наблюдатель тоже смотрит на происходящие в этом кадре слева в следующем справа.
Как насчет анимации?
Как насчет анимации?
Re: Урок 172. Perspective. Frustum. Ortho.
Объекты обычно действительно задаются на этапе инициализации, а все действия с ними происходят за счет матриц аккумулирующий трансформации.АнтонФ писал(а):Я не очень понимаю механизм работы. Мы создаем массив вершин и проекцию в самом начале, на этапе инициализации. Но разве это не должно делаться при отрисовке кадра, ведь в реальных задачах объекты перемещаются и наблюдатель тоже смотрит на происходящие в этом кадре слева в следующем справа.
Как насчет анимации?
если примитивно объяснять, что если создать иденичную матрицу 4x4, потом ее переместить, повернуть или изменить ее размер, то достаточно эту матрицу умножить на координаты любого объекта, чтобы с ним произошли все теже самые трансформации...
Т.е. никаких действий над объектами обычно не делают, а трансформируют специальные матрицы, а потом эту матрицу умножают на объект вот так:
Код: Выделить всё
uniform mat4 mvp; // model, view, projection matrix
attribute vec4 aPosition;
void main() {
gl_Position = mvp * aPosition;
}
Тема эта сложная сразу скажу, но без нее никак дальше двигаться не получиться
http://www.opengl-tutorial.org/beginner ... -matrices/
Re: Урок 172. Perspective. Frustum. Ortho.
Я с матрицами уже знаком (какую матрицу применить, чтобы повернуть налево, направо, сдвинуться...). Непонятно где и какими методами это все делать в методе "рендер". Я в свое время кодил под openGL 1.0 для ПК, так вот там было понятней. Сначала задаешь смещение всей сцены относительно глаза, потом для каждого объекта смещаешь систему координат, рисуешь, смещаешь обратно... и так пока всю сцену не отрисуешь. Тут я не вдуплю никак. Мы скормили OpenGL массив вершин в самом начале. А если объект не надо рисовать, допустим через 10 секунд он должен пропасть?Draz1w писал(а):АнтонФ писал(а): Т.е. никаких действий над объектами обычно не делают, а трансформируют специальные матрицы, а потом эту матрицу умножают на объект вот
Я же правильно понимаю, что метод render это и есть тот самый "gameloop" в котором надо обсчитывать новое положение объектов в зависимости от времени и произошедших событий?
Re: Урок 172. Perspective. Frustum. Ortho.
В GL20 немного не так, честно говоря в двух словах объяснить сложно, и у меня не хватит таланта но попробую .АнтонФ писал(а): Я в свое время кодил под openGL 1.0 для ПК, так вот там было понятней. Сначала задаешь смещение всей сцены относительно глаза, потом для каждого объекта смещаешь систему координат, рисуешь, смещаешь обратно... и так пока всю сцену не отрисуешь. Тут я не вдуплю никак. Мы скормили OpenGL массив вершин в самом начале. А если объект не надо рисовать, допустим через 10 секунд он должен пропасть?
Я же правильно понимаю, что метод render это и есть тот самый "gameloop" в котором надо обсчитывать новое положение объектов в зависимости от времени и произошедших событий?
В GL20 не надо таскать всю сцену для отрисовки объектов туда сюда... обычно создают 3 матрицы, матрицу камеры (вида), матрицу проекции, и матрицы трансформаций для каждого объекта.
Матрицы - это просто массивы float[16].
Чтобы переместить объект например просто использую такую конструкцию:
android.opengl.Matrix.translateM(mObjectMatrix, 0, x, y, z);
все 3 матрицы передаются как uniform переменные в шейдер (либо все 3 матрицы объединяют в одну и куммулятивную и передают ее одну).
Код: Выделить всё
attribute vec4 aPosition;
uniform mat4 m,v,p, mvp; // model, view, projection and cummulative mvp matrix
void main() {
gl_Position = p*v*m * aPosition;
}
Код: Выделить всё
attribute vec4 aPosition;
uniform mat4 m,v,p, mvp; // model, view, projection and cummulative mvp matrix
void main() {
gl_Position = mvp * aPosition;
}
Нету такого чтобы как раньше чтобы нарисовать объект ты туда сюда таскаешь систему координат, за счет того что у тебя есть возможность использовать разные матрицы, ты работаешь с объектом в глобальных координатах, а не в локальных как раньше.
Причем я когда разбирался, я не нашел нигде внятного объяснения по матрицам увы, поэтому ссылку дать не могу...
разбирался чисто методом тыка проб и ошибок
причем первое время просто делал не понимая нормально как работает
и уже только когда добрался до освещения с normal и bump mapping тогда уже осознал как оно все работает ))
Будем надеяться что на startandroid напишут нормальный мануал по матрицам
Re: Урок 172. Perspective. Frustum. Ortho.
Правильно ли я понял, что для реализации анимации надо шейдер вершин более сложный написать? Типа в нем и будут координаты вершин умножаться на матрицы. Еще как разбить массив вершин на отдельные объекты, чтобы потом к ним разные матрицы применять? Короче у меня тумана в голове больше, чем ясности. Пыталя разобраться в DX 11, там та же идеология с шейдерами и тоже минимум материала дальше статических кубиков с текстурами.Draz1w писал(а): В GL20 немного не так, честно говоря в двух словах объяснить сложно, и у меня не хватит таланта но попробую .
В GL20 не надо таскать всю сцену для отрисовки объектов туда сюда... обычно создают 3 матрицы,
Вот нигде не могу туториала найти, чтобы пример с анимацией был. Матрицы это так-то чисто математика. А вот где бы нормальный материал почитать по методам OpenGL ES, для реализации всего этого? Я пока не нашел, надеялся, что тут у Вас скоро появится следующий урок
Re: Урок 172. Perspective. Frustum. Ortho.
Да он простой блин а не сложныйАнтонФ писал(а): Правильно ли я понял, что для реализации анимации надо шейдер вершин более сложный написать? Типа в нем и будут координаты вершин умножаться на матрицы.
просто тупо в шейдере умножаешь
Код: Выделить всё
gl_Position = u_MVPMatrix * a_Position;
а вот вся сопутствующая лабуда вот тут...
http://www.learnopengles.com/android-le ... g-started/
с анимацией есть пример (если я не ошибся там вроде крутятся эти треугольнички)
вот тут есть примеры спрайтовой анимации
http://4pda.ru/forum/index.php?showtopic=418429
Re: Урок 172. Perspective. Frustum. Ortho.
Угу, я тоже столкнулся что на самом деле есть такой пробел.АнтонФ писал(а):Draz1w писал(а): там та же идеология с шейдерами и тоже минимум материала дальше статических кубиков с текстурами.
Причем вон про матрицы и большие объекты пусто... типа как из 3d редактора построить модель в openGL.
А дальше опять появляется материал, типа там про свет, тени, отражение и прочее ))
Я не знаю почему
Может кстати супер библию openGL почитать, там наверно должно быть, но у меня руки не дошли ))
На рутрекере есть английская версия.
Re: Урок 172. Perspective. Frustum. Ortho.
Я пытаюсь вот это перевести на русский. Вроде доходчиво пишут
начало туториала
http://developer.android.com/intl/ru/tr ... nment.html
про анимацию
http://developer.android.com/intl/ru/tr ... otion.html
вроде, моя мысль про допил вершинного шейдера оказалась верна
это без анимации:
это с анимацией:
начало туториала
http://developer.android.com/intl/ru/tr ... nment.html
про анимацию
http://developer.android.com/intl/ru/tr ... otion.html
вроде, моя мысль про допил вершинного шейдера оказалась верна
это без анимации:
Код: Выделить всё
ode]private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
Код: Выделить всё
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
Re: Урок 172. Perspective. Frustum. Ortho.
Тут главное не сдаться и вот этот первоначальный такой затык пройти, врубиться как это все работает.АнтонФ писал(а):Я пытаюсь вот это перевести на русский. Вроде доходчиво пишут
начало туториала
Я 4 раза бросал пытаясь разобраться с opengl пару дней посижу, потом на другие работы переключусь, брошу...
потом выделил время побольше... сидел копался... щас вон добрался наваял себе для отрисовки объекта какой шейдер:
Код: Выделить всё
attribute vec4 aPosition;
attribute vec2 aTextureCoord;
attribute vec3 aNormal;
attribute vec3 aTangent;
attribute vec3 aBinormal;
varying vec2 vTextureCoord;
varying vec3 vViewDir;
varying vec3 mPosition;
varying mat3 vTangentMat;
uniform mat4 m,v, mvp; // model, view matrix
uniform mat3 uNormalMatrix;
uniform vec2 uVec2TextureOffset;
void main() {
mPosition = vec3(v*m * aPosition);
vTextureCoord = aTextureCoord+uVec2TextureOffset;
gl_Position = mvp * aPosition;
vec3 norm = normalize(uNormalMatrix*aNormal);
vec3 tang = normalize(uNormalMatrix*aTangent);
vec3 bino = normalize(uNormalMatrix*aBinormal);
vTangentMat = mat3(
tang.x, bino.x, norm.x,
tang.y, bino.y, norm.y,
tang.z, bino.z, norm.z ) ;
vViewDir = vTangentMat * normalize(-mPosition);
}
[FRAGMENT]
precision mediump float;
varying vec2 vTextureCoord;
varying vec3 vViewDir;
varying vec3 mPosition;
varying mat3 vTangentMat;
uniform sampler2D uBaseMap;
uniform sampler2D uNormalMap;
uniform vec3 uKa; //ambient
uniform vec3 uKs; //specular
uniform float uShininess;
uniform vec3 uLightIntensity; // a,d,s ambient,diffuse,specular
uniform bool uDrawplane;
uniform vec2 uTileSize;
uniform vec2 uTileStart;
uniform vec3 uLightPos;
vec3 phongModel( vec3 norm, vec3 diffR,vec3 vLightVector,float dist) {
vec3 r = reflect( -vLightVector, norm );
vec3 ambient = uLightIntensity * uKa;
float sDotN = max( dot(vLightVector, norm), 0.0 );
vec3 diffuse = uLightIntensity * diffR * sDotN;
vec3 spec = vec3(0.0);
if( sDotN > 0.0 )
spec = uLightIntensity * uKs *
pow( max( dot(r,vViewDir), 0.0 ), uShininess );
return (ambient + diffuse + spec)/(0.8+0.01*dist*dist*dist);
}
void main() {
vec3 vLightVector = normalize(vTangentMat*(uLightPos - mPosition));
float dist = length(uLightPos - mPosition);
vec2 phase=vTextureCoord;;
if (uDrawplane) {
phase=fract(vTextureCoord / uTileSize);
phase.x=phase.x*uTileSize.x+uTileStart.x;
phase.y=phase.y*uTileSize.y+uTileStart.y;
}
vec4 normal = 2.0 * texture2D( uNormalMap, phase ) - 1.0;
vec4 texColor = texture2D(uBaseMap,phase);
gl_FragColor = vec4( phongModel(normal.xyz, texColor.rgb,vLightVector,dist), 1.0 );
}
Re: Урок 172. Perspective. Frustum. Ortho.
а можешь хоть в кратце своими словами объяснить такой момент:Draz1w писал(а): Тут главное не сдаться и вот этот первоначальный такой затык пройти, врубиться как это все работает.
Я 4 раза бросал пытаясь разобраться с opengl
....ка opengl и шейдеры.
в шейдере описываются некие переменные (attribute): одна матрица, две, числа какие-то...
как они в него передаются?
т.е. какие-то переменные, это те самые координаты вершин объекта, которые во времени не меняются, а какие-то - например позиция камеры или позиция объекта - меняются.
Как устанавливается связь между переменными в шейдере и переменными в JAVA?
Re: Урок 172. Perspective. Frustum. Ortho.
attribute это входные массивы данных в вершинный шейдер.
т.е. это все вершины и все что с ними может быть связано.
причем если в шейдере несколько attribute,
например
attribute vec4 aPosition;
attribute vec2 aTextureCoord;
то если вершин будет 10, то и текстурных координат должно быть 10,
т.е. массивы в атрибутах должны быть всегда одинаковой длинны.
Сами данные по атрибутам передаются 2мя командами:
GLES20.glEnableVertexAttribArray(attributeHolderIndex)
GLES20.glVertexAttribPointer(attributeHolderIndex, сами данные сложенные в буфер)
Причем нужно понимать что сама шейдерная программа как бы будет работать для каждого атрибута из массива...
ну например передается 2 вершины: (1,0,0) и (1,1,1) - их передают в вершинный шейдер,
так вот программа вершинного шейдера выполниться 2 раза, один раз для первой вершины, второй раз для второй.
т.е. атрибуты каждый раз в каждом такте будут разными.
а uniformы - для каждого прохода шейдера будут одинаковыми...
т.е. униформы для всего отрисовываемого объекта будут одними, для всех вершин одни и теже значения.
передаются в шейдер они одной командой:
GLES20.glUniform1f(данные)...
в зависимости от типа команда будет незначительно отличаться:
GLES20.glUniform1f - предать 1 float
GLES20.glUniform1i - передать 1 int
GLES20.glUniform2f - передать 2 float
GLES20.glUniformMatrix4fv - передать матрицу 4*4
varying - это массивы данных которые передаются из вершинного шейдера во фрагментный.
(грубо можно их представить как тоже что и атрибуты, но если атрибуты из java в шейдер, то varying - это связь между шейдерами). varying в java никак не нужно описывать.
правда с varying есть еще одна штука, важная для понимания... если в вершинном шейдере varying на каждую вершину, то
во фрагментном уже будет varying для каждого пикселя.
Как это - например у нас есть 2 вершины пусть в вершине (a) var=1; а в вершине (b) var=2,
то во фрагментном шейдере мы увидим линейную интерполяцию для каждого пикселя который надо отрисовать.
т.е. для 11 пикселей - во фрагментном шейдере var={1 , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2 }
ну т.е. просто будет вот такое линейное размазывание (градиент) между значениями в вершинах.
кстати в новых версиях шейдеров
attribute переименовали в in
varying переименовали в out
если встретите in и out в примерах шейдеров не пугайтесь, для 2.0 просто переименовывайте и все будет работать.
вот как-то все так.
http://4pda.ru/forum/index.php?showtopi ... ry22114046
т.е. это все вершины и все что с ними может быть связано.
причем если в шейдере несколько attribute,
например
attribute vec4 aPosition;
attribute vec2 aTextureCoord;
то если вершин будет 10, то и текстурных координат должно быть 10,
т.е. массивы в атрибутах должны быть всегда одинаковой длинны.
Сами данные по атрибутам передаются 2мя командами:
GLES20.glEnableVertexAttribArray(attributeHolderIndex)
GLES20.glVertexAttribPointer(attributeHolderIndex, сами данные сложенные в буфер)
Причем нужно понимать что сама шейдерная программа как бы будет работать для каждого атрибута из массива...
ну например передается 2 вершины: (1,0,0) и (1,1,1) - их передают в вершинный шейдер,
так вот программа вершинного шейдера выполниться 2 раза, один раз для первой вершины, второй раз для второй.
т.е. атрибуты каждый раз в каждом такте будут разными.
а uniformы - для каждого прохода шейдера будут одинаковыми...
т.е. униформы для всего отрисовываемого объекта будут одними, для всех вершин одни и теже значения.
передаются в шейдер они одной командой:
GLES20.glUniform1f(данные)...
в зависимости от типа команда будет незначительно отличаться:
GLES20.glUniform1f - предать 1 float
GLES20.glUniform1i - передать 1 int
GLES20.glUniform2f - передать 2 float
GLES20.glUniformMatrix4fv - передать матрицу 4*4
varying - это массивы данных которые передаются из вершинного шейдера во фрагментный.
(грубо можно их представить как тоже что и атрибуты, но если атрибуты из java в шейдер, то varying - это связь между шейдерами). varying в java никак не нужно описывать.
правда с varying есть еще одна штука, важная для понимания... если в вершинном шейдере varying на каждую вершину, то
во фрагментном уже будет varying для каждого пикселя.
Как это - например у нас есть 2 вершины пусть в вершине (a) var=1; а в вершине (b) var=2,
то во фрагментном шейдере мы увидим линейную интерполяцию для каждого пикселя который надо отрисовать.
т.е. для 11 пикселей - во фрагментном шейдере var={1 , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2 }
ну т.е. просто будет вот такое линейное размазывание (градиент) между значениями в вершинах.
кстати в новых версиях шейдеров
attribute переименовали в in
varying переименовали в out
если встретите in и out в примерах шейдеров не пугайтесь, для 2.0 просто переименовывайте и все будет работать.
вот как-то все так.
http://4pda.ru/forum/index.php?showtopi ... ry22114046
Re: Урок 172. Perspective. Frustum. Ortho.
Спасибо огромное за пояснение. А ссылка вообще шикарной кладезью оказалась.