Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions examples/jsm/misc/RollerCoaster.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ class RollerCoasterGeometry extends BufferGeometry {

const offset = new Vector3();

const sample1 = new Vector3();
const sample2 = new Vector3();
const rollQuaternion = new Quaternion();

for ( let i = 1; i <= divisions; i ++ ) {

point.copy( curve.getPointAt( i / divisions ) );
Expand All @@ -209,6 +213,20 @@ class RollerCoasterGeometry extends BufferGeometry {

quaternion.setFromAxisAngle( up, angle );

// banking

const bankDelta = 0.01;
const t = i / divisions;

sample1.copy( curve.getTangentAt( ( ( t - bankDelta ) % 1 + 1 ) % 1 ) );
sample2.copy( curve.getTangentAt( ( t + bankDelta ) % 1 ) );

let headingChange = Math.atan2( sample2.x, sample2.z ) - Math.atan2( sample1.x, sample1.z );
if ( headingChange > Math.PI ) headingChange -= Math.PI * 2;
if ( headingChange < -Math.PI ) headingChange += Math.PI * 2;

quaternion.premultiply( rollQuaternion.setFromAxisAngle( forward, - Math.atan( headingChange * 8 ) * 0.5 ) );

if ( i % 2 === 0 ) {

drawShape( step, color2 );
Expand Down Expand Up @@ -356,6 +374,11 @@ class RollerCoasterLiftersGeometry extends BufferGeometry {
const fromPoint = new Vector3();
const toPoint = new Vector3();

const sample1 = new Vector3();
const sample2 = new Vector3();
const bankedQuaternion = new Quaternion();
const rollQuaternion = new Quaternion();

for ( let i = 1; i <= divisions; i ++ ) {

point.copy( curve.getPointAt( i / divisions ) );
Expand All @@ -365,6 +388,22 @@ class RollerCoasterLiftersGeometry extends BufferGeometry {

quaternion.setFromAxisAngle( up, angle );

// banking

const bankDelta = 0.01;
const t = i / divisions;

sample1.copy( curve.getTangentAt( ( ( t - bankDelta ) % 1 + 1 ) % 1 ) );
sample2.copy( curve.getTangentAt( ( t + bankDelta ) % 1 ) );

let headingChange = Math.atan2( sample2.x, sample2.z ) - Math.atan2( sample1.x, sample1.z );
if ( headingChange > Math.PI ) headingChange -= Math.PI * 2;
if ( headingChange < -Math.PI ) headingChange += Math.PI * 2;

bankedQuaternion.copy( quaternion );
rollQuaternion.setFromAxisAngle( tangent, - Math.atan( headingChange * 8 ) * 0.5 );
bankedQuaternion.premultiply( rollQuaternion );

//

if ( point.y > 10 ) {
Expand Down Expand Up @@ -402,12 +441,11 @@ class RollerCoasterLiftersGeometry extends BufferGeometry {
} else {

fromPoint.set( 0, - 0.2, 0 );
fromPoint.applyQuaternion( quaternion );
fromPoint.applyQuaternion( bankedQuaternion );
fromPoint.add( point );

toPoint.set( 0, - point.y, 0 );
toPoint.applyQuaternion( quaternion );
toPoint.add( point );
toPoint.copy( fromPoint );
toPoint.y = 0;

extrudeShape( tube3, fromPoint, toPoint );

Expand Down
Binary file modified examples/screenshots/webgpu_xr_rollercoaster.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/screenshots/webxr_vr_rollercoaster.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed examples/textures/memorial.png
Binary file not shown.
21 changes: 21 additions & 0 deletions examples/webgpu_xr_rollercoaster.html
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@

const lookAt = new THREE.Vector3();

const tangent1 = new THREE.Vector3();
const tangent2 = new THREE.Vector3();
const bankQuaternion = new THREE.Quaternion();

let velocity = 0;
let progress = 0;

Expand Down Expand Up @@ -235,6 +239,23 @@
velocity -= tangent.y * 0.0000001 * delta;
velocity = Math.max( 0.00004, Math.min( 0.0002, velocity ) );

// banking

const bankDelta = 0.01;
const t1 = ( ( progress - bankDelta ) % 1 + 1 ) % 1;
const t2 = ( progress + bankDelta ) % 1;

tangent1.copy( curve.getTangentAt( t1 ) );
tangent2.copy( curve.getTangentAt( t2 ) );

let headingChange = Math.atan2( tangent2.x, tangent2.z ) - Math.atan2( tangent1.x, tangent1.z );
if ( headingChange > Math.PI ) headingChange -= Math.PI * 2;
if ( headingChange < -Math.PI ) headingChange += Math.PI * 2;

train.up.set( 0, 1, 0 );
bankQuaternion.setFromAxisAngle( tangent, - Math.atan( headingChange * 8 ) * 0.5 );
train.up.applyQuaternion( bankQuaternion );

train.lookAt( lookAt.copy( position ).sub( tangent ) );

//
Expand Down
21 changes: 21 additions & 0 deletions examples/webxr_vr_rollercoaster.html
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@

const lookAt = new THREE.Vector3();

const tangent1 = new THREE.Vector3();
const tangent2 = new THREE.Vector3();
const bankQuaternion = new THREE.Quaternion();

let velocity = 0;
let progress = 0;

Expand Down Expand Up @@ -234,6 +238,23 @@
velocity -= tangent.y * 0.0000001 * delta;
velocity = Math.max( 0.00004, Math.min( 0.0002, velocity ) );

// banking

const bankDelta = 0.01;
const t1 = ( ( progress - bankDelta ) % 1 + 1 ) % 1;
const t2 = ( progress + bankDelta ) % 1;

tangent1.copy( curve.getTangentAt( t1 ) );
tangent2.copy( curve.getTangentAt( t2 ) );

let headingChange = Math.atan2( tangent2.x, tangent2.z ) - Math.atan2( tangent1.x, tangent1.z );
if ( headingChange > Math.PI ) headingChange -= Math.PI * 2;
if ( headingChange < -Math.PI ) headingChange += Math.PI * 2;

train.up.set( 0, 1, 0 );
bankQuaternion.setFromAxisAngle( tangent, - Math.atan( headingChange * 8 ) * 0.5 );
train.up.applyQuaternion( bankQuaternion );

train.lookAt( lookAt.copy( position ).sub( tangent ) );

//
Expand Down
7 changes: 4 additions & 3 deletions src/math/Plane.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,10 @@ class Plane {
*
* @param {Line3} line - The line to compute the intersection for.
* @param {Vector3} target - The target vector that is used to store the method's result.
* @return {?Vector3} The intersection point.
* @param {boolean} [clampToLine=true] - Whether to clamp the intersection to the line segment.
* @return {?Vector3} The intersection point. Returns `null` if no intersection is detected.
*/
intersectLine( line, target ) {
intersectLine( line, target, clampToLine = true ) {

const direction = line.delta( _vector1 );

Expand All @@ -234,7 +235,7 @@ class Plane {

const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;

if ( t < 0 || t > 1 ) {
if ( ( clampToLine === true ) && ( t < 0 || t > 1 ) ) {

return null;

Expand Down
8 changes: 4 additions & 4 deletions src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -478,23 +478,23 @@ ${ flowData.code }

if ( offsetSnippet ) {

snippet = `texelFetchOffset( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet }, ${ offsetSnippet } )`;
snippet = `texelFetchOffset( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), int( ${ levelSnippet } ), ${ offsetSnippet } )`;

} else {

snippet = `texelFetch( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), ${ levelSnippet } )`;
snippet = `texelFetch( ${ textureProperty }, ivec3( ${ uvIndexSnippet }, ${ depthSnippet } ), int( ${ levelSnippet } ) )`;

}

} else {

if ( offsetSnippet ) {

snippet = `texelFetchOffset( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet }, ${ offsetSnippet } )`;
snippet = `texelFetchOffset( ${ textureProperty }, ${ uvIndexSnippet }, int( ${ levelSnippet } ), ${ offsetSnippet } )`;

} else {

snippet = `texelFetch( ${ textureProperty }, ${ uvIndexSnippet }, ${ levelSnippet } )`;
snippet = `texelFetch( ${ textureProperty }, ${ uvIndexSnippet }, int( ${ levelSnippet } ) )`;

}

Expand Down
11 changes: 11 additions & 0 deletions test/unit/src/math/Plane.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,17 @@ export default QUnit.module( 'Maths', () => {
a.intersectLine( l1, point );
assert.ok( point.equals( new Vector3( 3, 0, 0 ) ), 'Passed!' );

// plane lies outside the segment's endpoints
a = new Plane( new Vector3( 1, 0, 0 ), - 20 );
const l2 = new Line3( new Vector3( - 10, 0, 0 ), new Vector3( 10, 0, 0 ) );

assert.strictEqual( a.intersectLine( l2, point ), null, 'Default clamps to segment and returns null' );
assert.strictEqual( a.intersectLine( l2, point, true ), null, 'Explicit clampToLine=true returns null' );

const result = a.intersectLine( l2, point, false );
assert.ok( result === point, 'clampToLine=false returns the target vector' );
assert.ok( point.equals( new Vector3( 20, 0, 0 ) ), 'clampToLine=false returns infinite-line intersection' );

} );

QUnit.test( 'intersectsBox', ( assert ) => {
Expand Down
Loading