2013年6月12日 星期三

OpenGL基本實作(十)

根據OpenGL基本實作(九)的專案,修改其中表面的材質,並加入光照,如此就與iphone 3D Programm上的例子相當了,為了方便觀看,把整個程式改成LandScape方向顯示。除此之外,並大幅修改原始的程式,加入了六個Slider,右上的三個分別控制光照的X,Y,Z方位,範圍從-100~100。而其他的三個則控制小圖的物件方位,分別轉動X,Y,Z三個方向,範圍從-180~180度。這樣可以更瞭解光照與物件轉動的含義。

1. 首先開啓了一個新的專案

OpenGL基本實作(九)的各個檔案複製過來,會如此作,實在是無法完成一個xcode的專案複製,並且修改專案的名稱,因此使用最愚蠢的方法了。其中的裡面的其他檔案名稱倒是不必更改。



  

2.  從上向下修改,首先從GLSL的Simple.es2.vert開始

static const char* SimpleVertexShader = STRINGIFY(

//To keep things simple, we'll use the infinite light source model for diffuse combined with the infinite viewer model for specular. We'll also assume that the light is white.

//vec3 ComputeLighting(vec3 normal)
//{
//N = NormalMatrix * normal
//L = Normalize(LightPosition)
//E = (0, 0, 1)    
當觀眾在無限遠處時,E可以簡化成  [0, 0, 1] 
//H = Normalize(L + E)
//df = max(0, N ∙ L)    
(df)DiffuseFactor = max(0, dot(N, L))      ***  0 <= df <= 1//sf = max(0, N ∙ H)
//sf = sf ^ Shininess


Specular Lighting         

//return AmbientMaterial + DiffuseMaterial * df + SpecularMaterial * sf
//}

//  原來的項目,已不需要了,不再需要設定線條的顏色
//attribute vec4 SourceColor;

attribute vec4 Position;    // 原來的項目

uniform mat4 Projection;     // 原來的項目
uniform mat4 Modelview;      // 原來的項目

varying vec4 DestinationColor;  // 原來的項目

// 以下是光照項目的變數
attribute vec3 Normal;     // 法線
attribute vec3 DiffuseMaterial;  // 瀰漫

uniform mat3 NormalMatrix;    // 法線矩陣
uniform vec3 LightPosition;      // 照射位置
uniform vec3 AmbientMaterial;   // 環境
uniform vec3 SpecularMaterial;   // 鏡面
uniform float Shininess;             // 反光


//use uniforms to store light position, specular and ambient properties.

void main(void)
{

    vec3 N = NormalMatrix * Normal;
    vec3 L = normalize(LightPosition);
    vec3 E = vec3(0, 0, 1);
    vec3 H = normalize(L + E);

    float df = max(0.0, dot(N, L));
    float sf = max(0.0, dot(N, H));
    sf = pow(sf, Shininess);

    vec3 color = AmbientMaterial + df * DiffuseMaterial + sf * SpecularMaterial;

    //DestinationColor = SourceColor;
    DestinationColor = vec4(color, 1);  // replace

    gl_Position = Projection * Modelview * Position;
}
);


3.mainViewController.mm加入六個Slider來作為調整光照的位置及小圖示的轉動方向。


#import "mainViewController.h"

@interface mainViewController ()

@end

@implementation mainViewController
{

    UISlider  *sIconXRotateSlider;
    UISlider  *sIconYRotateSlider;
    UISlider  *sIconZRotateSlider;
   
    UISlider  *lightPosXSlider;
    UISlider  *lightPosYSlider;
    UISlider  *lightPosZSlider;

   
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
   
    CGRect screenBounds = [[UIScreen mainScreen] bounds];
   
    m_window = [[UIWindow alloc] initWithFrame: screenBounds];
   
    m_view = [[GLView alloc] initWithFrame: screenBounds];

    [m_window addSubview: m_view];
    [m_window makeKeyAndVisible];
   
    [self setSlideInterface1];
    [self setSlideInterface2];
    [self setSlideInterface3];
   
    [self setSlideInterfaceLightX];
    [self setSlideInterfaceLightY];
    [self setSlideInterfaceLightZ];
   
   
    [m_window addSubview:sIconXRotateSlider];
    [m_window addSubview:sIconYRotateSlider];
    [m_window addSubview:sIconZRotateSlider];
   
    [m_window addSubview:lightPosXSlider];
    [m_window addSubview:lightPosYSlider];
    [m_window addSubview:lightPosZSlider];

 }

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(BOOL)shouldAutorotate{
    return YES;
}

// 轉到Landscape 模式
-(NSInteger)supportedInterfaceOrientations{
   
    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2
   
    //    return UIInterfaceOrientationMaskPortrait;
    //    or
    return 24;
}

- (void)setSlideInterface1 {
   
    sIconXRotateSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
       
    [sIconXRotateSlider setCenter:CGPointMake(50, 550)];//位置放在x=50, y=550的位置
   
   
    [sIconXRotateSlider addTarget:self action:@selector(onSlider1ValueChange) forControlEvents:UIControlEventValueChanged];
   
   
    sIconXRotateSlider.minimumValue = -1;
    sIconXRotateSlider.maximumValue = 1;
    sIconXRotateSlider.continuous = YES;
   
    [sIconXRotateSlider setValue:0];
   
    [self.view addSubview:sIconXRotateSlider];
   
}

- (void) onSlider1ValueChange
{
    float myValue = sIconXRotateSlider.value;
   
    m_view->smallIconRotateXValue = myValue;
   
    //[m_view initSet:m_window.frame];
    [m_view resetdisplayLink];
}


- (void)setSlideInterface2 {
   
    sIconYRotateSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
   
    [sIconYRotateSlider setCenter:CGPointMake(50, 650)];//位置放在x=50, y=650的位置
   
   
    [sIconYRotateSlider addTarget:self action:@selector(onSlider2ValueChange) forControlEvents:UIControlEventValueChanged];
   
   
    sIconYRotateSlider.minimumValue = -1;
    sIconYRotateSlider.maximumValue = 1;
    sIconYRotateSlider.continuous = YES;
   
    [sIconYRotateSlider setValue:0];
   
    [self.view addSubview:sIconYRotateSlider];
   
}

- (void) onSlider2ValueChange
{
    float myValue = sIconYRotateSlider.value;
   
    m_view->smallIconRotateYValue = myValue;
   
    //[m_view initSet:m_window.frame];
    [m_view resetdisplayLink];
}


- (void)setSlideInterface3 {
   
    sIconZRotateSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
   
    [sIconZRotateSlider setCenter:CGPointMake(50, 750)];//位置放在x=50, y=750的位置
   
   
    [sIconZRotateSlider addTarget:self action:@selector(onSlider3ValueChange) forControlEvents:UIControlEventValueChanged];
   
   
    sIconZRotateSlider.minimumValue = -1;
    sIconZRotateSlider.maximumValue = 1;
    sIconZRotateSlider.continuous = YES;
   
    [sIconZRotateSlider setValue:0];
   
    [self.view addSubview:sIconZRotateSlider];
   
}

- (void) onSlider3ValueChange
{
    float myValue = sIconZRotateSlider.value;
   
    m_view->smallIconRotateZValue = myValue;
   
    //[m_view initSet:m_window.frame];
    [m_view resetdisplayLink];
}



- (void)setSlideInterfaceLightX{
   
    lightPosXSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
   
    [lightPosXSlider setCenter:CGPointMake(600, 850)];//位置放在x=600, y=850的位置
   
   
    [lightPosXSlider addTarget:self action:@selector(onSliderLinghtXValueChange) forControlEvents:UIControlEventValueChanged];
   
   
    lightPosXSlider.minimumValue = -100;
    lightPosXSlider.maximumValue = 100;
    lightPosXSlider.continuous = YES;
   
    [lightPosXSlider setValue:0.25];
   
    [self.view addSubview:lightPosXSlider];
   
}

- (void) onSliderLinghtXValueChange
{
    float myValue = lightPosXSlider.value;
   
    m_view->lightPosX = myValue;
   
    //[m_view initSet:m_window.frame];
   
    [m_view resetdisplayLink];
   
}

- (void)setSlideInterfaceLightY{
   
    lightPosYSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
   
    [lightPosYSlider setCenter:CGPointMake(600, 900)];//位置放在x=600, y=900的位置
   
   
    [lightPosYSlider addTarget:self action:@selector(onSliderLinghtYValueChange) forControlEvents:UIControlEventValueChanged];
   
   
    lightPosYSlider.minimumValue = -100;
    lightPosYSlider.maximumValue = 100;
    lightPosYSlider.continuous = YES;
   
    [lightPosYSlider setValue:0.25];
   
    [self.view addSubview:lightPosYSlider];
   
}

- (void) onSliderLinghtYValueChange
{
    float myValue = lightPosYSlider.value;
   
    m_view->lightPosY = myValue;
   
    //[m_view initSet:m_window.frame];
   
    [m_view resetdisplayLink];
   
}

- (void)setSlideInterfaceLightZ{
   
    lightPosZSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
   
    [lightPosZSlider setCenter:CGPointMake(600, 950)];//位置放在x=600, y=950的位置
   
   
    [lightPosZSlider addTarget:self action:@selector(onSliderLinghtZValueChange) forControlEvents:UIControlEventValueChanged];
   
   
    lightPosZSlider.minimumValue = -100;
    lightPosZSlider.maximumValue = 100;
    lightPosZSlider.continuous = YES;
   
    [lightPosZSlider setValue:1];
   
    [self.view addSubview:lightPosZSlider];
   
}

- (void) onSliderLinghtZValueChange
{
    float myValue = lightPosZSlider.value;
   
    m_view->lightPosZ = myValue;
   
    //[m_view initSet:m_window.frame];
   
    [m_view resetdisplayLink];
   
}


@end


4. GLView.h 加入Slider對應的變數

#import <UIKit/UIKit.h>

#import "Interfaces.hpp"
#import <QuartzCore/QuartzCore.h>

@interface GLView : UIView
{
@private
    IApplicationEngine* m_applicationEngine;
    IRenderingEngine* m_renderingEngine;
    EAGLContext* m_context;
    float m_timestamp;
   
@public
    float smallIconRotateXValue;
    float smallIconRotateYValue;
    float smallIconRotateZValue;
   
    float  lightPosX;
    float  lightPosY;
    float  lightPosZ;
   
    Quaternion old_orientation;
   
    CADisplayLink* displayLink;

}

- (void) drawView: (CADisplayLink*) displayLink;

- (id) initSet:(CGRect) frame;

- (void) resetdisplayLink;

@end





5. GLView.mm 加入變數對應的控制碼


#import "GLView.h"

@implementation GLView
{

}

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

- (id) initWithFrame: (CGRect) frame
{
    smallIconRotateXValue =0;
    smallIconRotateYValue =0;
    smallIconRotateZValue =0;
   
    lightPosX =0.25;
    lightPosY =0.25;
    lightPosZ =1;
   
    old_orientation = Quaternion(0, 0, 0, 1);

   
    if (self = [super initWithFrame:frame])
    {
        if  ([self initSet:frame] == nil)
            return nil;
    }
    return self;
}

- (id) initSet:(CGRect) frame
{
    CAEAGLLayer* eaglLayer = (CAEAGLLayer*) self.layer;
    eaglLayer.opaque = YES;
   
    //EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
    EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES1;
   
    m_context = [[EAGLContext alloc] initWithAPI:api];
   
    if (!m_context) {
        api = kEAGLRenderingAPIOpenGLES1;
        m_context = [[EAGLContext alloc] initWithAPI:api];
    }
   
    if (!m_context || ![EAGLContext setCurrentContext:m_context]) {
        //[self release];
        return nil;
    }
   
    if (api == kEAGLRenderingAPIOpenGLES1) {
        NSLog(@"Using OpenGL ES 1.1");
        //m_renderingEngine = WireframeES1::CreateRenderingEngine();
        m_renderingEngine = SolidES1::CreateRenderingEngine();
    } else {
        NSLog(@"Using OpenGL ES 2.0");
        //m_renderingEngine = WireframeES2::CreateRenderingEngine(); // 完成 m_colorRenderbuffer 設定
       
        m_renderingEngine = SolidES2::CreateRenderingEngine();  // replace
    }
   
    m_applicationEngine = ParametricViewer::CreateApplicationEngine(m_renderingEngine);
   
    m_applicationEngine->SetIconRotateValue(smallIconRotateXValue, smallIconRotateYValue, smallIconRotateZValue);

   
    [m_context
     renderbufferStorage:GL_RENDERBUFFER
     fromDrawable: eaglLayer];
   
    int width = CGRectGetWidth(frame);
    int height = CGRectGetHeight(frame);
    m_applicationEngine->Initialize(width, height);
       
    [self setdisplayLink];
   

    return self;
}

- (void) setdisplayLink
{
    [self drawView: nil];
    m_timestamp = CACurrentMediaTime();
   
    //CADisplayLink* displayLink;
    displayLink = [CADisplayLink displayLinkWithTarget:self
                                              selector:@selector(drawView:)];
   
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                      forMode:NSDefaultRunLoopMode];
}


- (void) resetdisplayLink
{
    displayLink = nil;
   
    m_applicationEngine->SetIconRotateValue(smallIconRotateXValue, smallIconRotateYValue, smallIconRotateZValue);
   
   
    [self drawView: nil];
   
    m_timestamp = CACurrentMediaTime();
   
    //CADisplayLink* displayLink;
    displayLink = [CADisplayLink displayLinkWithTarget:self
                                              selector:@selector(drawView:)];
   
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop]
                      forMode:NSDefaultRunLoopMode];
}



- (void) drawView: (CADisplayLink*) displayLink
{
    if (displayLink != nil) {
       
        m_applicationEngine->setLightPos(lightPosX, lightPosY, lightPosZ);       
        float elapsedSeconds = displayLink.timestamp - m_timestamp;
        m_timestamp = displayLink.timestamp;
        m_applicationEngine->UpdateAnimation(elapsedSeconds);  
    }
   
    m_applicationEngine->Render();
    [m_context presentRenderbuffer:GL_RENDERBUFFER];
}


- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event
{
    UITouch* touch = [touches anyObject];
    CGPoint location  = [touch locationInView: self];
    m_applicationEngine->OnFingerDown(ivec2(location.x, location.y));
}

- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event
{
    UITouch* touch = [touches anyObject];
    CGPoint location  = [touch locationInView: self];
    m_applicationEngine->OnFingerUp(ivec2(location.x, location.y));  //傳入所按的平面位置
}

- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
{
    UITouch* touch = [touches anyObject];
    CGPoint previous  = [touch previousLocationInView: self];
    CGPoint current = [touch locationInView: self];
    m_applicationEngine->OnFingerMove(ivec2(previous.x, previous.y),
                                      ivec2(current.x, current.y));
}


@end




6. Interfaces.hpp 加入所需要的虛擬函數

#pragma once
#include "Vector.hpp"
#include "Quaternion.hpp"
#include <vector>
#include <string>

using std::vector;
using std::string;

enum VertexFlags {
    VertexFlagsNormals = 1 << 0,  //  ==1
    VertexFlagsTexCoords = 1 << 1,  // ==2
};

struct IApplicationEngine {
    virtual void Initialize(int width, int height) = 0;
    virtual void Render() const = 0;
    virtual void UpdateAnimation(float timeStep) = 0;
    virtual void OnFingerUp(ivec2 location) = 0;
    virtual void OnFingerDown(ivec2 location) = 0;
    virtual void OnFingerMove(ivec2 oldLocation, ivec2 newLocation) = 0;
    virtual void SetIconRotateValue(float x, float y, float z) =0;  // add for icon rotation
    virtual void setLightPos(float x, float y, float z) = 0; // add for light position

    virtual ~IApplicationEngine() {}
};

struct ISurface {
    virtual int GetVertexCount() const = 0;
    virtual int GetLineIndexCount() const = 0;
    virtual int GetTriangleIndexCount() const = 0;
    virtual void GenerateVertices(vector<float>& vertices,
                                  unsigned char flags = 0) const = 0;
    virtual void GenerateLineIndices(vector<unsigned short>& indices) const = 0;
    virtual void GenerateTriangleIndices(vector<unsigned short>& indices) const = 0;
    virtual ~ISurface() {}
};

struct Visual {
    vec3 Color;
    ivec2 LowerLeft;
    ivec2 ViewportSize;
    Quaternion Orientation;
};

struct IRenderingEngine {
    virtual void Initialize(const vector<ISurface*>& surfaces) = 0;
    virtual void Render(const vector<Visual>& visuals) const = 0;
    virtual void setLightPos(float x, float y, float z) =0; //const = 0;  /// 不能使用const
    virtual ~IRenderingEngine() {}
};

// 此處的CreateApplicationEngine有重複到Function name,因此使用namespace
namespace ParametricViewer { IApplicationEngine* CreateApplicationEngine(IRenderingEngine*); }
//namespace ObjViewer    { IApplicationEngine* CreateApplicationEngine(IRenderingEngine*, IResourceManager*); }
//namespace Darwin       { IResourceManager* CreateResourceManager(); }
//namespace WireframeES1 { IRenderingEngine* CreateRenderingEngine(); }
//namespace WireframeES2 { IRenderingEngine* CreateRenderingEngine(); }

namespace SolidES1     { IRenderingEngine* CreateRenderingEngine(); }
namespace SolidES2     { IRenderingEngine* CreateRenderingEngine(); }



7. ApplicationEngine.ParametricViewer.cpp 計算放置3D Object的位置/方位及顏色


#include "Interfaces.hpp"
#include "ParametricEquations.hpp"

using namespace std;

namespace ParametricViewer {
  
    static const int SurfaceCount = 6;
    static const int ButtonCount = SurfaceCount - 1;
  
    struct Animation {
        bool Active;
        float Elapsed;
        float Duration;
        Visual StartingVisuals[SurfaceCount];
        Visual EndingVisuals[SurfaceCount];
    };
  
    // ApplicationEngine 公開繼承 IApplicationEngine,
    class ApplicationEngine : public IApplicationEngine {
    public:
        ApplicationEngine(IRenderingEngine* renderingEngine);
        ~ApplicationEngine();
        void Initialize(int width, int height);
        void OnFingerUp(ivec2 location);
        void OnFingerDown(ivec2 location);
        void OnFingerMove(ivec2 oldLocation, ivec2 newLocation);
        void Render() const;
        void UpdateAnimation(float dt);
        void SetIconRotateValue(float x, float y, float z);
        void setLightPos(float x, float y, float z);
             
    private:
        void PopulateVisuals(Visual* visuals) const;
        int MapToButton(ivec2 touchpoint) const;
        vec3 MapToSphere(ivec2 touchpoint) const;
        float m_trackballRadius;
        ivec2 m_screenSize;
        ivec2 m_centerPoint;
        ivec2 m_fingerStart;
        bool m_spinning;
        Quaternion m_orientation;
        Quaternion m_previousOrientation;
        int m_currentSurface;
        ivec2 m_buttonSize;
        int m_pressedButton;
        int m_buttonSurfaces[ButtonCount];
        Animation m_animation;
        IRenderingEngine* m_renderingEngine;
      
        float  smallIconRotateXValue;
        float  smallIconRotateYValue;
        float  smallIconRotateZValue;
      
        float  lightPosX;
        float  lightPosY;
        float  lightPosZ;

              
    };
  
    IApplicationEngine* CreateApplicationEngine(IRenderingEngine* renderingEngine)
    {
        return new ApplicationEngine(renderingEngine);
    }
  
    ApplicationEngine::ApplicationEngine(IRenderingEngine* renderingEngine) :
    m_spinning(false),
    m_pressedButton(-1),
    m_renderingEngine(renderingEngine)
    {
        m_animation.Active = false;
        m_buttonSurfaces[0] = 0;
        m_buttonSurfaces[1] = 1;
        m_buttonSurfaces[2] = 4;
        m_buttonSurfaces[3] = 3;
        m_buttonSurfaces[4] = 2;
        m_currentSurface = 5;
    }
  
    ApplicationEngine::~ApplicationEngine()
    {
        delete m_renderingEngine;
    }
  
    void ApplicationEngine::Initialize(int width, int height)
    {
        m_trackballRadius = width / 3;
        m_buttonSize.y = height / 10;
        m_buttonSize.x = 4 * m_buttonSize.y / 3;
        m_screenSize = ivec2(width, height - m_buttonSize.y);
        m_centerPoint = m_screenSize / 2;
      
        vector<ISurface*> surfaces(SurfaceCount);
        surfaces[0] = new Cone(3, 1);  // 設定半徑及高,其他
        surfaces[1] = new Sphere(1.4f);
        surfaces[2] = new Torus(1.4f, 0.3f);
        surfaces[3] = new TrefoilKnot(1.8f);
        surfaces[4] = new KleinBottle(0.2f);
        surfaces[5] = new MobiusStrip(1);
        m_renderingEngine->Initialize(surfaces);
        for (int i = 0; i < SurfaceCount; i++)
            delete surfaces[i];
    }
  
    void ApplicationEngine::PopulateVisuals(Visual* visuals) const
    {
        //設定所有圖像的顏色與大小,包含主圖及Button
        for (int buttonIndex = 0; buttonIndex < ButtonCount; buttonIndex++) {
          
            int visualIndex = m_buttonSurfaces[buttonIndex];
            visuals[visualIndex].Color = vec3(0.25f*3, 0.25f, 0.25f);  // Button上的顏色
            if (m_pressedButton == buttonIndex)
                visuals[visualIndex].Color = vec3(0.5f, 0.5f*3, 0.5f);  // 點選後的Button顏色
          
            // 設定每一個Button上的圖案大小
//            visuals[visualIndex].ViewportSize = m_buttonSize;
//            visuals[visualIndex].LowerLeft.x = buttonIndex * m_buttonSize.x;
//            visuals[visualIndex].LowerLeft.y = 0;
//            visuals[visualIndex].Orientation = Quaternion(); // 基本button的旋轉值為0
          
            visuals[visualIndex].ViewportSize = m_buttonSize;
            visuals[visualIndex].LowerLeft.x = 0;
            visuals[visualIndex].LowerLeft.y = m_screenSize.y - buttonIndex * m_buttonSize.y ;
            //visuals[visualIndex].Orientation = Quaternion(0,0,0,1); // 基本button的旋轉值為0

          
          
            float angleValueX = smallIconRotateXValue;  // -1 ~ 1 , 負值為順時鐘
            float angleX = M_PI_2 *angleValueX;
          
            float sinx = sin(angleX);
            float cosx = cos(angleX);
          
            float angleValueY = smallIconRotateYValue;  // -1 ~ 1 , 負值為順時鐘
            float angleY = M_PI_2 *angleValueY;
          
            float siny = sin(angleY);
            float cosy = cos(angleY);
          
            float angleValueZ = smallIconRotateZValue;  // -1 ~ 1 , 負值為順時鐘
            float angleZ = M_PI_2 *angleValueZ;
          
            float sinz = sin(angleZ);
            float cosz = cos(angleZ);
          
            Quaternion x = Quaternion(sinx*1,sinx*0, sinx*0, cosx);
            Quaternion y = Quaternion(siny*0,siny*1, siny*0, cosy);
            Quaternion z = Quaternion(sinz*0,sinz*0, sinz*1, cosz);
          
            Quaternion xy = x.Rotated(y);
            Quaternion xyz = xy.Rotated(z);
      
            visuals[visualIndex].Orientation = xyz;

        }
      
        // 顯示主圖的顏色,m_spinning代表手指按下的狀態,蓋掉前面所設的值
        visuals[m_currentSurface].Color = m_spinning ? vec3(1, 0, 0.75f) : vec3(1*3, 1, 0.5f);
        visuals[m_currentSurface].LowerLeft = ivec2(0, m_buttonSize.y);
        visuals[m_currentSurface].ViewportSize = ivec2(m_screenSize.x, m_screenSize.y);
        visuals[m_currentSurface].Orientation = m_orientation; //主圖的旋轉值
    }
  
    void ApplicationEngine::Render() const
    {
        vector<Visual> visuals(SurfaceCount);
      
        if (!m_animation.Active) {
            PopulateVisuals(&visuals[0]);
        } else {
            float t = m_animation.Elapsed / m_animation.Duration;
          
            for (int i = 0; i < SurfaceCount; i++) {
              
                // 找出起始的visuals[x] 及最後的visuals[y]
                const Visual& start = m_animation.StartingVisuals[i];
                const Visual& end = m_animation.EndingVisuals[i];
              
                Visual& tweened = visuals[i];  // 這時的 visuals[]中是空的
              
                // 以下將所有的值重新填到新的visuals[]中,根據現在所見的狀態
                tweened.Color = start.Color.Lerp(t, end.Color); //將顏色做線性插補取得時間變化值
                tweened.LowerLeft = start.LowerLeft.Lerp(t, end.LowerLeft);
                tweened.ViewportSize = start.ViewportSize.Lerp(t, end.ViewportSize);
                tweened.Orientation = start.Orientation.Slerp(t, end.Orientation);
            }
        }
      
        m_renderingEngine->setLightPos(lightPosX,lightPosY,lightPosZ);
      
        m_renderingEngine->Render(visuals);
    }
  
    void ApplicationEngine::UpdateAnimation(float dt)
    {
        if (m_animation.Active) {  // 改選成另一個物件
            m_animation.Elapsed += dt;
            if (m_animation.Elapsed > m_animation.Duration)
                m_animation.Active = false;
        }
    }
  
    void ApplicationEngine::SetIconRotateValue(float x, float y , float z)
    {
        smallIconRotateXValue = x;
        smallIconRotateYValue = y;
        smallIconRotateZValue = z;
    }
  
    void ApplicationEngine::setLightPos(float x, float y , float z)
    {
        lightPosX = x;
        lightPosY = y;
        lightPosZ = z;
    }

   
    // 3. 手指離開
    void ApplicationEngine::OnFingerUp(ivec2 location)
    {
        m_spinning = false;
      
        if (m_pressedButton != -1 && m_pressedButton == MapToButton(location) &&
            !m_animation.Active)  // 如果按選了其他的物件,就進行以下的程序
        {
            m_animation.Active = true;
            m_animation.Elapsed = 0;
            m_animation.Duration = 0.25f;
          
            PopulateVisuals(&m_animation.StartingVisuals[0]);
            swap(m_buttonSurfaces[m_pressedButton], m_currentSurface); // 點選的Button圖像與主圖像交換
            PopulateVisuals(&m_animation.EndingVisuals[0]);
        }
      
        m_pressedButton = -1;
    }
  
    //  1. 壓下手指
    void ApplicationEngine::OnFingerDown(ivec2 location)
    {
        m_fingerStart = location;
        m_previousOrientation = m_orientation; // 取得現在的旋轉值
        m_pressedButton = MapToButton(location);
        if (m_pressedButton == -1)
            m_spinning = true;
    }
  
    // 2. 移動手指讓物件轉動
    void ApplicationEngine::OnFingerMove(ivec2 oldLocation, ivec2 location)
    {
        if (m_spinning) {
            vec3 start = MapToSphere(m_fingerStart);
            vec3 end = MapToSphere(location);
            Quaternion delta = Quaternion::CreateFromVectors(start, end); // 取得方向向量
            m_orientation = delta.Rotated(m_previousOrientation); // 根據前一個旋轉值,計算再次旋轉後的值,此為主圖所用
        }
      
        if (m_pressedButton != -1 && m_pressedButton != MapToButton(location))
            m_pressedButton = -1;
    }
  
    // 確認所按的位置為主圖像的位置,並回傳所按的點,經計算後的3D位置。
    vec3 ApplicationEngine::MapToSphere(ivec2 touchpoint) const
    {
        vec2 p = touchpoint - m_centerPoint;
      
        // Flip the Y axis because pixel coords increase towards the bottom.
        p.y = -p.y;
      
        const float radius = m_trackballRadius;
        const float safeRadius = radius - 1;
      
        if (p.Length() > safeRadius) {
            float theta = atan2(p.y, p.x);
            p.x = safeRadius * cos(theta);
            p.y = safeRadius * sin(theta);
        }
      
        float z = sqrt(radius * radius - p.LengthSquared());
        vec3 mapped = vec3(p.x, p.y, z);
        return mapped / radius;
    }
  
    /*
    // 確認按到了Button 的位置,並回傳所按的Button代號。原始的
    int ApplicationEngine::MapToButton(ivec2 touchpoint) const
    {
        if (touchpoint.y  < m_screenSize.y - m_buttonSize.y)
            return -1;
      
        int buttonIndex = touchpoint.x / m_buttonSize.x;
        if (buttonIndex >= ButtonCount)
            return -1;
      
        return buttonIndex;
    }
    */
  
    // 確認按到了Button 的位置,並回傳所按的Button代號。 修改後給 landscape用
    int ApplicationEngine::MapToButton(ivec2 touchpoint) const
    {
        if (touchpoint.x  >  m_buttonSize.x)
            return -1;
      
        //m_screenSize.y - buttonIndex * m_buttonSize.y ;
        int buttonIndex = (touchpoint.y) / m_buttonSize.y;
        if (buttonIndex >= ButtonCount)
            return -1;
      
        return buttonIndex;
    }

  
}


8. RenderingEngine.WireframeES1.cpp  OPENGLES V1.1的主要呼叫程式碼


#include <OpenGLES/ES1/gl.h>
#include <OpenGLES/ES1/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"

//namespace WireframeES1 {
namespace SolidES1 {     // replace

   
    struct Drawable {
        GLuint VertexBuffer;
        GLuint IndexBuffer;
        int IndexCount;
    };
   
    class RenderingEngine : public IRenderingEngine {
    public:
        RenderingEngine();
        void Initialize(const vector<ISurface*>& surfaces);
        void Render(const vector<Visual>& visuals) const;
        void setLightPos(float x, float y, float z); // const // 使用const就變成惟讀
       
    private:
        vector<Drawable> m_drawables;
        GLuint m_colorRenderbuffer;
        GLuint m_depthRenderbuffer; // new var
        mat4 m_translation;
       
        float lightPosX;
        float lightPosY;
        float lightPosZ;

       
    };
   
    IRenderingEngine* CreateRenderingEngine()
    {
        return new RenderingEngine();
    }
   
    RenderingEngine::RenderingEngine()
    {
        glGenRenderbuffersOES(1, &m_colorRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
    }
   
    void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
    {
        vector<ISurface*>::const_iterator surface;
        for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
           
            // Create the VBO for the vertices.
            vector<float> vertices;
            //(*surface)->GenerateVertices(vertices);
            (*surface)->GenerateVertices(vertices, VertexFlagsNormals); // replace

           
            GLuint vertexBuffer;
            glGenBuffers(1, &vertexBuffer);  //設定GPU memory 給 Vertex用
            glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
            glBufferData(GL_ARRAY_BUFFER,   // 將vertex資料存到GPU memory
                         vertices.size() * sizeof(vertices[0]),  // 確認記憶體大小
                         &vertices[0],
                         GL_STATIC_DRAW);
           
            // Create a new VBO for the indices if needed.
            //int indexCount = (*surface)->GetLineIndexCount();
            int indexCount = (*surface)->GetTriangleIndexCount();

            GLuint indexBuffer;
            if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
                indexBuffer = m_drawables[0].IndexBuffer;
            } else {
                vector<GLushort> indices(indexCount);
                //(*surface)->GenerateLineIndices(indices);  // 4個 indices為一組
                (*surface)->GenerateTriangleIndices(indices);  // replace

               
                glGenBuffers(1, &indexBuffer);
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
                glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                             indexCount * sizeof(GLushort),
                             &indices[0],
                             GL_STATIC_DRAW);  // 表示该缓存区不会被修改
            }
           
            Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
            m_drawables.push_back(drawable);
        }
       
        // Extract width and height from the color buffer.  new
        int width, height;
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
                                        GL_RENDERBUFFER_WIDTH_OES, &width);
        glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES,
                                        GL_RENDERBUFFER_HEIGHT_OES, &height);

       
        // Create a depth buffer that has the same size as the color buffer.  new
        glGenRenderbuffersOES(1, &m_depthRenderbuffer);
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_depthRenderbuffer);
        glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
                                 width, height);


       
        // Create the framebuffer object.
        GLuint framebuffer;
        glGenFramebuffersOES(1, &framebuffer);
        glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES,
                                     GL_RENDERBUFFER_OES, m_colorRenderbuffer);
       
        glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES,  // new
                                     GL_RENDERBUFFER_OES, m_depthRenderbuffer);

       
        glBindRenderbufferOES(GL_RENDERBUFFER_OES, m_colorRenderbuffer);
       
       
        // Set up various GL state.
        glEnableClientState(GL_VERTEX_ARRAY);
       
        glEnableClientState(GL_NORMAL_ARRAY); // new
        glEnable(GL_LIGHTING);   // new
        glEnable(GL_LIGHT0);     // new
        glEnable(GL_DEPTH_TEST);   // new
       
        // Set up the material properties.  // new
        vec4 specular(0.5f, 0.5f, 0.5f, 1);
        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular.Pointer());
        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0f);

        m_translation = mat4::Translate(0, 0, -7);
    }
   
    void RenderingEngine::Render(const vector<Visual>& visuals) const
    {
        glClearColor(0.5f, 0.5f, 0.5f, 1);
        //glClear(GL_COLOR_BUFFER_BIT);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // replace   GL_DEPTH_BUFFER_BIT沒設到,會造成無法顯示

       
        vector<Visual>::const_iterator visual = visuals.begin();
        for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {
           
            // Set the viewport transform.
            ivec2 size = visual->ViewportSize;
            ivec2 lowerLeft = visual->LowerLeft;
            glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);            
           
            // Set the light position.  // new
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();
            //vec4 lightPosition(0.25, 0.25, 1, 0);
            vec4 lightPosition(lightPosX,lightPosY, lightPosZ,0);
            glLightfv(GL_LIGHT0, GL_POSITION, lightPosition.Pointer());

           
            // Set the model-view transform.
            mat4 rotation = visual->Orientation.ToMatrix();
            mat4 modelview = rotation * m_translation;
            glMatrixMode(GL_MODELVIEW); //指定哪一个矩阵是当前矩阵, GL_MODELVIEW/GL_PROJECTION/GL_TEXTURE
            glLoadMatrixf(modelview.Pointer()); //
           
            // Set the projection transform.
            float h = 4.0f * size.y / size.x;
            mat4 projection = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
            glMatrixMode(GL_PROJECTION);
            glLoadMatrixf(projection.Pointer());
         
            // Set the diffuse color.  //new
            vec3 color = visual->Color * 0.75f;
            vec4 diffuse(color.x, color.y, color.z, 1);
            glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse.Pointer());

           
//            // Draw the wireframe.
//            int stride = sizeof(vec3);
//            const Drawable& drawable = m_drawables[visualIndex];
//            glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
//            glVertexPointer(3, GL_FLOAT, stride, 0);
//            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
//            glDrawElements(GL_LINES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
           
            // Draw the surface.  // new and renew
            int stride = 2 * sizeof(vec3);
            const GLvoid* normalOffset = (const GLvoid*) sizeof(vec3);
            const Drawable& drawable = m_drawables[visualIndex];
            glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
            glVertexPointer(3, GL_FLOAT, stride, 0);
            glNormalPointer(GL_FLOAT, stride, normalOffset);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
            glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
        }

    }
   
void RenderingEngine::setLightPos(float x, float y, float z)  // const // 使用const就變成惟讀函數
    {
        lightPosX = x;
        lightPosY = y;
        lightPosZ = z;
    }

   
}





9. RenderingEngine.WireframeES2.cpp  OPENGLES V2.0的主要呼叫程式碼

#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#include "Interfaces.hpp"
#include "Matrix.hpp"
#include <iostream>

namespace SolidES2 {
    //WireframeES2 {

   
#define STRINGIFY(A)  #A

#include "./Shaders/Simple.es2.vert"
#include "./Shaders/Simple.es2.frag"

    struct UniformHandles {  // new   專門處理 Simple.es2.vert 中 uniform 的變數
        GLuint Modelview;
        GLuint Projection;
        GLuint NormalMatrix;
        GLuint LightPosition;
        GLint AmbientMaterial;
        GLint SpecularMaterial;
        GLint Shininess;
    };
   
    struct AttributeHandles {   // new 專門處理 Simple.es2.vert 中 attribute 的變數
        GLint Position;
        GLint Normal;
        GLint DiffuseMaterial;
    };

   
    struct Drawable {
        GLuint VertexBuffer;
        GLuint IndexBuffer;
        int IndexCount;
    };
   
    class RenderingEngine : public IRenderingEngine {
    public:
        RenderingEngine();
        void Initialize(const vector<ISurface*>& surfaces);
        void Render(const vector<Visual>& visuals) const;
        void setLightPos(float x, float y, float z) ;  // const // 使用const就變成惟讀
    private:
        GLuint BuildShader(const char* source, GLenum shaderType) const;
        GLuint BuildProgram(const char* vShader, const char* fShader) const;
        vector<Drawable> m_drawables;
        GLuint m_colorRenderbuffer;
        GLuint m_depthRenderbuffer; //new and replace
        //GLint m_projectionUniform;
        //GLint m_modelviewUniform;
        //GLuint m_positionSlot;
        //GLuint m_colorSlot;

        mat4 m_translation;
       
        UniformHandles m_uniforms;   // new  改成用struct 模式來控制 GLSL 檔中的uniform 變數
        AttributeHandles m_attributes;  // new  改成用struct 模式來控制 GLSL 檔中的 attribute 變數

        float lightPosX;
        float lightPosY;
        float lightPosZ;

       
    };
   
    IRenderingEngine* CreateRenderingEngine()
    {
        return new RenderingEngine();
    }
   
    RenderingEngine::RenderingEngine()
    {
        glGenRenderbuffers(1, &m_colorRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
    }
   
    void RenderingEngine::Initialize(const vector<ISurface*>& surfaces)
    {
        vector<ISurface*>::const_iterator surface;
        for (surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
           
            // Create the VBO for the vertices.
            vector<float> vertices;
           
            //(*surface)->GenerateVertices(vertices);
            (*surface)->GenerateVertices(vertices, VertexFlagsNormals);  // new / replace
            //Tell the ParametricSurface object that we need normals by passing in the new VertexFlagsNormals flag.

           
            GLuint vertexBuffer;
            glGenBuffers(1, &vertexBuffer);
            glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
            glBufferData(GL_ARRAY_BUFFER,
                         vertices.size() * sizeof(vertices[0]),
                         &vertices[0],
                         GL_STATIC_DRAW);
           
           
            // Create a new VBO for the indices if needed.
            //int indexCount = (*surface)->GetLineIndexCount();
            int indexCount = (*surface)->GetTriangleIndexCount();  // replace  改成三角形處理,數量不同

           
            GLuint indexBuffer;
            if (!m_drawables.empty() && indexCount == m_drawables[0].IndexCount) {
                indexBuffer = m_drawables[0].IndexBuffer;
            } else {
                vector<GLushort> indices(indexCount);
               
                //(*surface)->GenerateLineIndices(indices);
                (*surface)->GenerateTriangleIndices(indices);  // replace  改成三角形處理,
               

                glGenBuffers(1, &indexBuffer);
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
                glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                             indexCount * sizeof(GLushort),
                             &indices[0],
                             GL_STATIC_DRAW);
            }
           
           
            Drawable drawable = { vertexBuffer, indexBuffer, indexCount};
            m_drawables.push_back(drawable); // 新增drawable至 m_drawables 的尾端,必要時會進行記憶體配置。
        }
       
        // Extract width and height.  new
        int width, height;
        glGetRenderbufferParameteriv(GL_RENDERBUFFER,
                                     GL_RENDERBUFFER_WIDTH, &width);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER,
                                     GL_RENDERBUFFER_HEIGHT, &height);

       
        // Create a depth buffer that has the same size as the color buffer.  new
        glGenRenderbuffers(1, &m_depthRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, m_depthRenderbuffer);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);

       
        // Create the framebuffer object. (FBO)
        GLuint framebuffer;
        glGenFramebuffers(1, &framebuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
       
        // 设置FrameBuffer并使用glFramebufferRenderBuffer相互关联
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, //
                                  GL_RENDERBUFFER, m_colorRenderbuffer);
       
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,   // new
                                  GL_RENDERBUFFER, m_depthRenderbuffer);

       
        glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
       
       
        // Create the GLSL program.  // replace
        GLuint program = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
        glUseProgram(program);
       
        // Create the GLSL program.
        //GLuint simpleProgram = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
        //glUseProgram(simpleProgram);

       
       
//        m_positionSlot = glGetAttribLocation(simpleProgram, "Position");
//        m_colorSlot = glGetAttribLocation(simpleProgram, "SourceColor");
//        glEnableVertexAttribArray(m_positionSlot);
//       


        // Extract the handles to attributes and uniforms.  replace
        m_attributes.Position = glGetAttribLocation(program, "Position");
        m_attributes.Normal = glGetAttribLocation(program, "Normal");
        m_attributes.DiffuseMaterial = glGetAttribLocation(program, "DiffuseMaterial");
       

        m_uniforms.Projection = glGetUniformLocation(program, "Projection");
        m_uniforms.Modelview = glGetUniformLocation(program, "Modelview");
        m_uniforms.NormalMatrix = glGetUniformLocation(program, "NormalMatrix");
        m_uniforms.LightPosition = glGetUniformLocation(program, "LightPosition");
        m_uniforms.AmbientMaterial = glGetUniformLocation(program, "AmbientMaterial");
        m_uniforms.SpecularMaterial = glGetUniformLocation(program, "SpecularMaterial");
        m_uniforms.Shininess = glGetUniformLocation(program, "Shininess");

       
        // Set up some default material parameters.  // replace
        glUniform3f(m_uniforms.AmbientMaterial, 0.04f, 0.04f, 0.04f);
        glUniform3f(m_uniforms.SpecularMaterial, 0.5, 0.5, 0.5);
        glUniform1f(m_uniforms.Shininess, 50);
       
        //        // Set up some matrices.
        //        m_translation = mat4::Translate(0, 0, -7);
        //        m_projectionUniform = glGetUniformLocation(simpleProgram, "Projection");
        //        m_modelviewUniform = glGetUniformLocation(simpleProgram, "Modelview");
       
        // Initialize various state.  // replace
        glEnableVertexAttribArray(m_attributes.Position);
        glEnableVertexAttribArray(m_attributes.Normal);
        glEnable(GL_DEPTH_TEST);
       

        // Set up transforms.   (change line position)
        m_translation = mat4::Translate(0, 0, -7);

    }
   
    void RenderingEngine::Render(const vector<Visual>& visuals) const
    {
        glClearColor(0.5f, 0.5f, 0.5f, 1);
        //glClear(GL_COLOR_BUFFER_BIT);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  // replace
       

        vector<Visual>::const_iterator visual = visuals.begin();
       
        // 將所有的圖像都畫出,Button上的圖像,使用相對小的Size(64,48), 主圖大小為(320,432)
        // 0~5, 5指的是主畫面
        for (int visualIndex = 0; visual != visuals.end(); ++visual, ++visualIndex) {
           
            // Set the viewport transform.
            ivec2 size = visual->ViewportSize;
            ivec2 lowerLeft = visual->LowerLeft;
            glViewport(lowerLeft.x, lowerLeft.y, size.x, size.y);
           
            // Set the light position.  // new
            //vec4 lightPosition(0.25, 0.25, 1, 0);
            vec4 lightPosition(lightPosX,lightPosY, lightPosZ,0);
            glUniform3fv(m_uniforms.LightPosition, 1, lightPosition.Pointer());

           
            // Set the model-view transform.
            mat4 rotation = visual->Orientation.ToMatrix();  // 只有主圖像的旋轉四元值被讀入,並轉為矩陣。
            mat4 modelview = rotation * m_translation;   // m_translation  =[0,0, -7]
            //glUniformMatrix4fv(m_modelviewUniform, 1, 0, modelview.Pointer());
            glUniformMatrix4fv(m_uniforms.Modelview, 1, 0, modelview.Pointer());  // replace
           

            // Set the normal matrix.  new
            // It's orthogonal, so its Inverse-Transpose is itself!
            mat3 normalMatrix = modelview.ToMat3();
            glUniformMatrix3fv(m_uniforms.NormalMatrix, 1, 0, normalMatrix.Pointer());

           
            // Set the projection transform.
            float h = 4.0f * size.y / size.x;
            mat4 projectionMatrix = mat4::Frustum(-2, 2, -h / 2, h / 2, 5, 10);
            //glUniformMatrix4fv(m_projectionUniform, 1, 0, projectionMatrix.Pointer());
            glUniformMatrix4fv(m_uniforms.Projection, 1, 0, projectionMatrix.Pointer()); // replace
           

            // Set the color.
//            vec3 color = visual->Color;
//            glVertexAttrib4f(m_colorSlot, color.x, color.y, color.z, 1);
//           
            // Set the diffuse color.  // new and replace
            vec3 color = visual->Color * 0.75f;
            glVertexAttrib4f(m_attributes.DiffuseMaterial, color.x, color.y, color.z, 1);
           
            // Draw the wireframe.
            //int stride = sizeof(vec3);
            //const Drawable& drawable = m_drawables[visualIndex];
            //glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
            //glVertexAttribPointer(m_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
            //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
            //glDrawElements(GL_LINES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);
           
           
            // Draw the surface.  // new and replace
            int stride = 2 * sizeof(vec3);                          // replace
            const GLvoid* offset = (const GLvoid*) sizeof(vec3);    // new
            GLint position = m_attributes.Position;                 // new
            GLint normal = m_attributes.Normal;                     // new

            const Drawable& drawable = m_drawables[visualIndex];
            glBindBuffer(GL_ARRAY_BUFFER, drawable.VertexBuffer);
            glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, stride, 0);             // replace
           
            glVertexAttribPointer(normal, 3, GL_FLOAT, GL_FALSE, stride, offset);          // new

            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.IndexBuffer);
           
            glDrawElements(GL_TRIANGLES, drawable.IndexCount, GL_UNSIGNED_SHORT, 0);       // replace , use triangles
           
        }
    }
   
    GLuint RenderingEngine::BuildShader(const char* source, GLenum shaderType) const
    {
        GLuint shaderHandle = glCreateShader(shaderType);
        glShaderSource(shaderHandle, 1, &source, 0);
        glCompileShader(shaderHandle);
       
        GLint compileSuccess;
        glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
       
        if (compileSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
            std::cout << messages;
            exit(1);
        }
       
        return shaderHandle; 
    }
   
    GLuint RenderingEngine::BuildProgram(const char* vertexShaderSource,
                                         const char* fragmentShaderSource) const
    {
        GLuint vertexShader = BuildShader(vertexShaderSource, GL_VERTEX_SHADER);
        GLuint fragmentShader = BuildShader(fragmentShaderSource, GL_FRAGMENT_SHADER);
       
        GLuint programHandle = glCreateProgram();
        glAttachShader(programHandle, vertexShader);
        glAttachShader(programHandle, fragmentShader);
        glLinkProgram(programHandle);
       
        GLint linkSuccess;
        glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess);
        if (linkSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]);
            std::cout << messages;
            exit(1);
        }
         return programHandle;
    }
     
    void RenderingEngine::setLightPos(float x, float y, float z)  // const // 使用const就變成惟讀
    {
        lightPosX = x;
        lightPosY = y;
        lightPosZ = z;
    }

}

10. 結果,分別為啓動原始圖、調整光照的位置及轉動小圖中物件的方向






PS:在此表面運算使用三角運算取代線條








void ParametricSurface::GenerateLineIndices(vector<unsigned short>& indices) const
{
    indices.resize(GetLineIndexCount());
    vector<unsigned short>::iterator index = indices.begin();
    for (int j = 0, vertex = 0; j < m_slices.y; j++) {
        for (int i = 0; i < m_slices.x; i++) {
            int next = (i + 1) % m_divisions.x;
            *index++ = vertex + i;
            *index++ = vertex + next;
            *index++ = vertex + i;
            *index++ = vertex + i + m_divisions.x;
        }
        vertex += m_divisions.x;
    }
}

void
ParametricSurface::GenerateTriangleIndices(vector<unsigned short>& indices) const
{
    indices.resize(GetTriangleIndexCount());
    vector<unsigned short>::iterator index = indices.begin();
    for (int j = 0, vertex = 0; j < m_slices.y; j++) {
        for (int i = 0; i < m_slices.x; i++) {  // 此處要看上圖所繪,兩個三角形的點,故有六個
            int next = (i + 1) % m_divisions.x;
            *index++ = vertex + i;
            *index++ = vertex + next;
//重複 
            *index++ = vertex + i + m_divisions.x;  //重複
            *index++ = vertex + next;  
//重複 
            *index++ = vertex + next + m_divisions.x;
            *index++ = vertex + i + m_divisions.x; 
//重複
        }
        vertex += m_divisions.x;
    }
}