конус с заданной высотой, радиусом и кол-вом граней

Тема в разделе "WASM.BEGINNERS", создана пользователем NaZGuL, 21 авг 2005.

  1. NaZGuL

    NaZGuL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2004
    Сообщения:
    41
    Адрес:
    Russia
    Заранее прошу сильно не смеяться.

    Вопроса как такового нет, а есть просьба посмотреть прогу … программа должна создавать конус с заданной высотой, радиусом и кол-вом граней. Только дело в том что создается что-то, но на конус это не похоже.

    Может кто чего подскажет…
    Код (Text):
    1.  
    2. xor ebx,ebx
    3. ...
    4. fild [num]; кол-во граней
    5. fldpi ; число пи
    6. fadd st0,st0; пи+пи
    7. fdiv st0,st1; пи / кол-во граней
    8. fstp [alpha]; получился угол
    9. mov ecx,[num]; для цикла
    10. mov edi,model; указатель на массив
    11. push ebx;просто ноль, хотя нет, это начальный угол ( ну это для основания)
    12.  
    13. .gen_loop: ; цикл
    14.       ;запихнем точку (0,len,0)
    15.     mov eax,ebx
    16.     stosd
    17.     mov eax,[len]
    18.     stosd
    19.     mov eax,ebx
    20.     stosd
    21.  
    22.     fld dword [rad];радиус основания
    23.     fld dword [esp];угол
    24.     fsincos
    25.     fmul st0,st2; радиус * косинус (координата по х)
    26.     fstp dword [tmp]
    27.     mov eax,[tmp]
    28.     stosd
    29.     fmul st0,st2; радиус * синус (координата по у)
    30.     fstp dword [tmp]
    31.     mov eax,[tmp]
    32.     stosd
    33.     mov eax,ebx; ноль (координата по z)
    34.     stosd
    35.     fadd dword [alpha]; увеличим угол
    36.     fstp dword [esp];
    37. loop .gen_loop
    38.  
     
  2. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Ты не учитываешь, что fstp выталкивает st0 из стека fpu и смещает указатель вершины и то что было в st2 становится в st1 и т.д. Отсюда две ошибки:

    1) fmul st0,st2; радиус*синус (координата по y)

    После fstp радиус лежит в st1, а не st2 !

    2) fadd dword [alpha] ;увеличим угол

    после двух fstp тут лежит радиус, а не угол (угол у тебя затирается при fsincos)

    Лучше сделать так:
    Код (Text):
    1.     fld dword [rad] ;радиус
    2.     fld dword [esp] ;угол ! если = 0, то проще fldz
    3. .gen_loop:
    4.     ... ;запись точки (0,len,0) хотя не понятно, зачем они нужны ???
    5.     fld st0           ;копия угла
    6.     fsincos           ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    7.     fmul st0,st3      ;x
    8.     fstp dword [edi]
    9.     fmul st0,st2      ;y
    10.     fstp dword [edi+4]
    11.     mov [edi+8],ebx     ;z = 0
    12.     add edi,12
    13.     fadd dword [alpha] ;увеличиваем угол
    14.     loop .gen_loop
    15.     ;не забываем в конце очистить стек fpu
    16.     fstp st0
    17.     fstp st0
    18.     ;у тебя тут еще в st0 остается [num] от первой загрузки
    19.     ;поэтому либо нужен еще один fstp st0, либо замена fdiv st0,st1 на fdivrp st1,st0
     
  3. NaZGuL

    NaZGuL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2004
    Сообщения:
    41
    Адрес:
    Russia
    Я попробовал то что мне предложил Leo и нашел одну ошибку... это конечно мой косяк, ошибка была в том что были перепутаны координаты Y и Z. Вот код с исправленными ошибками, проверенно все работает :derisive:
    Код (Text):
    1.  
    2.     fild [num]  ; кол-во граней
    3.     fldpi       ; число пи
    4.     fadd st0,st0    ; пи+пи
    5.     fdivrp st1,st0  ; пи / кол-во граней
    6.     fstp [alpha]    ; получился угол
    7.     mov ecx,[num]   ; для цикла
    8.     ;inc ecx
    9.     mov edi,models   ; указатель на массив
    10.     push ebx    ;просто ноль, хотя нет, это начальный угол ( ну это для основания)
    11.  
    12.     fld dword [rad] ;радиус
    13.     fldz        ;начальный угол = 0
    14.  
    15. .gen_loop:
    16.  
    17.     ;запись точки (0,len,0)
    18.     mov  [edi],ebx     ;x = 0
    19.     add  edi,4
    20.     mov  eax,[len]
    21.     mov  [edi],eax     ;y = len
    22.     add  edi,4
    23.     mov  [edi],ebx     ;z = 0
    24.     add  edi,4
    25.     ;запись точки (rad*cos(theta),0,rad*sin(theta))
    26.     fld  st0       ;копия угла
    27.     fsincos        ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    28.     fmul st0,st3       ;x
    29.     fstp dword [edi]
    30.     add  edi,4
    31.     mov  [edi],ebx     ;y = 0
    32.     add  edi,4
    33.     fmul st0,st2       ;z
    34.     fstp dword [edi]
    35.     add  edi,4
    36.     fadd dword [alpha] ;увеличиваем угол
    37.  
    38.     ;запись точки (rad*cos(theta+alpha),0,rad*sin(theta+alpha))
    39.     fld  st0       ;копия угла
    40.     fsincos        ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    41.     fmul st0,st3       ;x
    42.     fstp dword [edi]
    43.     add  edi,4
    44.     mov  [edi],ebx     ;y = 0
    45.     add  edi,4
    46.     fmul st0,st2       ;z
    47.     fstp dword [edi]
    48.     add  edi,4
    49.  
    50. loop .gen_loop
    51.     ;не забываем в конце очистить стек fpu
    52.     fstp st0
    53.     fstp st0
    54.  
    55.     pop eax
    56.  




    И еще, на последок, вот полный исходник (на Fasm'e) с экзешником -> [​IMG] _1522313718__OpenGL.rar
     
  4. NaZGuL

    NaZGuL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2004
    Сообщения:
    41
    Адрес:
    Russia
    Всем приятного времени суток!

    Вот доделал программку, только хотелось бы ее оптимизировать. Может кто чего умного скажет...

    Вот код
    Код (Text):
    1.  
    2. ;====================================================
    3. ;--------------  СОЗДАНИЕ КОНУСА/ЦИЛИДРА-------------
    4. ;====================================================
    5. fild   [num]   ; кол-во граней
    6. fldpi          ; пи
    7. fadd    st0,st0; 2*пи
    8. fdivrp  st1,st0;
    9. fstp    [alpha]; 2*пи/кол-во граней
    10. ;----------------------------------------------------
    11. mov eax,[num]; кол-во боковых граней
    12. mov edi,model; указатель на объект
    13. ;----------------------------------------------------
    14. fld dword [rad2] ;радиус
    15. fld dword [rad1] ;радиус
    16. fldz    ;угол = 0
    17. .gen_loop:
    18.      ;==========================
    19.      ;-- запись точки (0,0,0) --
    20.      push eax
    21.      mov eax,ebx
    22.      mov ecx,3
    23.      .zero:
    24.        mov [edi],eax
    25.        add edi,4
    26.      loop .zero
    27.      ;=========================================================
    28.      ; запись точки (r1*cos(theta),0,r1*sin(theta))
    29.      fld  st0       ;копия угла
    30.      fsincos        ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    31.      fmul st0,st3       ;x
    32.      fstp dword [edi]
    33.      add  edi,4
    34.      mov  [edi],eax     ;y = 0
    35.      add  edi,4
    36.      fmul st0,st2       ;z
    37.      fstp dword [edi]
    38.      add  edi,4
    39.      ;=========================================================
    40.      fadd dword [alpha] ;увеличиваем угол
    41.      ;=========================================================
    42.      ; запись точки (r1*cos(theta+alpha),0,r1*sin(theta+alpha))
    43.      fld  st0       ;копия угла
    44.      fsincos        ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    45.      fmul st0,st3       ;x
    46.      fstp dword [edi]
    47.      add  edi,4
    48.      mov  [edi],eax     ;y = 0
    49.      add  edi,4
    50.      fmul st0,st2       ;z
    51.      fstp dword [edi]
    52.      add  edi,4
    53.      ;=========================================================
    54.      mov eax,[rad2]
    55.      test eax,eax
    56.      jz .copy_1
    57.  
    58.      ;--- копирование 2-х предыдущих точек ---
    59.      mov ecx,6
    60.      .copy_:
    61.        push dword [edi-24]
    62.        pop  dword [edi]
    63.        add edi,4
    64.      loop .copy_
    65.  
    66.      mov eax,[len]
    67.      ;=========================================================
    68.      ; запись точки (r2*cos(theta),len,r2*sin(theta))
    69.      fld  st0       ;копия угла
    70.      fsincos        ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    71.      fmul st0,st4       ;x
    72.      fstp dword [edi]
    73.      add  edi,4
    74.      ;mov  eax,[len]
    75.      mov  [edi],eax     ;y = len
    76.      add  edi,4
    77.      fmul st0,st3       ;z
    78.      fstp dword [edi]
    79.      add  edi,4
    80.      ;=========================================================
    81.      ;--- копирование 2-х предыдущих точек ---
    82.  
    83.      push dword [edi-36]
    84.      pop  dword [edi]
    85.      add edi,4
    86.      push dword [edi-36]
    87.      pop  dword [edi]
    88.      add edi,4
    89.      push dword [edi-36]
    90.      pop  dword [edi]
    91.      add edi,4
    92.      push dword [edi-24]
    93.      pop  dword [edi]
    94.      add edi,4
    95.      push dword [edi-24]
    96.      pop  dword [edi]
    97.      add edi,4
    98.      push dword [edi-24]
    99.      pop  dword [edi]
    100.      add edi,4
    101.  
    102.      fsub dword [alpha];уменьшим угол обратно
    103.      ;=========================================================
    104.      ; запись точки (r2*cos(theta+alpha),len,r2*sin(theta+alpha))
    105.      fld  st0       ;копия угла
    106.      fsincos        ;st0 - cos, st1 - sin, st2 - угол, st3 - радиус
    107.      fmul st0,st4       ;x
    108.      fstp dword [edi]
    109.      add  edi,4
    110.      ;mov  eax,[len]
    111.      mov  [edi],eax     ;y = len
    112.      add  edi,4
    113.      fmul st0,st3       ;z
    114.      fstp dword [edi]
    115.      add  edi,4
    116.      ;=========================================================
    117.      fadd dword [alpha] ;увеличиваем угол обатно еще раз
    118.      ;jmp .no_copy
    119.      ;=========================================================
    120.    .copy_1:
    121.      ;--- копирование 2-х предыдущих точек ---
    122.      mov ecx,6
    123.      .copy:
    124.        push dword [edi-24]
    125.        pop  dword [edi]
    126.        add edi,4
    127.      loop .copy
    128.    ;.no_copy:
    129.      ;=========================================================
    130.      ;--- запись точки (0,len,0) ----
    131.      mov  [edi],ebx     ;x = 0
    132.      add  edi,4
    133.      mov  eax,[len]
    134.      mov  [edi],eax     ;y = len
    135.      add  edi,4
    136.      mov  [edi],ebx     ;z = 0
    137.      add  edi,4
    138.      ;=========================================================
    139.   pop eax
    140.   dec eax
    141.   jnz .gen_loop
    142. ;=========================================================
    143. ;не забываем в конце очистить стек fpu
    144. fstp st0
    145. fstp st0
    146. fstp st0
    147.  




    P.S. У меня есть свои соображения, только мозгов не хватает их реализовать (если хватало бы писал бы сразу туториал для DX/OGL).

    1. Так вот, можно создать одну грань(т.е. 4 точки) и поворачивать вокруг центра на заранее вычесленный угол (вычислить sin/cos для alpha), а затем записывать это в буфер.

    2. Если можно вытолкнуть из стека FPU регистр st2, то можно загнать часть кода в процедуру.
     
  5. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    1) В каждом цикле изменяется максимум 2 точки, которые различаются только радиусом (при r2 > 0). Поэтому в цикле достаточно одного вычисления sin\cos, а остальные координаты можно просто копировать из предыдущих точек.

    2) Для используемой точности dword (single precision) действительно можно заменить fsincos поворотом на фикс.угол alpha (4 умножения и 2 сложения) - будет намного быстрее. Можно делать поворот точки по первому радиусу r1, а для второго радиуса использовать умножение на заранее вычисленный коэффициент m=r2/r1.

    3) Поскольку фигура симметричная, то достаточно вычислить точки для одного квадранта, а остальные - изменением знака X и Z (можно реализовать в целых числах как mov eax,mem1 + xor eax,80000000h + mov mem2,eax). Если попроще, то можно вычислять для 180 градусов (обратный порядок по X и изменение знака Z), если посложнее - для 45 градусов (с доп.заменой X и Z).

    4) Для копирования памяти вместо push mem1 + pop mem2 нужно использовать mov r32,mem1 + mov mem2,r32; причем не нужно каждый раз изменять edi - лучше использовать смещение [edi+4], [edi+8] и т.д. и затем изменять edi на суммарный размер.
     
  6. NaZGuL

    NaZGuL New Member

    Публикаций:
    0
    Регистрация:
    28 апр 2004
    Сообщения:
    41
    Адрес:
    Russia
    leo



    С пунктами 1 и 2 я полностью согласен (попробую реализовать и за одно проверю где код будет меньше), но вот п.3 я не понял. Если можешь поясни "на пальцах" :derisive:
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Поясняю на пальцах насчет симметрии. Самый простой вариант это расчитать половину точек, т.е. от 0 до 180 градусов (верхняя полуплоскость). Другая половина точек от 180 до 360 (нижняя полуплоскость) будет отличаться только знаками по координатам X и Z. Числа записаны в вещественном 4-байтном формате, где старший бит соответсвует знаку числа. Поэтому вместо того, чтобы грузить число в FPU и делать FCHS, можно просто сделать XOR старшего бита, т.е. поксорить с числом 80000000h (о нулевых значениях можно не беспокоиться, т.к. -0 для FPU такой же валидный ноль как и +0)

    Копирование будет выглядеть примерно так:
    Код (Text):
    1.     mov ecx,[num]
    2.     shr ecx,1         ;половина точек
    3.     mov edx,12*3*2    ;размер одной грани для конуса
    4.     cmp [rad2],0
    5.     jz .skip
    6.     add edx,edx       ;размер грани при rad2 > 0
    7. .skip   imul ecx,edx
    8.     mov edi,model     ;адрес уже просчитаных точек
    9.     lea esi,[edi+ecx] ;адрес куда будем копировать
    10. @@:
    11.     mov eax,[edi]
    12.     xor eax,80000000h ;x=-x
    13.     mov [esi],eax
    14.     mov eax,[edi+4]
    15.     mov [esi+4],eax
    16.     mov eax,[edi+8]
    17.     xor eax,80000000h ;z=-z
    18.     mov [esi+8],eax
    19.     add esi,12
    20.     add edi,12
    21.     sub ecx,12
    22.     jnz @B
    (при смене знаков х и z точка с углом t переходит в точку 180+t)

    Ес-но, размер кода несколько увеличивается. Поэтому это имеет смысл использовать, если нужно повысить скорость вычисления model. Это же кстати относится и к замене fsincos на поворот (умножения и сложения)