提交 dd9229b1 编写于 作者: W WestLangley

Added linewidth support

上级 93e740b8
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.Line2 = function ( geometry, material ) {
THREE.LineSegments2.call( this );
this.type = 'Line2';
this.geometry = geometry !== undefined ? geometry : new THREE.LineGeometry();
this.material = material !== undefined ? material : new THREE.LineMaterial( { color: Math.random() * 0xffffff } );
};
THREE.Line2.prototype = Object.assign( Object.create( THREE.LineSegments2.prototype ), {
constructor: THREE.Line2,
isLine2: true,
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.LineGeometry = function () {
THREE.LineSegmentsGeometry.call( this );
this.type = 'LineGeometry';
};
THREE.LineGeometry.prototype = Object.assign( Object.create( THREE.LineSegmentsGeometry.prototype ), {
constructor: THREE.LineGeometry,
isLineGeometry: true,
setPositions: function ( array ) {
// converts [ x1, y1, z1, x2, y2, z2, ... ] to pairs format
var length = array.length - 3;
var points = new Float32Array( 2 * length );
for ( var i = 0; i < length; i += 3 ) {
points[ 2 * i ] = array[ i ];
points[ 2 * i + 1 ] = array[ i + 1 ];
points[ 2 * i + 2 ] = array[ i + 2 ];
points[ 2 * i + 3 ] = array[ i + 3 ];
points[ 2 * i + 4 ] = array[ i + 4 ];
points[ 2 * i + 5 ] = array[ i + 5 ];
}
THREE.LineSegmentsGeometry.prototype.setPositions.call( this, points );
return this;
},
setColors: function ( array ) {
// converts [ r1, g1, b1, r2, g2, b2, ... ] to pairs format
var length = array.length - 3;
var colors = new Float32Array( 2 * length );
for ( var i = 0; i < length; i += 3 ) {
colors[ 2 * i ] = array[ i ];
colors[ 2 * i + 1 ] = array[ i + 1 ];
colors[ 2 * i + 2 ] = array[ i + 2 ];
colors[ 2 * i + 3 ] = array[ i + 3 ];
colors[ 2 * i + 4 ] = array[ i + 4 ];
colors[ 2 * i + 5 ] = array[ i + 5 ];
}
THREE.LineSegmentsGeometry.prototype.setColors.call( this, colors );
return this;
},
fromLine: function ( line ) {
var geometry = line.geometry;
if ( geometry.isGeometry ) {
this.setPositions( geometry.vertices );
} else if ( geometry.isBufferGeometry ) {
this.setPositions( geometry.position.array ); // assumes non-indexed
}
// set colors, maybe
return this;
},
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
* parameters = {
* color: <hex>,
* linewidth: <float>,
* resolution: <Vector2>, // to be set by renderer
* }
*/
THREE.UniformsLib.line = {
linewidth: { value: 1 },
resolution: { value: new THREE.Vector2( 1, 1 ) }
};
THREE.ShaderLib[ 'line' ] = {
uniforms: THREE.UniformsUtils.merge( [
THREE.UniformsLib.common,
THREE.UniformsLib.fog,
THREE.UniformsLib.line
] ),
vertexShader:
`
#include <common>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
uniform float linewidth;
uniform vec2 resolution;
attribute vec3 instanceStart;
attribute vec3 instanceEnd;
attribute vec3 instanceColorStart;
attribute vec3 instanceColorEnd;
varying vec2 vUv;
void main() {
#ifdef USE_COLOR
vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd;
#endif
float aspect = resolution.x / resolution.y;
vUv = uv;
// camera space
vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 );
vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 );
// clip space
vec4 clipStart = projectionMatrix * start;
vec4 clipEnd = projectionMatrix * end;
// ndc space
vec2 ndcStart = clipStart.xy / clipStart.w;
vec2 ndcEnd = clipEnd.xy / clipEnd.w;
// direction
vec2 dir = ndcEnd - ndcStart;
// account for clip-space aspect ratio
dir.x *= aspect;
dir = normalize( dir );
// perpendicular to dir
vec2 offset = vec2( dir.y, - dir.x );
// undo aspect ratio adjustment
dir.x /= aspect;
offset.x /= aspect;
// sign flip
if ( position.x < 0.0 ) offset *= - 1.0;
// endcaps
if ( position.y < 0.0 ) {
offset += - dir;
} else if ( position.y > 1.0 ) {
offset += dir;
}
// adjust for linewidth
offset *= linewidth;
// adjust for clip-space to screen-space conversion // maybe it should be based on viewport ...
offset /= resolution.y;
// select end
vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd;
// back to clip space
offset *= clip.w;
clip.xy += offset;
gl_Position = clip;
#include <logdepthbuf_vertex>
#include <worldpos_vertex>
#include <clipping_planes_vertex>
#include <fog_vertex>
}
`,
fragmentShader:
`
uniform vec3 diffuse;
uniform float opacity;
#include <common>
#include <color_pars_fragment>
#include <fog_pars_fragment>
#include <logdepthbuf_pars_fragment>
#include <clipping_planes_pars_fragment>
varying vec2 vUv;
void main() {
#include <clipping_planes_fragment>
if ( vUv.y < 0.5 || vUv.y > 0.5 ) {
float a = vUv.x - 0.5;
float b = vUv.y - 0.5;
float len2 = a * a + b * b;
if ( len2 > 0.25 ) discard;
}
vec4 diffuseColor = vec4( diffuse, opacity );
#include <logdepthbuf_fragment>
#include <color_fragment>
gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a );
#include <premultiplied_alpha_fragment>
#include <tonemapping_fragment>
#include <encodings_fragment>
#include <fog_fragment>
}
`
};
THREE.LineMaterial = function ( parameters ) {
THREE.ShaderMaterial.call( this, {
type: 'LineMaterial',
side: THREE.DoubleSide, // for now. there is an issue with segments that terminate behind the camera
uniforms: THREE.UniformsUtils.clone( THREE.ShaderLib[ 'line' ].uniforms ),
vertexShader: THREE.ShaderLib[ 'line' ].vertexShader,
fragmentShader: THREE.ShaderLib[ 'line' ].fragmentShader
} );
Object.defineProperties( this, {
color: {
enumerable: true,
get: function () {
return this.uniforms.diffuse.value;
},
set: function ( value ) {
this.uniforms.diffuse.value = value;
}
},
linewidth: {
enumerable: true,
get: function () {
return this.uniforms.linewidth.value;
},
set: function ( value ) {
this.uniforms.linewidth.value = value;
}
},
resolution: {
enumerable: true,
get: function () {
return this.uniforms.resolution.value;
},
set: function ( value ) {
this.uniforms.resolution.value.copy( value );
}
}
} );
this.setValues( parameters );
};
THREE.LineMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
THREE.LineMaterial.prototype.constructor = THREE.LineMaterial;
THREE.LineMaterial.prototype.isLineMaterial = true;
THREE.LineMaterial.prototype.copy = function ( source ) {
THREE.ShaderMaterial.prototype.copy.call( this, source );
this.color.copy( source.color );
this.linewidth = source.linewidth;
this.resolution = source.resolution;
// todo
return this;
};
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.LineSegments2 = function ( geometry, material ) {
THREE.Mesh.call( this );
this.type = 'LineSegments2';
this.geometry = geometry !== undefined ? geometry : new THREE.LineSegmentsGeometry();
this.material = material !== undefined ? material : new THREE.LineMaterial( { color: Math.random() * 0xffffff } );
};
THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototype ), {
constructor: THREE.LineSegments2,
isLineSegments2: true,
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.LineSegmentsGeometry = function () {
THREE.InstancedBufferGeometry.call( this );
this.type = 'LineSegmentsGeometry';
var plane = new THREE.BufferGeometry();
var positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
var uvs = [ 0, 1, 1, 1, 0, .5, 1, .5, 0, .5, 1, .5, 0, 0, 1, 0 ];
var index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
this.setIndex( index );
this.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
this.addAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
};
THREE.LineSegmentsGeometry.prototype = Object.assign( Object.create( THREE.InstancedBufferGeometry.prototype ), {
constructor: THREE.LineSegmentsGeometry,
isLineSegmentsGeometry: true,
setPositions: function ( array ) {
var lineSegments;
if ( array instanceof Float32Array ) {
lineSegments = array;
} else if ( Array.isArray( array ) ) {
lineSegments = new Float32Array( array );
}
var instanceBuffer = new THREE.InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz
this.addAttribute( 'instanceStart', new THREE.InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
this.addAttribute( 'instanceEnd', new THREE.InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
//
this.computeBoundingBox();
this.computeBoundingSphere();
return this;
},
setColors: function ( array ) {
var colors;
if ( array instanceof Float32Array ) {
colors = array;
} else if ( Array.isArray( array ) ) {
colors = new Float32Array( array );
}
var instanceColorBuffer = new THREE.InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb
this.addAttribute( 'instanceColorStart', new THREE.InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb
this.addAttribute( 'instanceColorEnd', new THREE.InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb
return this;
},
fromWireframeGeometry: function ( geometry ) {
this.setPositions( geometry.attributes.position.array );
return this;
},
fromEdgesGeometry: function ( geometry ) {
this.setPositions( geometry.attributes.position.array );
return this;
},
fromMesh: function ( mesh ) {
this.fromWireframeGeometry( new THREE.WireframeGeometry( mesh.geometry ) );
// set colors, maybe
return this;
},
fromLineSegements: function ( lineSegments ) {
var geometry = lineSegments.geometry;
if ( geometry.isGeometry ) {
this.setPositions( geometry.vertices );
} else if ( geometry.isBufferGeometry ) {
this.setPositions( geometry.position.array ); // assumes non-indexed
}
// set colors, maybe
return this;
},
computeBoundingBox: function () {
if ( this.boundingBox === null ) {
this.boundingBox = new THREE.Box3();
}
if ( this.attributes.instanceStart !== undefined ) {
this.boundingBox.setFromBufferAttribute( this.attributes.instanceStart );
var box = new THREE.Box3().setFromBufferAttribute( this.attributes.instanceEnd );
this.boundingBox.union( box );
}
},
computeBoundingSphere: function () {
var vector = new THREE.Vector3();
return function computeBoundingSphere() {
if ( this.boundingSphere === null ) {
this.boundingSphere = new THREE.Sphere();
}
if ( this.boundingBox === null ) {
this.computeBoundingBox();
}
var start = this.attributes.instanceStart;
var end = this.attributes.instanceEnd;
if ( start && end ) {
var center = this.boundingSphere.center;
this.boundingBox.getCenter( center );
var maxRadiusSq = 0;
for ( var i = 0, il = start.count; i < il; i ++ ) {
vector.fromBufferAttribute( start, i );
maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
vector.fromBufferAttribute( end, i );
maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
}
this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
if ( isNaN( this.boundingSphere.radius ) ) {
console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this );
}
}
};
}(),
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.Wireframe = function ( geometry, material ) {
THREE.Mesh.call( this );
this.type = 'Wireframe';
this.geometry = geometry !== undefined ? geometry : new THREE.LineSegmentsGeometry();
this.material = material !== undefined ? material : new THREE.LineMaterial( { color: Math.random() * 0xffffff } );
};
THREE.Wireframe.prototype = Object.assign( Object.create( THREE.Mesh.prototype ), {
constructor: THREE.Wireframe,
isWireframe: true,
copy: function ( source ) {
// todo
return this;
}
} );
/**
* @author WestLangley / http://github.com/WestLangley
*
*/
THREE.WireframeGeometry2 = function ( geometry ) {
THREE.LineSegmentsGeometry.call( this );
this.type = 'WireframeGeometry2';
this.fromWireframeGeometry( new THREE.WireframeGeometry( geometry ) );
// set colors, maybe
};
THREE.WireframeGeometry2.prototype = Object.assign( Object.create( THREE.LineSegmentsGeometry.prototype ), {
constructor: THREE.WireframeGeometry2,
isWireframeGeometry2: true,
copy: function ( source ) {
// todo
return this;
}
} );
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - lines - fat</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 {
background-color: #000;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
color: #ffffff;
top: 0px;
width: 100%;
padding: 5px;
font-family:Monospace;
font-size:13px;
text-align:center;
}
a {
color: #fff;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info"><a href="https://threejs.org" target="_blank">three.js</a> - fat lines</div>
<script src="../build/three.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/geometries/hilbert3D.js"></script>
<script src="js/Detector.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src='js/libs/dat.gui.min.js'></script>
<script src='js/lines/LineSegmentsGeometry.js'></script>
<script src='js/lines/LineGeometry.js'></script>
<script src='js/lines/WireframeGeometry2.js'></script>
<script src='js/lines/LineMaterial.js'></script>
<script src='js/lines/LineSegments2.js'></script>
<script src='js/lines/Line2.js'></script>
<script src='js/lines/Wireframe.js'></script>
<script>
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
var line, wireframe, renderer, scene, camera, controls;
var line1, wireframe1;
var renderStats;
var gui;
// viewport
var insetWidth;
var insetHeight;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setClearColor( 0x000000, 0.0 );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( -40, 0, 60 );
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.minDistance = 10;
controls.maxDistance = 500;
// Position and Color Data
var positions = [];
var colors = [];
var points = hilbert3D( new THREE.Vector3( 0, 0, 0 ), 20.0, 1, 0, 1, 2, 3, 4, 5, 6, 7 );
var spline = new THREE.CatmullRomCurve3( points );
var divisions = Math.round( 12 * points.length );
var color = new THREE.Color();
for ( var i = 0, l = divisions; i < l; i ++ ) {
var point = spline.getPoint( i / l );
positions.push( point.x, point.y, point.z );
color.setHSL( i / l, 1.0, 0.5 );
colors.push( color.r, color.g, color.b );
}
// THREE.Line2 ( LineGeometry, LineMaterial )
var geometry = new THREE.LineGeometry();
geometry.setPositions( positions );
geometry.setColors( colors );
var material = new THREE.LineMaterial( {
color: 0xffffff,
linewidth: 10, // in pixels
vertexColors: THREE.VertexColors,
//resolution: // to be set by renderer, eventually
} );
line = new THREE.Line2( geometry, material );
line.scale.set( 1, 1, 1 );
scene.add( line );
// THREE.Line ( BufferGeometry, LineBasicMaterial ) - rendered with gl.LINE_STRIP
var geo = new THREE.BufferGeometry();
geo.addAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
geo.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
var mat = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
line1 = new THREE.Line( geo, mat );
line1.visible = false;
scene.add( line1 );
// THREE.Wireframe ( WireframeGeometry2, LineMaterial )
//var geo = new THREE.BoxBufferGeometry( 16, 16, 4, 2, 2, 1 );
//var geo = new THREE.IcosahedronBufferGeometry( 8, 0 );
var geo = new THREE.PlaneBufferGeometry( 16, 16, 2, 2 );
var geometry = new THREE.WireframeGeometry2( geo );
var material = new THREE.LineMaterial( {
color: 0x4080ff,
linewidth: 10, // in pixels
//resolution: // to be set by renderer, eventually
} );
wireframe = new THREE.Wireframe( geometry, material );
wireframe.scale.set( 1, 1, 1 );
scene.add( wireframe );
// THREE.Line ( WireframeGeometry, LineBasicMaterial ) - rendered with gl.LINE
geo = new THREE.WireframeGeometry( geo );
var mat = new THREE.LineBasicMaterial( { color: 0x4080ff } );
wireframe1 = new THREE.LineSegments( geo, mat );
wireframe1.visible = false;
scene.add( wireframe1 );
//
window.addEventListener( 'resize', onWindowResize, false );
onWindowResize();
stats = new Stats();
document.body.appendChild( stats.dom );
initGui();
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
insetWidth = window.innerWidth / 4;
insetHeight = window.innerHeight / 4;
}
function animate() {
requestAnimationFrame( animate );
stats.update();
wireframe.geometry.maxInstancedCount = Math.floor( Date.now() / 1000 ) % wireframe.geometry.index.count - 1; // why - 1 needed ?
// main scene
// renderer will set this eventually
line.material.resolution.set( window.innerWidth, window.innerHeight );
wireframe.material.resolution.set( window.innerWidth, window.innerHeight );
renderer.setViewport( 0, 0, window.innerWidth, window.innerHeight );
renderer.render( scene, camera );
// inset scene
// renderer will set this eventually
//line.material.resolution.set( insetWidth, insetHeight );
//wireframe.material.resolution.set( insetWidth, insetHeight );
renderer.clearDepth(); // important!
renderer.setScissorTest( true );
renderer.setScissor( 20, 20, insetWidth, insetHeight );
renderer.setViewport( 20, 20, insetWidth, insetHeight );
renderer.render( scene, camera );
renderer.setScissorTest( false );
}
//
function initGui() {
gui = new dat.GUI();
var param = {
'line type': 0,
'line width': 10
};
gui.add( param, 'line type', { 'LineGeometry': 0, 'gl.LINE': 1 } ).onChange( function ( val ) {
switch ( val ) {
case '0':
line.visible = true;
wireframe.visible = true;
line1.visible = false;
wireframe1.visible = false;
break;
case '1':
line.visible = false;
wireframe.visible = false;
line1.visible = true;
wireframe1.visible = true;
break;
}
} );
gui.add( param, 'line width', 1, 40, 1 ).onChange( function ( val ) {
line.material.linewidth = val;
wireframe.material.linewidth = val;
} );
}
</script>
</body>
</html>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册