2022年6月6日 星期一

⚝ YI-ZHEN的筆記 week16

 

  • 內插 (Excel學習內插)
1. 開啟Excel 
2. time(介於0-1之間) alpha(介於0-1之間) angle(舊的角度/新的角度)
3. 內插公式 alpha*新的角度+(1-alpha)*舊的角度

  • 內插 (程式實作)
1. 建立新專案 (Week16_interpolation)
2. 複製並貼上 上週 Week15_angles_TRT_again 的程式
3. 但由於前面的程式中,alpha會混淆,因次要修改alpha的位置
    3-1 擺完動作後按s,之後按 r 在一直按 p 就可以播放動畫  

#include <GL/glut.h>
#include <stdio.h> ///為了 printf , fprintf, fopen, fclose
float angle[20], oldX=0; ///角度歸零
int angleID=0; ///0為第0個關節...以此類推
FILE * fout = NULL, * fin = NULL;
void myWrite(){
    if(fout==NULL) fout= fopen("file.txt", "w+");
    for(int i=0; i<20; i++){
        printf("%.2f ", angle[i]);
        fprintf(fout, "%.2f ", angle[i]);
    }
    printf("\n");
    fprintf(fout, "\n");
    ///少了fclose,因為不想印一行就結束,要多行一點
}
float OldAngle[20], NewAngle[20];
void myRead()
{
    if(fout!=NULL){fclose(fout); fout=NULL;}
    if(fin==NULL) fin= fopen("file.txt", "r");
    for(int i=0; i<20; i++){
        OldAngle[i] = NewAngle[i];
        fscanf(fin, "%f", &NewAngle[i]);
        ///fscanf(fin, "%f", &angle[i]);
    }
    glutPostRedisplay(); ///重畫畫面
}
void myInterpolate(float alpha){
    for(int i=0; i<20; i++){
        angle[i]= alpha* NewAngle[i]+ (1-alpha)* OldAngle[i];
        printf("%.2f ", angle[i]);
    }
    printf("\n");
    glutPostRedisplay(); ///重畫畫面
}
float alpha= 0;
void keyboard(unsigned char key, int x, int y)
{
    if(key == '0') angleID=0; ///預設
    if(key == '1') angleID=1;
    if(key == '2') angleID=2;
    if(key == '3') angleID=3;
    if(key == 'r') myRead();
    if(key == 's') myWrite(); ///save
    if(key == 'p') {
        myInterpolate(alpha);///內插
        alpha = (alpha+0.1);
        if(alpha>1) alpha= alpha-1;
    }
}
void mouse(int button, int state, int x, int y)
{
    oldX= x;
}
void motion(int x, int y)
{
    angle[angleID] += (x-oldX);
    ///myWrite(); ///沒必要一直寫檔
    oldX= x;
    glutPostRedisplay();
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1, 1, 1); ///白色的
    glRectf(0.3, 0.5, -0.3, -0.2); ///身體

    glPushMatrix(); ///右半邊
        glTranslatef(0.3, 0.4, 0);
        glRotatef(angle[0], 0, 0, 1);
        glTranslatef(-0.3, -0.4, 0);
        glColor3f(1, 0, 0); ///紅色
        glRectf(0.3, 0.5, 0.8, 0.3); ///手臂
        glPushMatrix();
            glTranslatef(0.8, 0.4, 0);/// 3. 把手肘掛在關節上
            glRotatef(angle[1], 0, 0, 1);/// 2. 旋轉
            glTranslatef(-0.8, -0.4, 0);/// 1. 把手肘旋轉中心放到中間
            glColor3f(0, 1, 0);
            glRectf(0.8, 0.5, 1.1, 0.3);/// 再畫手肘
        glPopMatrix();
    glPopMatrix();

    glPushMatrix(); ///左半邊
        glTranslatef(-0.3, 0.4, 0);
        glRotatef(angle[2], 0, 0, 1);
        glTranslatef(0.3, -0.4, 0);
        glColor3f(1, 0, 0); ///紅色
        glRectf(-0.3, 0.5, -0.8, 0.3); ///手臂
        glPushMatrix();
            glTranslatef(-0.8, 0.4, 0);/// 3. 把手肘掛在關節上
            glRotatef(angle[3], 0, 0, 1);/// 2. 旋轉
            glTranslatef(0.8, -0.4, 0);/// 1. 把手肘旋轉中心放到中間
            glColor3f(0, 1, 0);
            glRectf(-0.8, 0.5, -1.1, 0.3);/// 再畫手肘
        glPopMatrix();
    glPopMatrix();

    glutSwapBuffers();
}
int main(int argc,char**argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Week15_angles_TRT_again");

    glutKeyboardFunc(keyboard);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutDisplayFunc(display); ///不放Idle

    glutMainLoop();
}

4. 加入timer 讓他自動做內插,按p可以播放
    4-1 先4個動作,存好後把程式關掉
    4-2 利用glutTimerFunc(0, timer, 0) 來開始播放
    4-3 在 keyboard-->if(key== 'p') 的地方 進行設定(play)
    4-4 先myRead讀一行,再寫timer
    4-5 timer中,由t先算出alpha 
    4-6 接著遇到有整除時,做新舊交換
    4-7 丟進myInterpolate, 再做glutTimerFunc(33, timer, t+1); 
    4-8 其中的33為決定播放的時間

#include <GL/glut.h>
#include <stdio.h> ///為了 printf , fprintf, fopen, fclose
float angle[20], oldX=0; ///角度歸零
int angleID=0; ///0為第0個關節...以此類推
FILE * fout = NULL, * fin = NULL;
void myWrite(){
    if(fout==NULL) fout= fopen("file.txt", "w+");
    for(int i=0; i<20; i++){
        printf("%.2f ", angle[i]);
        fprintf(fout, "%.2f ", angle[i]);
    }
    printf("\n");
    fprintf(fout, "\n");
    ///少了fclose,因為不想印一行就結束,要多行一點
}
float OldAngle[20], NewAngle[20];
void myRead()
{
    if(fout!=NULL){fclose(fout); fout=NULL;}
    if(fin==NULL) fin= fopen("file.txt", "r");
    for(int i=0; i<20; i++){
        OldAngle[i] = NewAngle[i];
        fscanf(fin, "%f", &NewAngle[i]);
        ///fscanf(fin, "%f", &angle[i]);
    }
    glutPostRedisplay(); ///重畫畫面
}
void myInterpolate(float alpha){
    for(int i=0; i<20; i++){
        angle[i]= alpha* NewAngle[i]+ (1-alpha)* OldAngle[i];
        printf("%.2f ", angle[i]);
    }
    printf("\n");
    glutPostRedisplay(); ///重畫畫面
}
///float alpha= 0;
void timer(int t){
    float alpha = (t%100)/100.0; ///算出alpha
    if(t%100==0) myRead();///遇到30整除時,做新舊交接
    myInterpolate(alpha);
    glutTimerFunc(33, timer, t+1); ///33為決定播放的時間
}
void keyboard(unsigned char key, int x, int y)
{
    if(key == '0') angleID=0; ///預設
    if(key == '1') angleID=1;
    if(key == '2') angleID=2;
    if(key == '3') angleID=3;
    if(key == 'r') myRead();
    if(key == 's') myWrite(); ///save
    if(key == 'p') {
        myRead();///先讀一行
        glutTimerFunc(0, timer, 0); ///馬上開始播放動畫
        ///myInterpolate(alpha);///內插
        ///alpha = (alpha+0.1);
        ///if(alpha>1) alpha= alpha-1;
    }
}
void mouse(int button, int state, int x, int y)
{
    oldX= x;
}
void motion(int x, int y)
{
    angle[angleID] += (x-oldX);
    ///myWrite(); ///沒必要一直寫檔
    oldX= x;
    glutPostRedisplay();
}
void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3f(1, 1, 1); ///白色的
    glRectf(0.3, 0.5, -0.3, -0.2); ///身體

    glPushMatrix(); ///右半邊
        glTranslatef(0.3, 0.4, 0);
        glRotatef(angle[0], 0, 0, 1);
        glTranslatef(-0.3, -0.4, 0);
        glColor3f(1, 0, 0); ///紅色
        glRectf(0.3, 0.5, 0.8, 0.3); ///手臂
        glPushMatrix();
            glTranslatef(0.8, 0.4, 0);/// 3. 把手肘掛在關節上
            glRotatef(angle[1], 0, 0, 1);/// 2. 旋轉
            glTranslatef(-0.8, -0.4, 0);/// 1. 把手肘旋轉中心放到中間
            glColor3f(0, 1, 0);
            glRectf(0.8, 0.5, 1.1, 0.3);/// 再畫手肘
        glPopMatrix();
    glPopMatrix();

    glPushMatrix(); ///左半邊
        glTranslatef(-0.3, 0.4, 0);
        glRotatef(angle[2], 0, 0, 1);
        glTranslatef(0.3, -0.4, 0);
        glColor3f(1, 0, 0); ///紅色
        glRectf(-0.3, 0.5, -0.8, 0.3); ///手臂
        glPushMatrix();
            glTranslatef(-0.8, 0.4, 0);/// 3. 把手肘掛在關節上
            glRotatef(angle[3], 0, 0, 1);/// 2. 旋轉
            glTranslatef(0.8, -0.4, 0);/// 1. 把手肘旋轉中心放到中間
            glColor3f(0, 1, 0);
            glRectf(-0.8, 0.5, -1.1, 0.3);/// 再畫手肘
        glPopMatrix();
    glPopMatrix();

    glutSwapBuffers();
}
int main(int argc,char**argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Week15_angles_TRT_again");

    glutKeyboardFunc(keyboard);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutDisplayFunc(display); ///不放Idle

    glutMainLoop();
}
  • 相機(範例:https://jsyeh.org/3dcg10/)
1. 下載 [data][win32] 並解壓縮
2.  點擊 Projection 開始實作
3. eye 相機看你的位置(從哪裡看)


4. center 決定相機要看的中心位置
    (由下面圖片來說 是以人的左手當作中心,圍繞著手拍) 


5. up 為相機旋轉位置
6. 投影法


  • 相機(程式實作)
1. aspect ratio 為長寬比 (寬度除以高度)

static void resize(int width, int height)
{ ///aspect ratio 長寬比
    const float ar = (float) width / (float) height;

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION); ///投影-把3D投成2D畫面
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

    glMatrixMode(GL_MODELVIEW); ///3D經過轉換到最後的相機
    glLoadIdentity() ;
}

2. 結合剛剛教的,畫出茶壺再加上攝影機

#include <GL/glut.h>
void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutSolidTeapot(2); ///大茶壺

    glutSwapBuffers();
}
void motion(int x, int y)
{
    glMatrixMode(GL_MODELVIEW); ///3D經過轉換到最後的相機
    glLoadIdentity();
    gluLookAt((x-150)/15.0, (y-150)/15.0, 3, ///eye
              0, 0, 0, ///center
              0, 1, 0); ///up
    glutPostRedisplay();
}
void reshape(int w, int h)
{
    const float ar = (float) w / (float) h;

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION); ///投影-把3D投成2D畫面
    glLoadIdentity();
    gluPerspective(60, ar, 0.1, 100);

    glMatrixMode(GL_MODELVIEW); ///3D經過轉換到最後的相機
    glLoadIdentity() ;
    gluLookAt(0, 0, 3,
              0, 0, 0,
              0, 1, 0);
}
int main(int argc,char**argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutCreateWindow("Week16_lookat");

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMotionFunc(motion);

    glutMainLoop();
}









沒有留言:

張貼留言