Урок 172. OpenGL. Perspective. Frustum. Ortho.

Обсуждение уроков
Ответить
Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Урок 172. OpenGL. Perspective. Frustum. Ortho.

Сообщение damager82 » 08 дек 2015, 09:00

В этом уроке:
- используем perspective-режим
- описываем frustum
- используем ortho-режим


Click here to read this article!
Последний раз редактировалось damager82 06 июн 2017, 23:09, всего редактировалось 13 раз.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

danek130995
Сообщения: 42
Зарегистрирован: 25 янв 2015, 18:57

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение danek130995 » 10 дек 2015, 17:09

damager82, спасибо огромное за Ваш труд! Если не трудно, подскажите, пожалуйста:
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);
3) По поводу расчета ratio: данная формула справедлива, только когда у нас задается видимый объем в переделах от -1 до 1. Поэтому, я считаю, должна быть такая формула:

Код: Выделить всё

    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);
        }
4) Мне кажется, что в этой строчке опечатка:

Код: Выделить всё

 // синий треугольник
...
glDrawArrays(GL_TRIANGLES, 3, 6);
Должно быть:

Код: Выделить всё

 // синий треугольник
...
glDrawArrays(GL_TRIANGLES, 3, 3);
-так как нам нужно брать с 3 элемента массива 3 координаты, а не 6.
P.S. УРААА!! Я наконец-то Вас догнал!! Я полтора года шел, шел, и наконец-то дошел до самого последнего урока!! Спасибо Вам за все!

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение damager82 » 15 дек 2015, 23:23

1) Потому что матрица имеет размерность 4 на 4. А вот почему матрица имеет такую размерность, я уже не объясню. Это надо в геометрию углубляться.
2) В уроке я как раз пытался сказать, что z-bufer смотрит на "удаленность точки". И рисует ту, которая должна располагаться "ближе" к нам. А вот по умолчанию, без z-буфера, мы увидим на экране ту точку, которая была нарисована последней.
3) Верно, если больше единицы, то моя формула не сработает. Поправлю завтра.
4) Тоже верно, поправил.

Спасибо за замечания!
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

danek130995
Сообщения: 42
Зарегистрирован: 25 янв 2015, 18:57

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение danek130995 » 20 дек 2015, 19:49

damager82, да, я уже вспоминаю лекции по OpenGL в универе) Вот как выглядит матрица перспективного проецирования(glFrustum),нашел в лекциях:

Изображение
Вложения
матрица.png
матрица.png (2.79 КБ) 17603 просмотра

danek130995
Сообщения: 42
Зарегистрирован: 25 янв 2015, 18:57

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение danek130995 » 20 дек 2015, 20:02

damager82, на счет z-буфера. У нас треугольники рисуются с одинаковым z=1.0 - зеленый и синий. Мы в коде рисуем синий после зеленого. Если у нас одинаковый z, то по z-буферу мы должны увидеть тот, который был последним нарисован. Но я вижу наоборот-зеленый сверху, а должен быть синий. Почему так происходит?

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 11 янв 2016, 19:39

danek130995 писал(а):damager82, на счет z-буфера. У нас треугольники рисуются с одинаковым z=1.0 - зеленый и синий. Мы в коде рисуем синий после зеленого. Если у нас одинаковый z, то по z-буферу мы должны увидеть тот, который был последним нарисован. Но я вижу наоборот-зеленый сверху, а должен быть синий. Почему так происходит?
В данном случае просто когда рисуется вторая фигура происходит проверка на буфер глубины, видит что на этом уровне уже есть пиксель, и вторая фигура не рисуется в данном месте. т.е. еще раз как работает - если в буфере уже что-то записано, то пиксель не рисуется.
Поэтому с точки зрения производительности следует отрисовывать сначала ближние объекты - потом дальние (тогда получится что дальние фрагменты отбрасываются, а если делать наоборот от дальних к ближним , то будут обрабатываться все пиксели объекта рассчитываться, потом поверх них обсчитываться следующие пиксели, и т.д.)
А если бы у нас обе фигуры рисовались за один вызов draw, при одинаковом depth-buffer на самом деле может результат быть любой, вплоть до того что один пиксель с одной фигуры, а другой пиксель из другой, для этого специально смещают координату объектов на минимальную величину, например на 0.01f чтобы точно не было такой ситуации.

danek130995
Сообщения: 42
Зарегистрирован: 25 янв 2015, 18:57

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение danek130995 » 13 янв 2016, 12:21

Draz1w, спасибо Вам большое, теперь понял. Я просто не знал, что если на данном уровне уже пиксель есть нарисованный, т.е. в z - буфере уже что-то записано, то новый не будет рисоваться. Спасибо!

АнтонФ
Сообщения: 6
Зарегистрирован: 14 янв 2016, 16:49

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение АнтонФ » 14 янв 2016, 16:54

Я не очень понимаю механизм работы. Мы создаем массив вершин и проекцию в самом начале, на этапе инициализации. Но разве это не должно делаться при отрисовке кадра, ведь в реальных задачах объекты перемещаются и наблюдатель тоже смотрит на происходящие в этом кадре слева в следующем справа.
Как насчет анимации?

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 16 янв 2016, 14:09

АнтонФ писал(а):Я не очень понимаю механизм работы. Мы создаем массив вершин и проекцию в самом начале, на этапе инициализации. Но разве это не должно делаться при отрисовке кадра, ведь в реальных задачах объекты перемещаются и наблюдатель тоже смотрит на происходящие в этом кадре слева в следующем справа.
Как насчет анимации?
Объекты обычно действительно задаются на этапе инициализации, а все действия с ними происходят за счет матриц аккумулирующий трансформации.
если примитивно объяснять, что если создать иденичную матрицу 4x4, потом ее переместить, повернуть или изменить ее размер, то достаточно эту матрицу умножить на координаты любого объекта, чтобы с ним произошли все теже самые трансформации...
Т.е. никаких действий над объектами обычно не делают, а трансформируют специальные матрицы, а потом эту матрицу умножают на объект вот так:

Код: Выделить всё

	uniform mat4 mvp; // model, view, projection matrix
        attribute vec4 aPosition;
		
	void main() {
		
		gl_Position = mvp * aPosition;

}
можно конечно пытаться изменять и сами вершины объектов, но это операция очень долгая в вычислениях ведь вершин у объекта может быть тысячи. Поэтому трансформируют матрицы.

Тема эта сложная сразу скажу, но без нее никак дальше двигаться не получиться
http://www.opengl-tutorial.org/beginner ... -matrices/

АнтонФ
Сообщения: 6
Зарегистрирован: 14 янв 2016, 16:49

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение АнтонФ » 19 янв 2016, 07:25

Draz1w писал(а):
АнтонФ писал(а): Т.е. никаких действий над объектами обычно не делают, а трансформируют специальные матрицы, а потом эту матрицу умножают на объект вот
Я с матрицами уже знаком (какую матрицу применить, чтобы повернуть налево, направо, сдвинуться...). Непонятно где и какими методами это все делать в методе "рендер". Я в свое время кодил под openGL 1.0 для ПК, так вот там было понятней. Сначала задаешь смещение всей сцены относительно глаза, потом для каждого объекта смещаешь систему координат, рисуешь, смещаешь обратно... и так пока всю сцену не отрисуешь. Тут я не вдуплю никак. Мы скормили OpenGL массив вершин в самом начале. А если объект не надо рисовать, допустим через 10 секунд он должен пропасть?
Я же правильно понимаю, что метод render это и есть тот самый "gameloop" в котором надо обсчитывать новое положение объектов в зависимости от времени и произошедших событий?

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 19 янв 2016, 10:57

АнтонФ писал(а): Я в свое время кодил под openGL 1.0 для ПК, так вот там было понятней. Сначала задаешь смещение всей сцены относительно глаза, потом для каждого объекта смещаешь систему координат, рисуешь, смещаешь обратно... и так пока всю сцену не отрисуешь. Тут я не вдуплю никак. Мы скормили OpenGL массив вершин в самом начале. А если объект не надо рисовать, допустим через 10 секунд он должен пропасть?
Я же правильно понимаю, что метод render это и есть тот самый "gameloop" в котором надо обсчитывать новое положение объектов в зависимости от времени и произошедших событий?
В GL20 немного не так, честно говоря в двух словах объяснить сложно, и у меня не хватит таланта но попробую :).
В 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 напишут нормальный мануал по матрицам :)

АнтонФ
Сообщения: 6
Зарегистрирован: 14 янв 2016, 16:49

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение АнтонФ » 19 янв 2016, 13:24

Draz1w писал(а): В GL20 немного не так, честно говоря в двух словах объяснить сложно, и у меня не хватит таланта но попробую :).
В GL20 не надо таскать всю сцену для отрисовки объектов туда сюда... обычно создают 3 матрицы,
Правильно ли я понял, что для реализации анимации надо шейдер вершин более сложный написать? Типа в нем и будут координаты вершин умножаться на матрицы. Еще как разбить массив вершин на отдельные объекты, чтобы потом к ним разные матрицы применять? Короче у меня тумана в голове больше, чем ясности. Пыталя разобраться в DX 11, там та же идеология с шейдерами и тоже минимум материала дальше статических кубиков с текстурами.

Вот нигде не могу туториала найти, чтобы пример с анимацией был. Матрицы это так-то чисто математика. А вот где бы нормальный материал почитать по методам OpenGL ES, для реализации всего этого? Я пока не нашел, надеялся, что тут у Вас скоро появится следующий урок :D

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 19 янв 2016, 16:14

АнтонФ писал(а): Правильно ли я понял, что для реализации анимации надо шейдер вершин более сложный написать? Типа в нем и будут координаты вершин умножаться на матрицы.
Да он простой блин а не сложный :)
просто тупо в шейдере умножаешь

Код: Выделить всё

gl_Position = u_MVPMatrix  * a_Position;
вот просто одна строчка в шейдере трансформирует все вершины с помощью матрицы :)
а вот вся сопутствующая лабуда вот тут...
http://www.learnopengles.com/android-le ... g-started/
с анимацией есть пример (если я не ошибся там вроде крутятся эти треугольнички)

вот тут есть примеры спрайтовой анимации
http://4pda.ru/forum/index.php?showtopic=418429

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 19 янв 2016, 16:18

АнтонФ писал(а):
Draz1w писал(а): там та же идеология с шейдерами и тоже минимум материала дальше статических кубиков с текстурами.
Угу, я тоже столкнулся что на самом деле есть такой пробел.
Причем вон про матрицы и большие объекты пусто... типа как из 3d редактора построить модель в openGL.
А дальше опять появляется материал, типа там про свет, тени, отражение и прочее :)))
Я не знаю почему :)
Может кстати супер библию openGL почитать, там наверно должно быть, но у меня руки не дошли :)))
На рутрекере есть английская версия.

АнтонФ
Сообщения: 6
Зарегистрирован: 14 янв 2016, 16:49

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение АнтонФ » 19 янв 2016, 17:04

Я пытаюсь вот это перевести на русский. Вроде доходчиво пишут
начало туториала
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;" +
        "}";

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 20 янв 2016, 13:46

АнтонФ писал(а):Я пытаюсь вот это перевести на русский. Вроде доходчиво пишут
начало туториала
Тут главное не сдаться и вот этот первоначальный такой затык пройти, врубиться как это все работает.
Я 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 );
								
	}
освоишь уже можно будет очень много крутых вещей делать. очень крутая штука opengl и шейдеры.

АнтонФ
Сообщения: 6
Зарегистрирован: 14 янв 2016, 16:49

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение АнтонФ » 20 янв 2016, 18:50

Draz1w писал(а): Тут главное не сдаться и вот этот первоначальный такой затык пройти, врубиться как это все работает.
Я 4 раза бросал пытаясь разобраться с opengl :)
....ка opengl и шейдеры.
а можешь хоть в кратце своими словами объяснить такой момент:
в шейдере описываются некие переменные (attribute): одна матрица, две, числа какие-то...
как они в него передаются?
т.е. какие-то переменные, это те самые координаты вершин объекта, которые во времени не меняются, а какие-то - например позиция камеры или позиция объекта - меняются.
Как устанавливается связь между переменными в шейдере и переменными в JAVA?

Draz1w
Сообщения: 20
Зарегистрирован: 10 окт 2015, 17:07

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение Draz1w » 20 янв 2016, 20:52

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

АнтонФ
Сообщения: 6
Зарегистрирован: 14 янв 2016, 16:49

Re: Урок 172. Perspective. Frustum. Ortho.

Сообщение АнтонФ » 26 янв 2016, 07:44

Спасибо огромное за пояснение. А ссылка вообще шикарной кладезью оказалась.

Ответить