最近在看Eye2012的代码,决定一点一点转到Openframeworks里面。
那么第一步,就要建立一个房间了。
房间就是一个6面体,这个没什么,用一个 ofMesh 就可以了。
可以参考下面的代码建立一个Box
/*
construct room mesh
*/
float X = dims.x;
float Y = dims.y;
float Z = dims.z;
static ofVec3f verts[8] = {
ofVec3f(-X,-Y,-Z ), ofVec3f(-X,-Y, Z ),
ofVec3f( X,-Y, Z ), ofVec3f( X,-Y,-Z ),
ofVec3f(-X, Y,-Z ), ofVec3f(-X, Y, Z ),
ofVec3f( X, Y, Z ), ofVec3f( X, Y,-Z )
};
static GLuint vIndices[12][3] = {
{0,1,3}, {1,2,3}, // ceiling
{4,7,5}, {7,6,5}, // floor
{0,4,1}, {4,5,1}, // left
{2,6,3}, {6,7,3}, // right
{1,5,2}, {5,6,2}, // back
{3,7,0}, {7,4,0} // front
};
static ofVec3f vNormals[6] = {
ofVec3f( 0, 1, 0 ), // ceiling
ofVec3f( 0,-1, 0 ), // floor
ofVec3f( 1, 0, 0 ), // left
ofVec3f(-1, 0, 0 ), // right
ofVec3f( 0, 0,-1 ), // back
ofVec3f( 0, 0, 1 ) // front
};
static ofVec2f vTexCoords[4] = {
ofVec2f( 0.0f, 0.0f ),
ofVec2f( 0.0f, 1.0f ),
ofVec2f( 1.0f, 1.0f ),
ofVec2f( 1.0f, 0.0f )
};
//
static GLuint tIndices[12][3] = {
{0,1,3}, {1,2,3}, // ceiling
{0,1,3}, {1,2,3}, // floor
{0,1,3}, {1,2,3}, // left
{0,1,3}, {1,2,3}, // right
{0,1,3}, {1,2,3}, // back
{0,1,3}, {1,2,3} // front
};
int index = 0;
vector<unsigned int> indices;
vector<ofVec3f> posCoords;
vector<ofVec3f> normals;
vector<ofVec2f> texCoords;
for( int i=0; i<12; i++ ){
posCoords.push_back( verts[vIndices[i][0]] );
posCoords.push_back( verts[vIndices[i][1]] );
posCoords.push_back( verts[vIndices[i][2]] );
indices.push_back( index++ );
indices.push_back( index++ );
indices.push_back( index++ );
normals.push_back( vNormals[i/2] );
normals.push_back( vNormals[i/2] );
normals.push_back( vNormals[i/2] );
texCoords.push_back( vTexCoords[tIndices[i][0]] );
texCoords.push_back( vTexCoords[tIndices[i][1]] );
texCoords.push_back( vTexCoords[tIndices[i][2]] );
}
mesh_.addVertices(posCoords);
mesh_.addIndices(indices);
mesh_.addNormals(normals);
mesh_.addTexCoords(texCoords);
接下来就是渲染了,渲染用Shader。
首先给房间加上一些AO。
Vertex Shader ( 主要就是把 顶点位置,法线和眼向量传到片元)
uniform vec3 eyePos;
varying vec3 eyeDir;
varying vec4 vVertex;
varying vec3 vNormal;
void main()
{
vVertex = gl_Vertex;
vNormal = gl_Normal;//normalize( vec3( mMatrix * vec4( gl_Normal, 0.0 ) ) );
eyeDir = normalize( eyePos - vVertex.xyz );
gl_Position = gl_ModelViewProjectionMatrix * vVertex;
}
Fragment Shader
uniform float power;
varying vec3 eyeDir;
varying vec4 vVertex;
varying vec3 vNormal;
void main()
{
float aoLight = 1.0 - length( vVertex.xyz ) * ( 0.0008 + ( power * 0.001 ) );
gl_FragColor.rgb = vec3( aoLight );
gl_FragColor.a = 1.0;
}
AO的话就是以房间中心散射光线,(0.0008 + (power * 0.001 )) 就是控制半径,这样在边角就暗了,power用来控制明暗切换时,的变化。
效果如下:
接下来加一个顶灯,并且加上power的控制,实现开关灯效果
Fragment shader 加入如下代码
float aoDark = aoLight * 0.01;
float ceiling = 0.0;
if( vNormal.y > 0.5 ) ceiling = 1.0;// 定义法线朝下的是天花板
vec3 litRoomColor = vec3( aoLight + ceiling * lightPower );
vec3 darkRoomColor = vec3( aoDark );
gl_FragColor.rgb = mix( litRoomColor, darkRoomColor, power );
lightPower是uniform,根据power计算得出的,计算方式如下
float p = power * 5.0f * PI;
lightPower = cos( p ) * 0.5f + 0.5f;
效果如下:
上图天花板和墙壁的过渡不自然,不像灯光打出来的,还需要在天花板和墙壁的地方加一个glow效果
fragment shader:
float yPer = 1.0 - clamp( abs(vVertex.y-ceilingY)/(2.*roomDims.y), 0.0, 1.0 );// 把顶点到天花板的距离作为参数计算
float ceilingGlow = pow( yPer, 2.0 ) * 0.35;
ceilingGlow += pow( yPer, 100.0 );
ceilingGlow += pow( max( yPer - 0.7, 0.0 ), 3.0 ) * 4.0;
vec3 litRoomColor = vec3( aoLight + ( ceiling + ceilingGlow ) * lightPower );
最终效果:
视频: http://v.youku.com/v_show/id_XNDIzMTM4NDc2.html
git : https://github.com/Geistyp/OfwEye
ofw 0.071