//功能介绍:自定义sprite
//1、可以自定义锚点,使sprite的各个顶点与模型进行对齐,例如 左对齐、右对齐、上对齐、下对齐
//2、可以设定图片的九宫格,部分拉伸效果处理
//3、可以设定是否根据距离自动衰减标签大小
//4、可以设定统一颜色或者顶点颜色
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - FBX loader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
z-index: 100;
display:block;
}
#info a {
color: #046;
font-weight: bold;
}
</style>
</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - FBXLoader<br />
Character and animation from <a href="https://www.mixamo.com/" target="_blank" rel="noopener">Mixamo</a>
</div>
<script src="../build/three.js"></script>
<script src="js/libs/inflate.min.js"></script>
<script src="js/loaders/FBXLoader.js"></script>
<script src="js/loaders/TGALoader.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/WebGL.js"></script>
<script src="js/libs/stats.min.js"></script>
<script>
/*function CustomSprite(){
Object3D.call(this);
//this.type = 'CustomSprite'
}
CustomSprite.prototype = Object.assign( Object.create(Object3D.prototype), {
constructor: CustomSprite,
isCustomSprite: true,
onBeforeRender:
} );
Object.potoType*/
var container, stats, controls;
var camera, scene, renderer, light;
var clock = new THREE.Clock();
var mesh;
var mesh_cube;
if ( WEBGL.isWebGLAvailable() === false ) {
document.body.appendChild( WEBGL.getWebGLErrorMessage() );
}
init();
animate();
function init() {
container = document.createElement( 'div' );
document.body.appendChild( container );
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 200000 );
camera.position.set( 100, 200, 300 );
controls = new THREE.OrbitControls( camera );
controls.update();
scene = new THREE.Scene();
light = new THREE.HemisphereLight( 0xffffff, 0x444444 );
light.position.set( 0, 200, 0 );
scene.add( light );
light = new THREE.DirectionalLight( 0xffffff );
light.position.set( 0, 200, 100 );
light.castShadow = true;
light.shadow.camera.top = 180;
light.shadow.camera.bottom = - 100;
light.shadow.camera.left = - 120;
light.shadow.camera.right = 120;
scene.add( light );
createSprite();
var geometry_cube = new THREE.BufferGeometry();
var vertices_cube = new Float32Array( [
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0
] );
geometry_cube.addAttribute( 'position', new THREE.BufferAttribute( vertices_cube, 3 ) );
var material_cube = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
mesh_cube = new THREE.Mesh( geometry_cube, material_cube );
mesh_cube.scale.set(0.2, 0.2, 0.2);
scene.add( mesh_cube );
mesh_cube.add(mesh);
//mesh_cube.translateX(100);
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
// stats
stats = new Stats();
container.appendChild( stats.dom );
}
function createSprite(){
var textureLoader = new THREE.TextureLoader();
//九宫格的顶点坐标
let widthX = [0, 160, 1000, 1200];
let heightY = [0, 20, 80, 100];
let vv = [];
for(let i = 0; i < 4; i++){
for(let j = 0; j < 4; j++){
vv.push({x:widthX[i], y: heightY[j], z:0});
}
}
let vertices_data = [];
for(let m = 0; m < 3; m++){
for(let n = 0; n < 3; n++){
vertices_data.push(vv[4 * m + n].x, vv[4 * m + n].y, vv[4 * m + n].z);
vertices_data.push(vv[4 * (m + 1) + n + 1].x, vv[4 * (m + 1) + n + 1].y, vv[4 * (m + 1) + n + 1].z);
vertices_data.push(vv[4 * m + n + 1].x, vv[4 * m + n + 1].y, vv[4 * m + n + 1].z);
vertices_data.push(vv[4 * m + n].x, vv[4 * m + n].y, vv[4 * m + n].z);
vertices_data.push(vv[4 * (m + 1) + n].x, vv[4 * (m + 1) + n].y, vv[4 * (m + 1) + n].z);
vertices_data.push(vv[4 * (m + 1) + n + 1].x, vv[4 * (m + 1) + n + 1].y, vv[4 * (m + 1) + n + 1].z);
}
}
//九宫格的uv坐标
let u = [0, 0.25, 0.75, 1.0];
let v = [0, 0.25, 0.75, 1.0];
let uv = [];
for(let i = 0; i < 4; i++){
for(let j = 0; j < 4; j++){
uv.push({u: u[i], v: v[j]});
}
}
let uvs_data = [];
for(let m = 0; m < 3; m++){
for(let n = 0; n < 3; n++){
uvs_data.push(uv[4 * m + n].u, uv[4 * m + n].v);
uvs_data.push(uv[4 * (m + 1) + n + 1].u, uv[4 * (m + 1) + n + 1].v);
uvs_data.push(uv[4 * m + n + 1].u, uv[4 * m + n + 1].v);
uvs_data.push(uv[4 * m + n].u, uv[4 *m + n].v);
uvs_data.push(uv[4 * (m + 1) + n].u, uv[4 * (m + 1) + n].v);
uvs_data.push(uv[4 * (m + 1) + n + 1].u, uv[4 * (m + 1) + n + 1].v);
}
}
var geometry = new THREE.BufferGeometry();
var uvs = new Float32Array( uvs_data );
var vertices = new Float32Array( vertices_data );
geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
mesh = new THREE.Mesh( geometry, new THREE.ShaderMaterial( {
uniforms: {
uPos: {value: new THREE.Vector3(0)},
uSize: {value: new THREE.Vector2(window.innerWidth, window.innerHeight)},
uSizeAttenuation: {value: 0}, //根据距离衰减
uColor: {value: new THREE.Vector4(0.2,0.8,0.2,1)},
uMap: { value: textureLoader.load( 'erpanqushuibengfang/test.png' )},
},
vertexShader: `
uniform vec3 uPos;
uniform vec2 uSize;
uniform int uSizeAttenuation;
varying vec2 vUv;
void main() {
vUv = uv;
vec4 mvPosition = modelViewMatrix * vec4( uPos, 1.0 );
vec4 screenpos = projectionMatrix * mvPosition;
if(uSizeAttenuation == 1){
vec3 v = vec3(position.x, position.y, 0);
screenpos += vec4(v, 0);
} else {
vec3 v = vec3(position.x / uSize.x, position.y / uSize.y, 0);
screenpos += vec4(v * screenpos.w, 0);
}
gl_Position = screenpos;
}`,
fragmentShader: `
uniform vec4 uColor;
uniform sampler2D uMap;
varying vec2 vUv;
void main() {
vec2 uv = vec2(vUv.x, vUv.y);
gl_FragColor = texture2D( uMap, uv) * uColor;
//gl_FragColor = vec4(1.0);
}`//,
//wireframe:true
}) );
mesh.onBeforeRender = function ( renderer) {
var size = renderer.getDrawingBufferSize( new THREE.Vector2() );
this.material.uniforms.uSize.value = size;
};
mesh.receiveShadow = false;
mesh.castShadow = false;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
var delta = clock.getDelta();
//mesh_cube.translateX(delta);
renderer.render( scene, camera );
stats.update();
}
</script>
</body>
</html>
原图:
效果:
具体应用: