En smultring i gull
Vi bruker de samme geometriske betraktningene som i modulen Torus og overføring av punkter og indekser blir det samme.
Utfordringen her blir å sette og bruke materialer og lys.
Fragment shader
Fragment shaderen får satt materiale og lys i form av 10 uniform variable. Regnestykket med lysretninger og vinkler gjøres "for hånd". Denne jobben trenger vi ikke bekymre oss om når vi skriver "gammeldags" OpenGL. Målet er å få satte den predefinerte vektoren gl_FragColor.
#ifdef GL_ES precision mediump float; #endif varying vec3 vTransformedNormal; varying vec4 vPosition; uniform vec3 uMaterialAmbientColor; uniform vec3 uMaterialDiffuseColor; uniform vec3 uMaterialSpecularColor; uniform float uMaterialShininess; uniform vec3 uMaterialEmissiveColor; uniform bool uShowSpecularHighlights; uniform vec3 uAmbientLightingColor; uniform vec3 uPointLightingDiffuseColor; uniform vec3 uPointLightingSpecularColor; uniform vec3 uPointLightingLocation; void main(void) { vec3 ambientLightWeighting = uAmbientLightingColor; vec3 lightDirection = normalize(uPointLightingLocation - vPosition.xyz); vec3 normal = normalize(vTransformedNormal); vec3 specularLightWeighting = vec3(0.0, 0.0, 0.0); if (uShowSpecularHighlights) { vec3 eyeDirection = normalize(-vPosition.xyz); vec3 reflectionDirection = reflect(-lightDirection, normal); float specularLightBrightness = pow(max(dot(reflectionDirection, eyeDirection), 0.0), uMaterialShininess); specularLightWeighting = uPointLightingSpecularColor * specularLightBrightness; } float diffuseLightBrightness = max(dot(normal, lightDirection), 0.0); vec3 diffuseLightWeighting = uPointLightingDiffuseColor * diffuseLightBrightness; vec3 materialAmbientColor = uMaterialAmbientColor; vec3 materialDiffuseColor = uMaterialDiffuseColor; vec3 materialSpecularColor = uMaterialSpecularColor; vec3 materialEmissiveColor = uMaterialEmissiveColor; float alpha = 1.0; gl_FragColor = vec4( materialAmbientColor * ambientLightWeighting + materialDiffuseColor * diffuseLightWeighting + materialSpecularColor * specularLightWeighting + materialEmissiveColor, alpha ); }
Vertex shader
De tre variablene: uMVMatrix, uPMatrix og uNormalMatrix blir satt fra Javascriptkoden. aVertexPosition representerer det aktuelle punktet, slik det er ordnet i en buffer fra Javascriptet og aVertexNormal er normalen i punktet.
attribute vec3 aVertexNormal; // or in attribute vec3 aVertexPosition; uniform mat4 uNMatrix; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying vec3 vTransformedNormal; varying vec4 vPosition; void main(void) { vPosition = uMVMatrix * vec4(aVertexPosition, 1.0); gl_Position = uPMatrix * vPosition; vTransformedNormal=(uNMatrix * vec4(aVertexNormal, 1.0)).xyz; }
Javascript
Javascriptet som handterer vår tegning er inkludert som egen fil. De viktigste delene av denne koden er kommentert funksjon for funksjon nedenfor. Hele fila ser slik ut:
Det kan være lurt å kikke på OpenGL ES 2.0 Reference Pages [2] for å få en forklaring av de enkelte metodene.
De viktigste endringene fra den enkle torusen i modulen Torus er i rutinene initShaders() og drawScene()
I initShaders setter vi opp kontakt til de uniform variablene der vi skal plassere material- og lyssettinger.
function initShaders() { var fragmentShader = getShader(gl, "shader-fs"); var vertexShader = getShader(gl, "shader-vs"); // Create the shader program shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); // ok? if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert("Unable to initialize the shader program."); } gl.useProgram(shaderProgram); // connect shader attribute to buffers. // attributes, understood as attributes to verteces vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); gl.enableVertexAttribArray(vertexPositionAttribute); vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal"); gl.enableVertexAttribArray(vertexNormalAttribute); // mark light and material shaderProgram.materialAmbientColorUniform = gl.getUniformLocation(shaderProgram, "uMaterialAmbientColor"); shaderProgram.materialDiffuseColorUniform = gl.getUniformLocation(shaderProgram, "uMaterialDiffuseColor"); shaderProgram.materialSpecularColorUniform = gl.getUniformLocation(shaderProgram, "uMaterialSpecularColor"); shaderProgram.materialShininessUniform = gl.getUniformLocation(shaderProgram, "uMaterialShininess"); shaderProgram.materialEmissiveColorUniform = gl.getUniformLocation(shaderProgram, "uMaterialEmissiveColor"); shaderProgram.showSpecularHighlightsUniform = gl.getUniformLocation(shaderProgram, "uShowSpecularHighlights"); shaderProgram.ambientLightingColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientLightingColor"); shaderProgram.pointLightingLocationUniform = gl.getUniformLocation(shaderProgram, "uPointLightingLocation"); shaderProgram.pointLightingSpecularColorUniform = gl.getUniformLocation(shaderProgram, "uPointLightingSpecularColor"); shaderProgram.pointLightingDiffuseColorUniform = gl.getUniformLocation(shaderProgram, "uPointLightingDiffuseColor"); }
I drawScene overfører vi material- og lyssettinger til shaderen.
function drawScene() { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); perspectiveMatrix = makePerspective(45, viewAspect, 0.1, 100.0); loadIdentity(); // Move the drawing a bit from default eye-pos mvTranslate([-0.0, 0.0, -16.0]); // Save the current matrix, then rotate before we draw. mvPushMatrix(); mvRotate(torusRotation, [1, 0, 1]); // Draw the torus by binding the array buffer to the torus's vertices // array, setting attributes, and pushing it to GL. gl.bindBuffer(gl.ARRAY_BUFFER, torusVerticesBuffer); gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); // Set the normal attribute for the vertices. gl.bindBuffer(gl.ARRAY_BUFFER, torusVerticesNormalBuffer); gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0); // tell the shader about transformation status setMatrixUniforms(); // setup materials and light // material: gold gl.uniform3f(shaderProgram.materialAmbientColorUniform, 0.24725, 0.1995, 0.0745); gl.uniform3f(shaderProgram.materialDiffuseColorUniform, 0.7516, 0.6065, 0.2265); gl.uniform3f(shaderProgram.materialSpecularColorUniform, 0.62828, 0.55580, 0.36606); gl.uniform1f(shaderProgram.materialShininessUniform, 51.2); gl.uniform3f(shaderProgram.materialEmissiveColorUniform, 0.0, 0.0, 0.0); gl.uniform3f(shaderProgram.pointLightingLocationUniform, 10.0, 10.0, 5.0); gl.uniform3f(shaderProgram.ambientLightingColorUniform, 1.0, 1.0, 1.0); gl.uniform3f(shaderProgram.pointLightingDiffuseColorUniform, 1.0, 1.0, 1.0); gl.uniform3f(shaderProgram.pointLightingSpecularColorUniform, 1.0, 1.0, 1.0); gl.uniform1i(shaderProgram.showSpecularHighlightsUniform, true); // Draw the torus. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, torusVerticesIndexBuffer); gl.drawElements(gl.TRIANGLE_STRIP, (N+1)*(n+1)*2, gl.UNSIGNED_SHORT, 0); // Restore the original matrix mvPopMatrix(); // Update the rotation for the next draw, if it's time to do so. var currentTime = (new Date).getTime(); if (lastTorusUpdateTime) { var delta = currentTime - lastTorusUpdateTime; torusRotation += (30 * delta) / 1000.0; } lastTorusUpdateTime = currentTime; }
Dette er resultatet lagt i en iframe:
Du kan også inspisere resultatet og kildekoden på en enklere side:
index-mat.html
https://borres.hiof.no/wep/webgl/basis/torusgull/index-mat.html