Skip to content

Commit

Permalink
Merge pull request #6808 from perminder-17/sphere-Mapping
Browse files Browse the repository at this point in the history
Added a Method (`panorama(img)`) which adds a sphereMapped Background.
  • Loading branch information
davepagurek authored Feb 27, 2024
2 parents 4c13650 + a063911 commit d7b5d58
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 14 deletions.
65 changes: 56 additions & 9 deletions src/webgl/light.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ import p5 from '../core/main';
* @param {p5.Color} color color as a <a href="#/p5.Color">p5.Color</a>
* @chainable
*/
p5.prototype.ambientLight = function(v1, v2, v3, a) {
p5.prototype.ambientLight = function (v1, v2, v3, a) {
this._assert3d('ambientLight');
p5._validateParameters('ambientLight', arguments);
const color = this.color(...arguments);
Expand Down Expand Up @@ -229,7 +229,7 @@ p5.prototype.ambientLight = function(v1, v2, v3, a) {
* @param {p5.Color} color color as a <a href="#/p5.Color">p5.Color</a>
* @chainable
*/
p5.prototype.specularColor = function(v1, v2, v3) {
p5.prototype.specularColor = function (v1, v2, v3) {
this._assert3d('specularColor');
p5._validateParameters('specularColor', arguments);
const color = this.color(...arguments);
Expand Down Expand Up @@ -327,7 +327,7 @@ p5.prototype.specularColor = function(v1, v2, v3) {
* @param {p5.Vector} direction
* @chainable
*/
p5.prototype.directionalLight = function(v1, v2, v3, x, y, z) {
p5.prototype.directionalLight = function (v1, v2, v3, x, y, z) {
this._assert3d('directionalLight');
p5._validateParameters('directionalLight', arguments);

Expand Down Expand Up @@ -454,7 +454,7 @@ p5.prototype.directionalLight = function(v1, v2, v3, x, y, z) {
* @param {p5.Vector} position
* @chainable
*/
p5.prototype.pointLight = function(v1, v2, v3, x, y, z) {
p5.prototype.pointLight = function (v1, v2, v3, x, y, z) {
this._assert3d('pointLight');
p5._validateParameters('pointLight', arguments);

Expand Down Expand Up @@ -592,13 +592,60 @@ p5.prototype.pointLight = function(v1, v2, v3, x, y, z) {
* @alt
* light with slider having a slider for varying roughness
*/
p5.prototype.imageLight = function(img){
p5.prototype.imageLight = function (img) {
// activeImageLight property is checked by _setFillUniforms
// for sending uniforms to the fillshader
this._renderer.activeImageLight = img;
this._renderer._enableLighting = true;
};

/**
* The `panorama(img)` method transforms images containing
* 360-degree content, such as maps or HDRIs, into immersive
* 3D backgrounds that surround your scene. This is similar to calling
* `background(color)`; call `panorama(img)` before drawing your
* scene to create a 360-degree background from your image. It
* operates on the concept of sphere mapping, where the image is
* mapped onto an infinitely large sphere based on the angles of the
* camera.
*
* To enable 360-degree viewing, either use `orbitControl()` or try changing
* the orientation of the camera to see different parts of the background.
*
* @method panorama
* @param {p5.Image} img A 360-degree image to use as a background panorama
* @example
* <div class="notest">
* <code>
* let img;
* function preload() {
* img = loadImage('assets/outdoor_spheremap.jpg');
* }
* function setup() {
* createCanvas(100 ,100 ,WEBGL);
* }
* function draw() {
* panorama(img);
* imageMode(CENTER);
* orbitControl();
* noStroke();
* push();
* imageLight(img);
* specularMaterial('green');
* shininess(200);
* metalness(100);
* sphere(25);
* pop();
* }
* </code>
* </div>
* @alt
* The image transformed into a panoramic scene.
*/
p5.prototype.panorama = function (img) {
this.filter(this._renderer._getSphereMapping(img));
};

/**
* Places an ambient and directional light in the scene.
* The lights are set to ambientLight(128, 128, 128) and
Expand Down Expand Up @@ -634,7 +681,7 @@ p5.prototype.imageLight = function(img){
* @alt
* the light is partially ambient and partially directional
*/
p5.prototype.lights = function() {
p5.prototype.lights = function () {
this._assert3d('lights');
// Both specify gray by default.
const grayColor = this.color('rgb(128,128,128)');
Expand Down Expand Up @@ -698,7 +745,7 @@ p5.prototype.lights = function() {
* @alt
* Two spheres with different falloff values show different intensity of light
*/
p5.prototype.lightFalloff = function(
p5.prototype.lightFalloff = function (
constantAttenuation,
linearAttenuation,
quadraticAttenuation
Expand Down Expand Up @@ -892,7 +939,7 @@ p5.prototype.lightFalloff = function(
* @param {Number} [angle]
* @param {Number} [concentration]
*/
p5.prototype.spotLight = function(
p5.prototype.spotLight = function (
v1,
v2,
v3,
Expand Down Expand Up @@ -1153,7 +1200,7 @@ p5.prototype.spotLight = function(
* Three white spheres. Each appears as a different
* color due to lighting.
*/
p5.prototype.noLights = function(...args) {
p5.prototype.noLights = function (...args) {
this._assert3d('noLights');
p5._validateParameters('noLights', args);

Expand Down
32 changes: 27 additions & 5 deletions src/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const webgl2CompatibilityShader = readFileSync(
);

const defaultShaders = {
sphereMappingFrag: readFileSync(
join(__dirname, '/shaders/sphereMapping.frag'),
'utf-8'
),
immediateVert: readFileSync(
join(__dirname, '/shaders/immediate.vert'),
'utf-8'
Expand Down Expand Up @@ -80,6 +84,7 @@ const defaultShaders = {
imageLightDiffusedFrag: readFileSync(join(__dirname, '/shaders/imageLightDiffused.frag'), 'utf-8'),
imageLightSpecularFrag: readFileSync(join(__dirname, '/shaders/imageLightSpecular.frag'), 'utf-8')
};
let sphereMapping = defaultShaders.sphereMappingFrag;
for (const key in defaultShaders) {
defaultShaders[key] = webgl2CompatibilityShader + defaultShaders[key];
}
Expand Down Expand Up @@ -497,7 +502,7 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
this.curStrokeColor = this._cachedStrokeStyle = [0, 0, 0, 1];

this.curBlendMode = constants.BLEND;
this.preEraseBlend=undefined;
this.preEraseBlend = undefined;
this._cachedBlendMode = undefined;
if (this.webglVersion === constants.WEBGL2) {
this.blendExt = this.GL;
Expand Down Expand Up @@ -559,6 +564,7 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
this.executeRotateAndMove = false;

this.specularShader = undefined;
this.sphereMapping = undefined;
this.diffusedShader = undefined;
this._defaultLightShader = undefined;
this._defaultImmediateModeShader = undefined;
Expand Down Expand Up @@ -1127,6 +1133,7 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
this._pInst.resetMatrix();
this._pInst.image(fbo, -target.width / 2, -target.height / 2,
target.width, target.height);
this._pInst.clearDepth();
this._pInst.pop();
this._pInst.pop();
}
Expand Down Expand Up @@ -1186,7 +1193,7 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
this.curFillColor = this._cachedFillStyle.slice();
this.curStrokeColor = this._cachedStrokeStyle.slice();
// Restore blend mode
this.curBlendMode=this.preEraseBlend;
this.curBlendMode = this.preEraseBlend;
this.blendMode(this.preEraseBlend);
// Ensure that _applyBlendMode() sets preEraseBlend back to the original blend mode
this._isErasing = false;
Expand Down Expand Up @@ -1676,6 +1683,21 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
return this._getImmediateStrokeShader();
}

_getSphereMapping(img) {
if (!this.sphereMapping) {
this.sphereMapping = this._pInst.createFilterShader(
sphereMapping
);
}
this.uNMatrix.inverseTranspose(this.uMVMatrix);
this.uNMatrix.invert3x3(this.uNMatrix);
this.sphereMapping.setUniform('uFovY', this._curCamera.cameraFOV);
this.sphereMapping.setUniform('uAspect', this._curCamera.aspectRatio);
this.sphereMapping.setUniform('uNewNormalMatrix', this.uNMatrix.mat3);
this.sphereMapping.setUniform('uSampler', img);
return this.sphereMapping;
}

/*
* selects which fill shader should be used based on renderer state,
* for use with begin/endShape and immediate vertex mode.
Expand Down Expand Up @@ -2141,9 +2163,9 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
}

/* Binds a buffer to the drawing context
* when passed more than two arguments it also updates or initializes
* the data associated with the buffer
*/
* when passed more than two arguments it also updates or initializes
* the data associated with the buffer
*/
_bindBuffer(
buffer,
target,
Expand Down
24 changes: 24 additions & 0 deletions src/webgl/shaders/sphereMapping.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#define PI 3.141592

precision highp float;

uniform sampler2D uSampler;
uniform mat3 uNewNormalMatrix;
uniform float uFovY;
uniform float uAspect;

varying vec2 vTexCoord;

void main() {
float uFovX = uFovY * uAspect;
vec4 newTexColor = texture2D(uSampler, vTexCoord);
float angleY = mix(uFovY/2.0, -uFovY/2.0, vTexCoord.y);
float angleX = mix(uFovX/2.0, -uFovX/2.0, vTexCoord.x);
vec3 rotatedNormal = vec3( angleX, angleY, 1.0 );
rotatedNormal = uNewNormalMatrix * normalize(rotatedNormal);
vec2 suv;
suv.y = 0.5 + 0.5 * (-rotatedNormal.y);
suv.x = atan(rotatedNormal.z, rotatedNormal.x) / (2.0 * PI) + 0.5;
newTexColor = texture2D(uSampler, suv.xy);
gl_FragColor = newTexColor;
}

0 comments on commit d7b5d58

Please sign in to comment.