I want to make ray box intersections like in the volumetric clouds example.
I’ve been struggling with an annoying problem for a long time. I made a snippet from my app. Here is the github link:
You can move with wasd, the arrow keys and space.
As you can see in the screenshot, my problem are the ugly white dashed edges. I just can’t figure out where it’s coming from and what I can do about it.
I have tried to reduce the app as much as possible in the hope of limiting the phenomenon.
The RayBox intersection can be found in the shader cloudsFS.js in the shader folder in resources. threejs is initialized in threejs-component.js and in the main the composer, renderer and camera are passed to cloud. There’s nothing that would be complicated in any way, but as I said, I just can’t figure out where these ugly lines are coming from. I reduced the shader a lot so that all the volume calculations are gone. With these, the dashed lines would also go up. I suspect there is a missing setting in the composer, because the ray-cube-intersection is very simple. I have the box from the volumetric clouds example
import {THREE, OrbitControls, RenderPass, ShaderPass, EffectComposer, CopyShader, FXAAShader, WebGL} from './three-defs.js';
import {entity} from "./entity.js";
export const threejs_component = (() => {
class ThreeJSController extends entity.Component {
constructor() {
super();
}
InitEntity() {
if (!WebGL.isWebGL2Available()) {
return false;
}
const canvas = document.createElement('canvas');
const context = canvas.getContext('webgl2');
this.threejs_ = new THREE.WebGLRenderer({
canvas: canvas,
context: context,
antialias: true
});
this.threejs_.outputEncoding = THREE.sRGBEncoding;
this.threejs_.setPixelRatio(window.devicePixelRatio);
this.threejs_.shadowMap.enabled = true;
this.threejs_.shadowMap.type = THREE.PCFSoftShadowMap;
this.threejs_.physicallyCorrectLights = true;
this.threejs_.domElement.id = 'threejs';
this.container = document.getElementById('container');
this.threejs_.setSize(this.container.clientWidth, this.container.clientHeight);
this.container.appendChild( this.threejs_.domElement );
const aspect = this.container.clientWidth / this.container.clientHeight;
const fov = 50;
const near = 1;
const far = 1E6;
this.camera_ = new THREE.PerspectiveCamera(fov, aspect, near, far);
this.scene_ = new THREE.Scene();
this.threejs_.setClearColor( 0x000000 );
this.camera_.position.set(0, 0, 10000);
this.fxaaPass = new ShaderPass( FXAAShader );
var pixelRatio = this.threejs_.getPixelRatio();
this.fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( this.container.clientWidth * pixelRatio );
this.fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( this.container.clientHeight * pixelRatio );
this.composer_ = new EffectComposer(this.threejs_);
const renderPass = new RenderPass(this.scene_, this.camera_);
this.composer_.addPass(renderPass);
this.composer_.addPass(this.fxaaPass);
this.resolution_ = new THREE.Vector2();
this.threejs_.getDrawingBufferSize(this.resolution_);
this.target_ = new THREE.WebGLRenderTarget(this.resolution_.x, this.resolution_.y);
this.target_.stencilBuffer = false;
this.target_.depthBuffer = true;
this.target_.depthTexture = new THREE.DepthTexture();
this.target_.depthTexture.format = THREE.DepthFormat;
this.target_.depthTexture.type = THREE.FloatType;
this.target_.depthTexture.minFilter = THREE.NearestFilter;
this.target_.depthTexture.magFilter = THREE.NearestFilter;
window.addEventListener('resize', () => {this.OnResize_();}, false);
}//end init
Render() {
this.threejs_.setRenderTarget(this.target_);
this.threejs_.render(this.scene_, this.camera_);
this.threejs_.setRenderTarget( null );
this.composer_.render();
}
Update(timeElapsed) {
const player = this.FindEntity('player');
if (!player) {
return;
}
const pos = player._position;
}
OnResize_() {
let width, height;
if(window.innerWidth > window.innerHeight){
width = 1.0 * window.innerWidth;
height = 1.0 * window.innerHeight;
}
if(window.innerHeight > window.innerWidth){
width = 1.0 * window.innerWidth;
height = 1.0 * window.innerHeight;
}
this.camera_.aspect = width / height;
this.camera_.updateProjectionMatrix();
this.threejs_.setSize(width, height);
var pixelRatio = this.threejs_.getPixelRatio();
this.fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( this.container.clientWidth * pixelRatio );
this.fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( this.container.clientHeight * pixelRatio );
}
}//end class
return {
ThreeJSController: ThreeJSController,
};
})();
My FXAAShader doesn’t work either. I installed it as shown in the example. But what I do differently is to mount my own shader. I do that in the module. I access the threejs composer to add my own shader with addPass. Maybe I don’t understand the composer chain well enough
import {entity} from './entity.js';
import {THREE, ShaderPass, FXAAShader} from './three-defs.js';
import {cloud_model} from './cloud-model.js';
import { cloudsVS } from "../resources/shader/cloudsVS.js";
import { cloudsFS } from "../resources/shader/cloudsFS.js";
export const clouds = (() => {
class Clouds extends entity.Component {
constructor(params){
super();
this.Init(params);
}
Init(params){
this.params_ = params;
let source = this.params_.threejs;
const clouds = "./resources/textures/clouds/clouds_2.jpg";
const cloudmodel = new cloud_model.CloudModel({
renderer: source.threejs_,
clouds: clouds
});
this.sunDir = new THREE.Vector3(-1, 0, 0.5);
this.sunDir.normalize();
this.sunDist = 200E9;
this.sunPos = this.sunDir.multiplyScalar(this.sunDist);
let uniform = {
tDiffuse: { value: null },
tDepth: { value: null },
planetRadius: { value: 6350 },
cloudsInnerRadius: { value: 6356 },
cloudsOuterRadius: { value: 6371 },
oceanRadius: { value: null },
cameraNear: { value: source.camera_.near },
cameraFar: { value: source.camera_.far },
cameraPos: { value: source.camera_.position },
cameraForward: { value: null },
inverseProjection: { value: null },
inverseView: { value: null },
planetPos: { value: null },
sunColor: { value: null },
sunPos: { value: this.sunPos },
cloud: { value: cloudmodel.cloud},
worley: { value: cloudmodel.worley},
weather: { value: cloudmodel.weather},
};
this.clouds = new THREE.RawShaderMaterial({
glslVersion: THREE.GLSL3,
uniforms: uniform,
vertexShader: cloudsVS,
fragmentShader: cloudsFS,
});
source.composer_.addPass(new ShaderPass(this.clouds));
}
Update(_) {
let source = this.params_.threejs;
const forward = new THREE.Vector3();
source.camera_.getWorldDirection(forward);
this.clouds.uniforms.tDepth.value = source.target_.depthTexture;
this.clouds.uniforms.planetPos.value = new THREE.Vector3(0, 0, 0);
this.clouds.uniforms.cameraForward.value = forward;
this.clouds.uniforms.inverseProjection.value = source.camera_.projectionMatrixInverse;
this.clouds.uniforms.inverseView.value = source.camera_.matrixWorld;
this.clouds.uniforms.cameraNear.value = source.camera_.near;
this.clouds.uniforms.cameraFar.value = source.camera_.far;
this.clouds.uniforms.cameraPos.value = source.camera_.position;
this.clouds.uniforms.sunColor.value = new THREE.Vector3(1.0, 1.0, 1.0);
this.clouds.uniforms.sunPos.value = this.sunPos;
this.clouds.uniformsNeedUpdate = true;
}//end Update
}
return {
Clouds: Clouds
}
})();