自从我开始学习 OpenGL 以来,我想我还不如编写一个小型 C++ 框架(为我自己)来避免过度使用 C-ish 代码显然造成的恶心。 :) 由于我打算坚持使用 Qt,因此该框架使用了一些 Qt 类。
我真正需要的第一件事是使用着色器和程序的简单方法。这是我对着色器类的想法。
class Shader
{
public:
//create a shader with no source code
explicit Shader(GLenum shaderType);
//create a shader with source code and compile it
Shader(GLenum shaderType, const QString& sourceCode);
//create a shader from source file and compile it
Shader(GLenum shaderType, QFile& sourceFile);
~Shader();
//change the source code and recompile
void Source(QFile& sourceFile);
void Source(const QString& sourceCode);
GLuint get() const; //get the handle
private:
//common part for creation in different constructors
void createShader(GLenum shaderType);
//compile
void compile();
private:
GLuint handle;
};
不同功能的作用一定很明显。每个都调用相关的 OpenGL 例程,检查错误并在出现任何故障时抛出异常。构造函数调用 glCreateShader。现在是棘手的部分。析构函数需要调用 glDeleteShader(handle); 但在这种情况下我有一个进退两难的问题:
选项 1: 禁用分配和复制。这有避免引用计数的好处,也有被迫使用 shared_pointers 将它们放在 vector 中并在一般情况下传递的缺点。
选项 2:启用引用计数。这具有启用复制的明显优势,因此可以存储在容器中(稍后我需要将一系列着色器传递给程序)。缺点如下:
Shader s1(GL_VERTEX_SHADER, QFile("MyVertexShader.vp"));
Shader s2(s1);
s2.Source(QFile("MyOtherVertexShader.vp"));
如您所见,我通过 s2 更改了 s1 的源代码,因为它们共享相同的内部着色器句柄。老实说,我看不出这里有什么大问题。我写了这个类,所以我知道它的复制语义是这样的,我对此很满意。问题是我不确定这种设计是否可以接受。所有这一切都可以通过 Option1 + 共享指针来实现,唯一的区别是我不想每次创建着色器时都有一个共享指针(不是出于性能原因 - 只是为了语法方便)。
Q1:请对选项和整个想法发表评论(可选)。1
Q2:如果我选择选项 2,我是否必须自己实现它,或者在 boost 或 Qt 中有一个现成的类,我可以从中派生或拥有它的成员,我将获得免费引用数数?
问题 3:您是否同意将 Shader 设为抽象类并拥有三个派生类 VertexShader、FragmentShader 和 GeometryShader 会矫枉过正吗?
1 如果你应该向我推荐一个现有的 C++ OpenGL 框架,那很好(因为我还没有真正找到一个)但那真的应该作为旁注而不是回答我的问题。另请注意,我在文档的某处看到了一个 QGLShader 类,但它显然不存在于我的 Qt 版本中,我有理由立即避免升级。
更新
感谢您的回答。我最终决定通过删除源函数使我的着色器类不可变。着色器在创建时被编译并且没有非常量成员函数。因此,一个简单的引用计数可以立即解决我所有的问题。
最佳答案
我说的是使用选项 1:它可以做选项 2 可以做的所有事情(通过智能指针),而选项 2 让您支付间接成本,即使您不需要它。最重要的是,它可以说更容易编写。
同样,我曾经考虑过在包装 C API 时使用 handle-body/PIMPL,以允许从函数返回对象(不能保证 C 句柄类型可复制,因此间接访问是必要的)。我决定反对它因为 std::unique_ptr<T>执行不可移动 -> 可移动转换(就像 shared_ptr<T> 使 T 可复制)。从那时起,我将我的类设计为具有“最严格”的移动/复制语义。
然而,当谈到句法噪音时,你确实有道理! Boost.Phoenix 和 lambda 之类的东西往往会有所帮助。如果/当它们不是一个选项时,我会说写一个单独的 shared_shader或任何包装器(包装器包装器?)是有意义的,至少对于库级代码(我相信这里是这种情况)。我不知道有什么实用程序可以帮助处理繁琐的转发函数。
我对着色器也不太了解,所以我不确定我能否回答您的最后一个问题。我认为如果不同着色器的数量经常变化,那么创建一个类层次结构是有意义的。我不认为是这样;我还认为,即使是这种情况,因为您级别的实现正在包装一个预先存在的 API,如果/当添加了新的着色器时,重新访问代码以转发到该 API 也不会太麻烦。
既然你要的是 Phoenix niceness 的例子。
假设我不需要取消引用,我想做什么:
std::transform(begin, end, functor);
相反:
std::for_each(begin, end, *arg1 = ref(functor)(*arg1));
仍然可以使用 std::transform (为清楚起见,希望)使用一些 Phoenix 设施(construct IIRC),但这会花费分配。
关于c++ - 设计着色器类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7219633/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我在我的项目中有一个用户和一个管理员角色。我使用Devise创建了身份验证。在我的管理员角色中,我没有任何确认。在我的用户模型中,我有以下内容:devise:database_authenticatable,:confirmable,:recoverable,:rememberable,:trackable,:validatable,:timeoutable,:registerable#Setupaccessible(orprotected)attributesforyourmodelattr_accessible:email,:username,:prename,:surname,:
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=