Форум программистов, компьютерный форум, киберфорум
OpenGL
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
1

Преобразование в экранные координаты (неточность)

31.03.2017, 10:35. Просмотров 2229. Ответов 18
Метки нет (Все метки)

Здравствуйте! Я опять с дурацкими вопросами)

Возникла проблема с пробразованием object space - screen space. Сразу оговорюсь, что инфы про него просто тонна (например отличное обсуждение http://www.gamedev.ru/code/forum/?id=81580), но во всем написано примерно одно и то же (написано круто, да и понимание как примерно это работает меня только-только настигло или я не могу сделать нужный вывод из имеющейся математики, так что если кому-то покажется вопрос очевидным - заранее извиняюсь.

Собственно, я работаю с готовым движком. Есть сцена, заданная glFrustum, есть object space координаты точек ломаной. Я хочу перейти к экранным координатам. Шейдеры:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#version 120
 
attribute float line;
 
varying float t;
varying vec2 screen_pos;
 
vec2 screen_space(vec4 vertex)
{   
    return vec2( vertex.xy / vertex.w );
}
 
void main()
{
    vec4 pos  = gl_ModelViewProjectionMatrix * gl_Vertex;
    screen_pos = screen_space(pos);
    t = line;
    gl_Position = pos;
    gl_FrontColor = vec4(1, 0, 0, 1);
}
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#version 120
#extension GL_EXT_geometry_shader4 : enable
 
varying in float t[2];
varying in vec2 screen_pos[2];
 
varying float s;
 
void main()
{       
    gl_Position = vec4(screen_pos[0], 0, 1);
    gl_FrontColor = gl_FrontColorIn[0];
    s = t[0];
    EmitVertex();
    gl_Position = vec4(screen_pos[1], 0, 1);
    gl_FrontColor = gl_FrontColorIn[0];
    s = t[1];
    EmitVertex();   
    EndPrimitive();
}
В основном, это работает правильно, но есть один момент.
При виде сверху линия выглядит правильно (рис. 1), также и при наклоне и приближении к средней вершине (рис. 2). Но при дальнейшем приближении происходит перескок линий (рис. 3), но находятся они на правильной прямой. Посмотрев значения, я понял, что после перехода к Clip координатам у вершин за пределами сцены получаются отрицательные Z и W соответственно. Не особо понимая что с этим делать, я попробовал выкинуть знак при делении. И получилось вот что: линия перестали перескакивать, но при сильном приближении линия не доходит до края экрана (рис .4). Почему это происходит? Как так получается, что если передаются object space координаты то линия рисуется правильно, а после моих преобразований к экранным - нет?
Ради интереса я взял gluProject и посмотрел что считает она - перескок тоже есть, про второй эффект я проверю. Думается мне это как-то связано с параметрами glFrustum. Или это просто ошибка в расчете или точности вычислений?
ps. картинки набросаны схематично, скриншот сейчас нет возможности сделать.
0
Миниатюры
Преобразование в экранные координаты (неточность)   Преобразование в экранные координаты (неточность)   Преобразование в экранные координаты (неточность)  

Преобразование в экранные координаты (неточность)  
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
31.03.2017, 10:35
Ответы с готовыми решениями:

Преобразование координат мыши в мировые координаты
Привет всем! Начал писать 3d игру и возникла проблема: преобразование координат. Дело в том, что я...

Луч выбора (преобразование экранных координат в координаты сцены)
Хочу поделиться знанием связанным с получением луча выбора (преобразование экранных координат в...

Vb.net directx, slimdx преобразовать экранные координаты мыши в 3d координаты
vb.net directx, slimdx преобразовать экранные координаты мыши в 3d координаты необходимо...

Экранные координаты в мировые
Ребят всем доброго времени суток, подскажите как перевести координаты курсора т.е. (X и Y) в...

18
2016 / 1199 / 208
Регистрация: 26.02.2009
Сообщений: 4,577
Записей в блоге: 5
31.03.2017, 12:00 2
sharrowkyn, по коду я лично не могу понять что изначально планировалось сделать.
Поясните более подробно исходные данные и цель которую вы хотите получить.
А именно зачем вам
Цитата Сообщение от sharrowkyn Посмотреть сообщение
перейти к экранным координатам
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
31.03.2017, 16:07  [ТС] 3
snake32, я все бьюсь с жирной пунктирной линией (с которой вы мне уже раз помогли). Если смотреть на линию, которая получается glLineWidth - она одинаковой ширины независимо от сцены, с какого-то момента я ее подхватываю и рисую шейдерами. Найденный пример использовал для этого экранные координаты, я почему-то подумал, что это норм подход. Может быть ошибся. Но если я хочу линию не зависящую от перспективы, разве углы прямоугольника (линии) не должны считаться после проективных преобразований?

Добавлено через 2 часа 52 минуты
Выкладываю код, чтобы ясно было, что происходит.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void paintWideLine(int primitive, float lineWidth, float dash, float gap, float shift)
{
    if (lineWidth < maxLineWidth)
    {
        glLineWidth(5.0);
        glBegin(primitive);
        for (int i = 0; i < count; i++)
            glVertex3fv(vertecies[i]);
        glEnd();
    }
    else
    {
        glLineWidth(1.0);
        lineShaderProgram.setEnabled(true);
        lineShaderProgram.setUniform("viewport", viewport[0], viewport[1]);
        lineShaderProgram.setUniform("width", lineWidth);
        lineShaderProgram.setUniform("shift", shift);
        lineShaderProgram.setUniform("dash", dash, gap);
        int attributeLocation = lineShaderProgram.getAttribute("line");
 
        float length = 0;
        double screen1[2], screen2[2];
 
        getScreenCoordinates(*vertecies, mvpMatrix, viewport, screen2);
        glBegin(primitive);
        lineShaderProgram.setAttribute(attributeLocation, length);
        glVertex3fv(*vertecies++);
        for (int i = 1; i < count; i++, vertecies++)
        {
            memcpy(screen1, screen2, sizeof(screen2));
            getScreenCoordinates(*vertecies, mvpMatrix, viewport, screen2);
            length += hypot(screen2[0] - screen1[0], screen2[1] - screen1[1]);
            lineShaderProgram.setAttribute(attributeLocation, length);
            glVertex3fv(*vertecies);
        }
 
        glEnd();
        lineShaderProgram.setEnabled(false);
    }
}
Шейдеры:
glSlang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#version 120
 
attribute float line;
 
varying float t;
varying vec2 screen_pos;
 
uniform ivec2 viewport;
 
vec2 screen_space(vec4 vertex)
{   
    return vec2( vertex.xy / vertex.w );    
}
 
void main()
{
    vec4 pos  = gl_ModelViewProjectionMatrix * gl_Vertex;
    screen_pos = screen_space(pos);
    t = line;
    gl_Position = pos;
    gl_FrontColor = vec4(1, 0, 0, 1);
}
glSlang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#version 120
#extension GL_EXT_geometry_shader4 : enable
 
uniform float width;
uniform float shift;
uniform ivec2 viewport;
uniform ivec2 dash;
 
varying in float t[2];
varying in vec2 screen_pos[2];
 
varying float s;
 
void main()
{       
    vec2 v = normalize(screen_pos[1] - screen_pos[0]);
    vec2 n = vec2(-v.y, v.x);   
    gl_Position = vec4(screen_pos[0] + (width*n + shift*n)/viewport, 0, 1);
    gl_FrontColor = gl_FrontColorIn[0];
    s = t[0];
    EmitVertex();
    gl_Position = vec4(screen_pos[0] - (width*n - shift*n)/viewport, 0, 1);
    gl_FrontColor = gl_FrontColorIn[0];
    s = t[0];
    EmitVertex();
    gl_Position = vec4(screen_pos[1] + (width*n + shift*n)/viewport, 0, 1);
    gl_FrontColor = gl_FrontColorIn[1];
    s = t[1];
    EmitVertex();       
    EndPrimitive();
    
    gl_Position = vec4(screen_pos[0] - (width*n - shift*n)/viewport, 0, 1);
    gl_FrontColor = gl_FrontColorIn[0];
    s = t[0];
    EmitVertex();
    gl_Position = vec4(screen_pos[1] - (width*n - shift*n)/viewport, 0, 1);
    gl_FrontColor = gl_FrontColorIn[1];
    s = t[1];   
    EmitVertex();
    gl_Position = vec4(screen_pos[1] + (width*n + shift*n)/viewport, 0, 1);
    gl_FrontColor = gl_FrontColorIn[1];
    s = t[1];   
    EmitVertex();   
    EndPrimitive(); 
}
glSlang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#version 120
 
uniform ivec2 dash;
 
varying float s;
 
void main()
{
    float period = dash[0] + dash[1];
    if(period == 0.0 || mod(s, period) < dash[0])
        gl_FragColor = gl_Color;
    else
        gl_FragColor = vec4(0);
}
0
2016 / 1199 / 208
Регистрация: 26.02.2009
Сообщений: 4,577
Записей в блоге: 5
31.03.2017, 16:47 4
Как посчитать длину всей ломанной для каждой вершины на GPU я не знаю. Здесь нужна какая-то глобальная переменная
Но вот то что каждая вершина передаётся через glVertex это ад для CPU однозначно. Если вершин много(тысячи).
В этом случае поможет VBO.
+ можно сгруппировать отрисовку по материалам/шейдерам
+ находить локацию юниформы/атрибута на каждом кадре не обязательно.(у меня при загрузке/линковке programObject ищется и запоминается в отдельном массиве для юниформов,блоковюниформ,атрибу тов для каждого programObject)
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
TProgramObject = class
  private
    FID:GLuint;
  public
    // массивы константной длины
    Attrib:array[TAttrbEnum] of GLint;
    UniformBlock:array[TUniformBlockEnum] of GLint;
    Uniform:array[TUniformEnum] of GLint;
 
    constructor Create;
    destructor Destroy; override;
    procedure Bind; inline;
    function Get( param:GLenum ):GLint; inline;
    function GetInfoLog:string;
    procedure Link;
    procedure Attach( const source:string; shaderType:TShaderClass );           overload;
    procedure Attach( shader:TShader );                                         overload;
    function GetAttached:TArray<GLuint>;
    function GetUniformBlockIndex( const name:string ):GLuint;
 
    procedure UniformBlockBinding( const name:string; bind_point:GLuint );
    function UniformLocation( const name:string ):GLint;
    function AttribLocation( const name:string ):GLint;
  end;
 
procedure TProgramObject.Link;
    var ub:TUniformBlockEnum;
            u:TUniformEnum;
            a:TAttrbEnum;
            p:AnsiString;
begin
  glLinkProgram( FID );
  Assert( Get( GL_LINK_STATUS )<>GL_FALSE, GetInfoLog );
  glValidateProgram( FID );
  Assert( Get( GL_VALIDATE_STATUS )<>GL_FALSE, GetInfoLog );
 
  Assert( CheckOpenGLError, GetLastOpenGLError );
  for ub:=Low(ub) to High(ub) do
    UniformBlock[ub] := glGetUniformBlockIndex( FID, PGLChar(ubName[ub]) );
  for u:=Low(u) to High(u) do
    Uniform[u] := glGetUniformLocation( FID, PGLChar(uName[u]) );
  for a:=Low(a) to High(a) do
    Attrib[a] := glGetAttribLocation( FID, PGLChar(aName[a]) );
end;
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
31.03.2017, 20:24  [ТС] 5
snake32, по поводу VBO все верно, но у меня их нет) но glDrawArrays стоит сделать конечно. По поводу локаций атрибутов замечание принято, спасибо. Но код, к сожалению, не работает (при наклоне и приближении) А по поводу преобразований к screen space нет идей почему может искажение получаться? Или как можно по другому получить координаты вершин прямоугольника (отрезок толстой ломаной) не искаженные перспективой?
0
2016 / 1199 / 208
Регистрация: 26.02.2009
Сообщений: 4,577
Записей в блоге: 5
01.04.2017, 01:38 6
Попробуйте так (сам не проверял):
glSlang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#version 120
void main()
{
    gl_Position  = gl_ModelViewProjectionMatrix * gl_Vertex;
    gl_TexCoord[0] = gl_MultiTexCoord0;// line dist as TexCoord.s
    gl_FrontColor = gl_Color;
    gl_BackColor = gl_Color;
}
 
#version 120
#extension GL_EXT_geometry_shader4 : enable
uniform float width;
uniform float scale;
uniform vec2 vp;
void main()
{
    vec3 p0 = gl_PositionIn[0].xyz / gl_PositionIn[0].w;
    vec3 p1 = gl_PositionIn[1].xyz / gl_PositionIn[1].w;
    
    vec2 L = p1.xy - p0.xy;
    vec2 W = normalize(vec2(-L.y,L.x))*vp*width;
    
    gl_Position = vec4( p0.xy-W, p0.z, 1.0 );
    gl_FrontColor = gl_FrontColorIn[0];
    gl_BackColor = gl_BackColorIn[0];
    gl_TexCoord[0] = vec4( gl_TexCoordIn[0][0].s*scale, 0.0, 0.0, 1.0 );
    EmitVertex();
        
    gl_Position = vec4( p0.xy+W, p0.z, 1.0 );
    gl_FrontColor = gl_FrontColorIn[0];
    gl_BackColor = gl_BackColorIn[0];
    gl_TexCoord[0] = vec4( gl_TexCoordIn[0][0].s*scale, 1.0, 0.0, 1.0 );
    EmitVertex();
    
    gl_Position = vec4( p1.xy-W, p1.z, 1.0 );
    gl_FrontColor = gl_FrontColorIn[1];
    gl_BackColor = gl_BackColorIn[1];
    gl_TexCoord[0] = vec4( gl_TexCoordIn[1][0].s*scale, 0.0, 0.0, 1.0 );
    EmitVertex();       
    EndPrimitive();
    
    gl_Position = vec4( p1.xy+W, p1.z, 1.0 );
    gl_FrontColor = gl_FrontColorIn[1];
    gl_BackColor = gl_BackColorIn[1];
    gl_TexCoord[0] = vec4( gl_TexCoordIn[1][0].s*scale, 1.0, 0.0, 1.0 );
    EmitVertex();       
    EndPrimitive();
}
 
#version 120
uniform sampler2D tex;
void main()
{
    float alpha = texture2D( tex, gl_TexCoord[0].st ).a * gl_Color.a;
    if( alpha < 0.25 )
        discard;
    gl_FragColor = vec4( gl_Color.xyz, alpha );
}
Выходной тип примитива геометрического шейдера GL_TRIANGLE_STRIP, кол-во вершин 4;
Входной GL_LINES или GL_LINE_LOOP или GL_LINE_STRIP
Длину передаём как текстурную координату glTexCoord1f(dist) (значения вроде не обрезаются до 1.0 как для glColor, хотя могу ошибаться, тогда работать нормально не сможет);
Текстуру с нарисованным участком пунктирной линии загружаем как альфа канал(используется только он);
Sampler для S координаты настраиваем как GL_REPEAT(через glTexParameteri);
Ну и цвет линии через glColor4f (альфа тоже участвует);
Ах да. uniform'ы: width - ширина в пикселях, а vp = vec2(1.0/screenwidth, 1.0/screenheight)
scale - по-идеи, должен растягивать/сжимать текстуру по всей длине кривой.
Может чего не правильно написал. Надо в реалтайме поиграться с юниформами, если вообще что-то нарисует...

Добавлено через 34 минуты
Цитата Сообщение от sharrowkyn Посмотреть сообщение
но glDrawArrays стоит сделать конечно
Конечно стОит. VBO добавили по-моему даже раньше чем первые шейдеры.
1
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
01.04.2017, 08:42  [ТС] 7
Цитата Сообщение от snake32 Посмотреть сообщение
Попробуйте так
Если честно, я думаю этот код тоже будет давать искажения при наклоне и приближении (как на моих схематичных рисунках). Я пробовал считать координаты так (рисуя обычную линию с двумя вершинами на отрезок), и получал те же смещения вершин (хотя это неточно, надо перепроверить), когда у меня невидимые вершины переваливали за 0 по Z.
C
1
2
3
4
    vec3 p0 = gl_PositionIn[0].xyz / gl_PositionIn[0].w;
    vec3 p1 = gl_PositionIn[1].xyz / gl_PositionIn[1].w;
    
    gl_Position = vec4( p0.xyz, 1.0 );
Но вот что я действительно не пробовал, а попробовать стоит - оставить w, не нормировать, а наоборот домножить нормаль или как-то так. В понедельник буду пробовать. Спасибо большое!

Про текстуру я понял (шрифты по туториалу так сделал) и сам думал над этим, но если честно я не вижу зачем она тут нужна, если код примерно тот же, а текстурирование линии с меня не требуют. Ну то есть да, конечно она будет выглядеть лучше, но пока достаточно просто discard (кстати, не знал, прикольно)

Цитата Сообщение от snake32 Посмотреть сообщение
Конечно стОит. VBO добавили по-моему даже раньше чем первые шейдеры.
Ок, учту, спасбио за замечание.
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
05.04.2017, 09:50  [ТС] 8
Тут путем плясок с бубном почти удалось получить практически то, что нужно.

Но на самом деле вся проблема сводится к вопросу.
Допустим есть вектор в мировых координатах (получен умножением на mvp матрицу):
v(-62.69, -43.65, -23.52, -23.47)

Если сделать так:
C
1
gl_Position = vec4(v.xyz/v.w, 1);
Получаем искажения рис.3 - точка перелетает в положительные x,y
Если сделать так:
C
1
gl_Position = vec4(v.xyz/abs(v.w), 1)
Получаются искажения рис.4 - точка не уходит за границы экрана.
Но вот если сделать так:
C
1
2
3
4
float w = 1.0;
if(v.w < 0)
    w = -1.0;
gl_Position = vec4(v.xyz/abs(v.w), w);
То получаем ожидаемое положение точек. Отсюда я предполагаю, что мне не хватает какого-то шага при переводе в экранные координаты при w < 0. Может быть у кого-то есть идеи?
0
1229 / 596 / 74
Регистрация: 01.10.2012
Сообщений: 2,844
05.04.2017, 11:26 9
Цитата Сообщение от sharrowkyn Посмотреть сообщение
Может быть у кого-то есть идеи?
Знать бы нще чего Вы хотите добиться В этом топике Вы ссылаетесь на предыдущий, а в нем еще на что-то. Нехорошо, посты должны быть самодостаточны. Не верю что Вам действительно нужно явное преобразование из однородных координат в декартовы.

Хотите рисовать линию одной толщиной - GL_LINES, хотите чтобы к ней применялась перспектива - переходите к геометрии, лучше GL_QUADS. А если нужен пунктир - разбивайте линию на несколько. Если же есть какие-то проблемы - изложите их не растекаясь "мыслью по древу"
0
2016 / 1199 / 208
Регистрация: 26.02.2009
Сообщений: 4,577
Записей в блоге: 5
05.04.2017, 11:30 10
sharrowkyn, как вычисляется матрица проекции? При каких значениях получается отрицательная w?
По-моему так быть не должно. Или я не правильно понимаю смысл w в перспективной проекции...
Имхо, w должно быть строго больше 0. Иначе деление на 0 Или отрицательные w которая выворачивает сцену наизнанку.
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
05.04.2017, 12:10  [ТС] 11
Igor3D, я пытаюсь сделать линию/линию-пунктир произвольной толщиной (больше максимума glLineWidth) с произвольными значениями штриха/пропуска, не подвергающуюся перспективным искажениям - то есть полный аналог glLineWidth и glLineStipple, но за рамками ограничений OpenGl. По этому поводу я создал две темы в одной попросил помочь с геометрическим шейдером (решено), в другой поинтересовался есть ли какой хороший алгоритм (нет ответов). Больше там ничего интересного нет. Если у Вас есть желание помочь, я готов сжато и емко ответить на любой Ваш вопрос и выслушать любое предложение. Буду очень благодарен.

snake32, матрица проекции устанавливается glFrustum, к сожалению я вряд ли могу в ней что-то поправить (судя по гуглению соотношение front/back не очень). ModelView единичная.
Значения:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
frustum:
left    -0.004
right    0.004
bottom  -0.002
top      0.002
front    0.01
back     36.42
 
vertex:
x -74.87
y -32.13
z 71.37
w 1.00
Естественно, в шейдере просто берется gl_ModelViewProjectionMatrix*g l_Vertex, которые я посмотреть не могу, поэтому мировые значения считал и смотрел просто в вызывающем коде. Конечно, мог там где-то накосячить, но сравнивал с gluProject в параметрах все матрицы получены getDoublev - она дает те же результаты, поэтому я сомневаюсь.

Вообще, мне тоже кажется, что это все ересь - думается, у линии значения clip-space-координат интерполируются между вершинами и те, которые не проходят тест -w < xyz < w просто отбрасываются, а остальные уже нормально преобразуются в screen-space. Вот только тогда у меня дальше с идеями плохо.
0
2016 / 1199 / 208
Регистрация: 26.02.2009
Сообщений: 4,577
Записей в блоге: 5
05.04.2017, 12:52 12
Цитата Сообщение от sharrowkyn Посмотреть сообщение
ModelView единичная.
А как же вы приближаете/отдаляете?

Цитата Сообщение от sharrowkyn Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
frustum:
left* * -0.004
right * *0.004
bottom* -0.002
top * * *0.002
front * *0.01
back* * *36.42
 
vertex:
x -74.87
y -32.13
z 71.37
w 1.00
Может тупо точности не хватает? как бы на 3 порядка отличия вершин и параметров фрустума в шейдере то обычный float(не double)....

Цитата Сообщение от sharrowkyn Посмотреть сообщение
gl_ModelViewProjectionMatrix*g l_Vertex, которые я посмотреть не могу
Можно вычислить на CPU(если программируете на С++): есть замечательная библиотека GLM синтаксис и типы такие же как GLSL. У меня правда сайт сейчас не доступен...

Добавлено через 1 минуту
Или копать в сторону отладки шейдеров...
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
05.04.2017, 13:22  [ТС] 13
Цитата Сообщение от snake32 Посмотреть сообщение
А как же вы приближаете/отдаляете?
Я так сходу не отвечу (эту часть проекта я не трогал), но скорее всего пересчитывается проекционная матрица - меняются параметры glFrustum.
Цитата Сообщение от snake32 Посмотреть сообщение
Может тупо точности не хватает?
Цитата Сообщение от snake32 Посмотреть сообщение
Можно вычислить на CPU(если программируете на С++)
Да я значение в double на CPU руками считаю для отладки - получается как раз такие мировые с w < 0, думаю, что в шейдере качественно ничего не меняется в расчетах (насчет знаков я уверен 100%). Если честно, я думаю это тупик, да и на stackoverflow мне тоже кинули ссылки на то, как отсечение происходит. Почитаю вдумчиво, может достигну просветления.
Хотя конечно пара вопросов меня мучают:
Интересно, если бы удалось вырубить перспективную интерполяцию для gl_Position - что было бы (например взять более свежую версию glsl и сделать noperspective)? Для длины штриха удалось это сделать через расширение - он ровный и не искажается перспективой.
И как происходит рендер линии, когда задается glLineWidth(10)?
Попробую с другой стороны зайти - через фрагментный, может придумаю что (велосипед ).
Спасибо большое за помощь!
0
1229 / 596 / 74
Регистрация: 01.10.2012
Сообщений: 2,844
05.04.2017, 13:54 14
Цитата Сообщение от sharrowkyn Посмотреть сообщение
Igor3D, я пытаюсь сделать линию/линию-пунктир произвольной толщиной (больше максимума glLineWidth) с произвольными значениями штриха/пропуска, не подвергающуюся перспективным искажениям - то есть полный аналог glLineWidth и glLineStipple, но за рамками ограничений OpenGl.
Что за ограничения и чем Вас не устраивает простецкое GL_LINES? Зачем связываться с геометрическим шейдером?

Добавлено через 5 минут
Если не хватает максимума glLineWidth - то не проще ли нарисовать 2 (или более) линий?
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
05.04.2017, 14:09  [ТС] 15
Цитата Сообщение от Igor3D Посмотреть сообщение
Что за ограничения и чем Вас не устраивает простецкое GL_LINES?
По стандарту glLineWidth поддерживает только значение 1, у меня фактически рисует до 10. Мне поставили задачу сделать больше. В частности, это обусловлено тем, что изображение потом может пойти на печать и на большой формат (как захват изображения делается я слабо представляю, в этот кусок проекта я лазил очень локально), а там из-за больших разрешений - даже ширины линии 10 критически не хватает. Может быть эта проблема как-то обходится, но с серьезными переделками.
glLineStipple еще ничего, хотя все равно маска 16-битная с масштабированием. Соотношения штрих/пунктир типа 23px/17px не сделать, до кучи еще попросили сделать произвольный пунктир. То есть как бы пунктир пока можно оставить glLineStipple, но не исключено, что потом со временем вылезет, что он не подходит.

Добавлено через 6 минут
Цитата Сообщение от Igor3D Посмотреть сообщение
Если не хватает максимума glLineWidth - то не проще ли нарисовать 2 (или более) линий?
Найденные мною способы опираются на рендеры треугольников через геометрический шейдер. В любом случае (треугольник или доп. линии) эти способы тащат за собой расчет дополнительных координат вершин. Тот вариант, на который я опирался, дает мне искажения, описанные в этом топике.
Допустим, я буду рисовать несколько линий. Тогда мне нужно смещать координаты (ровно так же, как и для треугольников) доп. линий. Как бы так их сместить, чтобы в итоге линия (итоговая) была не искажена перспективой?
0
1229 / 596 / 74
Регистрация: 01.10.2012
Сообщений: 2,844
05.04.2017, 15:00 16
Цитата Сообщение от sharrowkyn Посмотреть сообщение
Тогда мне нужно смещать координаты (ровно так же, как и для треугольников) доп. линий. Как бы так их сместить, чтобы в итоге линия (итоговая) была не искажена перспективой?
Для начала и конца линии делаете gluProject, получаете координаты в пыкселях. Добавляете нужные половинки толщины и переводите опять в координаты модели с помощью gluUnProject. Рисуете - хотите линии, хотите quad

Тут правда есть одна бяка - линия или ее часть могут быть за пределами видимости. Ну придется найти пересечение с пресловутым "фрустумом" и плясать от точек пересечения. Это неприятная возня, особенно с учетом толщины, но с этим никто не торопит, сначала сделайте просто линии "в экране", когда заработает - все станет легче
0
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
05.04.2017, 15:33  [ТС] 17
Цитата Сообщение от Igor3D Посмотреть сообщение
Для начала и конца линии делаете gluProject, получаете координаты в пыкселях. Добавляете нужные половинки толщины и переводите опять в координаты модели с помощью gluUnProject. Рисуете - хотите линии, хотите quad
Все верно, так и сделал в геометрическом шейдере, только через GL_TRIANGLE_STRIP.
Цитата Сообщение от Igor3D Посмотреть сообщение
Тут правда есть одна бяка - линия или ее часть могут быть за пределами видимости. Ну придется найти пересечение с пресловутым "фрустумом" и плясать от точек пересечения. Это неприятная возня, особенно с учетом толщины, но с этим никто не торопит, сначала сделайте просто линии "в экране", когда заработает - все станет легче
Именно это и суть проблемы. Вершина за пределами видимости, w < 0, gluProject дает "некорректные" значения. А как найти пересечение с фрустумом с учетом толщины не подскажете?

Добавлено через 9 минут
Хм, то есть правильно ли я понимаю, что можно найти пересечение отрезка с frustum'ом, перейти уже от этой точки к экранным координатам и рисовать толстую линию от нее?
0
1229 / 596 / 74
Регистрация: 01.10.2012
Сообщений: 2,844
05.04.2017, 16:21 18
Цитата Сообщение от sharrowkyn Посмотреть сообщение
Все верно, так и сделал в геометрическом шейдере, только через GL_TRIANGLE_STRIP.
Не уверен, то что Вы называете "экранными" координатами (деление на w) - это по существу перевод из однородных в декартовы, до пикселей там еще далеко. gluProject проще и надежнее

Цитата Сообщение от sharrowkyn Посмотреть сообщение
Хм, то есть правильно ли я понимаю, что можно найти пересечение отрезка с frustum'ом, перейти уже от этой точки к экранным координатам и рисовать толстую линию от нее?
Да

Цитата Сообщение от sharrowkyn Посмотреть сообщение
А как найти пересечение с фрустумом с учетом толщины не подскажете?
В общих чертах - заменить линию на пр-к и найти пересечения для всех его 4 сторон
1
60 / 2 / 0
Регистрация: 01.03.2017
Сообщений: 20
Завершенные тесты: 1
05.04.2017, 16:44  [ТС] 19
Цитата Сообщение от Igor3D Посмотреть сообщение
Не уверен, то что Вы называете "экранными" координатами (деление на w) - это по существу перевод из однородных в декартовы, до пикселей там еще далеко. gluProject проще и надежнее
Да, признаю, я скорее говорю про NDC, которые мне и интересны, до пикселей там просто наложение NDC на viewport, которое достаточно просто. Да и gluProject очень простая функция, я уже исходники давно посмотрел.

Цитата Сообщение от Igor3D Посмотреть сообщение
Да
Спасибо за идею - буду пробовать.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.04.2017, 16:44

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Узнать экранные координаты точки
Есть камера, есть точка в трехмерном пространстве. Координаты точки известны. Есть матрица камеры и...

Мировые координаты через экранные
Здравствуйте!Мне необходимо найти мировые координаты в пространстве с помощью точки на экране(точка...

Преобразование мировых координат в экранные
Здравствуйте, требуется ваша помощь. Каким образом преобразовать двухмерные мировые координаты...

Преобразование мировых координат в экранные
Пишу рендерер 3д-объектов на лазарусе(object pascal) just for fun Нашёл такие формулы для...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
19
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.