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
26 changes: 25 additions & 1 deletion src/nodes/accessors/Bitangent.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Fn } from '../tsl/TSLCore.js';
import { normalGeometry, normalLocal, normalView, normalWorld } from './Normal.js';
import { tangentGeometry, tangentLocal, tangentView, tangentWorld } from './Tangent.js';
import { bitangentViewFrame } from './TangentUtils.js';
import { directionToFaceDirection } from '../display/FrontFacingNode.js';

/**
* Returns the bitangent node and assigns it to a varying if the material is not flat shaded.
Expand Down Expand Up @@ -47,7 +49,29 @@ export const bitangentLocal = /*@__PURE__*/ getBitangent( normalLocal.cross( tan
* @tsl
* @type {Node<vec3>}
*/
export const bitangentView = getBitangent( normalView.cross( tangentView ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' );
export const bitangentView = /*@__PURE__*/ ( Fn( ( { subBuildFn, geometry, material } ) => {

let node;

if ( subBuildFn === 'VERTEX' || geometry.hasAttribute( 'tangent' ) ) {

node = getBitangent( normalView.cross( tangentView ), 'v_bitangentView' ).normalize();

} else {

node = bitangentViewFrame;

}

if ( material.flatShading !== true ) {

node = directionToFaceDirection( node );

}

return node;

}, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'bitangentView' );

/**
* TSL object that represents the vertex bitangent in world space of the current rendered object.
Expand Down
26 changes: 25 additions & 1 deletion src/nodes/accessors/Tangent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { attribute } from '../core/AttributeNode.js';
import { cameraViewMatrix } from './Camera.js';
import { modelViewMatrix } from './ModelNode.js';
import { Fn, vec4 } from '../tsl/TSLBase.js';
import { tangentViewFrame } from './TangentUtils.js';
import { directionToFaceDirection } from '../display/FrontFacingNode.js';

/**
* TSL object that represents the tangent attribute of the current rendered object.
Expand Down Expand Up @@ -35,7 +37,29 @@ export const tangentLocal = /*@__PURE__*/ tangentGeometry.xyz.toVar( 'tangentLoc
* @tsl
* @type {Node<vec3>}
*/
export const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.toVarying( 'v_tangentView' ).normalize().toVar( 'tangentView' );
export const tangentView = /*@__PURE__*/ ( Fn( ( { subBuildFn, geometry, material } ) => {

let node;

if ( subBuildFn === 'VERTEX' || geometry.hasAttribute( 'tangent' ) ) {

node = modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.toVarying( 'v_tangentView' ).normalize();

} else {

node = tangentViewFrame;

}

if ( material.flatShading !== true ) {

node = directionToFaceDirection( node );

}

return node;

}, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'tangentView' );

/**
* TSL object that represents the vertex tangent in world space of the current rendered object.
Expand Down
46 changes: 46 additions & 0 deletions src/nodes/accessors/TangentUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { uv as getUV } from './UV.js';
import { positionView } from './Position.js';
import { normalView } from './Normal.js';

// Normal Mapping Without Precomputed Tangents
// http://www.thetenthplanet.de/archives/1180

const uv = getUV();

const q0 = positionView.dFdx();
const q1 = positionView.dFdy();
const st0 = uv.dFdx();
const st1 = uv.dFdy();

const N = normalView;

const q1perp = q1.cross( N );
const q0perp = N.cross( q0 );

const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) );
const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) );

const det = T.dot( T ).max( B.dot( B ) );
const scale = det.equal( 0.0 ).select( 0.0, det.inverseSqrt() );

/**
* Tangent vector in view space, computed dynamically from geometry and UV derivatives.
* Useful for normal mapping without precomputed tangents.
*
* Reference: http://www.thetenthplanet.de/archives/1180
*
* @tsl
* @type {Node<vec3>}
*/
export const tangentViewFrame = /*@__PURE__*/ T.mul( scale ).toVar( 'tangentViewFrame' );

/**
* Bitangent vector in view space, computed dynamically from geometry and UV derivatives.
* Complements the tangentViewFrame for constructing the tangent space basis.
*
* Reference: http://www.thetenthplanet.de/archives/1180
*
* @tsl
* @type {Node<vec3>}
*/
export const bitangentViewFrame = /*@__PURE__*/ B.mul( scale ).toVar( 'bitangentViewFrame' );
69 changes: 16 additions & 53 deletions src/nodes/display/NormalMapNode.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,11 @@
import TempNode from '../core/TempNode.js';
import { add } from '../math/OperatorNode.js';

import { normalView, transformNormalToView } from '../accessors/Normal.js';
import { positionView } from '../accessors/Position.js';
import { TBNViewMatrix } from '../accessors/AccessorsUtils.js';
import { uv } from '../accessors/UV.js';
import { faceDirection } from './FrontFacingNode.js';
import { Fn, nodeProxy, vec3 } from '../tsl/TSLBase.js';
import { nodeProxy, vec3 } from '../tsl/TSLBase.js';

import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from '../../constants.js';

// Normal Mapping Without Precomputed Tangents
// http://www.thetenthplanet.de/archives/1180

const perturbNormal2Arb = /*@__PURE__*/ Fn( ( inputs ) => {

const { eye_pos, surf_norm, mapN, uv } = inputs;

const q0 = eye_pos.dFdx();
const q1 = eye_pos.dFdy();
const st0 = uv.dFdx();
const st1 = uv.dFdy();

const N = surf_norm; // normalized

const q1perp = q1.cross( N );
const q0perp = N.cross( q0 );

const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) );
const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) );

const det = T.dot( T ).max( B.dot( B ) );
const scale = faceDirection.mul( det.inverseSqrt() );

return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize();

} );
import { directionToFaceDirection } from './FrontFacingNode.js';

/**
* This class can be used for applying normals maps to materials.
Expand Down Expand Up @@ -89,52 +59,45 @@ class NormalMapNode extends TempNode {

}

setup( builder ) {
setup( { material } ) {

const { normalMapType, scaleNode } = this;

let normalMap = this.node.mul( 2.0 ).sub( 1.0 );

if ( scaleNode !== null ) {

normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z );
let scale = scaleNode;

}

let outputNode = null;
if ( material.flatShading === true ) {

if ( normalMapType === ObjectSpaceNormalMap ) {
scale = directionToFaceDirection( scale );

outputNode = transformNormalToView( normalMap );
}

} else if ( normalMapType === TangentSpaceNormalMap ) {
normalMap = vec3( normalMap.xy.mul( scale ), normalMap.z );

const tangent = builder.hasGeometryAttribute( 'tangent' );
}

if ( tangent === true ) {
let output = null;

outputNode = TBNViewMatrix.mul( normalMap ).normalize();
if ( normalMapType === ObjectSpaceNormalMap ) {

} else {
output = transformNormalToView( normalMap );

outputNode = perturbNormal2Arb( {
eye_pos: positionView,
surf_norm: normalView,
mapN: normalMap,
uv: uv()
} );
} else if ( normalMapType === TangentSpaceNormalMap ) {

}
output = TBNViewMatrix.mul( normalMap ).normalize();

} else {

console.error( `THREE.NodeMaterial: Unsupported normal map type: ${ normalMapType }` );

outputNode = normalView; // Fallback to default normal view
output = normalView; // Fallback to default normal view

}

return outputNode;
return output;

}

Expand Down