En smultring i gull
Vi bruker de samme geometriske betraktningene som i modulen En smultring 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: torusscript-mat.js
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 En smultring 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, 640.0/480.0, 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:
Du kan også inspisere resultatet og kildekoden på en enklere side:
gull.html
http://www.it.hiof.no/~borres/dw/wgl/torus/index-mat.html