ããæ¥ãå¹æã®ãã次ã®ãã¢ãèŠãŠãçåãçããŸããïŒã¢ãã€ã«ããã€ã¹ã§SSAOãäœæããŠãèŠãç®ãé ããªããªãããã«ããããšã¯å¯èœã§ããïŒ
Galaxy Note 3 n9000ïŒmali T62ïŒãããã€ã¹ãšããŠæ¡çšãããŸãããç®æšã¯FPSã30以äžã§ãããå質ã¯äžã®å³ã®ããã«ãªããŸãã
ãã®å¹æã«ã€ããŠã¯è©³ãã説æããŸããããèªè ã¯ä»ã®ãœãŒã¹ïŒ wikiãŸãã¯steps3d ïŒããå¹æã«ã€ããŠåŠã¶ããšãã§ãããšæ³å®ãããŠããŸã ã ãã®èšäºã§ã¯ã¢ãã€ã«ãã©ãããã©ãŒã ãžã®é©å¿ã«éç¹ã眮ããŠããŸããããVarieties of SSAOãã»ã¯ã·ã§ã³ã§ç°¡åãªã¬ãã¥ãŒãè¡ãããŸãã
SSAOã¯ããã©ãŒãã³ã¹ã®é¢ã§éåžžã«å€§é£ãã®å¹æã§ãããšåæã«ãå¹³åçãªãŠãŒã¶ãŒã«ã¯ãŸã£ããèŠããªãã®ã§ãã¢ãã€ã«ããã€ã¹ã§ã¯ãŸã èŠãŠããŸããã ããã«ããããå éããã«ã¯ã MRTãµããŒããå¿ èŠã§ããããã¯ãOpenGL ESããŒãžã§ã³3.0ã§ã®ã¿ç»å ŽããŸããã
SSAOã®çš®é¡
ã¢ã«ãŽãªãºã ã®äž»ãªã¢ã€ãã¢ã¯ã空éå ã®ãµãŒãã§ã¹ãã€ã³ãã®ã·ã§ãŒãã£ã³ã°ã決å®ããããšã§ãã ç¹å®ã®ååŸå ã®ãã®ãã€ã³ãã®ã·ã£ããŠã€ã³ã°ã®çšåºŠã決å®ããããã«ããªããžã§ã¯ãã®ååšããã§ãã¯ããããªããžã§ã¯ãã®è¿ãã«ããã»ã©ããã€ã³ããã·ã§ãŒãã£ã³ã°ãããŸãã
ãã¡ããã3次å 空éã®ãµãŒãã§ã¹äžã®åãã€ã³ãã®ã·ã§ãŒãã£ã³ã°ãèšç®ããããšã¯äžå¯èœã§ãããããã¢ã«ãŽãªãºã ã®ãã¹ãŠã®äœæ¥ã¯ç»å空éã§å®è¡ãããŸãïŒãã®ããã ç»é¢ç©ºéã¢ã³ããšã³ããªã¯ã«ãŒãžã§ã³ãšåŒã°ããŸã ïŒã ã€ãŸããç»é¢äžã®ãã¯ã»ã«ã¯è¡šé¢äžã®ç¹ãšããŠæ©èœããŸãïŒå®éãå¿ ãããç»é¢äžã§ã¯ãªããSSAOãããã¡ãŒã®ãµã€ãºã¯ç»é¢ãµã€ãºãããå°ããããšãå€ãããããã¬ãŒã ãŸãã¯ãã¬ãŒã å ã®ãã¯ã»ã«ãèšãæ¹ãããæ£ç¢ºã§ãïŒã ãŸããè¿é£ã®ç©ºéã®ãã¹ãŠã®ãã€ã³ãã®å€ãåŠçããããšã¯äžå¯èœã§ãããããã£ãŠãéåžžã¯ãåé¡ã®ãã€ã³ãããç¹å®ã®ååŸå ã®ã©ã³ãã ãªãã€ã³ãã®å°ããªéžæã«å¶éãããŸãã
æãåçŽãªå®è£ ã§ã¯ã深床ãããã¡ã¯ã·ã§ãŒãã£ã³ã°ãèšç®ããã®ã«ååã§ã-ãã®ãããåé¡ã®ãã¯ã»ã«ã®z座æšã¯ããã®å·®ã«åºã¥ããŠãµã³ãã«ã®ãã¯ã»ã«ã®z座æšãšæ¯èŒãããã·ã§ãŒãã£ã³ã°ãèæ ®ãããŸãã
ãã ããäžã®å³ãèŠããšããã€ã³ãã®äžã®ãµãŒãã§ã¹èªäœãã·ã§ãŒãã£ã³ã°ã«ç¬èªã®ïŒã圹ã«ç«ããªããïŒè²¢ç®ãããŠããããšãããããŸãã ãã®çµæãç»åã¯ã°ã¬ãŒããŒã³ã§ååŸãããŸããã€ãŸããã·ã§ãŒãã£ã³ã°ããªãã¯ãã§ãã 次ã®ããã«ãªããŸãã
ãããåé¿ããã«ã¯ã深床ã«é¢ããæ å ±ã«å ããŠããã®æç¹ã§ã®æ³ç·ã«é¢ããæ å ±ãå¿ èŠã§ãã ãããè¡ãã«ã¯ãã·ãŒã³ã®ã¬ã³ããªã³ã°äžã«ãè²ã«å ããŠãå¥ã®éåžžã®ãããã¡ãŒã«ãæžã蟌ãŸããŸãã ããããæå®ãããšããµã³ãã«ãããã€ã³ãã®äœçœ®ãå€æŽããŠããæçšãªãè²¢ç®ãããããšãã§ããŸãã ããã¯ãåé¡ã®ãã€ã³ãã®æ³ç·ãšãµã³ãã«ã®ãã€ã³ãã®æ³ç·ãšã®éã®è§åºŠã«åºã¥ããŠè¡ãããŸããè§åºŠïŒè§åºŠïŒã90°ãã倧ããå Žå-ãµã³ãã«ã®æ³ç·ãå転ããããã«åºã¥ããŠãã€ã³ããåèšç®ãããŸã ã¢ã«ãŽãªãºã ã®ãã®ãããªå€æŽã¯ãå¿ èŠãªå Žæã«ã®ã¿ã·ã§ãŒãã£ã³ã°ãæäŸããŸãããæ·±å»ãªæ¬ ç¹ããããŸã-ãµã³ãã«ããã®åãã€ã³ãã«ã€ããŠã深床ãããã¡ãŒããã®èªã¿åãã«å ããŠãæ³ç·ã®ãã¯ã¹ãã£ããã®è¿œå èªã¿åãã衚瀺ãããŸãã ãŸããSSAOã®ããã«ããã¯ã¯ããŸããŸãªãããã¡ãŒããã®å€§éã®èªã¿åãã§ããããããã®èªã¿åãã¯ã©ã³ãã ãªé åºã§è¡ãããŸããããã¯ãã£ãã·ã¥ã匷å¶çµäºããŸãã ç¹ã«ã¢ãã€ã«ããã€ã¹ã§ã
å¥ã®ä¿®æ£ã¯ãçäœãè¿åãšããŠäœ¿çšããã®ã§ã¯ãªãããµã³ãã«ããã®ç¹ãäœçœ®ããåçã䜿çšããããšãæå³ããŸãã ãã®å Žåãæ€èšäžã®ãã€ã³ãã®æ³ç·ã«æ²¿ã£ãŠãã®çãæ¹åä»ããå¿ èŠããããŸãã
ãã®å Žåããµã³ãã«ããåãã€ã³ãã®æ³ç·ãèªã¿åãå¿ èŠã¯ãããŸããããã¹ãŠã®ãã€ã³ããæ¢ã«ããã¯ããªã®ã§ãåé¡ã®ãã€ã³ãã®æ³ç·ãååŸããã ãã§ååã§ãã
ç§ã®æèŠã§ã¯ããããæè¯ã®ä¿®æ£ã§ãããé©çšå¯èœã§ãã
å®è£
ãŸããæ³ç·ã深床ãè²ãä¿åããããã®ãããã¡ãå¿ èŠã§ãã OpenGL ES 3.0ã®ãã¯ãããžãŒ-è€æ°ã®ã¬ã³ããŒã¿ãŒã²ããã䜿çšããè€æ°ã®ãããã¡ãŒãäœæããŠãåæã«æžã蟌ã¿ãŸãã ã³ãŒãã§ã¯ã次ã®ããã«ãªããŸãïŒãã¯ã¹ãã£äœæã¯å¥ã®é¢æ°ãšããŠäœæããŸããïŒïŒ
// , ( ), GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; GLuint fbo; GLuint colorBuff; GLuint normBuff; GLuint depthBuff; // void createTexture(GLuint &id, int inFormat, int w, int h, int format, int type, int filter, int wrap, void* pix=NULL) { glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, 0, inFormat, w, h, 0, format, type, pix); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); } ... glGenFramebuffers(1, &fbo); // glBindFramebuffer(GL_FRAMEBUFFER, fbo); // width height - createTexture(colorBuff, GL_RGB8, width, height, GL_RGB, GL_UNSIGNED_BYTE, GL_NEAREST, GL_MIRRORED_REPEAT); createTexture(normBuff, GL_RGB8, width, height, GL_RGB, GL_UNSIGNED_BYTE, GL_NEAREST, GL_MIRRORED_REPEAT); createTexture(depthBuff, GL_DEPTH_COMPONENT24, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, GL_NEAREST, GL_MIRRORED_REPEAT); // , glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuff, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, normBuff, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthBuff, 0); int err = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (err != GL_FRAMEBUFFER_COMPLETE) LOGE("Main framebuffer error: %i", err); glDrawBuffers(2, buffers);
ããã«åæ§ã®æ¹æ³ã§ããã1ã€ã®ãã¯ã¹ãã£ã䜿çšããŠãSSAOã®äžã«ãããã¡ãäœæããå¿ èŠããããŸãã
SSAOã®äžã®ãããã¡ãŒ
glGenFramebuffers(1, &ssaoFbo1); glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo1); // , , GL_R8 createTexture(ssaoBuff1, GL_R8, width/ssaoScaleW, height/ssaoScaleH, GL_RED, GL_UNSIGNED_BYTE, GL_LINEAR, GL_MIRRORED_REPEAT); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoBuff1, 0); // glDrawBuffers ,
ãã®ãããã¡ã¯å°ãããããããŸããããä»ã®ãšããã¯ç»é¢è§£å床ãšåãã«ããŸãããïŒç§ã®å Žåã¯1920x1080ïŒã
z-bufferã«ã€ããŠãèšãå¿ èŠããããŸãã SSAOã§äœ¿çšããã«ã¯ãæåã«ç·åœ¢ã«ããå¿ èŠããããŸããããããªããšãäžéããã³ããã¯ã°ã©ãŠã³ãã§ç²ŸåºŠãå€§å¹ ã«å€±ãããŸãã éåžžããã®ããã«ã深床å€ã¯ãéåžžã®æ³ç·ãšäžç·ã«ãå¥ã®ãããã¡ã«æžã蟌ãŸããŸãã ãã ããè¿œå ã®ãããã¡ãŒã¯ããã©ãŒãã³ã¹ã®ç¹ã§ããŸãæ©èœããªããããå€ãç·åœ¢åããŠå¥ã®ãããã¡ãŒã«æžã蟌ãã®ã§ã¯ãªããçŸåšã®æšæºæ·±åºŠãããã¡ãŒïŒgl_FragDepthïŒã«çŽæ¥æžã蟌ã¿ãŸãã ããã«ãããåæ¯ã«ã¢ãŒãã£ãã¡ã¯ãïŒéåžžã«è¿ããã»ãŒæ£é¢ã®ã¯ãªããã³ã°ãã¬ãŒã³ã®è¿ãïŒãçºçããå¯èœæ§ããããŸãããåºæ¬çã«ãã®ãããªãããã¡ãŒã¯éåžžã«æ£åžžã«åäœããŸãã
ã·ãŒã³ã¯éåžžã©ããã¬ã³ããªã³ã°ãããŸãããå¯äžã®éãã¯è²ã®ã»ãã«æ³ç·ãèšé²ãã深床ãããã¡ããããã«å€æŽããããšã§ãã ã·ãŒã³ã¬ã³ããªã³ã°çšã®é ç¹ã·ã§ãŒããŒïŒ
#version 300 es uniform mat4 matrixProj; uniform mat4 matrixView; uniform vec3 lightPos; layout(location = 0) in vec3 vPos; // layout(location = 1) in vec3 nPos; // layout(location = 2) in vec3 tPos; // layout(location = 3) in vec2 tCoord; // out vec3 light; out vec3 gNorm; out float zPos; out vec2 texCoord; void main() { vec4 p = matrixProj*matrixView*vec4(vPos, 1.0); gl_Position = p; texCoord = tCoord; // , vec3 bitangent = cross(tPos, nPos); mat3 tbn = mat3(tPos, bitangent, nPos); light = normalize(lightPos-vPos)*tbn; zPos = pz; // z- - vec4 n = (matrixView*vec4(nPos, 0.0)); // gNorm = normalize(n.xyz); }
ãã©ã°ã¡ã³ãã·ã§ãŒããŒïŒ
#version 300 es precision highp float; // 24- , , 24 , uniform sampler2D texDiff; // uniform sampler2D texNorm; // layout(location = 0) out vec3 colorBuff; // layout(location = 1) out vec3 normBuff; // in vec3 light; in vec3 gNorm; in float zPos; in vec2 texCoord; const vec3 ambientColor = vec3(0.3); const float zFar = 40.0; // void main() { vec3 n = normalize(texture(texNorm, texCoord).xyz*2.0-1.0); vec3 l = normalize(light); vec3 c = texture(texDiff, texCoord).rgb; float a = clamp(dot(n, l), 0.0, 1.0); colorBuff = c*(a+ambientColor); // normBuff = normalize(gNorm)*0.5+0.5; // gl_FragDepth = zPos/zFar; // }
ãŸããåçå ã®ã©ã³ãã ãã€ã³ãã®é åïŒå®éã®éžæïŒãå¿ èŠã§ãã ã·ã§ãŒãã£ã³ã°ãçŸããããããã«ïŒããã°ãããç©ççã«ïŒ-åçå ã®ãã€ã³ãã®å¯åºŠã¯ãäžå€®ã§ã¯é«ããå¢çã§ã¯äœãããå¿ èŠããããŸãã ã€ãŸããæ£èŠååžã®æ³åãæã€ããšã§ãã
for (int i=0; i<samples; i++) { rndTable[i] = vec3(random(-1, 1), random(-1, 1), random(-1, -0)); // ( ) rndTable[i].normalize(); // rndTable[i] *= (i+1.0f)/samples; // ( ) }
ãã¡ããããµã³ãã«å ã®ãã€ã³ãã®æ°ã¯ããã»ã©å€ããããŸããã ãããŸã§ã§10ã«çããããŸãã
ãã ãããã®ãããªæ¬äŒŒä¹±æ°å€ã®ãµã³ãã«ã§ã¯ååã§ã¯ãããŸããããããã®å€ã¯åããã©ã°ã¡ã³ãå ã§ã®ã¿ã©ã³ãã ã§ããã次ã®ãã©ã°ã¡ã³ãã¯ããããªãã€ã¢ã¹ã¯ãããŸããåããã€ã³ããåããŸãã ãã®æ¬ ç¹ã解æ¶ããããã«ã圌ãã¯éåžžãç䌌ã©ã³ãã å€ãæã€å°ããªãã¯ã¹ãã£ãŒïŒçŽ4x4ãã¯ã»ã«ïŒã䜿çšããŸãã ããã§ãåãã©ã°ã¡ã³ãã§ããã®ãã¯ã¹ãã£ããå€ãååŸããããã«åºã¥ããŠåçãã€ã³ãã®å転è¡åãã³ã³ãã€ã«ã§ããŸãã ãããŠåæã«ãããããæ³ç·ã«å¯ŸããŠå転ãããŸããããã¯ãã§ã«æ³ç·ã®ãã¯ã¹ãã£ããèªã¿åãããŸãã ãããã£ãŠãçµæã®ãããªãã¯ã¹ã§ãã€ã³ããä¹ç®ããããããåæã«æ³ç·ã«å¯ŸããŠæ¹åä»ããç䌌ã©ã³ãã ãã¯ãã«ã«ãã£ãŠå転ãããŸãã ãã®ãããªè¡åã®æ§ç¯ã¯ãã°ã©ã ã·ã¥ãããéçšãšåŒã°ããŸã ã
ã·ã§ãŒããŒã§ã¯ã次ã®ããã«ãªããŸãã
vec3 normal = texture(normBuff, texCoord).xyz*2.0-1.0; vec3 rvec = texture(randMap, texCoord*scr).xyz*2.0-1.0; vec3 tangent = normalize(rvec-normal*dot(rvec, normal)); vec3 bitangent = cross(tangent, normal); mat3 rotate = mat3(tangent, bitangent, normal);
ãŸãã空éå ã®ãã€ã³ãã®åº§æšã埩å ããå¿ èŠããããŸãã ãããè¡ãã«ã¯ãç»å空éå ã®ãã€ã³ãã®åº§æšã«éèŠå€æã®éè¡åãæãããããŸãã¯ããç°¡åã«è¡ãããšãã§ããŸãïŒçŸåšã®ãã¯ã»ã«ãä»ããŠã«ã¡ã©ããåãããããã¯ãã«ïŒå ç·ïŒã«ãã®ãã¯ã»ã«ã®z座æšå€ãæããŸãã Z座æšã¯æ·±åºŠãããã¡ãŒã«æ ŒçŽãããã«ã¡ã©ããã®ããŒã ã¯èŠéè§ã«åºã¥ããŠæ§ç¯ãããŸããèŠéè§ã¯ãéèŠè¡åïŒæ圱è¡åïŒã®æ§ç¯ã«äœ¿çšãããŸã-ããã¯fovã§ãã ãŠããã©ãŒã ãä¿åããããšã«ãããã®å€ãå®æ°ãšããŠé ç¹ã·ã§ãŒããŒã«å ¥åããŸããã
#version 300 es const fov = 0.57735; layout(location = 0) in vec2 vPos; layout(location = 1) in vec2 tCoord; uniform float aspect; out vec2 texCoord; out vec3 viewRay; void main() { gl_Position = vec4(vPos, 0.0, 1.0); texCoord = tCoord; viewRay = vec3(-vPos.x*aspect*fov, -vPos.y*fov, 1.0); // , }
ãã¯ã»ã«ã·ã§ãŒããŒã§ã¯ãã¬ã€ã«åºã¥ããã€ã³ãã®äœçœ®ã次ã®ããã«åŸ©å ãããŸãã
float depth = texture(depthBuff, texCoord).x; // , depth *= zFar; // z- vec3 pos = viewRay*depth; //
å転è¡åãšãã€ã³ãã®äœçœ®ãåãåã£ããããµã³ãã«ããã·ã§ãŒãã£ã³ã°å€ãååŸããããšãã§ããŸãã
float acc = 0.0; for (int i=0; i<samples; i++) { vec3 samplePos = rotate*rndTable[i]; // samplePos = samplePos*radius+pos; // // , vec4 shift = proj*vec4(samplePos, 1.0); shift.xy /= shift.w; shift.xy = shift.xy*0.5+0.5; // z- float sampleDepth = texture(depthBuff, shift.xy).x*zFar; // - . , , smoothstep, - float distanceCheck = smoothstep(0.0, 1.0, radius/abs(pos.z-sampleDepth)); // - . - , step acc += step(sampleDepth, samplePos.z)*distanceCheck; }
çµæã¯ãŒãããå¯èœæ§ããããããã¬ãŠã¹ãŒããçšã«å¥ã®ãããã¡ãäœæããŸãã ãµã³ãã«ã®æ°ãå°ãªãããæçµçã«ã¯ãã¯ã¹ãã£ã®æäžéšã«ããåãªã圱ã«ãããããã¢ãŒãã£ãã¡ã¯ãã¯ããŸãç®ç«ããªãã¯ãã§ãã ããã§ããã£ãã·ã¥ã¯ãã§ã«ç§ãã¡ã®åŽã«ãããŸããSSAOã§ã®ã©ã³ãã ãªèªã¿åãã®å Žåããã£ãã·ã¥ãã¹ãåžžã«çºçããå Žåããã¯ã¹ãã£ããã®ãµã³ãã«ã¯é©åã«ãã£ãã·ã¥ãããã¯ãã§ãã
åçŽãŒããã·ã§ãŒããŒ
#version 300 es precision mediump float; uniform sampler2D ssaoBuff; layout(location = 0) out float outColor; in vec2 texCoord; const float blurSize = 2.5/1920.0; void main() { float sum = 0.0; sum += texture(ssaoBuff, vec2(texCoord.x, texCoord.y - 2.0*blurSize)).r * 0.0625; sum += texture(ssaoBuff, vec2(texCoord.x, texCoord.y - blurSize)).r * 0.25; sum += texture(ssaoBuff, vec2(texCoord.x, texCoord.y )).r * 0.375; sum += texture(ssaoBuff, vec2(texCoord.x, texCoord.y + blurSize)).r * 0.25; sum += texture(ssaoBuff, vec2(texCoord.x, texCoord.y + 2.0*blurSize)).r * 0.0625; outColor = sum; }
æ°Žå¹³ãŒããã·ã§ãŒããŒ
#version 300 es precision mediump float; uniform sampler2D ssaoBuff; layout(location = 0) out float outColor; in vec2 texCoord; const float blurSize = 2.5/1080.0; void main() { float sum = 0.0; sum += texture(ssaoBuff, vec2(texCoord.x - 2.0*blurSize, texCoord.y)).r * 0.0625; sum += texture(ssaoBuff, vec2(texCoord.x - blurSize, texCoord.y)).r * 0.25; sum += texture(ssaoBuff, vec2(texCoord.x, texCoord.y)).r * 0.375; sum += texture(ssaoBuff, vec2(texCoord.x + blurSize, texCoord.y)).r * 0.25; sum += texture(ssaoBuff, vec2(texCoord.x + 2.0*blurSize, texCoord.y)).r * 0.0625; outColor = sum; }
çµæãèŠãããšãã§ããŸãïŒ
å·Šäžé ã®æ°åã¯ã1ç§ãããã®ãã¬ãŒã æ°ã瀺ããŠããŸãã ããŸããªãã ããã«ãè¡šé¢ã®çžæš¡æ§ã«ã泚æããŠãã ããã åé¡ã¯ã深床ãããã¡ãè¡šãéã«ãè¡šé¢ãå®å šã«æ»ããã§ã¯ãªãããšã§ãã ããã§ã¯ãã¹ãŠãå®å šã«åé¢ãããŠãããè¡šé¢ã¯æ¢¯åã®ããã«èŠããããããµã³ãã«ã®ãã€ã³ãã®äžéšã¯ãããã®ãã¹ããããå ã«ããããã«èŠããŸãã
ãããã£ãŠããµã³ãã«ãäœæãããšãã¯ããŒãã®Z座æšããã§ã¯ãªããããšãã°0.1ãªã©ã®å°ããªå€ããéå§ããããšããå§ãããŸãã ãã®å Žåãåçã¯äžããåãåãããããã«ãªããŸãã
ãããŠããµã³ãã«ããã®ãã€ã³ãã¯ãã¹ããããã«åé¡ãããŸããã åçã¯è¯ããªããŸãïŒ
ããããFPSã¯ãŸã é«ããããŸããã
æé©å
æçœã§æãäžè¬çãªè§£æ±ºçã¯ããµã³ãã«å ã®ãã€ã³ãæ°ãæžãããSSAOãããã¡ãŒã®ãµã€ãºãå°ããããããšã§ãã ãããã¡ãŒãµã€ãºãååã«ãããšãFPSãçŽ150ïŒ å¢å ããŸãã ãã ãããããã¡ãŒã®ãµã€ãºãå€æŽãããšããªããžã§ã¯ãã®å¢çã§ã¢ãŒãã£ãã¡ã¯ããçºçãããããå€§å¹ ã«åæžããããšã¯ãããŸããã
ã¢ã«ãŽãªãºã ã®çµæãèŠãŠãã ãããç»åã®ã»ãšãã©ãçœã§ãã·ã§ãŒãã£ã³ã°ããŸã£ãããªãããšãããããŸãã ãã ããã¢ã«ãŽãªãºã ã¯ãã¯ã»ã«ããšã«æºããããŸãã äžèŠãªæçãã«ããã§ãããããªãã¹ã¯ãäœæãããšããã§ãããã
ãã®ãã¹ã¯ã¯ãããå°ãããããã¡ãŒã®SSAOã倧ãŸãã«èšç®ããããšã§ååŸã§ããŸãã ã€ãŸããå¥ã®ãããã¡ãŒãäœæããŸããããšãã°ãSSAOã®ãããã¡ãŒã®16åã®å¹ ãšé«ãã§ãã ãµã³ãã«ã®æ°ã5ã«æžãããŠãã©ã³ãã ã§ã¯ãªããåçã®äžå¿ããåãè·é¢ã«é 眮ããŸãã
for (int i=0; i<samplesLow; i++) { float angle = DEG2RAD*360.0f*i/samplesLow; rndTableLow[i] = vec3(sinf(angle), cosf(angle), -0.1); }
ã·ã£ããŠãã¹ã ãŒãºã«ç§»è¡ããªããã¹ã¯ãå¿ èŠãªã®ã§ãçµæãéåžžã«å¯Ÿç §çã«ããŸã-ãã¯ã»ã«ã¯é»ãŸãã¯çœã§ãïŒ
outColor = step(254.0/255.0, 1.0-(acc/float(samples)));
ãã©ãŒã·ã§ãŒããŒãç°¡çŽ åããã2ã€ã®ãã©ã°ã¡ã³ãã·ã§ãŒããŒã§ã¯ãªããæ£æ¹åœ¢ã®è§ã«4ã€ã®ãµã³ãã«ãããã·ã§ãŒããŒã«ãªããŸãã
#version 300 es precision mediump float; uniform sampler2D ssaoLowBuff; uniform float aspect; layout(location = 0) out float outColor; in vec2 texCoord; const float blurSize = 0.01; void main() { float sum = 0.0; sum += texture(ssaoLowBuff, vec2(texCoord.x - blurSize, texCoord.y - blurSize*aspect)).r; sum += texture(ssaoLowBuff, vec2(texCoord.x - blurSize, texCoord.y + blurSize*aspect)).r; sum += texture(ssaoLowBuff, vec2(texCoord.x, texCoord.y )).r; sum += texture(ssaoLowBuff, vec2(texCoord.x + blurSize, texCoord.y - blurSize*aspect)).r; sum += texture(ssaoLowBuff, vec2(texCoord.x + blurSize, texCoord.y + blurSize*aspect)).r; outColor = step(254.0/255.0, sum/5.0); }
ãã®ãã¹ã¯ãååŸããŸãã
ããã䜿çšããŠãSSAOãèšç®ããŸãïŒãããã¡ãŒãµã€ãºã1.5åã«æžããããµã³ãã«æ°ã8ã«æžãããŸããïŒã
ãã®çµæãFPSã¯å質ãèŠèŠçã«æãªãããšãªã3åã«ãªããŸããã ãã®æ¹æ³ã«ã¯æ¬ ç¹ããããŸã-ã·ãŒã³å ã«å€ãã®è§åºŠãŸãã¯ä»ã®ã·ã§ãŒãã£ã³ã°å Žæãããå Žåããã¹ã¯ã¯ã»ãŒå®å šã«é»ããªããŸããããã¯ããã®ãããªæé©åã®æå¹æ§ãå€§å¹ ã«äœäžããããšãæå³ããŸãã
å®å šãªSSAOãã©ã°ã¡ã³ãã·ã§ãŒããŒã³ãŒãïŒ
#version 300 es precision highp float; // 24- const int samples = 8; // const float radius = 0.5; // const float power = 2.0; // const float zFar = 40.0; // uniform sampler2D normBuff; // uniform sampler2D depthBuff; // uniform sampler2D randMap; // uniform sampler2D ssaoMask; // SSAO - uniform vec2 scr; // randMap, SSAO uniform vec3 rndTable[samples]; // uniform mat4 proj; // layout(location = 0) out float outColor; // in vec2 texCoord; // in vec3 viewRay; // void main() { // , - float k = texture(ssaoMask, texCoord).x; if (k==1.0) discard; // - float depth = texture(depthBuff, texCoord).x; if (depth==1.0) discard; depth *= zFar; vec3 pos = viewRay*depth; vec3 normal = texture(normBuff, texCoord).xyz*2.0-1.0; vec3 rvec = texture(randMap, texCoord*scr).xyz*2.0-1.0; vec3 tangent = normalize(rvec-normal*dot(rvec, normal)); vec3 bitangent = cross(tangent, normal); mat3 rotate = mat3(tangent, bitangent, normal); float acc = 0.0; for (int i=0; i<samples; i++) { vec3 samplePos = rotate*rndTable[i]; // samplePos = samplePos*radius+pos; // // , vec4 shift = proj*vec4(samplePos, 1.0); shift.xy /= shift.w; shift.xy = shift.xy*0.5+0.5; // z- float sampleDepth = texture(depthBuff, shift.xy).x*zFar; // - . , , smoothstep, - float distanceCheck = smoothstep(0.0, 1.0, radius/abs(pos.z-sampleDepth)); // - . - , step acc += step(sampleDepth, samplePos.z)*distanceCheck; } outColor = pow(1.0-(acc/float(samples)), power); // }
ãã¯ã¹ãã£ä»ããªããžã§ã¯ããšã®ã¹ã¯ãªãŒã³ã·ã§ããã®æ¯èŒ
ãã¢ä»ãã®ãããªïŒSSAOãµã€ãºã¯ç»é¢ã®2åïŒïŒ
ïŒSSAOãµã€ãºã¯ç»é¢ã®1.5åã§ãïŒïŒ
埮åŠ
ãã®éçšã§ãç§ã¯ããã€ãã®èå³æ·±ãããšã«åºããããŸããããå°ã話é¡ã«åããªãã®ã§ããã¿ãã¬ã®äžã«é ããŸããã
ãã€ããªãŒããŒ
ãã¯ã¹ãã£ãšã¢ãã«çšã®ã³ã³ããŒã¿ãŒãäœæãããšããARMããã»ããµãŒã§ã¯ãã€ãé ã x86 ãšç°ãªããšããäºå®ã«çŽé¢ããŸããã ãããã£ãŠããã€ããªãã¡ã€ã«ã«æžã蟌ãå Žåã1ãã€ããè¶
ããé·ãã®ãã¹ãŠã®ããŒã¿ã¿ã€ãã§ã¯ãåŸã§ããã€ã¹ã§ãããè¡ããªãããã«ããã€ãé ãéã«ããããšããå§ãããŸãã
ãã®ããã«ãç§ã¯é¢æ°ã䜿çšããŸããïŒ
ããšãã°ããã€ãé ãå€æŽãããããã€ãã®å€ã®ãã¡ã€ã«ãžã®åºåïŒQtã䜿çšïŒïŒ
ãã®ããã«ãç§ã¯é¢æ°ã䜿çšããŸããïŒ
- uint32_t htonlïŒuint32_t hostlongïŒ;
- uint16_t htonsïŒuint16_t hostshortïŒ;
ããšãã°ããã€ãé ãå€æŽãããããã€ãã®å€ã®ãã¡ã€ã«ãžã®åºåïŒQtã䜿çšïŒïŒ
#include <netinet/in.h> ... QDataStream out(&file); out << htons(s); // unsigned short out << htonl(*((unsigned int*)&f)); // float
åæ°ã»ãã¬ãŒã¿ãŒ
å°åã®èšå®ãšãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«å¿ããŠãsscanfé¢æ°ã¯æµ®åå°æ°ç¹æ°ã®è§£éãç°ãªãå ŽåããããŸãã ãããã䜿çšããŠå°æ°éšãšæŽæ°éšãåºåãããšãã§ããã©ããã§ã³ã³ãã䜿çšã§ããŸãã
äŸïŒ
readed1ãšreaded2ã®å€ã¯ãã·ã¹ãã ã«ãã£ãŠç°ãªãå ŽåããããŸãã éåžžããããã®èšå®ã¯ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®å°åèšå®ã§èšå®ãããŸãã ããã¯ãããšãã°* .objãã¡ã€ã«ã®ããŒãµãŒãäœæããå Žåã«èæ ®ããå¿ èŠããããŸãã
äŸïŒ
readed1 = sscanf("float: 1,5", "float: %f", &f); readed2 = sscanf("float: 1.5", "float: %f", &f);
readed1ãšreaded2ã®å€ã¯ãã·ã¹ãã ã«ãã£ãŠç°ãªãå ŽåããããŸãã éåžžããããã®èšå®ã¯ãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®å°åèšå®ã§èšå®ãããŸãã ããã¯ãããšãã°* .objãã¡ã€ã«ã®ããŒãµãŒãäœæããå Žåã«èæ ®ããå¿ èŠããããŸãã
ãã°ãªãŒããŒãããŒãã¬ãŒã
logcatã䜿çšããå Žåã¯ãAndroidã®ãã°ãã¯ãªã¢ããããšãå¿ããªãã§ãã ããã å°ãªããšãNote 3 n9000ã§ã¯ã倧éã®æ
å ±ããã°ã«åºåããããšïŒæ¯ç§ãçŸåšã®ãã¬ãŒã ã¬ãŒããããã«æžã蟌ãã ïŒããã¹ãŠãã²ã©ãé
ããªãå§ããŸãã é·ãéããã°ãæ¶å»ãããŸã§ïŒadb logcat -cã³ãã³ãïŒãäœãèµ·ãã£ãŠããã®ãç解ã§ããŸããã§ããã
ç°ãªãGPU
ã·ã§ãŒããŒãäœæããããç°ãªãGPUãæã€è€æ°ã®ããã€ã¹ã§ãã¹ããããšããã§ãããã äžèšã®SSAOã·ã§ãŒããŒã³ãŒãã¯maliã§ã¯æ£åžžã«æ©èœããŸãããadrenoïŒç¹ã«320ããã³330ïŒã§ã¯ãã°ããããŸãã ïŒå°ãªããšães 300ã·ã§ãŒããŒããŒãžã§ã³ã§ã¯ïŒadrenoãæ£ããæ©èœããªãã£ãããšãããããŸããããã以äžæ£ç¢ºã«èšãããšã¯ã§ããŸããããã«ãŠã³ã¿ãŒã¯ã€ã³ã¯ãªã¡ã³ããããŸãããåãå埩ããµã€ã¯ã«ã§æ©èœããããã§ãã ã·ã§ãŒããŒã³ãŒããå°ãå€æŽããã«ãŒããåãé€ãå¿
èŠããããŸããã
ã²ã©ãããã«èŠããŸããããã®ãããªå¥åŠãªæ¯ãèãã®çç±ã誰ããç¥ã£ãŠããå Žåã¯ãã³ã¡ã³ããŸãã¯PMã«æžããŠãã ããã
... float getSample(in int i, in mat3 rotate, in vec3 pos, in vec3 rnd) { vec3 samplePos = rotate*rnd; samplePos = samplePos*radius+pos; vec4 shift = proj*vec4(samplePos, 1.0); shift.xy /= shift.w; shift.xy = shift.xy*0.5+0.5; float sampleDepth = texture(depthBuff, shift.xy).x*zFar; float distanceCheck = smoothstep(0.0, 1.0, radius/abs(pos.z-sampleDepth)); return step(sampleDepth, samplePos.z)*distanceCheck; } void main() { ... float acc = 0.0; acc += getSample(0, rotate, pos, rndTable[0]); acc += getSample(1, rotate, pos, rndTable[1]); acc += getSample(2, rotate, pos, rndTable[2]); acc += getSample(3, rotate, pos, rndTable[3]); acc += getSample(4, rotate, pos, rndTable[4]); acc += getSample(5, rotate, pos, rndTable[5]); acc += getSample(6, rotate, pos, rndTable[6]); acc += getSample(7, rotate, pos, rndTable[7]); outColor = pow(1.0-(acc/float(samples)), power); }
ã²ã©ãããã«èŠããŸããããã®ãããªå¥åŠãªæ¯ãèãã®çç±ã誰ããç¥ã£ãŠããå Žåã¯ãã³ã¡ã³ããŸãã¯PMã«æžããŠãã ããã
NDKãããžã§ã¯ãã®IDEãšããŠã®QtCreator
å人çã«ã¯ãç¹ã«NDKã§æžããŠããã®ã§ãEclipseãAndroid StudioãããQtCreatorã奜ãã§ãã ãããã£ãŠãéåžžEclipseã§ãããžã§ã¯ããäœæããQtCreatorã«è»¢éããŸãã 誰ããèå³ãæã£ãŠããå Žåããããžã§ã¯ã転éããã»ã¹ã¯æ¬¡ã®ãšããã§ãã
Qt Creatorãéãã[ãã¡ã€ã«]-> [æ°ãããã¡ã€ã«ãŸãã¯ãããžã§ã¯ã...]-> [ãããžã§ã¯ãã®ã€ã³ããŒã]-> [æ¢åã®ãããžã§ã¯ãã®ã€ã³ããŒã]
次ã«ããããžã§ã¯ãã®ååãå ¥åããäœææžã¿ã®ãããžã§ã¯ããžã®ãã¹ã瀺ããŸãã ã³ãã³ãã©ã€ã³ãã Eclipseã§ãããžã§ã¯ããäœæãã NDKã®ãµããŒããè¿œå ããå ¬åŒããã¥ã¡ã³ãã§ãAndroidçšã®ãããžã§ã¯ããäœæããæ¹æ³ã«ã€ããŠèªãããšãã§ããŸãã
ãã®åŸããããžã§ã¯ãããªãŒã«è¡šç€ºãããã¡ã€ã«ãéžæããå®éã«ãããžã§ã¯ããäœæããŸãã Qt Creatorã¯ãããã®ãã¡ã€ã«ãèªåçã«äœæããŸãã
MyProject.config-ããã§ã¯ãã³ã³ãã€ã«çšã®å·®åãæå®ã§ããŸããããšãã°ãNEONããµããŒãããããã«ãïŒdefine __ARM_NEON__ãšããè¡ãè¿œå ããŸãã
MyProject.files-ãããžã§ã¯ãããªãŒã«é¢é£ãããã¹ãŠã®ãã¡ã€ã«
MyProject.includes-ããã§ã¯ããããžã§ã¯ãã§äœ¿çšãããã©ã€ãã©ãªã€ã³ã¯ã«ãŒããžã®ãã¹ãæå®ããå¿ èŠããããŸãã次ã«äŸã瀺ããŸãã
ãããžã§ã¯ãã®ã³ã³ãã€ã«ãšãããã€ã¡ã³ããå¶åŸ¡ããå°ããªã¹ã¯ãªãããäœæããããšãã§ããŸãã
[ãããžã§ã¯ã]ã¿ãã§ããã®ã¹ã¯ãªããã¯é©åãªã¢ã¯ã·ã§ã³ã«å²ãåœãŠãããŸãã
以äžã§ãæšæºã®Qt CreatorããŒã«ã䜿çšããŠãããžã§ã¯ããã¯ãªãŒã³ã¢ãããããã«ãããŠããã€ã¹ã«ã¢ããããŒãã§ããŸãã æ§æ匷調衚瀺ããªãŒãã³ã³ããªãŒããããã³GLSLããã³C ++ã®ãã®ä»ã®æ©èœã
Qt Creatorãéãã[ãã¡ã€ã«]-> [æ°ãããã¡ã€ã«ãŸãã¯ãããžã§ã¯ã...]-> [ãããžã§ã¯ãã®ã€ã³ããŒã]-> [æ¢åã®ãããžã§ã¯ãã®ã€ã³ããŒã]
ã¹ã¯ãªãŒã³ã·ã§ãã
次ã«ããããžã§ã¯ãã®ååãå ¥åããäœææžã¿ã®ãããžã§ã¯ããžã®ãã¹ã瀺ããŸãã ã³ãã³ãã©ã€ã³ãã Eclipseã§ãããžã§ã¯ããäœæãã NDKã®ãµããŒããè¿œå ããå ¬åŒããã¥ã¡ã³ãã§ãAndroidçšã®ãããžã§ã¯ããäœæããæ¹æ³ã«ã€ããŠèªãããšãã§ããŸãã
ã¹ã¯ãªãŒã³ã·ã§ãã
ãã®åŸããããžã§ã¯ãããªãŒã«è¡šç€ºãããã¡ã€ã«ãéžæããå®éã«ãããžã§ã¯ããäœæããŸãã Qt Creatorã¯ãããã®ãã¡ã€ã«ãèªåçã«äœæããŸãã
MyProject.config-ããã§ã¯ãã³ã³ãã€ã«çšã®å·®åãæå®ã§ããŸããããšãã°ãNEONããµããŒãããããã«ãïŒdefine __ARM_NEON__ãšããè¡ãè¿œå ããŸãã
MyProject.files-ãããžã§ã¯ãããªãŒã«é¢é£ãããã¹ãŠã®ãã¡ã€ã«
MyProject.includes-ããã§ã¯ããããžã§ã¯ãã§äœ¿çšãããã©ã€ãã©ãªã€ã³ã¯ã«ãŒããžã®ãã¹ãæå®ããå¿ èŠããããŸãã次ã«äŸã瀺ããŸãã
/home/torvald/android-ndk-r9/sources/android/cpufeatures /home/torvald/android-ndk-r9/sources/cxx-stl/stlport/stlport /home/torvald/android-ndk-r9/sources/cxx-stl/gabi++/include /home/torvald/android-ndk-r9/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.6/include /home/torvald/android-ndk-r9/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.6/include-fixed /home/torvald/android-ndk-r9/platforms/android-18/arch-arm/usr/include /home/torvald/android-ndk-r9/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.6/include/ /home/torvald/android-ndk-r9/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.6/include/-fixed
ãããžã§ã¯ãã®ã³ã³ãã€ã«ãšãããã€ã¡ã³ããå¶åŸ¡ããå°ããªã¹ã¯ãªãããäœæããããšãã§ããŸãã
#!/bin/sh case "$1" in clean) ndk-build clean && ant clean ;; deploy) adb install -r bin/MainActivity-debug.apk > /dev/null 2>&1 & # && adb logcat -c && adb logcat -s "SSAOTest" # Qt Creator - ;; run) #adb shell am start -n com.torvald.ssaotest/com.torvald.ssaotest.MainActivity > /dev/null 2>&1 & ;; *) #kill $(ps aux | grep "adb logcat" | grep -v "grep" | awk '{print $2}') > /dev/null 2>&1 & ndk-build NDK_DEBUG=0 -j9 && ant debug ;; esac
[ãããžã§ã¯ã]ã¿ãã§ããã®ã¹ã¯ãªããã¯é©åãªã¢ã¯ã·ã§ã³ã«å²ãåœãŠãããŸãã
ã¹ã¯ãªãŒã³ã·ã§ãã
以äžã§ãæšæºã®Qt CreatorããŒã«ã䜿çšããŠãããžã§ã¯ããã¯ãªãŒã³ã¢ãããããã«ãããŠããã€ã¹ã«ã¢ããããŒãã§ããŸãã æ§æ匷調衚瀺ããªãŒãã³ã³ããªãŒããããã³GLSLããã³C ++ã®ãã®ä»ã®æ©èœã
ãã¢
Androidã«OpenGL ES 3.0ãæèŒããããã€ã¹ãããå Žåã¯ãã¢ããªã±ãŒã·ã§ã³ãå®è¡ããŠã¿ãŠãã ããã GUIã§æéãç¡é§ã«ããªãããšã«æ±ºããã®ã§ãç¹å¥ãªèšå®ã¯ãªããå¶åŸ¡ã¯ç»é¢äžã®æ¡ä»¶ä»ãé åã«ãã£ãŠå®è¡ãããŸãã
- ã¹ã©ã€ãã¢ãã/ããŠã³-ãºãŒã ã€ã³/ãºãŒã ã¢ãŠã
- åºåãããã¡ãŒãå€æŽããŸãïŒssaoãlow ssaoãssao + colorãcolorã®ã¿ïŒ
- ãªã³/ãªããŒãã
- ã·ãŒã³ã®å€å
ç¡æã®ç»é¢é å-ã«ã¡ã©ã®å転
èšå®ãããã©ã¡ãŒã¿ãŒã¯æ¬¡ã®ãšããã§ãã
- ãµã³ãã«æ°= 8ã
- ssaoããã³blurãããã¡ãŒã®ãµã€ãºã¯ãç»é¢ã®è§£å床ã®1.5åã§ãã
- åæžãããssaoã®ãµã³ãã«æ°= 5ã
- çž®å°ssaoãããã¡ãŒã®ãµã€ãºã¯ãç»é¢è§£å床ã®16åå°ãããªããŸãã
ãœãŒã¹ã³ãŒã -ãã¹ãå€æŽããããšãå¿ããªãã§ãã ãã
apk -Note 3 n9000ïŒmali T62ïŒãNote 3 n9005ïŒadreno 330ïŒãNexus 5ïŒadreno 330ïŒãHTC OneïŒadreno 320ïŒã§ãã¹ãæžã¿
åç §è³æ
ãã®ãããžã§ã¯ãã§åœ¹ç«ã€ããŸããŸãªãªãã¡ã¬ã³ã¹ïŒsteps3dã®
Screen-Space Ambient OcclusionãSSAOãäœæããæ¹æ³ã¯ããã€ã
ã®OpenGL ES 3.0 APIãªãã¡ã¬ã³ã¹ã«ãŒã -ãžã®ç°¡åãªã¬ã€ããOpenGL ESã®3.0 SPECA
åçç¶ã®ã¹ã¯ãªãŒã³ç©ºéã¢ã³ããšã³ããªã¯ã«ãŒãžã§ã³ -åçç¶ã®SSAOå®è£ ãã1ã€ã®æ¹æ³
ã¹ããŒã³ããªããž3Dã¢ãã«ã -ç§ã¯ããã¢ã§äœ¿çšãããããšãæ©ã®ã¢ãã«
ãžã§ã³ã»ãã£ãããã³ã»ã°ã©ãã£ãã¯ã¹ïŒSSAOãã¥ãŒããªã¢ã« -ç§ã®æèŠã§ã¯ãåçSSAOã®æé©ãªå®è£
SSAO |
ããã¹ãããã¡ãŒã®ã²ãŒã ã¬ã³ããªã³ã°æ»æ -
ã²ãŒã éçºè åãã® zãããã¡ãŒç·åœ¢ä»£æ°ã®ããŸããŸãªãã¥ãŒ
SSAOã¢ãŒãã£ãã¡ã¯ããç¥ã -SSAOã®ã¢ãŒãã£ãã¡ã¯ã/ãžã£ã /äžæ£ç¢ºæ§ããã³ãããã®é€å»æ¹æ³