Interior Mapping shader self shadowing

three.jsGlslWebglShadowRaytracing

three.js Problem Overview


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: [email protected]
	// 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;	

}

three.js Solutions


Solution 1 - three.js

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshaderologyView Question on Stackoverflow
Solution 1 - three.jslcmylinView Answer on Stackoverflow