这样一道题:Search in Rotated Sorted Array II
这道题咋看上去可以有O(log(n)的解法,但是实际上只有O(n)的解法。
脑图软件推荐
脑图对信息的整理非常有帮助。比如之前做ITER那个项目一个人写程序时,经常在界面的地方忘记了自己写的数据处理的模块的API,经常需要翻过来翻过去看代码。可以用脑图的方式把程序的层次结构整理出来,一方面整理的过程有助于找到设计上逻辑不通的地方,另一方面便于之后的查询。若开始接触新的模块或做一些事情的时候,也可以这样整理一下。
实践路上遍布荆棘-Opengl常见问题记录
说多了都是泪啊。
三维渲染程序编译通过却总是看不见图像,看见图像了颜色又不对,出Opengl标准的想象中的boss们的小人被自己在心里默默扎了无数遍。。。
之后常见的错误都会记录在这里。
初步诊断
这里记录一下常见的问题可能的原因,可能的解决方法:
渲染一帧过程中切换shader不起作用:八成是新shader未通过编译,导致该shader无效,所以切换到该shader的命令也无效了。
视野内无物体:有可能是该帧初始化时没有清除缓存,也有可能是视角的转换矩阵设置错误。
渲染到屏幕缓存的过程中插入一段渲染到内存缓存的命令(可能是用于生成纹理),然后后面的渲染就看不见了:渲染到缓存时,一般会调整视窗范围,在后续的渲染到屏幕缓存命令前需要重置视窗为屏幕整体。
Shader的uniform变量一定要初始化
不然你永远得不到你想要的东西。
比如顶点shader中,你加一个modelspacetrans的矩阵吧,这个矩阵如果在程序中不初始化(gluniformxxx),那么等待你的可能是未知的随机矩阵。
Shader中,函数返回vec一定要显示定义vec
比如下面:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
vec3 FloatToRGBData(float attenuationRate){
int tmpI = floatBitsToInt(attenuationRate);
tmpI = floatBitsToInt(0.0342);
int ir = (0xff000000 & tmpI)>>24; //exp part
int ig = (0xff0000 & tmpI)>>16;
int ib = (0xff00 & tmpI)>>8;
float r = ir/256.0;
float g = ig/256.0;
float b = ib/256.0;
return vec3(r,g,b); //正确写法
}
vec3 FloatToRGBData(float attenuationRate){
int tmpI = floatBitsToInt(attenuationRate);
tmpI = floatBitsToInt(0.0342);
int ir = (0xff000000 & tmpI)>>24; //exp part
int ig = (0xff0000 & tmpI)>>16;
int ib = (0xff00 & tmpI)>>8;
float r = ir/256.0;
float g = ig/256.0;
float b = ib/256.0;
return (r,g,b); //错误写法
}
渲染每个场景前,一定也要初始化要渲染的Buffer
不然会出现这样的情况,比如Buffer里的深度信息都是零,那么你什么也渲染不上去,或者出现各种破烂哦。
所以两个函数要牢记心间:
1 |
|
勤输出出错信息,勤观察出错信息
opengl提供了一些用于出错信息输出的接口。
- 一个回调函数,opengl会在所有出错的时候调用这个回调函数
1 | //在初始化时添加回调函数 |
- 第二个回调函数,用于在Debug时输出详细信息
1 | //在初始化时添加回调函数 |
- 可以自己编写一个报错信息检查函数,可插入代码的任意位置,报告当前位置最后一个错误
1 | GLenum glCheckError_(const char *file, int line) |
蔚蓝海岸,富人口岸:尼斯-摩纳哥游记
其实这趟出来最主要的目的是去摩纳哥看看蒙特卡罗赌场。这个赌场就是当年蒙特卡罗方法的起源。汽车从艾克斯到尼斯需要3小时,而在尼斯车站直接就有去摩纳哥的公交。
下面跟着我一起经历这两天一夜的旅程吧。
摩纳哥在印象中就是富豪们的销金场,眼见的事实也确实如此。赌场虽号称是欧洲最大,但是看起来却不甚宏伟。黑底烫金的门脸,西装革履的门卫,嗯,多少还是有些派头的,那就合影一二吧。
在这里的街上,豪车是最稀松平常的了,BBA已然是平民车了。等等,这也不是普通的奔驰啊,爆炸的排气声浪也在表明其AMG的身份。
在赌场门口转了转,绕过巴黎饭店后,就来到了海边的高台。下面是接天的碧蓝海面,以及停满豪华游艇的海港。和马赛那挤满港口的渔船不同,这里都是带泳池,有工人忙着维护的游艇。
这是著名的巴黎饭店,曾经topgear有一集是三个人选一辆车,看谁的车能不被从门口开走。哈哈。
这门口一般都是停着这些价值不菲的豪车的。三个人最后是找了一辆根本没人会开的20世纪初的老爷车来放这的。
海风宜人,风景更宜人哦。
青年旅馆的电梯,因为在二楼,我也懒得坐这玩意儿了。
青年旅馆守则,嗯,与人为善。但是我给忘记了我晚上会打呼,估计给几位室友添麻烦了。
Allo Allo,哈哈,印度人的发音。
早上预定要去夏加尔博物馆的,时间未到,我便被这尖顶吸引来了。远观尚可,无奈前面停了好多车,只好照上半身啦。
在夏加尔博物馆,我仿佛自己给自己上了一趟美术课。
刚进馆时,咋一看,顿时有一种小学生蜡笔画既视感。我一边拿着导游器听着,一边准备走起。但是转身我立马被这副“摩西在燃烧的树枝前”(下图)给迷住了。恍惚之间,画上的海面仿佛有波光流转,画上密密麻麻的人物仿佛就站在了纸面上。我这才恍然大悟,这画简直是有魔力一般。
如果不明白我为什么说蜡笔画,可以看这一幅诺亚方舟。但是真正在现场仿佛会觉得画上的人物是雕刻出来的,整幅画一种跃然而起的感觉。
当然,后面他献给妻子的那一圈画实在是欣赏不能,也许是没静下心来吧。
在马蒂斯博物馆,终于能连玻璃也不隔着地近看大师地画作了。虽不比卢浮宫的惊人数量的画作,但是屏息之间,仿佛能看到画家如何一笔一笔抹出这些作品的,也是很难得。
可以用刷毛自然勾勒出细密的书页。
也可以把色彩的魅力发挥到极致。
哈
有种扫地僧的感觉。
之后就是现代艺术博物馆了,略不能理解。
怎么说呢,还是有点累的。
深度测试,阴影和深度剥离
下图是裸阴影(后期可通过模糊处理,得到一般的阴影,具体可参考著名opengl在线教程)
下面是深度图
基于深度缓存,更进一步是深度剥离(Depth peeling)方法,其原理就是从光源出发多次渲染后获得一正一反一正一反的偶数组深度缓存,在真正的图形渲染时,基于多层深度缓存,对每个像素计算其前面挡住光源的几何体的厚度。
深度剥离的难点在于边缘位置的处理,很容易出现异常点。需要容忍一定的误差,作模糊处理。
作为一个应用,可获得半透明物体的投影强度。如下图所示。
忙碌又闲适的8月第三周-马赛-电影-项目
马赛之行
成hao是法国留学硕士毕业后在ITER找到工作的,他妻子檖同学是马赛大学的毕业生,两人都在法国工作了,眼看应该也要在法国定居了。
上周六他们计划去马赛拿定制的结婚戒指,就把我给带上了。
终于,我要走出艾克斯小镇,踏上法国的港口重镇了。
来这里之前,我问过一些人,有人建议不要去那里,可以去去里昂之类的城市,但是鄙人新来,还不太识路,所以先去这个离住处仅半小时车程的城市转转也挺好的。
在这个有voyage标志的地方买票,要么不买,要么就买6次往返的联程票。共计25欧,比在马赛住一晚便宜多了,何乐不为呢。
那么就出发啦,坐着宽敞的梅赛德斯奔驰,就这么一路向马赛进发啦。
下车后,檖同学向我介绍了这个车站本身就是一大景点哦,我就这么听她说着说着不知不觉就到了码头,然后和他们分开后我就独自行动啦。
在码头有这么一个建筑,不锈钢的柱子搭着不锈钢的顶棚,像一面巨大的镜子罩着大伙。引得不少游人驻足留影。
我就这么从分开的地方出发了,走过了行人如织的码头,
走过了如林的桅杆,
走着走着就走进了一个城堡,圣约翰堡。
城堡陆陆续续建了几百年,厚实的墙壁不由让人感叹,这样的东西才能存在几百年啊。不过也有赖于当地没有丰富的地震史吧。不知有没有人研究地震历史对文明进程的影响规律。
走着走着,我一想,该有把椅子就好了,然后我就看到椅子了。空旷的堡顶平台,只有三三两两的游客,趁没人的时候坐着偷会懒真是惬意。
堡前的海湾里,填出了一块平台,那里有新建的地中海文明博物馆,馆外看着还是挺好的哈,现代的简洁线条和海湾自然的曲线,蓝天、黑壁、白墙、绿水,历史与现在形成了鲜明的对比。
沿着天桥,便从历史中抽身,进入了工业化世界了。
整个博物馆由钢铁和预制的钢精水泥柱搭建而成,斑驳的阳光从带孔的黑色墙壁漏下,没有感觉出什么美感,只是在地中海的艳阳下,给人们提供了一个遮阳而又通透的实用空间。
博物馆内部和墙壁间是斜度很小的围廊,从顶至底环绕而下,估计不走旁边的捷径这够我走一会了。
出了博物馆后,我又绕回了古堡,在另一边的天台上,拍了一下青铜雕像,并遥望了下一个目的地,请注意雕像右边那凸起的小山丘上的尖顶建筑,那就是金顶教堂了。
这牛是傲娇的,让你们摸,我这么高了再看你们怎么摸。
途中登山,一条马路从山顶下去又折向对面的山顶,置身其中仿佛对面要如《inception》似的翻折过来了。
强大的法院。
见过的最丑的奥迪,没有之一。
我后来看了一下,当天行走了有十多公里。一顿跋涉之后,我终于看到金顶的教堂了。
怎么说呢,登高望远确实有吸引力,一登上顶峰我所有的烦恼都丢下了。
山上好多国人,好幸福。找了最面善的同学给我拍了照。
海天相接,那里可看到地球的弧度。
这是金顶教堂正面的照片,里面虽然进去了,但是乏善可陈,毕竟也不好意思拿出手机咔嚓咔嚓一顿拍。
这有个仿名作的栏杆头雕塑,乍看还算可爱,但是比卢浮宫大理石的要差远啦。
二战的坦克。
另一处老教堂,可能历史要到罗马前了。
走回到车站,看着远方的曾经感觉那么遥不可及的目标,历经跋涉后不也在眼前嘛。
好啦,马赛就到这啦。
回家看我多多最可爱了。
羊排和饭。
加上饭后的甜点,生活真是惬意啊。不过哈格达斯太甜了,还是少吃为妙。
GLFW多上下文与多线程资源读取
感觉不惧英文后,能在网上找到很多更笃定、更自信的回答。
由于三维编程需要读取大量的资源,但是不能让窗口干等着啊,所以打算起新线程来读资源,主线程根据读取进度进行不同程度的渲染。
底层Opengl的API支持
Opengl是通过context间共享资源实现多线程加载的。虽然官方不太推荐,但是好歹给了一个方法。
GLFW封装的方法
但是我这从头学起的工程,都是基于GLFW编的,所以我就找了一圈,找到一个老司机的答案:
Make a second invisible window that has the main window as the parent (the last parameter is for list sharing)
E.g.: GLUtil::_loaderWindow = glfwCreateWindow(1, 1, “whatever”, nullptr, GLUtil::_mainWindow);
Create another thread and in its run()(or whatever) method call this: glfwMakeContextCurrent(GLUtil::_loaderWindow);
If you are using GLEW, build GLEW with the GLEW_MX define and call init() in the second thread as well. Read up on GLEW_MX about multithreaded usage. I strongly recommend boost thread specific pointers for this.
Remember to destroy the second window just like the main one. That’s it. I’ve been using this method for background resource loading for years and haven’t ran into any issues.
Hope it helps.
大意是直接用glfw通过与原上下文共享的方式创建新上下文即可,把新出现的窗口隐藏就行了。
然后主线程用主上下文,在资源读取线程中,将新的上下文设置为当前上下文即可。由于在创建时新的上下文使用了GLFWWindow作为最后一个参数,即与原上下文共享了列表(sharelist,一大堆显卡相关的东西),所以在使用新的上下文线程中可以进行shader编译、texture读取等等操作。
好吧,老司机说这么多年都这么过来了,我决定听老司机的了。
需要注意的事项
- OpenGL不允许在不同的context下共享顶点缓存(VAO)。
所以顶点缓存还需要在主线程中创建。
目前在线程中做的主要是将纹理的读取和处理放在非主线程中了。用c++11的std::thread非常方便,爱上新标准了。 - 在Load线程结束时需要加一句glfwMakeContextCurrent(mainWindow);具体原因还需要再看一下。
OpenGL Shading Language(GLSL)概览
翻了很久的learnopengl,快到结尾了,终于感觉入门了的感觉。
整个教程除了OpenGL的入门,反反复复介绍的就是利用shader进行各种花式渲染。
那么聪明如我的读者肯定就知道了,图形编程的关键是深入到shader编程,通过其提升渲染效率及提供高级渲染效果。
在教程的Debugging一节,打开了一扇门,其中提到了不同的显卡厂商在驱动中带的GLSL编译器的标准是略不同的。
NVIDIA比AMD要求松一些,适当兼容了不在OpenGL中不包含的情况,所以可能出现NVIDIA上的shader编译无问题的情况在AMD显卡上无法运行的情况。所以就有这样一个标准的Shader检查器(GLSL reference compiler)。良心啊,开源的,关键是显卡厂商就是不愿意统一,和JS、CSS等问题感觉类似。
各式各样的shader
有这样一系列的shader类型:
.vert - a vertex shader
.tesc - a tessellation control shader
.tese - a tessellation evaluation shader
.geom - a geometry shader
.frag - a fragment shader
.comp - a compute shader
其中,有一个比较特别的compute shader,细看之下应该就是OpenCL一类的底层吧,难怪NVIDIA这么厉害了,在GLSL标准外额外支持了一系列的API,然后就在并行计算上胜了AMD一招。
这个compute shader是脱离在GL的渲染流程之外的,是单独的glDispatchCompute函数对其执行的调用。问题是这个和opencl有什么关系呢?之后还得再看看,如果opencl足够好用了,这个感觉也没多大意思了。
项目的背景图案
经过两日的努力,终于做出了比较炫的地球了,这下项目界面的背景终于有着落了
ITER的安全培训
为了能够参加ITER工地的参观,我参加了ITER的安全培训。International。
培训的老师是一位工程经验丰富的法国大叔。强健的体魄,修身的蓝体恤和红牛仔裤,黑底与亮绿色边框的手机壳。To whom that thinks I am 25, I am not, I am double of that.”.
参加培训的有新员工,有合同承包商,有工地的工人。法国人、意大利人、英国人、美国人、中国人等等。
整个过程学习了。
比如:
Color Code
绿白绿白:表示信息
红白红白:表示禁止
蓝白蓝白:表示强制的
黑黄黑黄:表示警告
服装颜色之类的
各色头盔、各色背心在工地上是不同的角色,对于小组boss,应该有醒目的颜色,这样吊车操作等等人员就能清晰地知道是谁在指挥了。
不由得想起这样得协议性得东西在人得头脑中理解再转发确实恨低效啊,想到如果精确如机器能够瞬间搭建合理得工作协议,AI一出人类在效率上还怎么比得过。
天津爆炸事件
天津爆炸事件影响范围还是很广的。培训的过程中,讲师最常说的话是:“accident is expensive, if you don’t beleave, try accident.” 对于ITER的安全工作,他作为负责人相当自豪,目前还是零事故哦。
不允许用梯子
那还能不用梯子?在这里一定高度的作业必须用电动升降机,不允需要人扶的梯子。不由感慨发达国家还是略先进啊。
禁止抽烟
ITER现在整个厂区都不允许抽烟了!天台、阳台、办公室、走廊、厕所统统禁烟。
一是安全,另一方面他给我们语重心长地讲了抽烟对小孩不好,对环境不好。
他:你们了解不,你丢地每个烟屁股会污染多少水?
答:2~3升?
他:错!整整300~400升啊。你们知不知道,全法国一年要丢多少烟屁股?那位同学说的接近了,不止5000万,是整整5400万啊同学们。你以为大家丢大街上就不污染水啦?大雨一下,噗,自己算吧。这里有谁抽烟不?有儿女不?赶紧地戒了吧。
我给大叔点个赞。
发达国家的环保意识
这里进出工地的车子,在出工地前,是要通过一个洗轮胎的机器的,也不复杂,就是下面这个样子的:
但是!很遗憾,这一次没有时间去参观了,再等到秋高气爽时再去咯。
IMGUI用法小结
在本文中,“窗口”imgui在操作系统提供的窗口中创建的img界面容器。
“控件”指imgui在“窗口”中创建的界面元素。
字体导入与使用
由于是国内的项目,需要使用中文字体,因此借鉴imgui主页的例子。1
2
3
4
5ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
// For Microsoft IME, pass your HWND to enable IME positioning:
io.ImeWindowHandle = my_hwnd;
可以实现相应的中文输入。
基本上imgui也是个状态机,字体的颜色、窗口的背景等等均可通过PushStyle和PosStyle实现,所以以往接触过opengl立即模式的话应该很快能理解。
目前imgui没有实现运行时字体动态大小切换功能,一个比较费事的方法是在导入字体时生成多种大小的字体,在程序运行中通过PushFont和PopFont实现。
此外,imgui可支持子界面的缩放,适当运用也可以缓解字体缩放的困难,如#772 (comment)所示。
UI排版
主要是从参考文章中获取的信息。
imgui的排版建议开始按自动的来。
自动布局时,默认情况下,各控件由上到下依次显示。
可以使用GUILayout.BeginHoriztontal(),GUILayout.EndHorizontal(), GUILayout.BeginVertical(), and GUILayout.EndVertical().来控制各控件水平显示或垂直显示。可嵌套。
关于UI在主窗口的停靠,目前官方没有出排版套路,但是一些用户给出了解决方法。
目前我的做法是直接把子界面的位置固定在窗口内,只做一个隐藏弹出的切换。
c++11支持utf8 + vs2017 community
支持utf8了!再也不用与编码纠缠了,再见GTK,再见GB。
imgui窗口的定位
imgui所有的定位坐标都是相对于操作系统提供的总体窗口的。
imgui提供了一系列的函数用于窗口定位:
IMGUI_API ImVec2 GetContentRegionMax(); //窗口右下角坐标(含需要滚动条才能到达的区域)
IMGUI_API ImVec2 GetContentRegionAvail(); //窗口尺寸
IMGUI_API float GetContentRegionAvailWidth();//窗口尺寸宽度
IMGUI_API ImVec2 GetWindowContentRegionMin(); //窗口左上角坐标
IMGUI_API ImVec2 GetWindowContentRegionMax(); //窗口
IMGUI_API float GetWindowContentRegionWidth();
以及ImGui::GetIO().DisplaySize用于获得总体窗口的尺寸(在总体窗口缩放时会用到)。
隐去windows窗口标题栏
原文来自:http://blog.csdn.net/LYP951018/article/details/24503207
————————以下为原文——————————
case WM_SIZE:
{
LONG_PTR Style = ::GetWindowLongPtr(hWnd,GWL_STYLE);
Style = Style &~WS_CAPTION &~WS_SYSMENU &~WS_SIZEBOX;
::SetWindowLongPtr(hWnd, GWL_STYLE, Style);
break;
}
##