Hey community,
i am trying to use an enviroment map in my fragment shader. The goal is to create a reflection effect on a surface that is animated using perlin noise. This is my fragment shader:
uniform samplerCube uTexture;
varying vec3 vNormal;
varying float vPerlinStrength;
void main() {
vec3 envColor = textureCube(uTexture, vNormal).rgb;
float temp = vPerlinStrength + 0.5;
temp *= 0.5;
vec3 finalColor = envColor * temp;
gl_FragColor = vec4(finalColor, 1.0);
}
But when using this shader i get this error:
WebGL: INVALID_OPERATION: bindTexture: textures can not be used with multiple targets
And also my object has an all black surface so something is clearly not working.
I researched the error and apparently it is caused by applying the enviroment map to 2D and 3D surfaced at the same time. But the problem is that i can’t find where i am using the texture wrong.
Here is the javascript of my scene:
<script>
import { onMount } from 'svelte';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import organicVertexShader from '/src/lib/utils/shaders/sphere/organic-vertext.glsl';
import organicFragmentShader from '/src/lib/utils/shaders/sphere/organic-fragment.glsl';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
let scene, camera, renderer, sphere, controls, material;
async function loadEnvironmentMap() {
return new Promise((resolve, reject) => {
const rgbeLoader = new RGBELoader();
rgbeLoader.load(
'/src/lib/assets/enviroment.hdr',
(texture) => {
console.log('HDR image loaded');
const pmremGenerator = new THREE.PMREMGenerator(renderer);
const cubeRenderTarget = pmremGenerator.fromEquirectangular(texture);
scene.background = new THREE.Color(0xffffff);
//scene.background = cubeRenderTarget.texture;
//scene.environment = cubeRenderTarget.texture;
resolve(cubeRenderTarget.texture);
},
undefined,
reject
);
});
}
async function init() {
renderer = new THREE.WebGLRenderer({ antialias: true });
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
try {
const environmentMap = await loadEnvironmentMap();
const geometry = new THREE.IcosahedronGeometry(1, 200);
material = new THREE.ShaderMaterial({
uniforms: {
uTexture: { value: environmentMap },
uTime: { value: 0.0 },
uDistortionFrequency: { value: 1.0 },
uDistortionStrength: { value: 2.5 },
uDisplacementFrequency: { value: 2.0 },
uDisplacementStrength: { value: 0.2 }
},
vertexShader: organicVertexShader,
fragmentShader: organicFragmentShader
});
sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
camera.position.z = 5;
controls = new OrbitControls(camera, renderer.domElement);
controls.update();
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
const clock = new THREE.Clock();
const animate = function () {
const elapsedTime = clock.getElapsedTime();
material.uniforms.uTime.value = elapsedTime / 20;
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
animate();
} catch (error) {
console.error('Error loading environment map:', error);
}
}
onMount(async () => {
console.log('onMount');
await init();
console.log('initialized');
});
</script>
I already tried to remove these lines
scene.background = cubeRenderTarget.texture
scene.environment = cubeRenderTarget.texture;
but the error still persists.
I think i am doing something wrong in the way i am handleing the enviroment map and passing it to the shader, but i am a bit lost.
Any tipps and help would be really appriciated