Skip to content
Li, Xizhi edited this page Jan 28, 2018 · 6 revisions

3D Programming

NPL/ParaEngine provides a rich set of graphical API and libraries to create a sophisticated interactive 3D application. ParaEngine used to be a full-featured computer game engine, it is now built-in with NPLRuntime. ParaEngine implementation is C/C++ based. All of its API can be accessed via NPL scripts.

Rendering Pipeline

The rendering pipeline is hard-coded into CSceneObject class. The shader code of all 3d objects is predefined, which allows us to switch between fixed-function, programmable or deferred shading pipeline at runtime. However, one can also specify custom shaders at per object level, but it is up to the programmer to change those shaders when user switch say from deferred shading to a standard programmable pipeline.

The main render function begins at CParaEngineApp::Render(), which calls the viewport manager's render function. A viewport manager generally have a single viewport, but in case of stereo display, it may have two or more.

m_pViewportManager->UpdateViewport(m_d3dpp.BackBufferWidth, m_d3dpp.BackBufferHeight);
m_pViewportManager->Render(fElapsedTime, PIPELINE_3D_SCENE);
m_pViewportManager->Render(fElapsedTime, PIPELINE_UI);
m_pViewportManager->Render(fElapsedTime, PIPELINE_POST_UI_3D_SCENE);

It will render 3d scene first, followed by UI objects and then some post rendering stuffs. All viewports share the same CSceneObject class and CGUIRoot class, and calls CSceneObject::AdvanceScene and CGUIRoot::AdvanceGUI respectively. CSceneObject is the main singleton class for managing all 3d objects in the world. The main 3d rendering pipeline is hard-coded in CSceneObject::AdvanceScene, roughly as below.

  • draw mini scene graphs with their own render targets
  • PrepareRender() and generate sceneState containing objects that should be rendered in this frame.
    • we will sort objects into different queues for different rendering orders according to a number of criteria, like distance to the camera, whether it is transparent, object's shader (materials), size of the object, etc.
  • objects with their own render targets
    • RenderSelection(RENDER_OWNER_DRAW);
    • render all reflection map in the scene.
    • pOcean->UpdateReflectionTexture(sceneState);
    • RenderShadowMap(); the global shadow map
    • BlockWorldClient::GetInstance()->PrepareAllRenderTargets(); prepare render target first for deferred shading if fancy graphics is enabled in block world.
  • Draw Opache objects
    • RenderSelection(RENDER_GLOBAL_TERRAIN);
    • m_pBlockWorldClient->Render(BlockRenderPass_Opaque); draw opaque blocks
    • m_pBlockWorldClient->Render(BlockRenderPass_AlphaTest);
    • RenderSelection(RENDER_MESH_FRONT_TO_BACK); big static meshes
    • RenderSelection(RENDER_MESH_BACK_TO_FRONT); small static meshes
    • RenderSelection(RENDER_SPRITES);
    • RenderSelection(RENDER_CHARACTERS); all animated characters
    • RenderSelection(RENDER_SELECTION);
    • RenderSelection(RENDER_SKY_BOX);
    • RenderSelection(RENDER_MISSILES);
    • m_pBlockWorldClient->DoPostRenderingProcessing(BlockRenderPass_Opaque); deferred shading for opaque objects so far
  • Draw Transparent objects
    • m_pBlockWorldClient->Render(BlockRenderPass_ReflectedWater);
    • m_pBatchedElementDraw->DrawBatchedParticles(true);
    • m_pBlockWorldClient->Render(BlockRenderPass_AlphaBlended); blocks with alpha blending texture
    • RenderSelection(RENDER_TRANSPARENT_CHARACTERS);
    • m_pBlockWorldClient->DoPostRenderingProcessing(BlockRenderPass_AlphaBlended); deferred shading for transparent objects
    • RenderHeadOnDisplay(0);
    • pOcean->Render(&sceneState);
    • RenderSelection(RENDER_MESH_TRANSPARENT);
    • RenderSelection(RENDER_TRANSLUCENT_FACE_GROUPS);
    • RenderSelection(RENDER_POST_RENDER_LIST);
    • RenderSelection(RENDER_PARTICLES, dTimeDelta);
  • Call post processing callbacks in the NPL
  • Draw debug objects
    • GetPhysicsInterface()->DebugDrawWorld();
    • RenderSelection(RENDER_BOUNDINGBOX);
  • RenderSelection(RENDER_PORTAL_SYSTEM);
  • RenderHeadOnDisplay(1); overlay objects

Shaders & Materials

We use a hard-coded pipeline with predefined shaders (materials) for a given type of objects. Right now, we do not have an easy way to change those shaders or customize materials without changing the core engine. This is because managing shaders for all platforms (android/ios/pc with DirectX/OpenGL with/without deferred shading) is a tough task and we will handle this task for you to create a general-purpose rendering pipeline that ensures everything can be rendered correctly on all platforms with or without fancy graphics.

However, we do allow developers to overwrite all of our predefined shaders via NPL scripts, adding post rendering shaders or specify a custom shader for a scene object. The developers, however, need to provide several versions of the custom shader in order to support all platforms and all graphics levels. Please note, the fixed function pipeline is hard-coded in C++ and cannot be altered. See following sections for details.

Replace System Shaders

Here (search for render_tech) is the list of all predefined id for these system shaders, replacing the id(handle) with your own shader file will replace the actual shader used.

The following code will replace all character rendering shaders to a custom shader at "script/ide/Effect/Shaders/frozen.fxo". *.fxo is compiled version of *.fx file.

NPL.load("(gl)script/ide/event_mapping.lua");
local my_effect = ParaAsset.LoadEffectFile("frozen", "script/ide/Effect/Shaders/frozen.fxo");
local params = my_effect:GetParamBlock();
params:SetTexture(1,"Texture/Aries/ShaderResource/frozenNoise.dds");
my_effect:SetHandle(render_tech.TECH_CHARACTER);

Specify Custom Shaders

script/ide/Effect/frozenEffect.lua is a custom effect that one can apply to any ParaObject via NPL.

Please note, user defined effect handle should use id larger than 1000. Id less than 1000 is reserved for system use.

local my_effectHandle = 1002;
my_paraobject:SetField("render_tech", my_effectHandle);

see script/ide/Effect for more examples

Add Post Rendering Shaders

see script/ide/PostProcessor.lua for examples.

see script/apps/Aries/Creator/Game/Effects/ShaderManager.lua for a more advanced example in paracraft. One can write a MOD that registered a new command for a new shader effect like this CommandEffect.lua

Example 3D Projects

  • Paracraft: is a 3D animation software written completely in NPL with over half million lines of NPL code.
  • Haqi: is a 3D MMORPG written completely in NPL with over 1 million lines of NPL code.
Clone this wiki locally