需要電子檔書籍或者源碼可以Q羣:828202939 希望可以和大家一起學習、一起進步!!
如有錯別字或有理解不到位的地方,可以留言或者加微信15250969798,博主會及時修改!!!!!
本章節主要涉及的知識點是:
1、canvas繪製(繪製線、曲線)
2、threeJS中處理2個捱得極近的物體
3、紋理的控制(紋理的偏移控制)
4、精靈材質+canvas作爲紋理的運用
其他的都是一些基礎的知識
效果錄屏:
代碼:
<html>
<head>
<title>紋理偏移+Sprite標籤</title>
<style>
body {
background-color: #000;
margin: 0px;
overflow: hidden;
}
#WebGL {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 999;
}
</style>
</head>
<body>
<div id="WebGL"></div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
<script src="../../../build/three.js"></script>
<script src="../../../examples/js/controls/OrbitControls.js"></script>
<script src="./texture.js"></script>
</body>
</html>
'use strict';
var container, camera, scene, renderer, geometry, material, controls; //常用變量
var spotLight, mesh_sphere; //自定義對象變量
var target = new THREE.Vector3(0, 30, 0);
var webGLW = $('#WebGL').width();
var webGLH = $('#WebGL').height();
var textureLoader = new THREE.TextureLoader(); //紋理加載器
init();
animate();
function init() {
container = document.getElementById('WebGL');
rendererScene(); //場景渲染
sceneBackground();
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 50, 200);
camera.lookAt(target);
plane() //// 地面
lights(); //燈光:聚光燈
addMovePlane(scene); //推薦偏移的平面和圓
loadModel(); //添加模型
OrbitControls(camera, renderer); //OrbitControls控件模塊
window.addEventListener('resize', onWindowResize, false); //監聽屏幕變化
}
function sceneBackground() {
scene = new THREE.Scene();
// scene.background = new THREE.Color(0xcfcfcf);//可以用圖片代替作爲背景
var path = '../image/sky/';
var format = '.jpg';
new THREE.CubeTextureLoader().load([
path + 'px' + format, path + 'nx' + format, //右左
path + 'py' + format, path + 'ny' + format, //上下
path + 'pz' + format, path + 'nz' + format //前後
], function (res) {
scene.background = res;
});
// // scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); //霧
}
function plane() {
texture_plane = textureLoader.load('../image/textureOffset.png');
texture_plane.wrap = texture_plane.wrapT = THREE.RepeatWrapping; //平鋪重複
texture_plane.anisotropy = renderer.capabilities.getMaxAnisotropy();
// 地面
let geometry = new THREE.PlaneBufferGeometry(200, 200);
let grid_mesh = new THREE.Mesh(geometry, new THREE.MeshPhongMaterial({
color: 0x999999,
// depthWrite: false
}));
grid_mesh.rotation.x = -Math.PI / 2;
grid_mesh.receiveShadow = true;
scene.add(grid_mesh);
var grid = new THREE.GridHelper(200, 20, 0x000000, 0x000000);
grid.material.opacity = 0.2;
grid.material.transparent = true;
scene.add(grid);
}
function lights() { //光影自己改哦
var ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
//聚光燈
// SpotLight( color:顏色, intensity:強度, distance:發光距離, angle:角度, penumbra:邊緣範圍, decay:衰減 )
spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(0, 120, 0);
spotLight.angle = Math.PI / 6;
spotLight.penumbra = 0.05; //邊緣範圍,反比
spotLight.decay = 2; //衰減係數,反比
spotLight.distance = 400; //發光距離
spotLight.castShadow = true; //陰影
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.shadow.camera.near = 10; //近截面
spotLight.shadow.camera.far = 250;
scene.add(spotLight);
}
function lightsHelper(lightsObject) {
// 聚光燈顯示助手SpotLightHelper( light:燈光, color:顏色 )
var lightHelper = new THREE.SpotLightHelper(lightsObject, 0xdfdfdf);
scene.add(lightHelper);
let mesh = new THREE.Mesh(new THREE.PlaneBufferGeometry(100, 100), new THREE.MeshPhongMaterial({
color: 0x9cfcf99,
depthWrite: false
}));
mesh.rotation.x = -Math.PI / 2;
mesh.position.set(0, -20, 0)
mesh.receiveShadow = true;
scene.add(mesh);
}
var texture_plane;
function addMovePlane(scene) {
// 背景平面
let geometry02 = new THREE.PlaneBufferGeometry(150, 100);
let plane_back = new THREE.Mesh(geometry02, new THREE.MeshPhongMaterial({
map: texture_plane,
transparent: true,
}));
plane_back.position.set(0, 50, -100);
plane_back.name = 'plane';
let plane_back_make =makeTextSprite(plane_back.name,{
fontsize: 80,
borderColor: {r:180, g:125, b:125, a:0.4},/* 邊框顏色 */
backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景顏色 */
})
plane_back_make.center = new THREE.Vector2(0, 0);
plane_back_make.name='plane_back_make';
let plane_back_parameters=plane_back.geometry.parameters ;
plane_back_make.position.set(-(plane_back_parameters.width/2+15),plane_back.position.y , plane_back.position.z);
scene.add(plane_back,plane_back_make);
let circle = new THREE.Mesh(new THREE.CircleGeometry(60, 100, 100), new THREE.MeshPhongMaterial({
map: texture_plane,
transparent: true,
depthTest: false //關閉檢測,讓2個重疊的平面正確顯示
}));
circle.rotation.x = -Math.PI / 2;
circle.name = 'circle';
scene.add(circle);
}
var texture_sphere;
function loadModel() { //模型
//圓球
texture_sphere = textureLoader.load('../image/textureOffset.png');
texture_sphere.wrap = texture_sphere.wrapT = THREE.RepeatWrapping; //平鋪重複
mesh_sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry(20, 20, 20),
new THREE.MeshBasicMaterial({
color: 0xffffff,
map: texture_sphere,
side: 2,
transparent: true,
// wireframe: true
})
);
mesh_sphere.position.set(0, 30, 0)
mesh_sphere.name = 'sphere';
let mesh_sphere_make =makeTextSprite(mesh_sphere.name,{
fontsize: 80,
borderColor: {r:180, g:125, b:125, a:0.4},/* 邊框顏色 */
backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景顏色 */
})
mesh_sphere_make.center = new THREE.Vector2(0, 0);
mesh_sphere_make.name='mesh_sphere_make';
let mesh_sphere_parameters=mesh_sphere.geometry.parameters ;
mesh_sphere_make.position.set(-(mesh_sphere_parameters.radius+15),mesh_sphere.position.y , mesh_sphere.position.z);
scene.add(mesh_sphere,mesh_sphere_make);
}
/* 創建字體精靈 */
function makeTextSprite(message, parameters) {
if (parameters === undefined) parameters = {};
/* 字體 */
let fontface = parameters.hasOwnProperty("fontface") ?
parameters["fontface"] : "Arial";
/* 字體大小 */
let fontsize = parameters.hasOwnProperty("fontsize") ?
parameters["fontsize"] : 10;
/* 邊框厚度 */
let borderThickness = parameters.hasOwnProperty("borderThickness") ?
parameters["borderThickness"] : 4;
/* 邊框顏色 */
let borderColor = parameters.hasOwnProperty("borderColor") ?
parameters["borderColor"] : {
r: 0,
g: 0,
b: 0,
a: 1.0
};
/* 背景顏色 */
let backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
parameters["backgroundColor"] : {
r: 255,
g: 255,
b: 255,
a: 1.0
};
/* 創建畫布 */
let canvas = document.createElement('canvas');
let context = canvas.getContext('2d');
/* 字體加粗 */
context.font = "Bold " + fontsize + "px " + fontface;
/* 獲取文字的大小數據,高度取決於文字的大小 */
let metrics = context.measureText(message);
console.log('文字metrics::',metrics);
let textWidth = metrics.width;
/* 背景顏色 */
context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," +
backgroundColor.b + "," + backgroundColor.a + ")";
/* 邊框的顏色 */
context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," +
borderColor.b + "," + borderColor.a + ")";
context.lineWidth = borderThickness;
/* 繪製圓角矩形 */
roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 +
borderThickness, 30);
/* 字體顏色 */
context.fillStyle = "rgba(0, 0, 0, 1.0)";
context.fillText(message, borderThickness, fontsize + borderThickness);
/* 畫布內容用於紋理貼圖 */
let texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
let spriteMaterial = new THREE.SpriteMaterial({
map: texture
});
let sprite = new THREE.Sprite(spriteMaterial);
console.log(sprite.spriteMaterial);
/* 縮放比例 */
sprite.scale.set(10, 5, 1);
return sprite;
}
/**
* @method 繪製圓角矩形
* @param {*} ctx canvas畫布
* @param {*} x x位置
* @param {*} y y位置
* @param {*} w 寬
* @param {*} h 高
* @param {*} r 圓角的半徑
*/
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
// 起始點(左上圓角處的直線位置)
ctx.moveTo(x + r, y);
// 矩形上寬線條(突出來一點)
ctx.lineTo(x + w*1.5 - r, y);
// 繪製左上圓角(二次貝塞爾曲線)
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
// 右高線條
ctx.lineTo(x + w, y + h - r);
// 右下圓角
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
// 左下線條
ctx.lineTo(x + r, y + h);
// 左下圓角
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
// 左高線條
ctx.lineTo(x, y + r);
// 左上圓角
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function rendererScene() {
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.gammaInput = true;
renderer.gammaOutput = true;
container.appendChild(renderer.domElement);
}
function OrbitControls(camera, renderer) {
//OrbitControls控件操作模塊
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = target; //控制的target
// controls.autoRotate = true; //是否自動旋轉
// controls.autoRotateSpeed = 0.2; //自動旋轉速度,正比
}
/* 數據更新 */
function updata() {
// 設置紋理偏移
var time = Date.now() * 0.004;
// texture_sphere.offset.y = (Math.sin(time)*0.1);//往返偏移
texture_sphere.offset.x += 0.001; //左右偏移
if (texture_sphere.offset.x >= 0.5) {
texture_sphere.offset.x = 0;
}
texture_plane.offset.y -= 0.005;
}
function animate() {
requestAnimationFrame(animate);
if (controls) controls.update();
updata();
renderer.render(scene, camera);
};