<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>15_高光贴图</title>
<script type="text/javascript" src="Oak3D_v_0_5.js"></script>
<script id="per-fragment-lighting-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vTextureCoord;
varying vec3 vTransformedNormal;
varying vec4 vPosition;
uniform bool uUseColorMap;
uniform bool uUseSpecularMap;
uniform bool uUseLighting;
uniform vec3 uAmbientColor;
uniform vec3 uPointLightingLocation;
uniform vec3 uPointLightingSpecularColor;
uniform vec3 uPointLightingDiffuseColor;
uniform sampler2D uColorMapSampler;
uniform sampler2D uSpecularMapSampler;
void main(void) {
vec3 lightWeighting;
if (!uUseLighting) {
lightWeighting = vec3(1.0, 1.0, 1.0);
} else {
vec3 lightDirection = normalize(uPointLightingLocation - vPosition.xyz);
vec3 normal = normalize(vTransformedNormal);
float specularLightWeighting = 0.0;
float shininess = 32.0;
if (uUseSpecularMap) {
shininess = texture2D(uSpecularMapSampler, vec2(vTextureCoord.s, vTextureCoord.t)).r * 255.0;
}
if (shininess < 255.0) {
vec3 eyeDirection = normalize(-vPosition.xyz);
vec3 reflectionDirection = reflect(-lightDirection, normal);
specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), shininess);
}
float diffuseLightWeighting = max(dot(normal, lightDirection), 0.0);
lightWeighting = uAmbientColor
+ uPointLightingSpecularColor * specularLightWeighting
+ uPointLightingDiffuseColor * diffuseLightWeighting;
}
vec4 fragmentColor;
if (uUseColorMap) {
fragmentColor = texture2D(uColorMapSampler, vec2(vTextureCoord.s, vTextureCoord.t));
} else {
fragmentColor = vec4(1.0, 1.0, 1.0, 1.0);
}
gl_FragColor = vec4(fragmentColor.rgb * lightWeighting, fragmentColor.a);
}
</script>
<script id="per-fragment-lighting-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec3 aVertexNormal;
attribute vec2 aTextureCoord;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat4 uNMatrix;
varying vec2 vTextureCoord;
varying vec3 vTransformedNormal;
varying vec4 vPosition;
void main(void) {
vPosition = uMVMatrix * vec4(aVertexPosition, 1.0);
gl_Position = uPMatrix * vPosition;
vTextureCoord = aTextureCoord;
vTransformedNormal = (uNMatrix * vec4(aVertexNormal,1.0)).xyz;
}
</script>
<script type="text/javascript">
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {
}
if (!gl) {
alert("Could not initialise WebGL, sorry :-(");
}
}
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3) {
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "per-fragment-lighting-fs");
var vertexShader = getShader(gl, "per-fragment-lighting-vs");
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders");
}
gl.useProgram(shaderProgram);
shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);
shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
shaderProgram.colorMapSamplerUniform = gl.getUniformLocation(shaderProgram, "uColorMapSampler");
shaderProgram.specularMapSamplerUniform = gl.getUniformLocation(shaderProgram, "uSpecularMapSampler");
shaderProgram.useColorMapUniform = gl.getUniformLocation(shaderProgram, "uUseColorMap");
shaderProgram.useSpecularMapUniform = gl.getUniformLocation(shaderProgram, "uUseSpecularMap");
shaderProgram.useLightingUniform = gl.getUniformLocation(shaderProgram, "uUseLighting");
shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");
shaderProgram.pointLightingLocationUniform = gl.getUniformLocation(shaderProgram, "uPointLightingLocation");
shaderProgram.pointLightingSpecularColorUniform = gl.getUniformLocation(shaderProgram, "uPointLightingSpecularColor");
shaderProgram.pointLightingDiffuseColorUniform = gl.getUniformLocation(shaderProgram, "uPointLightingDiffuseColor");
}
function handleLoadedTexture(texture) {
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
var earthColorMapTexture;
var earthSpecularMapTexture;
function initTextures() {
earthColorMapTexture = gl.createTexture();
earthColorMapTexture.image = new Image();
earthColorMapTexture.image.onload = function () {
handleLoadedTexture(earthColorMapTexture)
}
earthColorMapTexture.image.src = "earth.jpg";
earthSpecularMapTexture = gl.createTexture();
earthSpecularMapTexture.image = new Image();
earthSpecularMapTexture.image.onload = function () {
handleLoadedTexture(earthSpecularMapTexture)
}
earthSpecularMapTexture.image.src = "earth-specular.gif";
}
var mvMatrix;
var mvMatrixStack = [];
var pMatrix;
function mvPushMatrix() {
var copy = new okMat4();
mvMatrix.clone(copy);
mvMatrixStack.push(copy);
}
function mvPopMatrix() {
if (mvMatrixStack.length == 0) {
throw "Invalid popMatrix!";
}
mvMatrix = mvMatrixStack.pop();
}
function setMatrixUniforms() {
gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix.toArray());
gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix.toArray());
var normalMatrix = mvMatrix.inverse().transpose();
gl.uniformMatrix4fv(shaderProgram.nMatrixUniform, false, normalMatrix.toArray());
}
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
var sphereVertexNormalBuffer;
var sphereVertexTextureCoordBuffer;
var sphereVertexPositionBuffer;
var sphereVertexIndexBuffer;
function initBuffers() {
var latitudeBands = 30;
var longitudeBands = 30;
var radius = 13;
var vertexPositionData = [];
var normalData = [];
var textureCoordData = [];
for (var latNumber = 0; latNumber <= latitudeBands; latNumber++) {
var theta = latNumber * Math.PI / latitudeBands;
var sinTheta = Math.sin(theta);
var cosTheta = Math.cos(theta);
for (var longNumber = 0; longNumber <= longitudeBands; longNumber++) {
var phi = longNumber * 2 * Math.PI / longitudeBands;
var sinPhi = Math.sin(phi);
var cosPhi = Math.cos(phi);
var x = cosPhi * sinTheta;
var y = cosTheta;
var z = sinPhi * sinTheta;
var u = 1 - (longNumber / longitudeBands);
var v = 1 - (latNumber / latitudeBands);
normalData.push(x);
normalData.push(y);
normalData.push(z);
textureCoordData.push(u);
textureCoordData.push(v);
vertexPositionData.push(radius * x);
vertexPositionData.push(radius * y);
vertexPositionData.push(radius * z);
}
}
var indexData = [];
for (var latNumber = 0; latNumber < latitudeBands; latNumber++) {
for (var longNumber = 0; longNumber < longitudeBands; longNumber++) {
var first = (latNumber * (longitudeBands + 1)) + longNumber;
var second = first + longitudeBands + 1;
indexData.push(first);
indexData.push(second);
indexData.push(first + 1);
indexData.push(second);
indexData.push(second + 1);
indexData.push(first + 1);
}
}
sphereVertexNormalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexNormalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
sphereVertexNormalBuffer.itemSize = 3;
sphereVertexNormalBuffer.numItems = normalData.length / 3;
sphereVertexTextureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexTextureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordData), gl.STATIC_DRAW);
sphereVertexTextureCoordBuffer.itemSize = 2;
sphereVertexTextureCoordBuffer.numItems = textureCoordData.length / 2;
sphereVertexPositionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexPositionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
sphereVertexPositionBuffer.itemSize = 3;
sphereVertexPositionBuffer.numItems = vertexPositionData.length / 3;
sphereVertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereVertexIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STREAM_DRAW);
sphereVertexIndexBuffer.itemSize = 1;
sphereVertexIndexBuffer.numItems = indexData.length;
}
var earthAngle = 180;
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
pMatrix = okMat4Proj(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
var useColorMap = document.getElementById("color-map").checked;
gl.uniform1i(shaderProgram.useColorMapUniform, useColorMap);
var useSpecularMap = document.getElementById("specular-map").checked;
gl.uniform1i(shaderProgram.useSpecularMapUniform, useSpecularMap);
var lighting = document.getElementById("lighting").checked;
gl.uniform1i(shaderProgram.useLightingUniform, lighting);
if (lighting) {
gl.uniform3f(
shaderProgram.ambientColorUniform,
parseFloat(document.getElementById("ambientR").value),
parseFloat(document.getElementById("ambientG").value),
parseFloat(document.getElementById("ambientB").value)
);
gl.uniform3f(
shaderProgram.pointLightingLocationUniform,
parseFloat(document.getElementById("lightPositionX").value),
parseFloat(document.getElementById("lightPositionY").value),
parseFloat(document.getElementById("lightPositionZ").value)
);
gl.uniform3f(
shaderProgram.pointLightingSpecularColorUniform,
parseFloat(document.getElementById("specularR").value),
parseFloat(document.getElementById("specularG").value),
parseFloat(document.getElementById("specularB").value)
);
gl.uniform3f(
shaderProgram.pointLightingDiffuseColorUniform,
parseFloat(document.getElementById("diffuseR").value),
parseFloat(document.getElementById("diffuseG").value),
parseFloat(document.getElementById("diffuseB").value)
);
}
mvMatrix = okMat4Trans(0, 0, -40.0);
mvMatrix.rot(OAK.SPACE_LOCAL, 23.4, 1, 0, -1, true);
mvMatrix.rotY(OAK.SPACE_LOCAL, earthAngle, true);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, earthColorMapTexture);
gl.uniform1i(shaderProgram.colorMapSamplerUniform, 0);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, earthSpecularMapTexture);
gl.uniform1i(shaderProgram.specularMapSamplerUniform, 1);
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexPositionBuffer);
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, sphereVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexTextureCoordBuffer);
gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, sphereVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexNormalBuffer);
gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, sphereVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereVertexIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, sphereVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
}
var lastTime = 0;
function animate() {
var timeNow = new Date().getTime();
if (lastTime != 0) {
var elapsed = timeNow - lastTime;
earthAngle += 0.05 * elapsed;
}
lastTime = timeNow;
}
function tick() {
okRequestAnimationFrame(tick);
drawScene();
animate();
}
function webGLStart() {
var canvas = document.getElementById("lesson15-canvas");
initGL(canvas);
initShaders();
initBuffers();
initTextures();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
tick();
}
</script>
</head>
<body onload="webGLStart();">
<canvas id="lesson15-canvas" style="border: none;" width="500" height="500"></canvas><br />
<input type="checkbox" id="color-map" checked />开启颜色贴图<br />
<input type="checkbox" id="specular-map" checked />开启高光贴图<br />
<input type="checkbox" id="lighting" checked />开启光照<br />
<h2>点光源:</h2>
<table style="border: 0; padding: 10px;">
<tr>
<td><b>位置:</b>
<td>X: <input type="text" id="lightPositionX" value="-10.0" />
<td>Y: <input type="text" id="lightPositionY" value="4.0" />
<td>Z: <input type="text" id="lightPositionZ" value="-20.0" />
</tr>
<tr>
<td><b>镜面反射颜色:</b>
<td>R: <input type="text" id="specularR" value="5.0" />
<td>G: <input type="text" id="specularG" value="5.0" />
<td>B: <input type="text" id="specularB" value="5.0" />
</tr>
<tr>
<td><b>漫反射颜色:</b>
<td>R: <input type="text" id="diffuseR" value="0.8" />
<td>G: <input type="text" id="diffuseG" value="0.8" />
<td>B: <input type="text" id="diffuseB" value="0.8" />
</tr>
</table>
<h2>环境光:</h2>
<table style="border: 0; padding: 10px;">
<tr>
<td><b>颜色:</b>
<td>R: <input type="text" id="ambientR" value="0.4" />
<td>G: <input type="text" id="ambientG" value="0.4" />
<td>B: <input type="text" id="ambientB" value="0.4" />
</tr>
</table>
<br />
</body>
</html>
15、高光贴图
创建日期:2024-06-21
更新日期:2025-01-12
简介
一个来自三线小城市的程序员开发经验总结。