WebGL 1.0 OpenGL ES 2.0 Google Chrome 12.0.742.100 Canvas 3d JS Library 2.2 |
■[ Canvas 3d JS Library ]で標準シェーダー [ サンプルページの表示 ]サンプルページの表示には1分以上かかります |
Prev Top Next | ||||
|
今回は[ Canvas 3d JS Library ]に標準で実装されているシェーダーを使ってみます。
ただ、[ Canvas 3d JS Library ]ライブラリのソースそのままでは正しく動作してくれないところがあったため、修正しています。 ほかにも半球ライティングの仕様を変更しています。
無圧縮版の[ Canvas 3d JS Library ]ライブラリのソースを修正しました。圧縮版のソースは、無圧縮版のソース内にある半角スペースや改行コードを取り除いたり、 変数を一文字にしたりして総バイト数を少なくしただけなので、圧縮版と無圧縮版のソースを混在させても問題なく動作します。 圧縮版のソースを作成する気はまったくないのでどうしても圧縮版にしたい人は自分で作成してください。
今回は [ Canvas 3d JS Library ]の バージョン 2.2 のライブラリを修正しました。 他のバージョンを修正すると正しく動作しなくなる可能性がありますので、必ず バージョン 2.2 のライブラリを修正してください。
コピーボタンですが、Internet Explorer での動作のみ確認しています。Google Chrome ではコピーできません。
---canvas3dapi/shaders/model/cartoon/cartoon_fs.js---
/* Copyright (c) 2008 Seneca College Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/) */ c3dl.cartoon_fs = "uniform sampler2D myTex;" + "uniform sampler2D celShadeTex;" + "uniform int usingTexture;" + "varying vec4 texCoord;" + "varying vec3 norm;" + "varying vec3 pos;" + /* light fragPos normal intensity */ "void c3dl_celPointLight(in Light light, in vec3 fragPos, in vec3 normal, inout float intensity)"+ "{" + " vec3 rayDir = vec3(light.position) - fragPos;" + " intensity += max(dot(normalize(rayDir),normal),0.0);" + "}" + /* light normal intensity */ "void c3dl_celDirLight(in Light light, in vec3 normal, inout float intensity)"+ "{" + " intensity += max(dot(normalize(vec3(-light.position)),normal), 0.0);" + "}" + /* light fragPos normal intensity */ "void c3dl_celSpotLight(in Light light, in vec3 fragPos, in vec3 normal, inout float intensity)" + "{" + // ray direction goes from light position to fragment. " vec3 rayDir = fragPos - vec3(light.position);" + " rayDir = normalize(rayDir);" + " float spotDot = dot(rayDir, normalize(light.spotDirection));" + // if the fragment is within the cone // don't light up the back side of the object " if( dot(-normal, rayDir ) > 0.0 && spotDot > cos(radians(light.spotCutoff)) )" + " {" + " intensity += max(dot(-normal, rayDir), 0.0);" + " }" + "}" + /* */ "void main(void)" + "{" + " if(lightingOn == false)" + " {" + " gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);" + " }" + " else" + " {" + " vec3 n = normalize(norm);" + " vec4 color = vec4(1.0, 1.0, 1.0, 1.0);" + " if( usingTexture == 1 )" + " {" + " vec3 texel = vec3(texture2D(myTex, texCoord.xy));" + " color = vec4(texel, 1.0);" + " }" + " float intensity = 0.0;" + // iterate over all the lights, and keep incrementing color values // the color values are passed by reference and modified. " for(int i = 0; i < C3DL_MAX_LIGHTS; i++)" + " {" + " if(lights[i].isOn == true) " + " {" + " if(lights[i].type == 1)" + " {" + " c3dl_celDirLight(lights[i], n, intensity);" + " }" + " else if(lights[i].type == 2)" + " {" + " c3dl_celPointLight(lights[i], pos, n, intensity);" + " }" + " else" + " {" + " c3dl_celSpotLight(lights[i], pos, n, intensity);" + " }" + " }" + " if( i >= C3DL_MAX_LIGHTS - 1 ) break; " + " }" + // The texture wrapping wasn't set, so make sure // we don't sample a wrong value. " intensity = clamp(intensity, 0.1, 0.9);" + " vec3 celTexel = vec3(texture2D(celShadeTex, vec2(intensity, 0.0)));" + " gl_FragColor = color * vec4(celTexel, 1.0);" + " }" + "}";トゥーンシェーダーのフラグメントシェーダーソースです。
修正箇所は日本語で記述している箇所です。元のソースでは ATI Radeon HD 5700 のビデオカードの場合正しく動作しませんでした。 で上記のように修正するとなぜか正しく動作しました(笑)。 for文の条件式と同じことをやってるだけなので、本来まったく必要のないロジックです。意味わからんなあ。
ちなみに NVIDIA GeForce Go7600 では元のソースでも正しく動作しました。こっちのほうがロースペックなのに。
おまけでトゥーンシェーダーで使用しているトゥーンマップをアップしときます。
---canvas3dapi/shaders/model/gooch/gooch_callback.js---
/* Copyright (c) 2008 Seneca College Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/) */ /* */ c3dl.gooch_callback = function (renderingObj, scene) { var renderer = renderingObj.getRenderer(); var gl = renderingObj.getContext(); var geometry = renderingObj.getGeometry(); var effect = geometry.getEffect(); var programObjID = renderingObj.getProgramObjectID(); gl.useProgram(programObjID); var modelViewMatrix = c3dl.peekMatrix(); c3dl.matrixMode(c3dl.PROJECTION); var projectionMatrix = c3dl.peekMatrix(); c3dl.matrixMode(c3dl.MODELVIEW); var modelViewProjMatrix = c3dl.multiplyMatrixByMatrix(projectionMatrix, modelViewMatrix); renderer.setUniformMatrix(programObjID, "modelViewMatrix", modelViewMatrix, scene, "gooch"); renderer.setUniformMatrix(programObjID, "modelViewProjMatrix", modelViewProjMatrix, scene, "gooch"); // Commenting out until a fix is solved for the 2-object outline bug // Only render the outline, which is a single pixel thick if the user // wants it and the effect exists. if (effect.getParameter("outline") == true && renderer.SOLID_COLOR_EFFECT_ID) { gl.enable(gl.POLYGON_OFFSET_FILL); gl.polygonOffset(2.0, 2.0); // use the solid color effect since it's fast and we don't have // to send unnecessary data. var outlineProgID = renderer.SOLID_COLOR_EFFECT_ID; gl.enable(gl.CULL_FACE); gl.cullFace(gl.FRONT); gl.useProgram(outlineProgID); renderer.setUniformf(outlineProgID, "color", [0, 0, 0], scene, "outlinegooch"); var modelViewMatrix = c3dl.peekMatrix(); c3dl.matrixMode(c3dl.PROJECTION); var projectionMatrix = c3dl.peekMatrix(); c3dl.matrixMode(c3dl.MODELVIEW); var MVPMatrix = c3dl.multiplyMatrixByMatrix(projectionMatrix, modelViewMatrix); renderer.setUniformMatrix(outlineProgID, "modelViewProjMatrix", MVPMatrix, scene, "outlinegooch"); var contextWidth = renderer.getContextWidth(); var contextHeight = renderer.getContextHeight(); for (var primSet = 0; primSet < geometry.getPrimitiveSets().length; primSet++) { var currColl = geometry.getPrimitiveSets()[primSet]; // Prevent C3DL from reporting an error, so check if attrib exsits // before trying to set it. // This is a kludge for Safari and Chrome since they want these attributes //////////////////////////// var normalAttribLoc = scene.curContextCache.attributes["outlinegooch"+primSet+"Normal"]; if(normalAttribLoc ==undefined ) { normalAttribLoc = gl.getAttribLocation(outlineProgID, "Normal"); scene.curContextCache.attributes["outlinegooch"+primSet+"Normal"] = normalAttribLoc; } if (normalAttribLoc != -1 && currColl.getNormals()) { renderer.setVertexAttribArray(outlineProgID, "Normal", 3, currColl.getVBONormals(), scene, "outlinegooch"+primSet); } var texAttribLoc = scene.curContextCache.attributes["outlinegooch"+primSet+"Texture"]; if(texAttribLoc ==undefined ) { texAttribLoc = gl.getAttribLocation(outlineProgID, "Texture"); scene.curContextCache.attributes["outlinegooch"+primSet+"Texture"] = texAttribLoc; } if (texAttribLoc != -1 && currColl.getTexCoords()) { renderer.setVertexAttribArray(outlineProgID, "Texture", 2, currColl.getVBOTexCoords(), scene, "outlinegooch"+primSet); } ////////////////////////// End kludge renderer.setVertexAttribArray(outlineProgID, "Vertex", 3, currColl.getVBOVertices(), scene, "outlinegooch"+primSet); gl.viewport(1, -1, contextWidth, contextHeight); gl.drawArrays(renderer.getFillMode(), 0, currColl.getVertices().length / 3); gl.viewport(-1, -1, contextWidth, contextHeight); gl.drawArrays(renderer.getFillMode(), 0, currColl.getVertices().length / 3); gl.viewport(-1, 1, contextWidth, contextHeight); gl.drawArrays(renderer.getFillMode(), 0, currColl.getVertices().length / 3); gl.viewport(1, 1, contextWidth, contextHeight); gl.drawArrays(renderer.getFillMode(), 0, currColl.getVertices().length / 3); } // restore normal backface culling gl.cullFace(gl.BACK); gl.viewport(0, 0, contextWidth, contextHeight); gl.disable(gl.POLYGON_OFFSET_FILL); gl.polygonOffset(0.0, 0.0); } gl.useProgram(programObjID); // render all the collation elements. Every collation element in an object will // have the same tranformation for (var coll = 0; coll < geometry.getPrimitiveSets().length; coll++) { var currColl = geometry.getPrimitiveSets()[coll]; var dummyAttribLoc = scene.curContextCache.attributes["gooch"+coll+"dummyAttrib"]; if(dummyAttribLoc ==undefined ) { dummyAttribLoc = gl.getAttribLocation(programObjID, "dummyAttrib"); scene.curContextCache.attributes["gooch"+coll+"dummyAttrib"] = dummyAttribLoc; } if (dummyAttribLoc !== -1 && currColl.getNormals()) { renderer.setVertexAttribArray(programObjID, "dummyAttrib", 3, currColl.getVBONormals(), scene, "gooch"+coll); } var normalAttribLoc = scene.curContextCache.attributes["gooch"+coll+"Normal"]; if(normalAttribLoc ==undefined ) { normalAttribLoc = gl.getAttribLocation(programObjID, "Normal"); scene.curContextCache.attributes["gooch"+coll+"Normal"] = normalAttribLoc; } // if the object acutally has normals and the normal attribute was found // if (normalAttribLoc !== -1 && currColl.getNormals()) { // the top matrix is the modelview matrix. var NormalMatrix = c3dl.inverseMatrix(modelViewMatrix); NormalMatrix = c3dl.transposeMatrix(NormalMatrix); renderer.setUniformMatrix(programObjID, "normalMatrix", NormalMatrix, scene, "gooch"+coll); renderer.setVertexAttribArray(programObjID, "Normal", 3, currColl.getVBONormals(), scene, "gooch"+coll); } else { gl.disableVertexAttribArray(normalAttribLoc); } var texAttribLoc = scene.curContextCache.attributes["gooch"+coll+"Texture"]; if(texAttribLoc ==undefined ) { texAttribLoc = gl.getAttribLocation(programObjID, "Texture"); scene.curContextCache.attributes["gooch"+coll+"Texture"] = texAttribLoc; } var texID = renderer.getTextureID(currColl.getTexture()); // if the texture isn't loaded, but this collation element has one, // queue one up if (texID == -1 && currColl.getTexture()) { renderer.addTexture(currColl.getTexture()); } if (texID != -1 && currColl.getTexture() && currColl.getTexCoords() && texAttribLoc != -1) { // make texture unit 0 active gl.activeTexture(gl.TEXTURE0); // bind the collations texture object to texture unit 0 and make it active. gl.bindTexture(gl.TEXTURE_2D, texID); renderer.setVertexAttribArray(programObjID, "Texture", 2, currColl.getVBOTexCoords(), scene, "gooch"+coll); renderer.setUniformi(programObjID, "myTex", 0, scene, "gooch"+coll); renderer.setUniformi(programObjID, "usingTexture", true, scene, "gooch"+coll); } else { gl.disableVertexAttribArray(texAttribLoc); renderer.setUniformi(programObjID, "usingTexture", false, scene, "gooch"+coll); } renderer.setUniformf(programObjID, "warmColor", effect.getParameter("warmColor"), scene, "gooch"+coll); renderer.setUniformf(programObjID, "coolColor", effect.getParameter("coolColor"), scene, "gooch"+coll); renderer.setUniformf(programObjID, "surfaceColor", effect.getParameter("surfaceColor"), scene, "gooch"+coll); renderer.setVertexAttribArray(programObjID, "Vertex", 3, currColl.getVBOVertices(), scene, "gooch"+coll); gl.drawArrays(renderer.getFillMode(), 0, currColl.getVertices().length / 3); } }半球ライティングの管理ソースです。
修正箇所は日本語コメントの範囲内です。
元のソースがテクスチャーを使用していなかったので、テクスチャーを使用できるように修正します。
修正方法は、トゥーンシェーダー側のソースをコピペして、文字列を"gooch"に修正しただけです。
---canvas3dapi/shaders/model/gooch/gooch_vs.js---
/* Copyright (c) 2008 Seneca College Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/) */ c3dl.gooch_vs = "varying vec3 ViewVec;" + "varying vec3 ecPos;" + "varying vec3 tnorm;" + "attribute vec3 Texture;" + "varying vec4 texCoord;" + "attribute vec3 Vertex;" + "attribute vec3 Normal;" + "attribute vec3 dummyAttrib;" + "uniform mat4 modelViewMatrix;" + "uniform mat4 modelViewProjMatrix;" + "uniform mat4 normalMatrix;" + "void main(void){" + // Dummy attrib so safari and chrome render // this object properly. " vec3 dummy = dummyAttrib;" + " mat3 normalMatrix3x3 = mat3(normalMatrix[0][0],normalMatrix[0][1],normalMatrix[0][2],normalMatrix[1][0],normalMatrix[1][1],normalMatrix[1][2],normalMatrix[2][0],normalMatrix[2][1],normalMatrix[2][2]);" + // ecPos = vertex in eye coordinate space. " ecPos = vec3(modelViewMatrix * vec4(Vertex,1.0));" + " tnorm = normalize(normalMatrix3x3 * Normal);" + // a normalized vector pointing from the vector to the light " ViewVec = normalize(-ecPos);" + " gl_Position = modelViewProjMatrix * vec4(Vertex, 1.0);" + " texCoord = vec4(Texture,1.0);" + "}";半球ライティングの頂点シェーダーソースです。
テクセルを追加しています。
---canvas3dapi/shaders/model/gooch/gooch_fs.js---
/* Copyright (c) 2008 Seneca College Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/) */ c3dl.gooch_fs = "float DiffuseWarm = 0.5;" + "float DiffuseCool = 0.5;" + // parameters "uniform vec3 surfaceColor;" + "uniform vec3 warmColor;" + "uniform vec3 coolColor;" + "uniform sampler2D myTex;" + "uniform int usingTexture;" + "varying vec4 texCoord;" + "varying vec3 ViewVec;" + "varying vec3 ecPos;"+ "varying vec3 tnorm;" + /* Light light [in] vec3 nviewVec [in] vec3 ntnorm [in] float spec [inout] float NdotL [inout] */ "void c3dl_goochPointLight(in Light light, in vec3 nviewVec, in vec3 ntnorm, inout float NdotL, inout float spec)" + "{" + // lightVec = dir of light " vec3 lightVec = normalize(vec3(light.position) - ecPos);" + " vec3 ReflectVec = normalize(reflect(lightVec, ntnorm));" + " NdotL = (dot(lightVec, ntnorm) + 1.0) * 0.5;" + " spec += max(dot(ReflectVec, -nviewVec), 0.0);" + "}" + /* light nviewVec ntnorm NdotL spec */ //"void c3dl_goochDirLight(in Light light, in vec3 nviewVec, in vec3 ntnorm, inout float NdotL, inout float spec)" + "void c3dl_goochDirLight(in Light light, in vec3 nviewVec, in vec3 ntnorm, inout float NdotL, inout float spec, inout float NdotP)" + "{"+ // when the user specifies the the direction of the light, they are // specifying the direction the light is going towards. " vec3 lightVec = vec3(-light.position);" + // calculate how intense the light is. // NdotL is added for each light. // ハーフランバートだな " NdotL = (dot(lightVec, ntnorm) + 1.0) * 0.5;" + " NdotP = dot(vec3( 0, 1, 0 ), ntnorm);" + " vec3 ReflectVec = normalize(reflect(lightVec, ntnorm));" + " spec += max(dot(ReflectVec, -nviewVec), 0.0);" + "}"+ /* */ "void main(void) {" + //" vec3 kcool = min(coolColor + DiffuseCool * surfaceColor, 1.0);"+ //" vec3 kwarm = min(warmColor + DiffuseWarm * surfaceColor, 1.0);" + " vec3 kcool = coolColor * DiffuseCool * surfaceColor;" + " vec3 kwarm = warmColor * DiffuseWarm * surfaceColor;" + " vec3 nviewVec = normalize(ViewVec);" + " vec3 ntnorm = normalize(tnorm);" + " float NdotL = 0.0;" + " float NdotP = 0.0;" + " float spec = 0.0;" + // Gooch effects should only have one light so the contour of the object // is properly rendered. So, only accept the first active light as the light // source. " bool appliedLight = false;" + " vec3 color = vec3(1.0, 1.0, 1.0);" + " if( usingTexture == 1 )" + " {" + " color = vec3(texture2D(myTex, texCoord.xy));" + " }" + " if(lightingOn == true)" + " {" + " for(int i = 0; i < C3DL_MAX_LIGHTS; i++)" + " {" + " if ( appliedLight == false)"+ " {"+ " if( lights[i].isOn == true)" + " {" + " if(lights[i].type == 1)" + " {" + //" c3dl_goochDirLight(lights[i], nviewVec, ntnorm, NdotL, spec);"+ " c3dl_goochDirLight(lights[i], nviewVec, ntnorm, NdotL, spec, NdotP);"+ " appliedLight = true;" + " }" + " else" + " {" + " c3dl_goochPointLight(lights[i], nviewVec, ntnorm, NdotL, spec);"+ " appliedLight = true;" + " }" + " }" + " }" + " if( i >= C3DL_MAX_LIGHTS - 1 ) break; " + " }"+ " }" + " NdotL = clamp(NdotL, 0.1, 1.0);"+ " NdotP = clamp(NdotP, 0.0, 1.0);"+ //" vec3 kfinal = mix(kcool, kwarm, NdotL);" + " vec3 hemisphere = mix(kwarm, kcool, NdotP);" + " spec = pow(spec,16.0);" + //" gl_FragColor = vec4(min(kfinal + spec, 1.0), 1.0);" + " gl_FragColor = vec4( min( color * NdotL + hemisphere + spec, 1.0 ), 1.0 );" + "}";半球ライティングのフラグメントシェーダーソースです。
がっつり修正しました(笑)。詳細はソースを見てください。
最後に対応するブラウザは、Google Chrome のみです。以上!!