张春成

V2

2022/07/16阅读:11主题:默认主题

视角渲染

视角渲染

不同的视角下看到同一个东西通常会得到不同的图像。我就搭建了这样一个场景,即模拟高空俯瞰一小片陆地的场景。

这算是一个框架上的尝试,它是在渲染过程中,尝试对同一个三维场景进行多次渲染。


场景、眼睛和绘图

本文的代码可见我的GITHUB主页 Terrain-1[1]

三维场景的绘制逻辑相当的直观和简单,它可以直观地写成下面的过程

  • 有一个场景,这个是事先搭建好的,在计算机的内存里以合适的格式存储着,我们称为 scene;
  • 场景中有许多物体,它们一般是 mesh 的结构;
  • 到此为止,场景和其中的物体还是不可见的,因为并没有人去观察它们;
  • 我们可以定义观察者 (camera),它就是一台摄像机,它有自己的位置、视角和视野范围等参数;
  • 场景及其物体就只有通过观察者才能具有形态,或者说渲染;
  • 渲染的过程是通过渲染器( renderer)来完成;
  • 而渲染器其实是一个中介,只有对它指定 DOM 元素(或者类似的东西)之后,它才会把观察到的内容渲染到 DOM 上。

这个过程的伪代码如下

// Init scene, camera and renderer
const scene = new THREE.scene()
const camera = new THREE.PerspectiveCamera(**kwargs)
const renderer = new THREE.WebGLRenderer({ antialiastrue });

// Put the renderer on the page
const div = document.createElement(’div’)
div.appendChild(renderer.domElement)

// Put the mesh into the scene
scene.add(mesh)

// Render and animation in frames
function render({
 renderer.render(scene, camera)
}

function animate({
  // Repeat in every frame
 requestAnimationFrame(animate);

 // Update the next frame
  /* Some beautiful codes */
 update(mesh)

  // Render the scene
 render();
}

一小块地

我们可以使用合适的函数生成崎岖不平的一小块地,再给定光照方向,就可以渲染出下面的三维场景。

// Generate continues noisy map in xy directions
const perlin = new ImproveNoise()

// The scaler controlls the flat-quality
const scaler = 1.0

// Continues noise in x- and y-directions.
(x, y) => perlin.noise(x, y) * scaler
Untitled
Untitled

我们比较关注图中每个地方的表面方向,因此可以做一个标签来表示它的法线。法线这个东西对于物体的渲染和感知都非常重要,但它在出现在这里的目的却十分单纯,就是为了显示鼠标指向哪里。

Untitled
Untitled
Untitled
Untitled

下面,我们在场景中添加不止一个观察者,这些观察者像飞在天上一样随时运动,对它们的约束是要始终指向鼠标的落点,也就是绘制表面法线的点。

多次渲染

在许多场景中,我们有不止一个观察者。如果要让它们的眼睛都看向鼠标的话,就需要对同一个场景进行多次渲染。也就是说,我们有了这样一组数据结构

  • scene 是固定的,它有且只有一个,我们的鼠标与它交互;
  • 多个观察者其实需要多个联动的数据结构,以观察者 A 举例来说,它拥有自己的眼睛、渲染器和前端DOM,合在一起称为 group-A,它包括一些私有元素
    • camera-A
    • renderer-A & DOM-A
{
 // Bind the DOMs and renderers
  // groupA
 DOMA.appendChild(rendererA.domElement)
 // groupB
  DOMB.appendChild(rendererB.domElement)
 ...
}

// Animate with the groups
function animate({
  // Repeat in every frame
 requestAnimationFrame(animate);

 // Update the next frame
  /* Some beautiful codes */
 update(mesh)

  // Render the scene
 // render()
  // Render each group
 [groupA, groupB, groupC].map(group => {
  const {_camera, _renderer} = group;
  _renderer.render(scene, _camera);
 })
}

这样,就可以针对同一个场景进行不同视角的渲染。

下图中的辅助线就代表观察者的视角方向和视野大小。

多个观察者的三维场景
多个观察者的三维场景

多个观察者的三维场景

图中的三个球代表三个观察者,他们看到的视野如下图所示

同一场景的多观察者渲染
同一场景的多观察者渲染

同一场景的多观察者渲染

参考资料

[1]

Terrain-1: https://listenzcc.github.io/home-page-2/terrain-1/

分类:

后端

标签:

后端

作者介绍

张春成
V2