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的本地指令:
编译流程:
- 前端解析:将Cg源码解析为抽象语法树(AST)
- 语义分析:检查类型一致性、语义正确性
- 中间代码生成:生成与硬件无关的中间表示
- 目标代码生成:根据Profile将中间代码转换为特定API的着色器
- 优化阶段:应用平台特定的优化策略
编译模式:
- 离线编译:预编译为二进制格式,运行时直接加载
- 运行时编译:应用程序运行时动态编译,支持热重载
- 交叉编译:同一份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选择策略:
- 功能需求匹配:根据所需着色功能选择支持该功能的Profile
- 硬件兼容性:考虑目标用户GPU的支持情况
- 性能优化:不同Profile在特定硬件上性能表现不同
- 平台一致性:确保所有目标平台都有对应的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,并在项目设置中添加相应的包含路径和库文件链接。
890

被折叠的 条评论
为什么被折叠?



