1. A concise explanation of the problem you’re experiencing.
I want to integrate the volume raycaster into Cesium,I’ve been doing it these days.I use the Volume Ray Casting (http://www.lebarba.com/) for creating the rays and raymarching ,but it still failed,I doubt whether the rays cooridnate is incorrect in my way.
2. A minimal code example. If you’ve found a bug, this helps us reproduce and repair it.
class CubePrimitive {
constructor(options) {
this.geometry = options.geometry;
this.uniformMap = options.uniformMap;
this.backVertexShader = `precision highp float;
attribute vec3 position;
varying vec3 v_pos;
void main(){
v_pos=position;
gl_Position = czm_modelViewProjection * vec4(position,1.0);
}`;
this.backFragmentShader = `precision highp float;
const float xyzLimit=30000000.0;
varying vec3 v_pos;
void main(){
gl_FragColor = vec4((v_pos+xyzLimit/2.0)/xyzLimit,1.0); //move it to [0,1]
}`;
this.frontVertexShader = `precision highp float;
const float xyzLimit=30000000.0;
attribute vec3 position;
varying vec3 v_pos;
varying vec4 v_prjPos;
void main(){
v_pos=position;
v_prjPos=czm_modelViewProjection * vec4(position,1.0);
gl_Position = v_prjPos;
}`;
this.frontFragmentShader = `precision highp float;
const float xyzLimit=30000000.0;
uniform sampler2D u_volumeTexture;
uniform sampler2D u_colorTexture;
uniform sampler2D u_backTexture;
uniform sampler2D u_depthTexture;
uniform vec3 u_minPos;
uniform vec3 u_maxPos;
varying vec3 v_pos;
varying vec4 v_prjPos;
const float zdef=63.0;
const float zslice=8.0;
float sampleAs3DTexture(vec3 texCoord){
float colorSlice1, colorSlice2;
vec2 texCoordSlice1, texCoordSlice2;
float zSliceNumber1 = floor(texCoord.z * zdef);
float zSliceNumber2 = min( zSliceNumber1 + 1.0, zdef);
float zDifference = mod(texCoord.z * zdef, 1.0);
texCoord.xy /= zslice;
texCoordSlice1 = texCoordSlice2 = texCoord.xy;
texCoordSlice1.x += mod(zSliceNumber1, zslice ) / zslice;
texCoordSlice1.y += floor((zdef - zSliceNumber1) / zslice) / zslice;
texCoordSlice1.y=1.0-texCoordSlice1.y;
texCoordSlice2.x += mod(zSliceNumber2, zslice ) / zslice;
texCoordSlice2.y += floor((zdef - zSliceNumber2) / zslice) / zslice;
texCoordSlice2.y=1.0-texCoordSlice2.y;
colorSlice1 = texture2D(u_volumeTexture, texCoordSlice1).r;
colorSlice2 = texture2D(u_volumeTexture, texCoordSlice2).r;
return mix(colorSlice1, colorSlice2, zDifference);
}
const vec3 oneOverRadii=vec3(1.567855942887398e-7,1.567855942887398e-7,1.573130351105623e-7);
const vec3 oneOverRadiiSquared=vec3(2.458172257647332e-14,2.458172257647332e-14,2.4747391015697002e-14);
const float centerToleranceSquared=0.1;
// from cesium source code
vec3 cartesianToCartographic(vec3 cartesian){
//scaleToGeodeticSurface
float x2 = cartesian.x * cartesian.x * oneOverRadii.x * oneOverRadii.x;
float y2 = cartesian.y * cartesian.y * oneOverRadii.y * oneOverRadii.y;
float z2 = cartesian.z * cartesian.z * oneOverRadii.z * oneOverRadii.z;
float squaredNorm = x2 + y2 + z2;
float ratio = sqrt(1.0 / squaredNorm);
vec3 intersection = cartesian*ratio;
// If the position is near the center, the iteration will not converge.
if (squaredNorm < centerToleranceSquared) {
}
vec3 gradient=intersectiononeOverRadiiSquared2.0;
float lambda = (1.0 - ratio) * length(cartesian) / (0.5 * length(gradient));
float correction = 0.0;
float func;
float denominator;
float xMultiplier;
float yMultiplier;
float zMultiplier;
float xMultiplier2;
float yMultiplier2;
float zMultiplier2;
float xMultiplier3;
float yMultiplier3;
float zMultiplier3;
const int loopCount = 100;
for (int i=0; i < loopCount; ++i) {
lambda -= correction;
xMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquared.x);
yMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquared.y);
zMultiplier = 1.0 / (1.0 + lambda * oneOverRadiiSquared.z);
xMultiplier2 = xMultiplier * xMultiplier;
yMultiplier2 = yMultiplier * yMultiplier;
zMultiplier2 = zMultiplier * zMultiplier;
xMultiplier3 = xMultiplier2 * xMultiplier;
yMultiplier3 = yMultiplier2 * yMultiplier;
zMultiplier3 = zMultiplier2 * zMultiplier;
func = x2 * xMultiplier2 + y2 * yMultiplier2 + z2 * zMultiplier2 - 1.0;
denominator = x2 * xMultiplier3 * oneOverRadiiSquared.x +
y2 * yMultiplier3 * oneOverRadiiSquared.y +
z2 * zMultiplier3 * oneOverRadiiSquared.z;
float derivative = -2.0 * denominator;
correction = func / derivative;
if (abs(func) > 1e-12) break;
}
vec3 p=cartesian*vec3(xMultiplier,yMultiplier,zMultiplier);
//geodeticSurfaceNormal
vec3 n=p*oneOverRadiiSquared;
n=normalize(n);
vec3 h = cartesian-p;
float longitude = degrees(atan(n.y, n.x));
float latitude = degrees(asin(n.z));
float height = sign(dot(h, cartesian)) * length(h);
return vec3(longitude-u_minPos.x,latitude-u_minPos.y,height-u_minPos.z)/(u_maxPos-u_minPos);
//return (cartesian+xyzLimit/2.0)/xyzLimit;
}
void main(){
vec2 texc = vec2(((v_prjPos.x / v_prjPos.w) + 1.0 ) / 2.0,
((v_prjPos.y / v_prjPos.w) + 1.0 ) / 2.0 );
vec3 backPos = texture2D(u_backTexture, texc).xyz;
backPos=backPos*xyzLimit-xyzLimit/2.0;
vec3 frontPos = v_pos;
vec3 dir = backPos - frontPos;
// raycast sampling properties
const int numSamples = 50;
float stepSize = 1.0/float(numSamples);
// Perform the ray marching:
vec3 pos = frontPos;
vec3 step = normalize(dir) * stepSize;
float travel = length(dir);
vec4 color;
for (int i=0; i < numSamples; ++i) {
if (travel <= 0.0) break;
vec3 volumePos=cartesianToCartographic(pos);
float val = sampleAs3DTexture(volumePos);
vec4 val_color = vec4(texture2D(u_colorTexture, vec2(val, 0.0)).rgb, val);
color.rgb += (1.0 - color.a) * val_color.a * val_color.rgb;
color.a += (1.0 - color.a) * val_color.a;
if (color.a >= 0.95) break;
pos += step;
travel -= stepSize;
}
gl_FragColor = texture2D(u_backTexture, texc);
}`;
this.framebuffer = options.framebuffer;
this.autoClear = Cesium.defaultValue(options.autoClear, false);
this.show = true;
this.backCommand = undefined;
this.frontCommand = undefined;
this.clearCommand = undefined;
if (this.autoClear) {
this.clearCommand = new Cesium.ClearCommand({
color: new Cesium.Color(0.0, 0.0, 0.0, 0.0),
depth: 1.0,
framebuffer: this.framebuffer,
pass: Cesium.Pass.OPAQUE
});
}
}
createCommand(context, isback) {
var vertexArray = Cesium.VertexArray.fromGeometry({
context: context,
geometry: this.geometry,
bufferUsage: Cesium.BufferUsage.STATIC_DRAW,
});
var shaderProgram;
var renderState;
if (isback) {
shaderProgram = Cesium.ShaderProgram.fromCache({
context: context,
vertexShaderSource: this.backVertexShader,
fragmentShaderSource: this.backFragmentShader
});
renderState = Cesium.RenderState.fromCache({
depthTest: {
enabled: true
},
cull: {
enabled: true,
face: Cesium.CullFace.FRONT
},
depthMask: false,
blending: Cesium.BlendingState.ALPHA_BLEND
});
return new Cesium.DrawCommand({
owner: this,
vertexArray: vertexArray,
modelMatrix: Cesium.Matrix4.IDENTITY,
shaderProgram: shaderProgram,
framebuffer: this.framebuffer,
renderState: renderState,
pass: Cesium.Pass.OPAQUE
});
} else {
shaderProgram = Cesium.ShaderProgram.fromCache({
context: context,
vertexShaderSource: this.frontVertexShader,
fragmentShaderSource: this.frontFragmentShader
});
renderState = Cesium.RenderState.fromCache({
depthTest: {
enabled: true
},
cull: {
enabled: true,
face: Cesium.CullFace.BACK
},
depthMask: false,
blending: Cesium.BlendingState.ALPHA_BLEND
});
return new Cesium.DrawCommand({
owner: this,
vertexArray: vertexArray,
uniformMap: this.uniformMap,
modelMatrix: Cesium.Matrix4.IDENTITY,
shaderProgram: shaderProgram,
renderState: renderState,
pass: Cesium.Pass.OPAQUE
});
}
}
update(frameState) {
if (!this.show) {
return;
}
if (!Cesium.defined(this.backCommand)) {
this.backCommand = this.createCommand(frameState.context, true);
}
if (!Cesium.defined(this.frontCommand)) {
this.frontCommand = this.createCommand(frameState.context, false);
}
if (Cesium.defined(this.clearCommand)) {
frameState.commandList.push(this.clearCommand);
}
frameState.commandList.push(this.backCommand); //First render pass
frameState.commandList.push(this.frontCommand); //Second render pass
}
isDestroyed() {
return false;
}
destroy() {
if (Cesium.defined(this.backCommand)) {
this.backCommand.shaderProgram = this.backCommand.shaderProgram && this.backCommand.shaderProgram.destroy();
}
if (Cesium.defined(this.frontCommand)) {
this.frontCommand.shaderProgram = this.frontCommand.shaderProgram && this.frontCommand.shaderProgram.destroy();
}
return Cesium.destroyObject(this);
}
}
function render(data) {
// data neghip_64x64x64_uint8.raw
var minLon = 70;
var maxLon = 138.39092;
var minLat = 3;
var maxLat = 54.39436;
var minHeight = 0;
var maxHeight = 600000;
var position_min = new Cesium.Cartesian3.fromDegrees(minLon, minLat, minHeight);
var position_max = new Cesium.Cartesian3.fromDegrees(maxLon, maxLat, maxHeight);
var ellipsoid = viewer.scene.globe.ellipsoid;
var cartesian3 = new Cesium.Cartesian3(position_max.x, position_max.y, position_max.z);
var cartographic = ellipsoid.cartesianToCartographic(cartesian3);
var lat = Cesium.Math.toDegrees(cartographic.latitude);
var lng = Cesium.Math.toDegrees(cartographic.longitude);
var alt = cartographic.height;
var topBound = ;
var botBound = ;
var stepCount = 100;
var lonStep = (maxLon - minLon) / stepCount;
for (var i = 0; i <= stepCount; i++) {
var lon = minLon + i * lonStep;
topBound.push(lon, maxLat);
lon = maxLon - i * lonStep;
botBound.push(lon, minLat)
}
var degreesArray = [minLon, minLat,
minLon, maxLat
];
degreesArray = degreesArray.concat(topBound);
degreesArray.push(maxLon, minLat);
degreesArray = degreesArray.concat(botBound);
var polygon = new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray(degreesArray)
),
height: maxHeight,
extrudedHeight: 0
});
var geometry = Cesium.PolygonGeometry.createGeometry(polygon);
var geoInstance = new Cesium.GeometryInstance({
geometry: geometry
});
var context = viewer.scene.context;
var colorRender = [
107, 226, 16, 255,
228, 214, 8, 255,
231, 210, 8, 255,
234, 202, 8, 255,
242, 128, 7, 255,
243, 113, 7, 255,
243, 102, 7, 255,
244, 83, 7, 255,
244, 70, 7, 255,
244, 60, 7, 255,
244, 43, 7, 255,
244, 29, 7, 255,
146, 5, 196, 255,
97, 5, 138, 255,
97, 5, 138, 255,
91, 5, 120, 255,
85, 5, 102, 255,
79, 5, 83, 255,
73, 5, 65, 255
];
var colorTexture = new Cesium.Texture({
context:context,
width: colorRender.length / 4,
height: 1,
pixelFormat: Cesium.PixelFormat.RGBA,
pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE,
source: {
arrayBufferView: new Uint8Array(colorRender)
},
sampler: new Cesium.Sampler({
wrapS: Cesium.TextureWrap.CLAMP_TO_EDGE,
wrapT: Cesium.TextureWrap.CLAMP_TO_EDGE,
minificationFilter: Cesium.TextureMinificationFilter.LINEAR,
magnificationFilter: Cesium.TextureMagnificationFilter.LINEAR
})
});
colorTexture.type = ‘sampler2D’;
var volumnTextureData = makeTexture(data);
var volumeTexture = new Cesium.Texture({
context: context,
width: volumnTextureData.width,
height: volumnTextureData.height,
pixelFormat: Cesium.PixelFormat.RGBA,
pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE,
source: {
arrayBufferView: volumnTextureData.data
},
sampler: new Cesium.Sampler({
wrapS: Cesium.TextureWrap.CLAMP_TO_EDGE,
wrapT: Cesium.TextureWrap.CLAMP_TO_EDGE,
minificationFilter: Cesium.TextureMinificationFilter.LINEAR,
magnificationFilter: Cesium.TextureMagnificationFilter.LINEAR
})
});
volumeTexture.type = ‘sampler2D’;
var f_backTexture = new Cesium.Texture({
context: context,
width: context.drawingBufferWidth,
height: context.drawingBufferHeight,
pixelFormat: Cesium.PixelFormat.RGBA,
pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE
});
f_backTexture.type = ‘sampler2D’;
var f_depthTexture = new Cesium.Texture({
context: context,
width: context.drawingBufferWidth,
height: context.drawingBufferHeight,
pixelFormat: Cesium.PixelFormat.DEPTH_COMPONENT,
pixelDatatype: Cesium.PixelDatatype.UNSIGNED_INT,
sampler: new Cesium.Sampler({
wrapS: Cesium.TextureWrap.CLAMP_TO_EDGE,
wrapT: Cesium.TextureWrap.CLAMP_TO_EDGE,
minificationFilter: Cesium.TextureMinificationFilter.LINEAR,
magnificationFilter: Cesium.TextureMagnificationFilter.LINEAR
})
});
f_depthTexture.type = ‘sampler2D’;
var framebuffer = new Cesium.Framebuffer({
context: context,
colorTextures: [f_backTexture],
depthTexture: f_depthTexture
});
var primitive = new CubePrimitive({
geometry: geometry,
primitiveType: Cesium.PrimitiveType.TRIANGLES,
uniformMap: {
u_backTexture:function(){
return f_backTexture;
},
u_depthTexture: function(){
return f_depthTexture;
},
u_volumeTexture:function(){
return volumeTexture;
},
u_colorTexture:function(){
return colorTexture;
},
u_minPos:function(){
return new Cesium.Cartesian3(minLon,minLat,minHeight);
},
u_maxPos:function(){
return new Cesium.Cartesian3(maxLon,maxLat,maxHeight);
}
},
framebuffer: framebuffer,
autoClear: true
});
viewer.scene.primitives.add(primitive);
}
3. Context. Why do you need to do this? We might know a better way to accomplish your goal.
4. The Cesium version you’re using, your operating system and browser.
Cesium1.56
Chrome74.0.3729.157