我目前正尝试使用来自Google图片的高度贴图中的three.js的PlaneBufferGeometry创建一些平滑地形:
https://forums.unrealengine.com/filedata/fetch?id=1192062&d=1471726925
但结果有点不稳定..
(对不起,这是我的第一个问题,显然我需要10个声望来发布图片,否则我会...但是这里更好一点:live demo!左键单击+拖动旋转,滚动到缩放)
我想,就像我说的那样,一个平滑的地形,所以我做错了什么,或者这只是结果,我之后需要以某种方式使其平滑?
这是我的代码:
const IMAGE_SRC = 'terrain2.png';
const SIZE_AMPLIFIER = 5;
const HEIGHT_AMPLIFIER = 10;
var WIDTH;
var HEIGHT;
var container = jQuery('#wrapper');
var scene, camera, renderer, controls;
var data, plane;
image();
// init();
function image() {
var image = new Image();
image.src = IMAGE_SRC;
image.onload = function() {
WIDTH = image.width;
HEIGHT = image.height;
var canvas = document.createElement('canvas');
canvas.width = WIDTH;
canvas.height = HEIGHT;
var context = canvas.getContext('2d');
console.log('image loaded');
context.drawImage(image, 0, 0);
data = context.getImageData(0, 0, WIDTH, HEIGHT).data;
console.log(data);
init();
}
}
function init() {
// initialize camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, .1, 100000);
camera.position.set(0, 1000, 0);
// initialize scene
scene = new THREE.Scene();
// initialize directional light (sun)
var sun = new THREE.DirectionalLight(0xFFFFFF, 1.0);
sun.position.set(300, 400, 300);
sun.distance = 1000;
scene.add(sun);
var frame = new THREE.SpotLightHelper(sun);
scene.add(frame);
// initialize renderer
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.append(renderer.domElement);
// initialize controls
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = .05;
controls.rotateSpeed = .1;
// initialize plane
plane = new THREE.PlaneBufferGeometry(WIDTH * SIZE_AMPLIFIER, HEIGHT * SIZE_AMPLIFIER, WIDTH - 1, HEIGHT - 1);
plane.castShadow = true;
plane.receiveShadow = true;
var vertices = plane.attributes.position.array;
// apply height map to vertices of plane
for(i=0, j=2; i < data.length; i += 4, j += 3) {
vertices[j] = data[i] * HEIGHT_AMPLIFIER;
}
var material = new THREE.MeshPhongMaterial({color: 0xFFFFFF, side: THREE.DoubleSide, shading: THREE.FlatShading});
var mesh = new THREE.Mesh(plane, material);
mesh.rotation.x = - Math.PI / 2;
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
plane.computeFaceNormals();
plane.computeVertexNormals();
scene.add(mesh);
animate();
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
controls.update();
}
答案 0 :(得分:1)
结果是锯齿状,因为高度贴图的颜色深度较低。我冒昧地为高度贴图的一部分着色(Photoshop中的油漆桶,0公差,非连续),这样你就可以自己看到具有相同颜色值的区域有多大,即相同的高度。
相同颜色的区域将在您的地形中形成高原。这就是为什么你的地形有高原和尖锐的台阶。
您可以做的是平滑几何的Z值或使用高度图,该高度图使用16位或事件32位作为高度信息。当前高度图仅使用8位,即256个值。
答案 1 :(得分:0)
你可以做的一件事就是从高度图中采样不仅仅是一个像素。现在,顶点索引直接对应于数据阵列中的像素位置。您只需更新图像中的z值即可。
for(i=0, j=2; i < data.length; i += 4, j += 3) {
vertices[j] = data[i] * HEIGHT_AMPLIFIER;
}
相反,你可以这样做:
这样你就可以在相同高度的区域的边界处得到一些平滑。
第二种选择是使用类似模糊内核的东西(高斯模糊非常昂贵,但也许像快速的盒子模糊对你有用)。
由于您只使用一个字节,因此分辨率非常有限,您应首先将该图像转换为float32:
const highResData = new Float32Array(data.length / 4);
for (let i = 0; i < highResData.length; i++) {
highResData[i] = data[4 * i] / 255;
}
现在数据采用的格式允许更高的数值分辨率,因此我们现在可以平滑。你可以为float32用例调整一些like the StackBlur,使用ndarrays和ndarray-gaussian-filter或者自己实现一些简单的东西。基本思路是找到均匀着色平台中所有值的平均值。
希望有所帮助,祝你好运:)