Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
227fe69
Extending p5.texture for cubemap textures
Garima3110 Dec 24, 2023
8e2d05c
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Dec 25, 2023
317d915
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Dec 28, 2023
917de2f
Added vertex and fragment shaders for cubemaps
Garima3110 Dec 28, 2023
5139c0a
Updated src/webgl/shaders/lighting.glsl file for cubemaps
Garima3110 Dec 28, 2023
45e33d5
Storing the diffuse irradiance in a cubemap texture
Garima3110 Dec 28, 2023
1d54fad
Added caching mechanism for shaders
Garima3110 Dec 29, 2023
1ff8702
Updated caching for some shaders
Garima3110 Dec 29, 2023
6cd7856
Updated p5.Texture.js
Garima3110 Dec 29, 2023
4401ebd
Updated cubeVertex and cubeFragment shaders
Garima3110 Dec 29, 2023
37751d9
renamed cubemap shader files
Garima3110 Dec 29, 2023
93b8b50
Updated p5.RendererGL.js
Garima3110 Dec 29, 2023
66dc0dc
Updated p5.Texture.js
Garima3110 Dec 29, 2023
cffda69
Updated lighting.glsl
Garima3110 Dec 29, 2023
751b16a
Added TEXTURE_CUBE
Garima3110 Dec 29, 2023
29e7a14
Added gl.SAMPLER_CUBE uniform type to p5.Shader.js
Garima3110 Dec 29, 2023
7981fdc
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Dec 31, 2023
e7cd392
Minor changes in SAMPLER_CUBE uniform type
Garima3110 Dec 31, 2023
f30af0e
Minor updates on caching shaders
Garima3110 Dec 31, 2023
d51c4a8
Merge branch 'processing:main' into cubeMap
Garima3110 Jan 4, 2024
38bcaab
Merge branch 'processing:main' into cubeMap
Garima3110 Jan 8, 2024
2558755
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Jan 13, 2024
773198a
Updated RendererGL.js
Garima3110 Jan 13, 2024
bbc7c72
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Jan 15, 2024
ffd9097
Reordered some code in p5.RendererGL.js
Garima3110 Jan 16, 2024
cc77e7e
Minor fixes
Garima3110 Jan 20, 2024
518b0f0
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Jan 20, 2024
c124738
Fragment shader error fixed
Garima3110 Jan 23, 2024
38e6e84
Merge remote-tracking branch 'upstream/main' into cubeMap
Garima3110 Jan 23, 2024
a585ef5
Minor updates
Garima3110 Jan 23, 2024
f118a3b
some fixes
Garima3110 Jan 24, 2024
2da03d1
Merge branch 'processing:main' into cubeMap
Garima3110 Jan 29, 2024
5961be8
Minor changes
Garima3110 Mar 30, 2024
4515c09
Some changes with cubemap implementation
Garima3110 Jun 20, 2024
be6d27f
Minor changes
Garima3110 Jun 24, 2024
6dc9916
fix
Garima3110 Jun 24, 2024
3133e80
Merge branch 'processing:main' into cubeMap
Garima3110 Nov 2, 2024
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
54 changes: 45 additions & 9 deletions src/webgl/p5.RendererGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import './p5.Matrix';
import './p5.Framebuffer';
import { readFileSync } from 'fs';
import { join } from 'path';
import { MipmapTexture } from './p5.Texture';
import { CubemapTexture, MipmapTexture } from './p5.Texture';

const STROKE_CAP_ENUM = {};
const STROKE_JOIN_ENUM = {};
Expand Down Expand Up @@ -40,6 +40,14 @@ const webgl2CompatibilityShader = readFileSync(
join(__dirname, '/shaders/webgl2Compatibility.glsl'),
'utf-8'
);
const cubemapFragmentShader=readFileSync(
join(__dirname,'/shaders/cubeFragment.glsl'),
'utf8'
);
const cubemapVertexShader=readFileSync(
join(__dirname,'/shaders/cubeVertex.glsl'),
'utf8'
);

const defaultShaders = {
immediateVert: readFileSync(
Expand Down Expand Up @@ -1902,6 +1910,8 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
let smallWidth = 200;
let width = smallWidth;
let height = Math.floor(smallWidth * (input.height / input.width));
let cubemapTexture;
const faces = [];
newFramebuffer = this._pInst.createFramebuffer({
width, height, density: 1
});
Expand All @@ -1913,23 +1923,49 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
defaultShaders.imageLightDiffusedFrag
);
}
// Create a shader for cubemap conversion
const cubemapShader = this._pInst.createShader(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just above this, we create and cache a shader so that we only ever need one copy. Can we add that caching here too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have applied caching mechanism to possibly all the shaders. I am not sure whether this aligns with what you were suggesting through this @davepagurek .PLease have a look into the changes I've made.
Thanks.!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't want to wrap all the existing shader sources in a caching function, since those are just the sources for one part of a shader (e.g. just the vertex or fragment source, and often not the full source either, since we need to add a prefix to it.) A caching function would be good for this createShader call (since you're still creating a new shader every time this line is hit, currently.) A few lines up, this.diffusedShader already does caching, but can be refactored to use the same caching system you use here if you're factoring that out into a common pattern.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh actually I see that you've added that in _getCubemapShader. I think rather than making a new shader here, we can just use const cubemapShader = this._getCubemapShader() instead.

cubemapVertexShader,
cubemapFragmentShader);

// Render each face of the cubemap
for (let i = 0; i < 6; ++i) {
newFramebuffer.draw(() => {
cubemapShader.use();
cubemapShader.setUniform('equirectangularMap', input);
cubemapShader.setUniform('projection', captureProjection);
cubemapShader.setUniform('view', captureViews[i]);

this._pInst.noStroke();
this._pInst.rectMode(constants.CENTER);
this._pInst.noLights();
this._pInst.rect(0, 0, width, height);

// Capture the rendered face and store it in the faces array
faces[i] = this._pInst.get(0, 0, width, height);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also probably not the source of the error, but we might need to put this outside of the draw(...) block, and use faces[i] = newFramebuffer.get() instead of this._pInst.get(...).

});
}
// Use the diffusedShader for rendering
newFramebuffer.draw(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not the cause of the error you're seeing, but I think we probably no longer need this newFramebuffer.draw(...) block since we are no longer using this framebuffer as the texture. (I think that means we actually need to call newFramebuffer.free() here to avoid a small memory leak?)

this._pInst.shader(this.diffusedShader);
this.diffusedShader.setUniform('environmentMap', input);
this._pInst.noStroke();
this._pInst.rectMode(constants.CENTER);
this._pInst.noLights();
this._pInst.rect(0, 0, width, height);
// Render the cubemap using the stored faces
for (let i = 0; i < 6; ++i) {
this._pInst.image(faces[i], 0, 0, width, height);
}
});
this.diffusedTextures.set(input, newFramebuffer);
return newFramebuffer;
// Initialize CubemapTexture class with faces
cubemapTexture=new CubemapTexture(this._pInst,faces, {});
cubemapTexture.init(faces);
this.diffusedTextures.set(input, cubemapTexture);
return cubemapTexture;
}

/*
* used in imageLight,
* To create a texture from the input non blurry image, if it doesn't already exist
* Creating 8 different levels of textures according to different
* sizes and atoring them in `levels` array
* sizes and storing them in `levels` array
* Creating a new Mipmap texture with that `levels` array
* Storing the texture for input image in map called `specularTextures`
* maps the input p5.Image to a p5.MipmapTexture
Expand Down Expand Up @@ -2087,7 +2123,7 @@ p5.RendererGL = class RendererGL extends p5.Renderer {
// this.activeImageLight has image as a key
// look up the texture from the diffusedTexture map
let diffusedLight = this.getDiffusedTexture(this.activeImageLight);
shader.setUniform('environmentMapDiffused', diffusedLight);
shader.setUniform('environmentMapDiffusedCubemap', diffusedLight);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure but I feel diffusedLight is also a sampler2D texture, could it be passed as a uniform with samplerCube texture?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, diffusedLight is obtained from getDiffusedTexture, which returns a CubemapTexture object. Since environmentMapDiffusedCubemap in the shader expects a cubemap texture (samplerCube), so I think diffusedLight is being correctly assigned to the environmentMapDiffusedCubemap uniform in the shader, which is of type samplerCube.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh...sorry. I overlooked this, previously we had diffusedLight with sampler2D texture so I got confused. I see you have updated getDiffusedTexture()

let specularLight = this.getSpecularTexture(this.activeImageLight);
// In p5js the range of shininess is >= 1,
// Therefore roughness range will be ([0,1]*8)*20 or [0, 160]
Expand Down
54 changes: 53 additions & 1 deletion src/webgl/p5.Texture.js
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,64 @@ export function checkWebGLCapabilities({ GL, webglVersion }) {
: gl.getExtension('OES_texture_half_float');
const supportsHalfFloatLinear = supportsHalfFloat &&
gl.getExtension('OES_texture_half_float_linear');
const supportsCubemap = gl.getExtension('OES_texture_cube_map');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might only be necessary for WebGL 1, is that something you can double check? If it's built into WebGL2, then this line would be supportsCubemap = webglVersion === constants.WEBGL2 || gl.getExtesion('OES_texture_cube_map')

Copy link
Member Author

@Garima3110 Garima3110 Dec 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes , You are absolutely correct .
WebGL2 supports cubemap textures natively, so we don't need to explicitly check for the OES_texture_cube_map extension in most cases.
Mybad!
I'll just update this one too.

return {
float: supportsFloat,
floatLinear: supportsFloatLinear,
halfFloat: supportsHalfFloat,
halfFloatLinear: supportsHalfFloatLinear
halfFloatLinear: supportsHalfFloatLinear,
cubemap: supportsCubemap
};
}

export class CubemapTexture extends p5.Texture {
constructor(renderer, faces, settings) {
super(renderer, faces, settings);
}

glFilter(_filter) {
const gl = this._renderer.GL;
// TODO: Support other filters if needed
return gl.LINEAR;
}

_getTextureDataFromSource() {
return this.src;
}

init(faces) {
const gl = this._renderer.GL;
this.glTex = gl.createTexture();

this.bindTexture();
for (let faceIndex = 0; faceIndex < faces.length; faceIndex++) {
// Set up each face of the cubemap
gl.texImage2D(
gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex,
0,
this.glFormat,
this.glFormat,
this.glDataType,
faces[faceIndex]
);
}

// Set parameters for the cubemap
gl.texParameteri(gl.TEXTURE_CUBE_MAP
, gl.TEXTURE_MAG_FILTER, this.glMagFilter);
gl.texParameteri(gl.TEXTURE_CUBE_MAP
, gl.TEXTURE_MIN_FILTER, this.glMinFilter);
gl.texParameteri(gl.TEXTURE_CUBE_MAP
, gl.TEXTURE_WRAP_S, this.glWrapS);
gl.texParameteri(gl.TEXTURE_CUBE_MAP
, gl.TEXTURE_WRAP_T, this.glWrapT);

this.unbindTexture();
}

update() {
// Custom update logic, if needed
}
}

export default p5.Texture;
23 changes: 23 additions & 0 deletions src/webgl/shaders/cubeFragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#version 330 core
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now this shader will only work in WebGL 2 mode. For shaders we want to work in both versions, we add these macros to the start https://github.com/processing/p5.js/blob/main/src/webgl/shaders/webgl2Compatibility.glsl by concatenating it here:

for (const key in defaultShaders) {
defaultShaders[key] = webgl2CompatibilityShader + defaultShaders[key];
}

...and by adding an appropriate prefix for the vertex/fragment shaders like this:
this._defaultLightShader = new p5.Shader(
this,
this._webGL2CompatibilityPrefix('vert', 'highp') +
defaultShaders.lightVert,

To make this file use it, it would involve taking out the #version (that's added by the prefix we add), and replacing out and in with the macros OUT and IN which get #defined to the appropriate keyword depending on what WebGL version is being used. It also means not explicitly declaring out vec4 FragColor and instead using OUT_COLOR, which we also automatically add a definition for.

out vec4 FragColor;
in vec3 localPos;

uniform sampler2D equirectangularMap;

const vec2 invAtan = vec2(0.1591, 0.3183);

vec2 SampleSphericalMap(vec3 v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding a comment mentioning https://learnopengl.com/PBR/IBL/Diffuse-irradiance as a source so that we can refer back to it in the future

{
vec2 uv = vec2(atan(v.z, v.x), asin(v.y));
uv *= invAtan;
uv += 0.5;
return uv;
}

void main()
{
vec2 uv = SampleSphericalMap(normalize(localPos));
vec3 color = texture(equirectangularMap, uv).rgb;

FragColor = vec4(color, 1.0);
}
13 changes: 13 additions & 0 deletions src/webgl/shaders/cubeVertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#version 330 core
layout (location = 0) in vec3 aPos;

out vec3 localPos;

uniform mat4 projection;
uniform mat4 view;

void main()
{
localPos = aPos;
gl_Position = projection * view * vec4(localPos, 1.0);
}
4 changes: 2 additions & 2 deletions src/webgl/shaders/lighting.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ uniform float uQuadraticAttenuation;
// boolean to initiate the calculateImageDiffuse and calculateImageSpecular
uniform bool uUseImageLight;
// texture for use in calculateImageDiffuse
uniform sampler2D environmentMapDiffused;
uniform sampler2D environmentMapDiffusedCubemap;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be samplerCube?

// texture for use in calculateImageSpecular
uniform sampler2D environmentMapSpecular;
// roughness for use in calculateImageSpecular
Expand Down Expand Up @@ -111,7 +111,7 @@ vec3 calculateImageDiffuse( vec3 vNormal, vec3 vViewPosition ){
vec3 worldCameraPosition = vec3(0.0, 0.0, 0.0); // hardcoded world camera position
vec3 worldNormal = normalize(vNormal);
vec2 newTexCoor = mapTextureToNormal( worldNormal );
vec4 texture = TEXTURE( environmentMapDiffused, newTexCoor );
vec4 texture = textureCube( environmentMapDiffusedCubemap, newTexCoor );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously, we were using the TEXTURE, which refers to a macro in https://github.com/processing/p5.js/blob/main/src/webgl/shaders/webgl2Compatibility.glsl to be either texture2D in WebGL1, or texture in WebGL2.

We need to do something similar for cubemap textures. In that file we'd have to #define TEXTURE_CUBE to either be textureCube in WebGL 1, or just texture in WebGL 2, and then use TEXTURE_CUBE(...) here.

// this is to make the darker sections more dark
// png and jpg usually flatten the brightness so it is to reverse that
return smoothstep(vec3(0.0), vec3(0.8), texture.xyz);
Expand Down