2013年6月15日 星期六

OpenGL基本實作(十一) (Per-Pixel Lighting & Toon Shading)

延續前一個實作練習原本的是vertex lighting,加入Per-Pixel LightingToon Shading,所以加入一個segmented Controller來做選擇器,來比對三者之間的效果。

在計算機圖形學中Per-Pixel Lighting是指照明的圖像或場景的渲染圖像上的每個像素,計算照明的任何技術。這是對比到其他流行的照明方法,如vertex lighting,其計算照明的3D模型的每一個頂點,然後內插模型的多面得到的值,計算最終的每個像素的顏色值。

Per-Pixel Lighting是常用技術,如法線貼圖,凹凸貼圖,鏡面反射,陰影卷。這些技術中的每一個都被點亮的表面提供了一些附加的數據或場景,和光源的最終外觀和感覺的表面。

大多數現代視頻遊戲引擎實現照明採用
Per-Pixel Lighting的技術,而不是vertex lighting,以實現增加細節和真實感。 如Doom3等遊戲的,其核心引擎是實現一個完全的Per-Pixel Lighting著色引擎的第一場遊戲




Toon Shading可參考wiki網址上的說明,與常規渲染不同的是,卡通渲染的光照效果是經過去真實感處理的。最常見的就是NPR效果。參考下面網頁可以比對其中的效果。

參考網頁http://tw.myblog.yahoo.com/teddy-animtion/article?mid=1098



參考3D Programming書上所提供的技術,主要修改GLSL檔的內容,其他部分並無需修改。但是需在前一個實作中加入Segmented Controller,因此些微修改控制的部分,惟一的缺點是,每一次切換會讓繪圖物件的方位回到初始位置。

Per-Pixel Lighting

PixelLighting.es2.frag檔的內容
static const char* SimpleFragmentShader4Pixel = STRINGIFY(

varying mediump vec3 EyespaceNormal;
varying lowp vec3 Diffuse;

uniform highp vec3 LightPosition;
uniform highp vec3 AmbientMaterial;
uniform highp vec3 SpecularMaterial;
uniform highp float Shininess;

void main(void)
{

//EyespaceNormal = NormalMatrix * Normal;
highp vec3 N = normalize(EyespaceNormal);  //與vertex lighting差在 normalize
highp vec3 L = normalize(LightPosition);
highp vec3 E = vec3(0, 0, 1);     // 當觀眾在無限遠處時,E可以簡化成  [0, 0, 1]
highp vec3 H = normalize(L + E);

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

// Diffuse = DiffuseMaterial;
lowp vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial;

gl_FragColor = vec4(color, 1);  // gl_FragColor = DestinationColor;
}
                                                        
);



PixelLighting.es2.vert檔的內容
static const char* SimpleVertexShader4Pixel = STRINGIFY(

attribute vec4 Position;
attribute vec3 Normal;
attribute vec3 DiffuseMaterial;

uniform mat4 Projection;
uniform mat4 Modelview;
uniform mat3 NormalMatrix;

varying vec3 EyespaceNormal;
varying vec3 Diffuse;

void main(void)
{
EyespaceNormal = NormalMatrix * Normal;
Diffuse = DiffuseMaterial;
gl_Position = Projection * Modelview * Position;
}
);

vertex lighting相比,只是將原來Simple.es2.vert檔運算的部分轉移到PixelLighting.es2.frag,並將N計算多一個Normalize而已,其它看起來都一樣。

Toon Shading

vertex部分與PixelLighting.es2.vert相同,因此延用。以下是Fragment部分

ToonShading.es2.frag

static const char* ToonShader = STRINGIFY(

varying mediump vec3 EyespaceNormal;
varying lowp vec3 Diffuse;

uniform highp vec3 LightPosition;
uniform highp vec3 AmbientMaterial;
uniform highp vec3 SpecularMaterial;
uniform highp float Shininess;

void main(void)
{
highp vec3 N = normalize(EyespaceNormal);
highp vec3 L = normalize(LightPosition);
highp vec3 E = vec3(0, 0, 1);
highp vec3 H = normalize(L + E);

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

// 卡通效果,與PixelLighting不同之處
//--------------------------------------
if (df < 0.1) df = 0.0;
else if (df < 0.3) df = 0.3;
else if (df < 0.6) df = 0.6;
else df = 1.0;

sf = step(0.5, sf);
//---------------------------------------


lowp vec3 color = AmbientMaterial + df * Diffuse + sf * SpecularMaterial;

gl_FragColor = vec4(color, 1);
}
);


為了將以上兩種效果與vertex lighting作比較,因此在程式中加入Segmented Controller,以下就差異的部分列出。

1. 檔案列表,多出三個GLSL檔



 

2. mainViewController.mm


#import "mainViewController.h"

@interface mainViewController ()
{
    int GLSL_mode;
}

@end

@implementation mainViewController
{

    UISlider  *sIconXRotateSlider;
    UISlider  *sIconYRotateSlider;
    UISlider  *sIconZRotateSlider;
   
    UISlider  *lightPosXSlider;
    UISlider  *lightPosYSlider;
    UISlider  *lightPosZSlider;
   
    UISegmentedControl *GLSL_Selector;
  
 
}
- (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];
   
    [self setGLSL_Selector];
   

    [m_window addSubview:sIconXRotateSlider];
    [m_window addSubview:sIconYRotateSlider];
    [m_window addSubview:sIconZRotateSlider];
   
    [m_window addSubview:lightPosXSlider];
    [m_window addSubview:lightPosYSlider];
    [m_window addSubview:lightPosZSlider];
   
    [m_window addSubview:GLSL_Selector];
   
    GLSL_mode = 0;

}

- (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) setGLSL_Selector
{
    //[self removeSubViewByLabelClass];
   
    NSArray *itemArray =[NSArray arrayWithObjects:@"vertex lighting", @"pixel lighting", @"Toon Shading",nil];
   
    //使用陣列來建立UISegmentedControl
    GLSL_Selector = [[UISegmentedControl alloc] initWithItems:itemArray];
   
    //設定外觀大小與初始選項
    GLSL_Selector.segmentedControlStyle = UISegmentedControlStyleBar;
    GLSL_Selector.frame = CGRectMake(20.0, 100.0, 500.0, 44.0);
   
    [GLSL_Selector setCenter:CGPointMake(700, 500)];
   
    GLSL_Selector.selectedSegmentIndex = 0;     
    GLSL_Selector.tag = 1;
   
    // 由於設定成LandScape,X在垂直方向
    GLSL_Selector.transform = CGAffineTransformMakeRotation( M_PI / 2.0);
   
    //設定所觸發的事件條件與對應事件
    [GLSL_Selector addTarget:self action:@selector(chooseOne:) forControlEvents:UIControlEventValueChanged];
   
    //加入畫面中並釋放記憶體
    [self.view addSubview:GLSL_Selector];
   
}

- (void)chooseOne:(id)sender {
   
    GLSL_mode = [sender selectedSegmentIndex];
   
    [m_view setGLSL:GLSL_mode];
   
    [m_view initSet:m_window.frame];
   
}

@end




3. GLView.h

#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;
   
    int GLSL_mode;
   
    Quaternion old_orientation;
   
    CADisplayLink* displayLink;
}

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

- (id) initSet:(CGRect) frame;

- (void) setGLSL:(int) mode;

- (void) resetdisplayLink;

@end




4. 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;
   
    GLSL_mode = 0;
   

    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_applicationEngine->setGLSL(GLSL_mode);
  
 
    [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) setGLSL:(int)mode
{
    GLSL_mode = mode;
}


- (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];
}

.....

@end


5. 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 void setGLSL(int mode) =0;
    //virtual Quaternion get_m_orientation() =0;
    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 void setGLSL(int mode) =0;
    ///virtual Quaternion get_m_orientation () const =0;
    virtual ~IRenderingEngine() {}
};

// 此處的CreateApplicationEngine有重複到Function name,因此使用namespace
namespace ParametricViewer { IApplicationEngine* CreateApplicationEngine(IRenderingEngine*); }
namespace SolidES1     { IRenderingEngine* CreateRenderingEngine(); }
namespace SolidES2     { IRenderingEngine* CreateRenderingEngine(); }
  

6. ApplicationEngine.ParametricViewer.cpp

#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);
        void setGLSL(int mode);
        //Quaternion get_m_orientation();
        //void set_m_orientation(Quaternion in_orientation);
       
    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;
       
        int    GLSL_Mode;
       
        //Quaternion  old_m_orientation;
       
    };
   
    .....
   
    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->setGLSL(GLSL_Mode);
       

        m_renderingEngine->Initialize(surfaces);
       
        for (int i = 0; i < SurfaceCount; i++)
            delete surfaces[i];
    }
   
    .....
       
    void ApplicationEngine::setGLSL(int mode)
    {
        GLSL_Mode = mode;
    }

   
   .....
   
}


7. RenderingEngine.WireframeES2.cpp
#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"
   
#include "./Shaders/PixelLighting.es2.frag"
#include "./Shaders/PixelLighting.es2.vert"
   
#include "./Shaders/ToonShading.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就變成惟讀
        void setGLSL(int mode);
    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;
       
        int GLSL_Mode;
       
    };
   
    IRenderingEngine* CreateRenderingEngine()
    {
        return new RenderingEngine();
    }
   
    RenderingEngine::RenderingEngine()
    {
        glGenRenderbuffers(1, &m_colorRenderbuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, m_colorRenderbuffer);
       
        GLSL_Mode = 0;
    }
   
    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;
       
        if (GLSL_Mode == 0)
            program = BuildProgram(SimpleVertexShader, SimpleFragmentShader);
        else if (GLSL_Mode ==1)
            program = BuildProgram(SimpleVertexShader4Pixel, SimpleFragmentShader4Pixel);
        else
            program = BuildProgram(SimpleVertexShader4Pixel, ToonShader);
       

       
        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::setGLSL(int mode)  // const // 使用const就變成惟讀
    {
        GLSL_Mode = mode;
    }


}




8.結果比較,分別是@"vertex lighting", @"pixel lighting", @"Toon Shading",其中pixel lighting看起來真實感較佳。




沒有留言: