2017年6月14日 星期三

Week16 閻覃的上課筆記

Week16 閻覃的上課筆記.md

Week16 閻覃的上課筆記

貼圖

在老師的幫助下我實現了貼兩張不同的圖片。

貼圖的時候需要OpenCV,相關步驟在之前的部落格有提到過。

首先建立一個Image Class

Image.h

 
1
//
2
// Created by Ethan on 2017/6/12.
3
//
4
#include <opencv/highgui.h> ///for cvLoadImage()
5
#include <opencv/cv.h> ///for cvCvtColor()
6
7
#ifdef __APPLE__
8
#include <GLUT/glut.h>
9
#else
10
#include <GL/glut.h>
11
#endif
12
13
14
#ifndef INC_05052553_WEEK15_IMAGE_H
15
#define INC_05052553_WEEK15_IMAGE_H
16
17
18
class Image {
19
public:
20
    Image(char *filename);
21
22
    GLUquadric *quad;
23
    GLuint id;
24
    IplImage *img;
25
};
26
27
28
#endif //INC_05052553_WEEK15_IMAGE_H

Image.cpp

 
1
//
2
// Created by Ethan on 2017/6/12.
3
//
4
5
#include "Image.h"
6
7
Image::Image(char *filename) {
8
    img = cvLoadImage(filename); ///OpenCV讀圖
9
    cvCvtColor(img, img, CV_BGR2RGB); ///OpenCV轉色彩 (需要cv.h)
10
    quad = gluNewQuadric();
11
    glGenTextures(1, &id); /// 產生Generate 貼圖ID
12
    glBindTexture(GL_TEXTURE_2D, id); ///綁定bind 貼圖ID
13
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖T, 就重覆貼圖
14
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); /// 貼圖參數, 超過包裝的範圖S, 就重覆貼圖
15
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /// 貼圖參數, 放大時的內插, 用最近點
16
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); /// 貼圖參數, 縮小時的內插, 用最近點
17
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, img->imageData);
18
19
}

在程式碼中,可以新建幾個貼圖

 
1
Image *background;
2
Image *platform;
3
background = new Image("background.jpg");
4
platform = new Image("platform.jpg");

之後就可以結合打光,在Display中貼圖了。

打光控制

有時候,貼圖會很暗,是因為打光的原因,如果將打光禁用就可以維持圖片本來的顏色。

以下程式碼在display函式中:

 
1
        // draw background
2
        glEnable(GL_TEXTURE_2D);
3
        glDisable(GL_LIGHTING);
4
        glBindTexture(GL_TEXTURE_2D, background->id);
5
        glPushMatrix();
6
        {
7
            glTranslatef(0, .5, 0);
8
9
            glRotatef(90, 0, 1, 0);
10
            glRotatef(90, 1, 0, 0);
11
            gluQuadricTexture(background->quad, 1);
12
            gluSphere(background->quad, 2, 20, 20);
13
        }
14
        glPopMatrix();
15
        glDisable(GL_TEXTURE_2D);
16
        glEnable(GL_LIGHTING);
17

首先啟用貼圖,關閉打光

之後畫出一個有貼圖的圓球

最後禁用貼圖,啟用打光。

切換貼圖

在剛才的程式碼中有一行

 
1
glBindTexture(GL_TEXTURE_2D, background->id);

這是說將接下來的貼圖切換到background的id上,所以就會貼background.jpg

比如我還想貼一個平台的圖片,那麼就可以繼續加程式碼:

 
1
        // platform
2
        glEnable(GL_TEXTURE_2D);
3
        glBindTexture(GL_TEXTURE_2D, platform->id);
4
        glPushMatrix();
5
        {
6
            glBegin(GL_POLYGON);
7
            {
8
                const float size =1;
9
                const float y = -0.54f;
10
                glNormal3f(0,1,0);
11
                glTexCoord2f(0, 0);
12
                glVertex3f(-size, y, +size);
13
                glTexCoord2f(1, 0);
14
                glVertex3f(+size, y, +size);
15
                glTexCoord2f(1, 1);
16
                glVertex3f(+size, y, -size);
17
                glTexCoord2f(0, 1);
18
                glVertex3f(-size, y, -size);
19
            }
20
            glEnd();
21
22
        }
23
        glPopMatrix();
24
        glDisable(GL_TEXTURE_2D);
25

這裡遇到了幾個難點,因為畫了一個平台,所以法向量如果不調整會出錯,光照會變得很昏暗,所以應該將法向量手動調整一下,才可以顯示出貼圖,否則就是一片漆黑。如果關閉打光也可以正常顯示,不過我這裡是要求開啟打光的,所以要設置法向量。

解決音畫不同步問題(卡拍子)

需要include以下檔案

 
1
#include <ctime>
2
#include <ratio>
3
#include <chrono>

開始播放時記錄開始播放的系統時間

startTime = std::chrono::high_resolution_clock::now();

在timer函式中算出時間差

 
x
1
std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
2
std::chrono::duration<double, std::milli> time_span = t2 - director->startTime;
3
float newTime = (float) (BPM * time_span.count() / 30000.0);

其中BPM是歌曲的BPM,這個公式是根據我的程式產生的。

我的程式中,一拍(1beat)等於 2frame

用於計算角度等的time可以看作frame的序號

在這裡通過獲取當前系統時間,算出經過了多少時間,再通過BPM(60s中有多少beat)算出當前經過了多少beat,這時就可以換算出當前經過了多少frame,因此直接跳到當前的frame,計算角度就好。

通過這樣計算,無論電腦卡頓還是窗口拖動影響,都不會卡拍子。

沒有留言:

張貼留言