How to get direction towards camera from vertex? (in a vertex shader, glsl) - three.js

I have this code:
vec4 localPosition = vec4( position, 1.);
vec4 worldPosition = modelMatrix * localPosition;
vec3 look = normalize( vec3(cameraPosition) - vec3(worldPosition) );
vec3 transformed = vec3( position ) + look;
But for some reason, it just moves the vertex 1 unit towards the origin point in the scene (0,0,0).
I need it to move the vertex towards the camera(where you are viewing the scene from).
I can't seem to find clear information anywhere on how to accomplish this.

It was a three.js issue.. Had to set the isShaderMaterial = true, in order to get the cameraPosition to update. o_o
material.isShaderMaterial = true; //We need to set this so that the cameraPosition uniform is updated in the shader
material.onBeforeCompile = function ( shader ) {
shader.vertexShader = shader.vertexShader.replace(
'#include <begin_vertex>',
[
'float myOffset = 0.0;',
'myOffset = (vColor.r + vColor.g + vColor.b) < 3.0 ? 0.01 : 0.0;',
'vec4 localPosition = vec4( position, 1.);',
'vec4 worldPosition = modelMatrix * localPosition;',
'vec3 look = myOffset * normalize( cameraPosition - vec3(worldPosition) );',
'vec3 transformed = vec3( position ) + look;'
].join( '\n' )
);
material.userData.shader = shader;
};

if you have a view matrix, transform the vertex position to view coordinate and then you can do transformation according to the camera axis.

Related

Changing fresnel falloff on ThreeJS shader

I've been making use of this shader inside of my ThreeJS project, except I've more or less copied the code verbatim because I have no idea how to write a shader function. Basically I want to edit the rate of falloff on the fresnel effect so that it's only really the edges that are using the colour with a slight glow coming inside
var material = THREE.extendMaterial(THREE.MeshStandardMaterial, {
// Will be prepended to vertex and fragment code
header: 'varying vec3 vNN; varying vec3 vEye;',
fragmentHeader: 'uniform vec3 fresnelColor;',
// Insert code lines by hinting at a existing
vertex: {
// Inserts the line after #include <fog_vertex>
'#include <fog_vertex>': `
mat4 LM = modelMatrix;
LM[2][3] = 0.0;
LM[3][0] = 0.0;
LM[3][1] = 0.0;
LM[3][2] = 0.0;
vec4 GN = LM * vec4(objectNormal.xyz, 1.0);
vNN = normalize(GN.xyz);
vEye = normalize(GN.xyz-cameraPosition);`
},
fragment: {
'gl_FragColor = vec4( outgoingLight, diffuseColor.a );' :
`gl_FragColor.rgb += ( 1.0 - -min(dot(vEye, normalize(vNN) ), 0.0) ) * fresnelColor;`
},
// Uniforms (will be applied to existing or added)
uniforms: {
diffuse: new THREE.Color( 'black' ),
fresnelColor: new THREE.Color( 'blue' )
}
});
I've tried changing the number in this line gl_FragColor.rgb += ( **1.0** - -min(dot(vEye, normalize(vNN) ), 0.0) ) * fresnelColor; and whilst that did stop the gradient of the fresnel, it was a hard stop, as though it was limiting levels instead of the rate of gradient.
I just need help with how I can make the fall off not as far into my models so that it's only really the edges that have it
Maybe this will help:
fragment: {
'gl_FragColor = vec4( outgoingLight, diffuseColor.a );' : `
float m = ( 1.0 - -min(dot(vEye, normalize(vNN)), 0.0) );
m = pow(m, 8.); // the greater the second parameter, the thinner effect you get
gl_FragColor.rgb += m * fresnelColor;
`

ThreeJS Shader Dynamic Texture

I have this shader code below. I want to add a new uniform for another texture and make it that it would be applied to the vertices that is divisible by 4.
uniform vec3 color;
uniform sampler2D texture;
varying vec4 vColor;
void main() {
vec4 outColor = texture2D( texture, gl_PointCoord );
if ( outColor.a < 0.5 ) discard;
gl_FragColor = outColor * vec4( color * vColor.xyz, 0.5 );
float depth = gl_FragCoord.z / gl_FragCoord.w;
const vec3 fogColor = vec3( 0.0 );
float fogFactor = smoothstep( 200.0, 600.0, depth );
gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
}
I want to add a condition something like index % 4 === 0 ? firstTexture : secondTexture but I do not know how to get the vertex index and perform a modulo operator in the shader language.
WebGL GLSL does not provide a vertex index, so you'll have to provide that data manually. For more information, see this question.
The modulus operator in GLSL is a function called mod().

Convert ndc coordinates to world coordinates in fragment shader threejs

My goal is to draw a circle around my mouse cursor over a plane.
I get NDC coordinates (-1 to +1) that represent my cursor position:
const rect = targetHTML.getBoundingClientRect();
const mousePositionX = event.clientX - rect.left;
const mousePositionY = event.clientY - rect.top;
this._currentPoint = {
x: (mousePositionX / targetHTML.clientWidth * 2 - 1),
y: (mousePositionY / targetHTML.clientHeight * -2 + 1),
};
I pass it to my fragment shader via uniforms:
this._cursorMaterial.uniforms.uBrushPosition.value =
new window.THREE.Vector2(this._currentPoint.x, this._currentPoint.y);
In my fragment shader, I want to convert it to a world coordinate in order to compare it to the fragment world location.
// vertex shader
varying vec4 vPos;
void main() {
vPos = modelMatrix * vec4(position, 1.0 );
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
}
// fragment shader
varying vec4 vPos;
uniform vec2 uBrushPosition;
void main() {
// convert uBrush position to world space
// uBrushPosition
vec3 brushWorldPosition = ?
//
if (distance(brushWorldPosition, vpos) < 10.) {
gl_FragColor = vec4(1., 0., 0., .5);
}
discard;
Not in the shader, but you can send it in as a uniform.
var mouseWorld = new THREE.Vector3( mouse.x, mouse.y, distanceFromCamera )
mouseWorld.unproject( camera )

Custom Phong Shader for THREE.JS Object

Goal: Calculate normals in the vertex shader for displaced vertices.
Current State: Some hacky code that I don't believe is 100% correct.
--- progress ---
vert is the modified position of the vertex
vertNormal is the modified position of the vertex applied to the normals ( basically a clone )
vec3 objectNormal = normalize(cross(vert-position,vertNormal-position));
vec3 transformedNormal = normalMatrix * objectNormal;
vNormal = normalize( transformedNormal );
http://fallingcode.com/servedFiles/normals.jpg
I just need some feedback about that part of the vertex shader code at this point.
After #WestLangley's help, I've reached my goal. The waves in the image are just to show the result. I'll have to research equations to make them more natural looking.
So, the normals are being calculated correctly and the environment reflection (a THREE.JS cubemap) is working correctly too.
http://www.fallingcode.com/servedFiles/calculatedNormals.jpg
The following code in the vertex shader is what calculates the normals after vertices have been moved along the normal (the z axis in this case).
// the displacement function
float displace( vec3 pos ) {
float amplitude;
amplitude = sin( pos.y + time ) * 0.1;
return amplitude;
}
float df = displace( position );
vec3 displacedPosition = position + normalize( normal ) * df;
float delta = 0.01;
vec3 newNormal = vec3( df - displace( position + vec3( delta, 0, 0 ) ), df - displace( position + vec3( 0, delta, 0 ) ), delta );
newNormal = normalize( newNormal );
vNormal = normalize( normalMatrix * newNormal );

Interior Mapping shader self shadowing

I'm tinkering with Joost van Dongen's Interior mapping shader and I'm trying to implement self-shadowing. Still I couldn't quite figure out what coordinates shadow casting light vectors need to be in. You can see somewhat working demo at here I've attached the light position with an offset to the camera position just to see whats happening but obviously it doesn't look right either.
Shader code is below. Look for SHADOWS DEV in fragment shader. Vectors in question are: shad_E and shad_I.
vertex shader:
varying vec3 oP; // surface position in object space
varying vec3 oE; // position of the eye in object space
varying vec3 oI; // incident ray direction in object space
varying vec3 shad_E; // shadow light position
varying vec3 shad_I; // shadow direction
uniform vec3 lightPosition;
void main() {
// inverse veiw matrix
mat4 modelViewMatrixInverse = InverseMatrix( modelViewMatrix );
// surface position in object space
oP = position;
// position of the eye in object space
oE = modelViewMatrixInverse[3].xyz;
// incident ray direction in object space
oI = oP - oE;
// link the light position to camera for testing
// need to find a way for world space directional light to work
shad_E = oE - lightPosition;
// light vector
shad_I = oP - shad_E;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
fragment shader:
varying vec3 oP; // surface position in object space
varying vec3 oE; // position of the eye in object space
varying vec3 oI; // incident ray direction in object space
varying vec3 shad_E; // shadow light position
varying vec3 shad_I; // shadow direction
uniform vec3 wallFreq;
uniform float wallsBias;
uniform vec3 wallCeilingColor;
uniform vec3 wallFloorColor;
uniform vec3 wallXYColor;
uniform vec3 wallZYColor;
float checker(vec2 uv, float checkSize) {
float fmodResult = mod( floor(checkSize * uv.x) + floor(checkSize * uv.y), 2.0);
if (fmodResult < 1.0) {
return 1.0;
} else {
return 0.85;
}
}
void main() {
// INTERIOR MAPPING by Joost van Dongen
// http://interiormapping.oogst3d.net/
// email: joost#ronimo-games.com
// Twitter: #JoostDevBlog
vec3 wallFrequencies = wallFreq / 2.0 - wallsBias;
//calculate wall locations
vec3 walls = ( floor( oP * wallFrequencies) + step( vec3( 0.0 ), oI )) / wallFrequencies;
//how much of the ray is needed to get from the oE to each of the walls
vec3 rayFractions = ( walls - oE) / oI;
//texture-coordinates of intersections
vec2 intersectionXY = (oE + rayFractions.z * oI).xy;
vec2 intersectionXZ = (oE + rayFractions.y * oI).xz;
vec2 intersectionZY = (oE + rayFractions.x * oI).zy;
//use the intersection as the texture coordinates for the ceiling
vec3 ceilingColour = wallCeilingColor * checker( intersectionXZ, 2.0 );
vec3 floorColour = wallFloorColor * checker( intersectionXZ, 2.0 );
vec3 verticalColour = mix(floorColour, ceilingColour, step(0.0, oI.y));
vec3 wallXYColour = wallXYColor * checker( intersectionXY, 2.0 );
vec3 wallZYColour = wallZYColor * checker( intersectionZY, 2.0 );
// SHADOWS DEV // SHADOWS DEV // SHADOWS DEV // SHADOWS DEV //
vec3 shad_P = oP; // just surface position in object space
vec3 shad_walls = ( floor( shad_P * wallFrequencies) + step( vec3( 0.0 ), shad_I )) / wallFrequencies;
vec3 shad_rayFr = ( shad_walls - shad_E ) / shad_I;
// Cast shadow from ceiling planes (intersectionXZ)
wallZYColour *= mix( 0.3, 1.0, step( shad_rayFr.x, shad_rayFr.y ));
verticalColour *= mix( 0.3, 1.0, step( rayFractions.y, shad_rayFr.y ));
wallXYColour *= mix( 0.3, 1.0, step( shad_rayFr.z, shad_rayFr.y ));
// SHADOWS DEV // SHADOWS DEV // SHADOWS DEV // SHADOWS DEV //
// intersect walls
float xVSz = step(rayFractions.x, rayFractions.z);
vec3 interiorColour = mix(wallXYColour, wallZYColour, xVSz);
float rayFraction_xVSz = mix(rayFractions.z, rayFractions.x, xVSz);
float xzVSy = step(rayFraction_xVSz, rayFractions.y);
interiorColour = mix(verticalColour, interiorColour, xzVSy);
gl_FragColor.xyz = interiorColour;
}
Based on my very limited understanding of what you're trying to implement, it seems you would need to take the location of the intersection between the eye vector and the interior plane it hits, then trace it back to the light.
To trace back to the light, you would first have to check if the interior plane intersected by the eye vector is back-facing from the light's perspective, which would make it in shadow. If it's front-facing then you have to ray cast from within the room to the light and check for an intersection with any of the other interior planes.

Resources