418341 สภาพแวดลอมการทำางานคอมพวเตอรกราฟกสการบรรยายครงท 14
ประมข ขนเงน[email protected]
Environment Map
• การใช texture เกบแสงทพงจาก สงแวดลอม“ ” เขาหาวตถในทศทางตางๆ
• สมมตวาวตถเปน จด“ ”
• Texture ใชในการตอบคำาถามวา แสงทพงเขาหา“วตถในทศทาง (x,y,z) มสอะไร”
Environment Map
Cube Map
• เปนวธเกบ environment map แบบหนง• ใชภาพหกภาพมาประกอบกนเปนลกบาศก
Cube Map ใน OpenGL
• เราสามารถใช cube map ใน OpenGL ไดตงแต OpenGL เวอรชน 1.3
• ตองใช extension ชอ EXT_texture_cube_map
• หมายความวาเวลาเขยนโปรแกรมใน Windows จะตองใช GLEW
การสราง Cube Map
• มขนตอนคลายกบการสราง texture ธรรมดา
– Enable การใช cube map
– สราง handle ของ cube map ดวย glGenTextures
– ทำาการ bind cube map ทสรางขน
– Download รปทใชทำา cube map ลงส GPU
Enable การใช Cube Map
• ใหสง
glEnable(GL_TEXTURE_CUBE_MAP_EXT);
• และอยาลมสง
glDisable(GL_TEXTURE_CUBE_MAP_EXT);
กอนใชงาน texture แบบอน
การสราง Handle ของ Cube Map
• เชนเดยวกบการสราง texture อนเราตองประกาศตวแปรประเภท GLunit เพอใชเกบชอของ cube map
GLuint cubeMap;
• หลงจากนนใช glGenTextures สราง texture ตามปกต
glGenTextures(1, &cubeMap);
Bind Cube Map ทสรางขน• สง glBindTexture โดยใช target เปน
GL_TEXTURE_CUBE_MAP_EXT
glBindTexture(GL_TEXTURE_CUBE_MAP_EXT, cubeMap)
Download รป• ใชคำาสง glTexImage2D หรอ
gluBuild2DMipmaps เพอ download รปเชนเดม แตเราตอง download รปจำานวนทงหมด 6 รปสำาหรบ 6 ดานของลกบาศก
• เราสามารถระบวาจะ download รปของดานไหนไดดวยการระบ target ของคำาสงทงสองดงในสไลดหนาตอไป
Target สำาหรบ Download รป
Target ดานGL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT ขวาGL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT ซายGL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT บนGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT ลางGL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT หนาGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT หลง
ตวอยางโคด• ผมสรางฟงกชน loadCubeMapSide ไวสำาหรบ
download รปเขาไปยงดานหนงของ cube map โดยกำาหนด– Target ทจะ download รปลงไป– ชอไฟลของรปนน
• loadCubeMapSide ใช DevIL ในการดงขอมลรปออกมาจากไฟล
loadCubeMapSide
void loadCubeMapSide(GLuint target, const char *imageName)
{ILuint image;ilGenImages(1, &image);ilBindImage(image);ilLoadImage((wchar_t *)imageName);ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE)gluBuild2DMipmaps(target, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH),
ilGetInteger(IL_IMAGE_HEIGHT), ilGetInteger(IL_IMAGE_FORMAT),
GL_UNSIGNED_BYTE, ilGetData());
ilDeleteImages(1, &image);}
โคดตวอยาง• ผมเขยนฟงกชน initCubeMap เพอ load รปทง
สำาหรบทง 6 ดาน
• ใน initCubeMap ผมเรยก loadCubeMapSide เปนจำานวนหกครงเพอ download รป
initCubeMap
void initCubeMap(){
glEnable(GL_TEXTURE_CUBE_MAP_EXT);glGenTextures(1, &cubeMap);glBindTexture(GL_TEXTURE_CUBE_MAP_EXT, cubeMap);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
loadCubeMapSide(GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT, "../images/cm_right.jpg");loadCubeMapSide(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT, "../images/cm_left.jpg");loadCubeMapSide(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT, "../images/cm_top.jpg");loadCubeMapSide(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT, "../images/cm_bottom.jpg");loadCubeMapSide(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT, "../images/cm_front.jpg");loadCubeMapSide(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT, "../images/cm_back.jpg");
glDisable(GL_TEXTURE_CUBE_MAP_EXT);}
การนำา Cube Map ไปใชงาน• กระจก = การสะทอนแสง
• แกวใส = การหกเหแสง
หลกการสรางกระจก• สราง “skybox” หรอกลองทมรปทองฟา ลอมรอบ
วตถไว
• สำาหรบ fragment แตละ fragment ใหคำานวณทศทางทแสงทเดนทางจากตาไปยงตำาแหนงของ fragment แลวสะทอนออกไป
• ใหนำาทศทางทไดไปอานขอมลจาก cube map
หลกการสรางกระจก
การสรางกระจกใน OpenGL
• โดยปกตแลวเวลาจะอานขอมลจาก cube map เราจะตองใช texture coordinate 3 ตว เนองจากทศทางเปนทศทางในสามมต
• เราสามารถกำาหนดทศทางไดเองดวยคำาสง glTexCoord3d
• แตละ component ของทศทางจะมคาตงแต -1 ถง 1– ไมใช 0 ถง 1 เหมอนกบ texture coordinate อนๆ
การสรางกระจกใน OpenGL
• Texture coordinate ทจะใชมสามตวคอ s, t, และ r
• เราสามารถสงให OpenGL สราง texture coordinate ใหโดยอตโนมตไดดวยคำาสง glEnable(GL_TEXTURE_GEN_?)– ถาอยากใหสราง s ใหโดยอตโนมตกสง
glEnable(GL_TEXTURE_GEN_S);– ถาอยากใหสราง t ใหโดยอตโนมตกสง
glEnable(GL_TEXTURE_GEN_T);
การสรางกระจกใน OpenGL• นอกจากนยงตองบอกดวยวาจะใหสราง texture
coordinate ใหแบบใด ดวยคำาสง glTexGeni
• ในกรณการสรางกระจกเราตองสง
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
ตวอยางโคดvoid display(){
glEnable(GL_TEXTURE_CUBE_MAP_EXT);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT);
glEnable(GL_TEXTURE_GEN_S);glEnable(GL_TEXTURE_GEN_T);glEnable(GL_TEXTURE_GEN_R);
glutSolidSphere(1.5, 50, 50);
glutSwapBuffers();}
ด demo
การใช Cube Map ใน GLSL• GLSL ใหผใชสามารถประกาศ uniform parameter
ประเภท samplerCube ใน shader ได เชน
uniform samplerCube env_map;
void main(){::
}
การใช Cube Map ใน GLSL
• เวลาอานขอมลจาก cube map ใหใชคำาสง texureCube โดย– Parameter ตวแรกเปนตวแปรประเภท samplerCube– Parameter ตวทสองเปนคาประเภท vec3
• ตวอยาง
color = textureCube(env, vec3(1,0,0));
การใช Cube Map ใน GLSL
• ตวแปรประเภท vec3 ทเราใหไปตองเปนเวกเตอรหนงหนวยทแตละมตมคาอยในชวง [-1,1]
• คาทอานไดจาก cube map คอคาของสทจดทเกดจากการยงรงสจากจด (0,0,0) ไปในทศทางทกำาหนดดวยตวแปร vec3 ทใหฟงกชน textureCube ไปตดกบกลองลกบาศกทมความยาวดานละสองหนวยทมจดศนยกลางอยทจด (0,0,0)
การใช Cube Map ใน GLSL
การทำากระจกใน Cg• ให vertex program คำานวณ– ตำาแหนงใน world space ของแต fragment– Normal ใน world space แตละ fragment
• ให fragment program รบตำาแหนงของตา
• แลวให fragment program คำานวณ– เวกเตอรทศทางการสะทอนแสงซงเกดจากแสงจากตา
เดนทางไปยงตำาแหนงของ fragment– เอาเวกเตอรทศทางทไดไปอานสจาก cube map
Vertex Program สำาหรบทำากระจกvarying vec3 normal;varying vec3 position;
void main(){ gl_Position = ftransform(); position = (gl_ModelViewMatrix * gl_Vertex).xyz; normal = (gl_NormalMatrix * gl_Normal).xyz;}
Vertex Program สำาหรบทำากระจก• ความหมายของตวแปร– position ใชเกบตำาแหนงใน world space– normal ใชเกบเวกเตอรตงฉากใน world space
• เวลาเขยนโปรแกรมภาษา C ตองทำาให modelview matrix เปน model เฉยๆ ซงทำาไดโดยการยก view matrix ไปคณเขากบ projection matrix (เหมอนในคาบทแลว)
Fragment Program สำาหรบทำากระจกuniform vec3 eye_position;uniform samplerCube env;
varying vec3 position;varying vec3 normal;
void main(){ vec3 n = normalize(normal); vec3 eye_to_point = normalize(position - eye_position); vec3 reflected = reflect(eye_to_point, n); gl_FragColor = textureCube(env, reflected);}
Fragment Program สำาหรบทำากระจก• เราทำาการคำานวณเวกเตอรทศทางของแสงทเดนทาง
จากตาไปยงตำาแหนงของ fragment ดวยคำาสง
vec3 eye_to_point = normalize(position - eye_position);
• หลงจากนนคำานวณทศทางทแสงสะทอนออกไปดวยคำาสง
vec3 reflected = reflect(eye_to_point, n);
• ฟงกชน reflect มไวสำาหรบคำานวณเวกเตอรแสงสะทอน
Fragment Program สำาหรบทำากระจก• ขนสดทาย เรานำาเอาทศทางของเวกเตอรแสง
สะทอนไปอานคาจาก cube map
gl_FragColor = textureCube(env, reflected);
ด demo
การทำาวตถผวมนวาว• เราอาจมองวาพนผวของวตถมนวาวมสวนประกอบ
อยสองสวน– สวนหนงมพฤตกรรมเหมอนกระจก– อกสวนมพฤตกรรมตาม lighting model อน เชน
phong lighting model
• สของพนผวประเภทนเกดจากการนำาเอาสทไดจากการสะทอนแสงแบบกระจกมารวมกบสทไดจากพฤตกรรมการสะทอนแสงอนๆ
การทำาวตถผวมนวาว• เราสามารถคำานวณสของทงสองสวน – สมมตวาสวนแรกไดส a และ– สวนทสองไดส b
• เรากำาหนดเลข w (ยอคำาวา weight) โดยท 0 ≤ w ≤ 1 แลวใหสขนสดทายมคาเทากบ
color = w × a + (1-w) × b
ด demo
การหกเหแสง
การจำาลองการหกเหของแสง• การหกเหของแสงเปนไปตาม กฎของสเนลล
(Snell’s Law)2211 sinsin
เมอ• คอดรรชนหกเหของตวกลางแรก• คอดรรชนหกเหของตวกลางทสอง• และ คอมมระหวางทางเดนของแสงกบ normal ตามรป
1
2
1 2
การจำาลองการหกเหของแสง• คาดรรชนหกเหของแสงเปนคาคงตวของตวกลางแบบ
ตางๆ– ถาตองการจะรคากตองไปเปดหนงสอ
• ภาษา GLSL มฟงกชนอำานวยความสะดวกใหเราสามารถคำานวณทศทางในการหกแสงไดอยางงายดาย คอ ฟงกชน reflectrefract(vec3 I, vec3 N, float etaRatio)– I คอเวกเตอรทแสงเดนทางเขาวตถ (เวกเตอร PO)– N คอเวกเตอรตงฉาก– etaRatio คอคา – ฟงกชนนจะคนคาทศทางทแสดงหกเหออกมา (เวกเตอร OQ)
21 /
การสรางแกวใน GLSL
• ใชหลกการเดยวกบการสรางกระจกในคาบทแลว– ใช fragment program คำานวณทศทางทแสงหกเห– นำาทศทางทแสงหกเหไปอานคาจาก cube map แลวนำา
คานมาเปนส• เราทำาการคำานวณทกอยางใน world space– ดงนนใช vertex program ตวเดยวกบโปรแกรมทแลว
ได
Fragment Program สำาหรบจำาลองแกว
uniform vec3 eye;uniform samplerCube env;uniform float eta_ratio;
varying vec3 position;varying vec3 normal;
void main(){ vec3 n = normalize(normal); vec3 eye_to_point = normalize(position - eye); vec3 refracted = refract(eye_to_point, n, eta_ratio); vec4 refraction = textureCube(env, refracted); gl_FragColor = refraction;}
ด demo
ขอสงเกต• การหกเหแสงทเหนใน demo ไมใชการหกเหแสง
แบบทเกดขนจรงในธรรมชาต• ทำาไม? เพราะมนมการหกเหแสงแคครงเดยว!
ความจรงรปโดนทเปนรปปด เพราะฉะนนกวาแสงจะไปหา skybox ไดตองมการหกเหมากกวาหนงครง
ขอสงเกต (ตอ)
สงทเราทำา สงทควรจะเปน
ขอสงเกต (ตอ)
• ทำาไมเราถงไมทำาใหมนตรงกบความเปนจรง?• เพราะมนทำายากมาก!– เราตองรวาแสงเขาไปสวตถทจดไหน– เราตองรวาแสงออกไปสวตถทจดไหน– OpenGL หรอ GLSL ไมไดเกบขอมลเหลานไวใหเรา
• ดงนนเราจง โกง ดวยการคดวามการหกเหแสงแคครง“ ”เดยว
• ในคอมพวเตอรกราฟกส การโกงเชนนเปนเรองทพบเหนไดบอยมาก เพราะมนชวยทำาใหภาพสวยไดโดยไมตองเปลองเวลาคำานวณมาก
ปรากฏการณ Fresnel
• จะเหนวาตวอยางท demo ไปยงไมคอยสวยและเหมอนจรงเทาไหร
• เพราะแกวนนไมไดหกเหแสงเพยงอยางเดยว มนยงมการสะทอนแสงดวย
• ปรากฏการณทแสงสวนสะทอนทพนผววตถแตแสงบางสวนหกเหทพนผววตถเรยกวา ปรากฏการณ Fresnel
• การคำานวณปรมาณแสงทสะทอนและหกเหจรงๆ ในธรรมชาตนนใชสตรทซบซอน ดงนนเราจะโกงโดยฝนสตรขนมาเอง
ปรากฏการณ Fresnel (ตอ)
• สมมตวาเราคำานวณสทไดจากการสะทอนแสงเกบไวในตวแปร a
• และคำานวณสทไดจากการหกเหแสงไวในตวแปร b• เราตองการเอาสทงสองมารวมกน เพอจำาลอง
ปรากฏการณ Fresnel ดวยสตร:color = w × a + (1-w) × b
ปรากฏการณ Fresnel (ตอ)
• เราสามารถคำานวณคา w ไดดงตอไปน (สตรนฝนขนมาเอง)
โดยท– bias, scale, และ power คอคาทผใชกำาหนดขนมา– I คอเวกเตอรทศทางทแสงเดนทางเขาสวตถ– N คอเวกเตอรตงฉาก
))))(1(,1min(,0max( powerNIscalebiasw
Fragment Programสำาหรบจำาลองปรากฏการณ Fresnel
uniform vec3 eye;uniform samplerCube env;uniform float eta_ratio;uniform float fresnel_bias;uniform float fresnel_scale;uniform float fresnel_power;
varying vec3 position;varying vec3 normal;
void main(){ vec3 n = normalize(normal); vec3 eye_to_point = normalize(position - eye); vec3 refracted = refract(eye_to_point, n, eta_ratio); vec3 reflected = reflect(eye_to_point, n); vec4 refraction = textureCube(env, refracted); vec4 reflection = textureCube(env, reflected); float reflected_weight = fresnel_bias + fresnel_scale * pow(1.0 + dot(n, eye_to_point), fresnel_power); reflected_weight = max(0.0, min(reflected_weight, 1.0)); gl_FragColor = reflected_weight * reflection + (1.0-reflected_weight) * refraction;}
ด demo
Chromatic Dispersion
• แสงขาวทเราเหน ความจรงประกอบดวยแสงความถตางๆ สตางๆ มากมาย
• แสงสตางๆ เหลานเมอหกเหจะมมมในการหกเหตางๆ กน ทำาใหแยกออกจากกนมาเปนแถบๆ
• เราจงเหนปรากฏการณเชน รงกนนำา หรอแถบสเมอแสงเดนทางผานปรซม
Chromatic Dispersion (ตอ)
การจำาลอง Chromatic Dispersion ใน Cg
• สใน OpenGL มสามยานความถคอ R, G, และ B• เราสามารถแคกำาหนดให eta_ratio ของสามยาน
ความถนมคาแตกตางกน เพอจำาลอง chromatic dispersion ได
Fragment Program สำาหรบจำาลอง Chromatic Dispersion
uniform vec3 eye;uniform samplerCube env;uniform vec3 eta_ratio;uniform float fresnel_bias;uniform float fresnel_scale;uniform float fresnel_power;
varying vec3 position;varying vec3 normal;
void main(){ vec3 n = normalize(normal); vec3 eye_to_point = normalize(position - eye);
vec3 refracted_r = refract(eye_to_point, n, eta_ratio.r); vec3 refracted_g = refract(eye_to_point, n, eta_ratio.g);
vec3 refracted_b = refract(eye_to_point, n, eta_ratio.b); vec3 refraction_r = textureCube(env, refracted_r).rgb * vec3(1,0,0); vec3 refraction_g = textureCube(env, refracted_g).rgb * vec3(0,1,0); vec3 refraction_b = textureCube(env, refracted_b).rgb * vec3(0,0,1); vec4 refraction = vec4(refraction_r + refraction_g + refraction_b, 1);
Fragment Program สำาหรบจำาลอง Chromatic Dispersion
vec3 reflected = reflect(eye_to_point, n); vec4 reflection = textureCube(env, reflected); float reflected_weight = fresnel_bias + fresnel_scale * pow(1.0 + dot(n, eye_to_point),
fresnel_power); reflected_weight = max(0.0, min(reflected_weight, 1.0)); gl_FragColor = reflected_weight * reflection + (1.0-reflected_weight) * refraction;}
ด demo