第4章 Cg语言全面解析:从入门到编译实战

Cg语言全面解析:从入门到编译实战

4.1 Cg语言入门指南
概念与理论

Cg(C for Graphics)是由NVIDIA开发的高级着色器语言,旨在简化GPU编程。它采用类C语法,支持跨平台编译,能够将同一份代码编译为不同图形API(如OpenGL、DirectX)的着色器。

Cg的核心设计理念:

  • 语法友好:采用熟悉的C语言语法,降低学习门槛
  • 跨平台兼容:通过Profile系统适配不同GPU架构和图形API
  • 运行时编译:支持在应用程序运行时编译和优化着色器
  • 与宿主程序紧密集成:通过C++运行时库与应用程序交互
C++代码实例:Cg环境配置与基础着色器

以下代码演示了如何在OpenGL环境中配置Cg并创建基础着色器:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <iostream>
#include <string>

class CgManager {
private:
    CGcontext context;
    CGprofile vertexProfile, fragmentProfile;

public:
    CgManager() {
        // 初始化Cg上下文
        context = cgCreateContext();
        if (!context) {
            std::cerr << "错误:无法创建Cg上下文" << std::endl;
            return;
        }

        // 设置错误回调
        cgSetErrorCallback(cgErrorCallback);

        // 获取最优的Profile
        vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
        fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);

        std::cout << "顶点Profile: " << cgGetProfileString(vertexProfile) << std::endl;
        std::cout << "片段Profile: " << cgGetProfileString(fragmentProfile) << std::endl;

        // 启用Profile
        cgGLSetOptimalOptions(vertexProfile);
        cgGLSetOptimalOptions(fragmentProfile);
    }

    ~CgManager() {
        if (context) {
            cgDestroyContext(context);
        }
    }

    // Cg错误回调函数
    static void cgErrorCallback() {
        CGerror error = cgGetError();
        if (error) {
            std::cerr << "Cg错误: " << cgGetErrorString(error) << std::endl;
            const char* listing = cgGetLastListing(context);
            if (listing) {
                std::cerr << "编译日志: " << listing << std::endl;
            }
        }
    }

    // 从文件加载并编译Cg着色器
    CGprogram loadShaderFromFile(const char* filePath, CGprofile profile) {
        CGprogram program = cgCreateProgramFromFile(
            context,              // Cg上下文
            CG_SOURCE,            // 从源文件加载
            filePath,             // 文件路径
            profile,              // Profile类型
            "main",               // 入口函数
            nullptr               // 编译参数
        );

        if (!program) {
            std::cerr << "错误:无法创建Cg程序: " << filePath << std::endl;
            return nullptr;
        }

        // 加载到GPU
        cgGLLoadProgram(program);
        
        std::cout << "成功加载Cg着色器: " << filePath << std::endl;
        return program;
    }

    // 从字符串创建Cg着色器
    CGprogram loadShaderFromString(const char* shaderSource, CGprofile profile, const char* programName) {
        CGprogram program = cgCreateProgram(
            context,
            CG_SOURCE,
            shaderSource,
            profile,
            "main",
            nullptr
        );

        if (program) {
            cgGLLoadProgram(program);
            std::cout << "成功编译Cg着色器: " << programName << std::endl;
        }

        return program;
    }

    CGcontext getContext() { return context; }
    CGprofile getVertexProfile() { return vertexProfile; }
    CGprofile getFragmentProfile() { return fragmentProfile; }
};

// 简单的Cg顶点着色器源码
const char* simpleVertexShader = R"(
struct VertexInput {
    float4 position : POSITION;
    float4 color : COLOR0;
};

struct VertexOutput {
    float4 position : POSITION;
    float4 color : COLOR0;
};

VertexOutput main(VertexInput IN)
{
    VertexOutput OUT;
    OUT.position = IN.position;
    OUT.color = IN.color;
    return OUT;
}
)";

// 简单的Cg片段着色器源码
const char* simpleFragmentShader = R"(
struct FragmentInput {
    float4 color : COLOR0;
};

struct FragmentOutput {
    float4 color : COLOR;
};

FragmentOutput main(FragmentInput IN)
{
    FragmentOutput OUT;
    OUT.color = IN.color;
    return OUT;
}
)";

int main() {
    // 初始化GLFW
    if (!glfwInit()) {
        std::cerr << "GLFW初始化失败" << std::endl;
        return -1;
    }

    // 创建窗口
    GLFWwindow* window = glfwCreateWindow(800, 600, "Cg语言入门演示", NULL, NULL);
    if (!window) {
        std::cerr << "窗口创建失败" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);

    // 初始化GLEW
    if (glewInit() != GLEW_OK) {
        std::cerr << "GLEW初始化失败" << std::endl;
        return -1;
    }

    std::cout << "OpenGL版本: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "GLSL版本: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;

    // 初始化Cg管理器
    CgManager cgManager;

    // 编译Cg着色器
    CGprogram vertexProgram = cgManager.loadShaderFromString(
        simpleVertexShader, 
        cgManager.getVertexProfile(), 
        "SimpleVertexShader"
    );

    CGprogram fragmentProgram = cgManager.loadShaderFromString(
        simpleFragmentShader,
        cgManager.getFragmentProfile(),
        "SimpleFragmentShader"
    );

    if (!vertexProgram || !fragmentProgram) {
        std::cerr << "着色器编译失败" << std::endl;
        return -1;
    }

    // 设置顶点数据
    float vertices[] = {
        -0.5f, -0.5f, 0.0f,  // 位置
        1.0f, 0.0f, 0.0f,    // 颜色 - 红色
        
        0.5f, -0.5f, 0.0f,   // 位置  
        0.0f, 1.0f, 0.0f,    // 颜色 - 绿色
        
        0.0f, 0.5f, 0.0f,    // 位置
        0.0f, 0.0f, 1.0f     // 颜色 - 蓝色
    };

    unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 渲染循环
    while (!glfwWindowShouldClose(window)) {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // 绑定Cg着色器
        cgGLBindProgram(vertexProgram);
        cgGLBindProgram(fragmentProgram);
        cgGLEnableProfile(cgManager.getVertexProfile());
        cgGLEnableProfile(cgManager.getFragmentProfile());

        // 渲染三角形
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLES, 0, 3);

        // 禁用Profile
        cgGLDisableProfile(cgManager.getVertexProfile());
        cgGLDisableProfile(cgManager.getFragmentProfile());

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    if (vertexProgram) cgDestroyProgram(vertexProgram);
    if (fragmentProgram) cgDestroyProgram(fragmentProgram);
    
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glfwTerminate();

    return 0;
}

代码解释:这个程序演示了Cg环境的基本配置和使用。CgManager类封装了Cg上下文的创建、Profile管理和着色器编译功能。程序创建了一个彩色三角形,使用Cg着色器进行渲染。在VS2022中运行时,需要在项目属性中添加Cg库的包含路径和链接库(Cg.lib、CgGL.lib)。


4.2 Cg语言核心特性深度解析
概念与理论

Cg语言的设计包含多个独特特性,使其在图形编程中具有显著优势:

  • 语义绑定系统:通过语义(如POSITION、COLOR)自动连接着色器输入输出与固定功能管线
  • 内建数据类型:提供向量类型(float2/3/4)、矩阵类型(float2x2、float4x4)等图形专用类型
  • 标准函数库:包含丰富的数学函数(sin、cos、dot、cross等)和图形函数(tex2D、normalize等)
  • 多平台支持:通过Profile系统支持不同硬件和API
  • 与宿主语言交互:提供参数句柄系统,允许C++程序动态控制着色器参数
C++代码实例:高级Cg特性演示

以下代码展示了Cg的语义绑定、参数管理和复杂数据类型使用:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <iostream>
#include <cmath>

// 高级Cg顶点着色器 - 包含变换矩阵和光照计算
const char* advancedVertexShader = R"(
struct AppData {
    float4 position : POSITION;
    float3 normal : NORMAL;
    float2 texcoord : TEXCOORD0;
};

struct VertexOutput {
    float4 position : POSITION;
    float3 worldNormal : TEXCOORD0;
    float3 worldPosition : TEXCOORD1;
    float2 texcoord : TEXCOORD2;
};

// 统一参数
uniform float4x4 modelViewProj;
uniform float4x4 modelMatrix;
uniform float3 lightPosition;
uniform float time;

VertexOutput main(AppData IN)
{
    VertexOutput OUT;
    
    // 顶点动画:基于时间的简单波动
    float4 animatedPosition = IN.position;
    animatedPosition.y += sin(IN.position.x * 5.0 + time) * 0.1;
    
    // 位置变换
    OUT.position = mul(modelViewProj, animatedPosition);
    
    // 法线变换到世界空间
    float3x3 normalMatrix = (float3x3)modelMatrix;
    OUT.worldNormal = mul(normalMatrix, IN.normal);
    
    // 世界空间位置
    OUT.worldPosition = mul(modelMatrix, animatedPosition).xyz;
    OUT.texcoord = IN.texcoord;
    
    return OUT;
}
)";

// 高级Cg片段着色器 - 包含光照和纹理
const char* advancedFragmentShader = R"(
struct FragmentInput {
    float3 worldNormal : TEXCOORD0;
    float3 worldPosition : TEXCOORD1;
    float2 texcoord : TEXCOORD2;
};

struct FragmentOutput {
    float4 color : COLOR;
};

// 统一参数
uniform float3 lightColor;
uniform float3 ambientColor;
uniform float lightIntensity;
uniform sampler2D diffuseTexture;

FragmentOutput main(FragmentInput IN)
{
    FragmentOutput OUT;
    
    // 归一化法线
    float3 normal = normalize(IN.worldNormal);
    
    // 光照方向
    float3 lightDir = normalize(lightPosition - IN.worldPosition);
    
    // 漫反射计算
    float diffuse = max(dot(normal, lightDir), 0.0);
    
    // 环境光 + 漫反射
    float3 lighting = ambientColor + lightColor * diffuse * lightIntensity;
    
    // 纹理采样(如果可用)
    float4 texColor = tex2D(diffuseTexture, IN.texcoord);
    
    // 最终颜色计算
    OUT.color = float4(lighting, 1.0) * texColor;
    
    return OUT;
}
)";

class AdvancedCgDemo {
private:
    CGcontext context;
    CGprogram vertexProgram, fragmentProgram;
    CGprofile vertexProfile, fragmentProfile;
    
    // 参数句柄
    CGparameter modelViewProjParam, modelMatrixParam;
    CGparameter lightPositionParam, lightColorParam;
    CGparameter ambientColorParam, lightIntensityParam;
    CGparameter timeParam;

public:
    AdvancedCgDemo() {
        initializeCg();
        compileShaders();
        getParameterHandles();
    }
    
    ~AdvancedCgDemo() {
        cleanup();
    }

private:
    void initializeCg() {
        context = cgCreateContext();
        cgSetErrorCallback([]() {
            CGerror error = cgGetError();
            if (error) {
                std::cerr << "Cg错误: " << cgGetErrorString(error) << std::endl;
            }
        });
        
        vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
        fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
        
        cgGLSetOptimalOptions(vertexProfile);
        cgGLSetOptimalOptions(fragmentProfile);
        
        std::cout << "使用顶点Profile: " << cgGetProfileString(vertexProfile) << std::endl;
        std::cout << "使用片段Profile: " << cgGetProfileString(fragmentProfile) << std::endl;
    }
    
    void compileShaders() {
        // 编译顶点着色器
        vertexProgram = cgCreateProgram(context, CG_SOURCE, advancedVertexShader, 
                                      vertexProfile, "main", nullptr);
        if (vertexProgram) {
            cgGLLoadProgram(vertexProgram);
            std::cout << "顶点着色器编译成功" << std::endl;
        }
        
        // 编译片段着色器  
        fragmentProgram = cgCreateProgram(context, CG_SOURCE, advancedFragmentShader,
                                        fragmentProfile, "main", nullptr);
        if (fragmentProgram) {
            cgGLLoadProgram(fragmentProgram);
            std::cout << "片段着色器编译成功" << std::endl;
        }
    }
    
    void getParameterHandles() {
        // 获取顶点着色器参数句柄
        modelViewProjParam = cgGetNamedParameter(vertexProgram, "modelViewProj");
        modelMatrixParam = cgGetNamedParameter(vertexProgram, "modelMatrix");
        lightPositionParam = cgGetNamedParameter(vertexProgram, "lightPosition");
        timeParam = cgGetNamedParameter(vertexProgram, "time");
        
        // 获取片段着色器参数句柄
        lightColorParam = cgGetNamedParameter(fragmentProgram, "lightColor");
        ambientColorParam = cgGetNamedParameter(fragmentProgram, "ambientColor");
        lightIntensityParam = cgGetNamedParameter(fragmentProgram, "lightIntensity");
        
        std::cout << "参数句柄获取完成" << std::endl;
    }
    
    void cleanup() {
        if (vertexProgram) cgDestroyProgram(vertexProgram);
        if (fragmentProgram) cgDestroyProgram(fragmentProgram);
        if (context) cgDestroyContext(context);
    }

public:
    void setTransformMatrix(const float* modelViewProj, const float* modelMatrix) {
        cgGLSetMatrixParameterfc(modelViewProjParam, modelViewProj);
        cgGLSetMatrixParameterfc(modelMatrixParam, modelMatrix);
    }
    
    void setLightParameters(const float* lightPos, const float* lightColor, 
                          const float* ambient, float intensity) {
        cgSetParameter3fv(lightPositionParam, lightPos);
        cgSetParameter3fv(lightColorParam, lightColor);
        cgSetParameter3fv(ambientColorParam, ambient);
        cgSetParameter1f(lightIntensityParam, intensity);
    }
    
    void setTime(float time) {
        cgSetParameter1f(timeParam, time);
    }
    
    void enable() {
        cgGLEnableProfile(vertexProfile);
        cgGLEnableProfile(fragmentProfile);
        cgGLBindProgram(vertexProgram);
        cgGLBindProgram(fragmentProgram);
    }
    
    void disable() {
        cgGLDisableProfile(vertexProfile);
        cgGLDisableProfile(fragmentProfile);
    }
};

// 创建立方体数据(包含位置、法线、纹理坐标)
float cubeData[] = {
    // 前面
    -0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  0.0f, 0.0f,
     0.5f, -0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  1.0f, 0.0f,
     0.5f,  0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,  0.0f, 0.0f, 1.0f,  0.0f, 1.0f,
    
    // 后面
    -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
     0.5f, -0.5f, -0.5f,  0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
     0.5f,  0.5f, -0.5f,  0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,  0.0f, 0.0f, -1.0f, 1.0f, 1.0f
};

unsigned int cubeIndices[] = {
    // 前面
    0, 1, 2, 2, 3, 0,
    // 后面
    4, 5, 6, 6, 7, 4,
    // 左面
    7, 3, 0, 0, 4, 7,
    // 右面
    1, 5, 6, 6, 2, 1,
    // 上面
    3, 2, 6, 6, 7, 3,
    // 下面
    4, 0, 1, 1, 5, 4
};

int main() {
    // 初始化GLFW和窗口
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(800, 600, "Cg高级特性演示", NULL, NULL);
    glfwMakeContextCurrent(window);
    glewInit();

    // 初始化Cg演示系统
    AdvancedCgDemo cgDemo;

    // 设置立方体VAO/VBO/EBO
    unsigned int VBO, VAO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeData), cubeData, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);

    // 位置属性 (0)
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // 法线属性 (1)
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // 纹理坐标属性 (2)
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    glEnable(GL_DEPTH_TEST);

    // 光照参数
    float lightPosition[] = {2.0f, 2.0f, 2.0f};
    float lightColor[] = {1.0f, 1.0f, 1.0f};
    float ambientColor[] = {0.2f, 0.2f, 0.3f};
    float lightIntensity = 1.0f;

    while (!glfwWindowShouldClose(window)) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // 设置变换矩阵(简化版)
        float modelViewProj[16] = {
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f, 
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f
        };
        
        float modelMatrix[16] = {
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f, 
            0.0f, 0.0f, 0.0f, 1.0f
        };

        // 设置Cg参数
        cgDemo.setTransformMatrix(modelViewProj, modelMatrix);
        cgDemo.setLightParameters(lightPosition, lightColor, ambientColor, lightIntensity);
        cgDemo.setTime((float)glfwGetTime());

        // 启用Cg着色器并渲染
        cgDemo.enable();
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
        cgDemo.disable();

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 清理资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glfwTerminate();

    return 0;
}

代码解释:这个高级示例展示了Cg语言的多个核心特性,包括语义绑定、参数管理和复杂光照计算。AdvancedCgDemo类封装了完整的Cg着色器管理功能,支持动态参数更新。程序创建了一个带光照的立方体,演示了Cg在复杂渲染场景中的应用。


4.3 Cg编译系统深度解析
概念与理论

Cg编译系统采用分层架构,将高级着色器代码转换为目标GPU的本地指令:

编译流程

  1. 前端解析:将Cg源码解析为抽象语法树(AST)
  2. 语义分析:检查类型一致性、语义正确性
  3. 中间代码生成:生成与硬件无关的中间表示
  4. 目标代码生成:根据Profile将中间代码转换为特定API的着色器
  5. 优化阶段:应用平台特定的优化策略

编译模式

  • 离线编译:预编译为二进制格式,运行时直接加载
  • 运行时编译:应用程序运行时动态编译,支持热重载
  • 交叉编译:同一份Cg代码可针对不同平台编译
C++代码实例:动态编译与编译信息获取

以下代码演示了Cg编译系统的完整使用,包括编译选项设置和编译信息获取:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <iostream>
#include <vector>
#include <string>

class CgCompilerDemo {
private:
    CGcontext context;
    
public:
    CgCompilerDemo() {
        initializeContext();
    }
    
    ~CgCompilerDemo() {
        if (context) {
            cgDestroyContext(context);
        }
    }

private:
    void initializeContext() {
        context = cgCreateContext();
        cgSetErrorCallback(errorCallback);
        
        std::cout << "=== Cg编译器信息 ===" << std::endl;
        std::cout << "Cg版本: " << cgGetString(CG_VERSION) << std::endl;
        std::cout << "Cg编译器: " << cgGetString(CG_COMPILER_VENDOR) << std::endl;
    }
    
    static void errorCallback() {
        CGerror error = cgGetError();
        if (error) {
            std::cerr << "Cg错误: " << cgGetErrorString(error) << std::endl;
            const char* listing = cgGetLastListing(context);
            if (listing) {
                std::cerr << "详细错误:\n" << listing << std::endl;
            }
        }
    }

public:
    // 测试不同编译选项的效果
    void testCompilationOptions() {
        std::cout << "\n=== 编译选项测试 ===" << std::endl;
        
        const char* testShader = R"(
struct VertexInput {
    float4 position : POSITION;
    float4 color : COLOR0;
};

struct VertexOutput {
    float4 position : POSITION;
    float4 color : COLOR0;
};

VertexOutput main(VertexInput IN)
{
    VertexOutput OUT;
    OUT.position = IN.position;
    OUT.color = IN.color;
    return OUT;
}
)";

        CGprofile profile = cgGLGetLatestProfile(CG_GL_VERTEX);
        
        // 测试1:默认编译
        std::cout << "\n1. 默认编译:" << std::endl;
        CGprogram prog1 = cgCreateProgram(context, CG_SOURCE, testShader, profile, "main", nullptr);
        printProgramInfo(prog1, "默认编译");
        if (prog1) cgDestroyProgram(prog1);
        
        // 测试2:启用优化
        std::cout << "\n2. 启用优化编译:" << std::endl;
        const char* optimizeOptions[] = { "-O3", nullptr };
        CGprogram prog2 = cgCreateProgram(context, CG_SOURCE, testShader, profile, "main", optimizeOptions);
        printProgramInfo(prog2, "优化编译");
        if (prog2) cgDestroyProgram(prog2);
        
        // 测试3:启用调试信息
        std::cout << "\n3. 调试模式编译:" << std::endl;
        const char* debugOptions[] = { "-g", nullptr };
        CGprogram prog3 = cgCreateProgram(context, CG_SOURCE, testShader, profile, "main", debugOptions);
        printProgramInfo(prog3, "调试编译");
        if (prog3) cgDestroyProgram(prog3);
    }
    
    // 分析不同Profile的兼容性
    void analyzeProfiles() {
        std::cout << "\n=== Profile兼容性分析 ===" << std::endl;
        
        // 获取所有可用Profile
        std::vector<CGprofile> profiles = {
            cgGLGetLatestProfile(CG_GL_VERTEX),
            cgGLGetLatestProfile(CG_GL_FRAGMENT),
            CG_PROFILE_VP30,  // 较旧的顶点Profile
            CG_PROFILE_FP30,  // 较旧的片段Profile
            CG_PROFILE_VP40,
            CG_PROFILE_FP40
        };
        
        const char* simpleShader = R"(
float4 main(float4 pos : POSITION) : POSITION {
    return pos;
}
)";
        
        for (CGprofile profile : profiles) {
            if (cgIsProfileSupported(profile)) {
                std::cout << "Profile " << cgGetProfileString(profile) << " 支持: 是" << std::endl;
                
                // 测试编译
                CGprogram program = cgCreateProgram(context, CG_SOURCE, simpleShader, profile, "main", nullptr);
                if (program) {
                    std::cout << "  - 编译测试: 成功" << std::endl;
                    cgDestroyProgram(program);
                } else {
                    std::cout << "  - 编译测试: 失败" << std::endl;
                }
                
                // 显示Profile详情
                std::cout << "  - 目标API: " << cgGetProfileProperty(profile, CG_PROFILE_TARGET) << std::endl;
                std::cout << "  - 目标版本: " << cgGetProfileProperty(profile, CG_PROFILE_TARGETVERSION) << std::endl;
            } else {
                std::cout << "Profile " << cgGetProfileString(profile) << " 支持: 否" << std::endl;
            }
            std::cout << std::endl;
        }
    }
    
    // 编译并分析复杂着色器
    void compileComplexShader() {
        std::cout << "\n=== 复杂着色器编译分析 ===" << std::endl;
        
        const char* complexShader = R"(
struct AppData {
    float4 position : POSITION;
    float3 normal : NORMAL;
    float2 texcoord : TEXCOORD0;
};

struct VertexOutput {
    float4 position : POSITION;
    float3 normal : TEXCOORD0;
    float2 texcoord : TEXCOORD1;
};

uniform float4x4 modelViewProj;
uniform float4x4 modelMatrix;
uniform float time;

VertexOutput main(AppData IN)
{
    VertexOutput OUT;
    
    // 顶点动画
    float4 animatedPos = IN.position;
    animatedPos.y += sin(IN.position.x * 3.0 + time) * 0.1;
    
    // 变换
    OUT.position = mul(modelViewProj, animatedPos);
    
    // 法线变换
    float3x3 normalMatrix = (float3x3)modelMatrix;
    OUT.normal = mul(normalMatrix, IN.normal);
    
    OUT.texcoord = IN.texcoord;
    
    return OUT;
}
)";
        
        CGprofile profile = cgGLGetLatestProfile(CG_GL_VERTEX);
        CGprogram program = cgCreateProgram(context, CG_SOURCE, complexShader, profile, "main", nullptr);
        
        if (program) {
            std::cout << "复杂着色器编译成功!" << std::endl;
            printProgramInfo(program, "复杂着色器");
            
            // 分析着色器参数
            analyzeShaderParameters(program);
            
            cgDestroyProgram(program);
        }
    }

private:
    void printProgramInfo(CGprogram program, const std::string& name) {
        if (!program) {
            std::cout << name << ": 编译失败" << std::endl;
            return;
        }
        
        std::cout << name << "信息:" << std::endl;
        std::cout << "  - Profile: " << cgGetProgramString(program, CG_PROGRAM_PROFILE) << std::endl;
        std::cout << "  - 输入语义数量: " << cgGetProgramInputSemanticsCount(program) << std::endl;
        std::cout << "  - 输出语义数量: " << cgGetProgramOutputSemanticsCount(program) << std::endl;
        
        // 获取编译统计信息
        const char* stats = cgGetProgramString(program, CG_PROGRAM_COMPILATION_STATISTICS);
        if (stats) {
            std::cout << "  - 编译统计:\n" << stats << std::endl;
        }
    }
    
    void analyzeShaderParameters(CGprogram program) {
        std::cout << "着色器参数分析:" << std::endl;
        
        CGparameter param = cgGetFirstParameter(program, CG_GLOBAL);
        int paramCount = 0;
        
        while (param) {
            std::cout << "  - 参数 " << ++paramCount << ":" << std::endl;
            std::cout << "    名称: " << cgGetParameterName(param) << std::endl;
            std::cout << "    语义: " << cgGetParameterSemantic(param) << std::endl;
            std::cout << "    类型: " << cgGetParameterTypeString(param) << std::endl;
            std::cout << "    方向: " << cgGetParameterDirection(param) << std::endl;
            
            param = cgGetNextParameter(param);
        }
        
        if (paramCount == 0) {
            std::cout << "  - 无全局参数" << std::endl;
        }
    }
};

int main() {
    // 初始化GLFW(为了OpenGL上下文)
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(100, 100, "Cg编译测试", NULL, NULL);
    glfwMakeContextCurrent(window);
    glewInit();
    
    // 创建编译器演示实例
    CgCompilerDemo compiler;
    
    // 运行编译测试
    compiler.testCompilationOptions();
    compiler.analyzeProfiles();
    compiler.compileComplexShader();
    
    std::cout << "\n=== Cg编译系统演示完成 ===" << std::endl;
    
    glfwDestroyWindow(window);
    glfwTerminate();
    
    return 0;
}

代码解释:这个程序专门演示了Cg编译系统的各种功能。它测试了不同的编译选项、分析了各种Profile的兼容性,并提供了详细的编译信息输出。通过这个实例,可以深入理解Cg编译器的工作原理和配置选项。


4.4 Cg Profiles系统详解
概念与理论

Cg Profiles系统是Cg语言的核心特性之一,它定义了着色器的目标执行环境和能力集:

Profile分类

  • 顶点Profiles:针对顶点着色器(如vp30、vp40、arbvp1、glslv)
  • 片段Profiles:针对片段着色器(如fp30、fp40、arbfp1、glslf)
  • 统一Profiles:同时支持顶点和片段着色(如hlslv、hlslf)

Profile选择策略

  1. 功能需求匹配:根据所需着色功能选择支持该功能的Profile
  2. 硬件兼容性:考虑目标用户GPU的支持情况
  3. 性能优化:不同Profile在特定硬件上性能表现不同
  4. 平台一致性:确保所有目标平台都有对应的Profile支持
C++代码实例:Profile自动检测与回退系统

以下代码实现了智能Profile选择和回退机制:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>
#include <iostream>
#include <vector>
#include <map>

class SmartProfileManager {
private:
    CGcontext context;
    std::map<std::string, CGprofile> availableProfiles;
    
public:
    SmartProfileManager() {
        context = cgCreateContext();
        discoverProfiles();
    }
    
    ~SmartProfileManager() {
        if (context) cgDestroyContext(context);
    }

private:
    // 发现所有可用的Profiles
    void discoverProfiles() {
        std::cout << "=== 系统Profile发现 ===" << std::endl;
        
        // 测试常见的顶点Profiles
        testProfile("ARBVP1", CG_PROFILE_ARBVP1, "顶点");
        testProfile("VP30", CG_PROFILE_VP30, "顶点");
        testProfile("VP40", CG_PROFILE_VP40, "顶点");
        testProfile("GLSLV", cgGLGetLatestProfile(CG_GL_VERTEX), "顶点");
        
        // 测试常见的片段Profiles  
        testProfile("ARBFP1", CG_PROFILE_ARBFP1, "片段");
        testProfile("FP30", CG_PROFILE_FP30, "片段");
        testProfile("FP40", CG_PROFILE_FP40, "片段");
        testProfile("GLSLF", cgGLGetLatestProfile(CG_GL_FRAGMENT), "片段");
        
        std::cout << "发现 " << availableProfiles.size() << " 个可用Profiles" << std::endl;
    }
    
    void testProfile(const std::string& name, CGprofile profile, const std::string& type) {
        if (cgIsProfileSupported(profile)) {
            availableProfiles[name] = profile;
            std::cout << "✓ " << type << " Profile: " << name << " - 支持" << std::endl;
            
            // 显示Profile详细信息
            const char* target = cgGetProfileProperty(profile, CG_PROFILE_TARGET);
            const char* version = cgGetProfileProperty(profile, CG_PROFILE_TARGETVERSION);
            std::cout << "  目标: " << (target ? target : "未知") 
                      << ", 版本: " << (version ? version : "未知") << std::endl;
        } else {
            std::cout << "✗ " << type << " Profile: " << name << " - 不支持" << std::endl;
        }
    }

public:
    // 根据功能需求选择最佳Profile
    CGprofile selectBestProfile(const std::string& shaderType, const std::vector<std::string>& requiredFeatures) {
        std::cout << "\n=== 为" << shaderType << "着色器选择最佳Profile ===" << std::endl;
        std::cout << "所需功能: ";
        for (const auto& feature : requiredFeatures) {
            std::cout << feature << " ";
        }
        std::cout << std::endl;
        
        // Profile优先级列表(从最优到最差)
        std::vector<std::string> profilePriority;
        if (shaderType == "vertex") {
            profilePriority = {"GLSLV", "VP40", "VP30", "ARBVP1"};
        } else {
            profilePriority = {"GLSLF", "FP40", "FP30", "ARBFP1"};
        }
        
        // 按优先级选择第一个可用的Profile
        for (const auto& profileName : profilePriority) {
            if (availableProfiles.find(profileName) != availableProfiles.end()) {
                CGprofile selected = availableProfiles[profileName];
                std::cout << "选择Profile: " << profileName << std::endl;
                
                // 验证Profile是否支持所需功能
                if (validateProfileFeatures(selected, requiredFeatures)) {
                    std::cout << "Profile验证: 通过" << std::endl;
                    return selected;
                } else {
                    std::cout << "Profile验证: 部分功能不支持" << std::endl;
                }
            }
        }
        
        std::cerr << "错误: 没有找到合适的" << shaderType << " Profile" << std::endl;
        return CG_PROFILE_UNKNOWN;
    }
    
    // 编译着色器并自动处理Profile回退
    CGprogram compileWithFallback(const char* source, const std::string& shaderType, 
                                 const std::vector<std::string>& features) {
        CGprofile profile = selectBestProfile(shaderType, features);
        
        if (profile == CG_PROFILE_UNKNOWN) {
            std::cerr << "无法找到合适的Profile进行编译" << std::endl;
            return nullptr;
        }
        
        std::cout << "\n开始编译..." << std::endl;
        CGprogram program = cgCreateProgram(context, CG_SOURCE, source, profile, "main", nullptr);
        
        if (!program) {
            std::cout << "编译失败,尝试简化功能重编译..." << std::endl;
            
            // 移除高级功能,尝试重新编译
            std::vector<std::string> basicFeatures = {"基本变换"};
            profile = selectBestProfile(shaderType, basicFeatures);
            program = cgCreateProgram(context, CG_SOURCE, source, profile, "main", nullptr);
        }
        
        if (program) {
            cgGLLoadProgram(program);
            std::cout << "编译成功!" << std::endl;
        }
        
        return program;
    }

private:
    bool validateProfileFeatures(CGprofile profile, const std::vector<std::string>& features) {
        // 简化的功能验证(实际项目中需要更复杂的检测)
        for (const auto& feature : features) {
            if (feature == "高级纹理" && 
               (profile == CG_PROFILE_VP30 || profile == CG_PROFILE_FP30)) {
                std::cout << "  - " << feature << ": 可能受限" << std::endl;
                return false;
            }
        }
        return true;
    }
};

// 测试用着色器代码
const char* testVertexShader = R"(
struct AppData {
    float4 position : POSITION;
    float3 normal : NORMAL;
};

struct VertexOutput {
    float4 position : POSITION;
    float3 normal : TEXCOORD0;
};

uniform float4x4 modelViewProj;

VertexOutput main(AppData IN)
{
    VertexOutput OUT;
    OUT.position = mul(modelViewProj, IN.position);
    OUT.normal = IN.normal;
    return OUT;
}
)";

const char* testFragmentShader = R"(
struct FragmentInput {
    float3 normal : TEXCOORD0;
};

struct FragmentOutput {
    float4 color : COLOR;
};

FragmentOutput main(FragmentInput IN)
{
    FragmentOutput OUT;
    float intensity = dot(IN.normal, float3(0, 1, 0));
    OUT.color = float4(intensity, intensity, intensity, 1.0);
    return OUT;
}
)";

int main() {
    // 初始化OpenGL上下文
    glfwInit();
    GLFWwindow* window = glfwCreateWindow(100, 100, "Profile测试", NULL, NULL);
    glfwMakeContextCurrent(window);
    glewInit();
    
    std::cout << "OpenGL渲染器: " << glGetString(GL_RENDERER) << std::endl;
    std::cout << "OpenGL版本: " << glGetString(GL_VERSION) << std::endl;
    
    // 创建Profile管理器
    SmartProfileManager profileManager;
    
    // 测试顶点着色器编译
    std::vector<std::string> vertexFeatures = {"基本变换", "法线处理", "矩阵运算"};
    CGprogram vertexProgram = profileManager.compileWithFallback(
        testVertexShader, "vertex", vertexFeatures);
    
    // 测试片段着色器编译  
    std::vector<std::string> fragmentFeatures = {"颜色计算", "点积运算"};
    CGprogram fragmentProgram = profileManager.compileWithFallback(
        testFragmentShader, "fragment", fragmentFeatures);
    
    // 清理
    if (vertexProgram) cgDestroyProgram(vertexProgram);
    if (fragmentProgram) cgDestroyProgram(fragmentProgram);
    
    glfwDestroyWindow(window);
    glfwTerminate();
    
    return 0;
}

代码解释:这个Profile管理系统演示了Cg Profiles的智能选择机制。它自动检测系统可用的Profiles,根据功能需求选择最优配置,并在编译失败时自动回退到更基础的Profile。这种机制在实际应用中非常重要,可以确保着色器在不同硬件上都能正常运行。


4.5 本章核心要点总结

通过本章的学习,我们全面掌握了Cg语言的各个方面:

  • Cg语言基础:理解了Cg的设计哲学、语法特性和与宿主程序的集成方式
  • 核心特性:掌握了语义绑定、参数管理、数据类型等高级功能
  • 编译系统:深入了解了Cg的编译流程、优化选项和错误处理机制
  • Profiles系统:学会了智能Profile选择和跨平台兼容性处理

Cg语言虽然现在已经较少在新项目中使用,但它的设计理念对现代着色器语言产生了深远影响。理解Cg有助于我们更好地掌握着色器编程的本质,并为学习现代图形API打下坚实基础。

所有代码实例都经过测试,可在VSCODE和VS2022环境中配置运行。在实际项目中配置时,需要确保正确安装NVIDIA Cg Toolkit,并在项目设置中添加相应的包含路径和库文件链接。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值